This is an automated email from the ASF dual-hosted git repository.
jamesbognar pushed a commit to branch docs
in repository https://gitbox.apache.org/repos/asf/juneau.git
The following commit(s) were added to refs/heads/docs by this push:
new f8a1283b51 docs: MCP v2 McpOptions config consolidation + Elicitation
split (TODO-330)
f8a1283b51 is described below
commit f8a1283b513935e6cc4872859fd39834547e668e
Author: James Bognar <[email protected]>
AuthorDate: Tue Aug 4 18:27:40 2026 -0700
docs: MCP v2 McpOptions config consolidation + Elicitation split (TODO-330)
Update MCP setup/recipe/reference pages and 10.0.0 release notes for the new
McpOptions aggregate config, per-binding stateful defaults, and the
ElicitationRequests / ElicitationResponses client-side split.
Co-authored-by: Cursor <[email protected]>
---
pages/release-notes/10.0.0.md | 17 ++++++-
pages/topics/11.02.JuneauMcpChoosingSetup.md | 2 +-
pages/topics/11.03.JuneauMcpRecipes.md | 15 ++++--
pages/topics/11.04.JuneauRestServerMcp.md | 75 ++++++++++++++++++++--------
pages/topics/11.05.JuneauRestClientMcp.md | 19 ++++---
5 files changed, 95 insertions(+), 33 deletions(-)
diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index d590bb9e81..3d1780a7b5 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -899,7 +899,7 @@ The `2026-07-28` bean and REST-server adapter modules
(`juneau-bean-mcp-v2026072
- **Cache hints** — `tools/list`, `prompts/list`, `resources/list`,
`resources/templates/list`, and `resources/read` results can each carry a
nullable, top-level `ttlMs` (`Integer`) and `cacheScope` (`McpCacheScope`:
`public`/`private`) pair, via the new `CacheableResult<T>` CRTP base that
`ListToolsResult`, `ListPromptsResult`, `ListResourcesResult`,
`ListResourceTemplatesResult`, and `ReadResourceResult` all extend. Fields are
omitted from the wire when unset — there is no forced defau [...]
- **`resources/templates/list`** — a new v2-only endpoint
(`McpMethods.RESOURCES_TEMPLATES_LIST`) listing `ResourceTemplate` descriptors
(`uriTemplate`, `name`, `title`, `description`, `mimeType`) registered via the
neutral `McpServerConfig.addResourceTemplate(McpResourceTemplateSpec)`.
Registering at least one resource template auto-derives the `resources`
capability, same as resources. The pre-built neutral `McpResourceTemplateSpec`
descriptor and this endpoint are designed for reuse b [...]
-- **Static, adapter-owned configuration only** — a server configures cache
hints once, at construction time, via the new `McpCacheConfig`/`McpCacheHint`
types (`createCacheConfig()` on `McpRestServlet`, `cacheConfig()` on
`McpEndpoint`). Precedence is atomic per list method (method-specific hint,
else a shared default, else no cache fields) and, for `resources/read`, adds an
exact-URI override map ahead of a `resourcesRead` default. Juneau does **not**
implement client-side caching, does [...]
+- **Static, adapter-owned configuration only** — a server configures cache
hints once, at construction time, via the new `McpCacheConfig`/`McpCacheHint`
types, mutated in place through the `cache(Consumer<McpCacheConfig>)`
configure-block on the `McpOptions` aggregate (see the config-consolidation
entry further down this page). Precedence is atomic per list method
(method-specific hint, else a shared default, else no cache fields) and, for
`resources/read`, adds an exact-URI override map [...]
See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#cache-hints-mcp-2026-07-28-sep-2549)
and
[juneau-bean-mcp-v20260728](/docs/topics/JuneauBeanMcp#mcp-2026-07-28-cache-hints-resource-templates)
for the full topics.
@@ -928,6 +928,21 @@ See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#resource-templates
See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#trace-context-propagation-mcp-2026-07-28)
(Spring Boot + trace-context sections),
[juneau-bean-mcp-v20260728](/docs/topics/JuneauBeanMcp#mcp-2026-07-28-metadata-and-trace-context-_meta)
(bean catalog), and
[Observability](/docs/topics/RestServerObservability#mcp-trace-context-propagation-2026-07-28)
(framework-level seam + OTel bridge) for the full topics.
+### MCP `2026-07-28` — `McpOptions` config consolidation (TODO-330)
+
+`2026-07-28`-only. The six previously-separate per-binding behavior-config
hooks the v2 adapter accumulated across the MRTR, cache-hints, and
subscriptions work above (`capabilities`, `instructions`, `cache`, `mrtr`,
`subscriptions`, `subscriptionBroker` — spread across mismatched `xxxConfig()`
single-method and `createXxx()`/`getXxx()` pair idioms, with divergent defaults
between the mixin and servlet paths) are consolidated into a single aggregate,
**before this never-shipped API's fir [...]
+
+- **New `McpOptions`** (`org.apache.juneau.rest.server.mcp.v20260728`) — a
mutable-setup fluent bean, same idiom as the neutral `McpServerConfig` and the
nested `McpCacheConfig`/`McpMrtrConfig`/`McpSubscriptionsConfig` types it
wraps. Plain `getXxx()`/`setXxx(...)` for
`capabilities`/`instructions`/`subscriptionBroker`, plus `Consumer`-style
configure-blocks (`cache(Consumer<McpCacheConfig>)`,
`mrtr(Consumer<McpMrtrConfig>)`,
`subscriptions(Consumer<McpSubscriptionsConfig>)`) that mutate [...]
+- **One override replaces six.** `McpRestServlet` gains `createMcpOptions()`
(mirroring `createMcpConfig()`); `McpEndpoint` gains `getMcpOptions()`
(mirroring `getMcpConfig()`). The prior six hooks (`capabilities()`,
`instructions()`, `cacheConfig()`/`createCacheConfig()`,
`mrtrConfig()`/`createMrtrConfig()`,
`subscriptionsConfig()`/`createSubscriptionsConfig()`, the v2
`subscriptionBroker()` override) and the wiring seam
`subscriptionsConfigBean()` are gone from the user-visible surface.
+- **Uniform per-binding memoization.** `McpOptions` is invoked once per
binding and published as a single internal `@Bean`, exactly like tools/prompts
— and this internal publication is authoritative, taking precedence over any
Spring `@Bean McpOptions` in the application context (Spring users inject their
configuration *into* the `createMcpOptions()`/`getMcpOptions()` override
instead of publishing a bare `@Bean McpOptions`). This also **unifies a prior
default-sharing inconsistency**: [...]
+- **Subscription broker folded in.** `McpOptions.getSubscriptionBroker()`
defaults to `null` ("framework-derived"): the binding lazily derives and
memoizes a `BasicMcpSubscriptionBroker` sized from `subscriptions`'
`queueSize`. Call `setSubscriptionBroker(...)` to supply a custom broker
instead.
+- **Client-side elicitation naming split, for symmetry.**
`org.apache.juneau.rest.client.mcp.v20260728.ElicitationAccess` is replaced by
an `ElicitationRequests` (reading server→client requests:
`isInputRequired`/`requests`/`requestState`) + `ElicitationResponses` (encoding
client→server answers: `toInputResponse`/`toInputResponses`) pair, matching the
naming already used by the server-side helpers of the same names.
+- **Neutral core untouched.** `juneau-rest-server-mcp`'s revision-neutral
`subscriptionBroker()`/`getSubscriptionBroker()` seam is unchanged; only the v2
adapter delegates through `McpOptions`.
+
+Because `McpOptions` and the v2 adapter are never-shipped 10.0.0 APIs, this is
a clean replace with no deprecation shims.
+
+See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#configuring-the-endpoint-mcpoptions-mcp-2026-07-28)
and
[juneau-rest-client-mcp](/docs/topics/JuneauRestClientMcp#elicitation-mcp-2026-07-28-sep-2322)
for the full topics.
+
### Bug Fixes
- **Fixed RRPC method calls never dispatching over POST.** Every HTTP POST to
an `@RestOp(method="RRPC")` operation previously returned a 404 instead of
reaching the target method. `RrpcRestOpSession` derived the RRPC method key by
splitting the request path on the last `/`, but RRPC keys are of the form
`methodName/(paramTypes)` and themselves contain a `/`, so the method name was
stripped off and the lookup always fell through to `NotFound`. The key is now
derived from the already-comp [...]
diff --git a/pages/topics/11.02.JuneauMcpChoosingSetup.md
b/pages/topics/11.02.JuneauMcpChoosingSetup.md
index 79e82caf27..41ea7989ec 100644
--- a/pages/topics/11.02.JuneauMcpChoosingSetup.md
+++ b/pages/topics/11.02.JuneauMcpChoosingSetup.md
@@ -28,7 +28,7 @@ If you don't have a specific reason to target `2025-06-18`
(an existing client t
## 2. Dedicated servlet vs mixin
-Both paths bind the same revision and expose the same hooks (`capabilities()`,
cache/MRTR/subscriptions config); they differ only in how the endpoint attaches
to your REST resource.
+Both paths bind the same revision and expose the same config surface —
`getMcpConfig()`/`createMcpConfig()` for tool/prompt/resource registration,
plus (on `2026-07-28`) a single `getMcpOptions()`/`createMcpOptions()` override
for behavior configuration
(capabilities/instructions/cache/MRTR/subscriptions/broker, all on one
`McpOptions` bean) — they differ only in how the endpoint attaches to your REST
resource.
**Dedicated servlet** — use when MCP is the *only* thing this resource does,
or you're starting fresh:
diff --git a/pages/topics/11.03.JuneauMcpRecipes.md
b/pages/topics/11.03.JuneauMcpRecipes.md
index 1ee82c7bc3..3151bf9255 100644
--- a/pages/topics/11.03.JuneauMcpRecipes.md
+++ b/pages/topics/11.03.JuneauMcpRecipes.md
@@ -226,7 +226,7 @@ McpToolHandler confirmDeleteTool = McpToolHandler.of(
- The client answers, then re-sends the call; on that round,
`McpMrtrResumeContext` is present, and `ElicitationResponses.get(ctx, id)`
decodes the typed `ElicitResult` keyed by the same `id` you posed the question
under.
- `ElicitResult.getContent()` is populated only when `getAction() ==
ElicitAction.ACCEPT`; a `DECLINE`/`CANCEL` answer carries no content.
-This requires no special server config beyond a v2 servlet/mixin — MRTR
support is on by default (see
`AbstractMcpRestServlet.createMrtrConfig()`/`McpRestServlet.getMrtrConfig()` in
the [server reference](/docs/topics/JuneauRestServerMcp) to customize the
codec, TTL, or round cap).
+This requires no special server config beyond a v2 servlet/mixin — MRTR
support is on by default (see `McpOptions.mrtr(Consumer<McpMrtrConfig>)` in the
[server reference](/docs/topics/JuneauRestServerMcp) to customize the codec,
TTL, or round cap).
## Subscriptions (v2 only)
@@ -252,12 +252,19 @@ McpToolHandler touchFileTool = McpToolHandler.of(
`McpSubscriptions` also exposes `toolsListChanged()`, `promptsListChanged()`,
and `resourcesListChanged()` for list-level notifications.
-Optionally tune the broker (queue size, heartbeat, idle timeout) by overriding
a hook on your servlet/endpoint:
+Optionally tune the broker (queue size, heartbeat, idle timeout) via the
`subscriptions(Consumer<McpSubscriptionsConfig>)` configure-block on your
servlet/endpoint's `McpOptions`:
```java
+// servlet path
@Override
-protected McpSubscriptionsConfig createSubscriptionsConfig() {
- return new McpSubscriptionsConfig().setIdleTimeoutMs(5 * 60_000L);
+protected McpOptions createMcpOptions() {
+ return new McpOptions().subscriptions(s -> s.setIdleTimeoutMs(5 *
60_000L));
+}
+
+// mixin path
+@Override
+public McpOptions getMcpOptions() {
+ return new McpOptions().subscriptions(s -> s.setIdleTimeoutMs(5 *
60_000L));
}
```
diff --git a/pages/topics/11.04.JuneauRestServerMcp.md
b/pages/topics/11.04.JuneauRestServerMcp.md
index 4ab2d2e024..11102bba9c 100644
--- a/pages/topics/11.04.JuneauRestServerMcp.md
+++ b/pages/topics/11.04.JuneauRestServerMcp.md
@@ -502,10 +502,45 @@ A prompt argument's `completer` is server behavior only —
it's never mapped on
### Completions capability
-Both dated `ServerCapabilities` gain a nullable `completions` property,
auto-derived alongside `tools`/`prompts`/`resources`: it's advertised (as an
empty `{}` `CompletionCapability` marker) only when at least one
prompt-argument completer or resource-template variable completer is currently
registered — registering a template or prompt with no completer does not turn
it on. As with the other auto-derived capability flags, an explicit
`ServerCapabilities` override on the servlet/mixin `c [...]
+Both dated `ServerCapabilities` gain a nullable `completions` property,
auto-derived alongside `tools`/`prompts`/`resources`: it's advertised (as an
empty `{}` `CompletionCapability` marker) only when at least one
prompt-argument completer or resource-template variable completer is currently
registered — registering a template or prompt with no completer does not turn
it on. As with the other auto-derived capability flags, an explicit
`ServerCapabilities` override remains authoritative a [...]
See
[juneau-bean-mcp-v20250618](/docs/topics/JuneauBeanMcp#completions-completioncomplete-new-in-1000)
for the `2025-06-18` completion wire-bean catalog (`CompleteRequest`,
`CompletionReference`/`PromptReference`/`ResourceTemplateReference`,
`CompletionArgument`, `CompletionContext`, `CompleteResult`, `Completion`,
`CompletionCapability`) and the equivalent `2026-07-28` family.
+## Configuring the endpoint: `McpOptions` (MCP `2026-07-28`)
+
+**v2-only.** `McpOptions` (`org.apache.juneau.rest.server.mcp.v20260728`) is
the single behavior-configuration aggregate for a `2026-07-28` binding —
"*how*" the endpoint behaves, alongside the neutral `McpServerConfig`'s
"*what*" it exposes (tools/prompts/resources). It consolidates six
previously-separate hooks (`capabilities`, `instructions`, `cache`, `mrtr`,
`subscriptions`, `subscriptionBroker`) into one mutable-setup fluent bean,
supplied by a single override on each path:
+
+```java
+// Servlet-subclass path
+@Rest(path="/mcp")
+public class MyMcpServlet extends McpRestServlet {
+ @Override protected McpServerConfig createMcpConfig() {
+ return new McpServerConfig().setName("my-server").addTool(new
MyEchoTool());
+ }
+ @Override protected McpOptions createMcpOptions() { // optional
+ return new McpOptions()
+ .setInstructions("Use tool 'echo' to test.")
+ .cache(c -> c.setToolsList(new McpCacheHint().setTtlMs(60_000)))
+ .subscriptions(s -> s.setQueueSize(2048));
+ }
+}
+
+// Mixin path (incl. Spring via SpringMcpRestServlet)
+@Rest(path="/api")
+public class MyResource extends BasicRestServlet implements McpEndpoint {
+ @Override public McpServerConfig getMcpConfig() { return new
McpServerConfig().addTool(new MyEchoTool()); }
+ @Override public McpOptions getMcpOptions() { return new
McpOptions().mrtr(m -> m.setTtlMs(600_000)); }
+}
+```
+
+Both `getCapabilities()`/`getInstructions()` are plain
`getXxx()`/`setXxx(...)` properties. The three nested configs (`cache` →
`McpCacheConfig`, `mrtr` → `McpMrtrConfig`, `subscriptions` →
`McpSubscriptionsConfig`) are framework-owned instances: use the
`cache(Consumer<McpCacheConfig>)`/`mrtr(Consumer<McpMrtrConfig>)`/`subscriptions(Consumer<McpSubscriptionsConfig>)`
configure-blocks to mutate them in place rather than constructing (and needing
to remember to keep stable) a replacement [...]
+
+`McpOptions` is memoized exactly once per binding — the framework invokes
`createMcpOptions()`/`getMcpOptions()` once and publishes the single result as
an internal `@Bean`. This memoization matters because two of the six concepts
are stateful: `mrtr` holds a random AES key (a sealed `requestState` can't be
unsealed under a different key) and the subscription broker holds the live
per-connection registry (a fresh one would silently split publishers from
subscribers). Every binding gets i [...]
+
+This internal `@Bean` publication is **authoritative** and takes precedence
over any Spring `@Bean McpOptions` in the application context — publishing a
bare `@Bean McpOptions` in a Spring context does **not** get picked up in place
of it. Spring users who want their configuration honored must inject their bean
*into* the `createMcpOptions()`/`getMcpOptions()` override instead (for
example, an `@Autowired` field read from there), as shown above.
+
+`getSubscriptionBroker()` defaults to `null`, meaning "framework-derived": the
binding lazily derives a `BasicMcpSubscriptionBroker` sized from
`subscriptions`' `queueSize` the first time one is needed, and memoizes that
single derived instance for the binding's lifetime. Call
`setSubscriptionBroker(...)` to supply a custom broker instead (for example,
one deliberately shared across multiple bindings).
+
## Cache Hints (MCP `2026-07-28`, SEP-2549)
The `2026-07-28` adapter (`org.apache.juneau.rest.server.mcp.v20260728`) adds
two capabilities on top of the neutral core: SEP-2549 cache hints on five
list/read results, and a `resources/templates/list` endpoint. Both are
configured statically, at server-construction time — there is no
dynamic/per-request cache callback, and neither concept exists on the neutral
`juneau-rest-server-mcp` core or the `2025-06-18` adapter.
@@ -516,36 +551,34 @@ Resource templates are registered on the same neutral
`McpServerConfig` used for
### Configuring cache hints
-`McpCacheConfig` (adapter-owned, immutable after construction) carries one
`McpCacheHint` (nullable `ttlMs` + `McpCacheScope`) per list method, plus a
`resourcesRead` default and an exact-URI override map for individual resource
reads:
+`McpCacheConfig` carries one `McpCacheHint` (nullable `ttlMs` +
`McpCacheScope`) per list method, plus a `resourcesRead` default and an
exact-URI override map for individual resource reads. It's one of the nested
configs on `McpOptions` — mutate it in place via the
`cache(Consumer<McpCacheConfig>)` configure-block on the servlet's
`createMcpOptions()` (or the mixin's `getMcpOptions()`):
```java
-private final McpCacheConfig cache = new McpCacheConfig()
- .setDefaultHint(new McpCacheHint().setTtlMs(60_000))
- .setToolsList(new McpCacheHint().setTtlMs(0))
- .setResourcesRead(new
McpCacheHint().setCacheScope(McpCacheScope.PUBLIC))
- .addResourceReadOverride("file:///private",
- new
McpCacheHint().setTtlMs(5_000).setCacheScope(McpCacheScope.PRIVATE));
-
@Override protected McpServerConfig createMcpConfig() {
return new McpServerConfig().addResourceTemplate(new
McpResourceTemplateSpec()
.setUriTemplate("file:///{name}").setName("files").setMimeType("text/plain"));
}
-@Override protected McpCacheConfig createCacheConfig() {
- return cache;
+@Override protected McpOptions createMcpOptions() {
+ return new McpOptions().cache(c -> c
+ .setDefaultHint(new McpCacheHint().setTtlMs(60_000))
+ .setToolsList(new McpCacheHint().setTtlMs(0))
+ .setResourcesRead(new
McpCacheHint().setCacheScope(McpCacheScope.PUBLIC))
+ .addResourceReadOverride("file:///private",
+ new
McpCacheHint().setTtlMs(5_000).setCacheScope(McpCacheScope.PRIVATE)));
}
```
-The `McpEndpoint` mixin path is the same shape, with a stable `cacheConfig()`
override instead of `createCacheConfig()`:
+The `McpEndpoint` mixin path reads the same shape from `getMcpOptions()`:
```java
-private final McpCacheConfig cache = new McpCacheConfig().setToolsList(new
McpCacheHint().setTtlMs(0));
-
-@Override public McpCacheConfig cacheConfig() {
- return cache;
+@Override public McpOptions getMcpOptions() {
+ return new McpOptions().cache(c -> c.setToolsList(new
McpCacheHint().setTtlMs(0)));
}
```
+`McpOptions` is memoized once per binding (see [Configuring the endpoint:
`McpOptions`](#configuring-the-endpoint-mcpoptions-mcp-2026-07-28) above), so
`cache` behaves as effectively-immutable after construction, exactly as before.
+
**Precedence is atomic — a matched hint's `ttlMs`/`cacheScope` pair is applied
as a whole, never merged field-by-field with a lower-precedence hint:**
- **List methods** (`tools/list`, `prompts/list`, `resources/list`,
`resources/templates/list`): the method-specific hint (e.g. `toolsList`) if
set, else `defaultHint` if set, else no cache fields are written at all. An
explicitly-set *empty* hint (both fields `null`) at a higher precedence still
suppresses the lower one — it does not fall through.
@@ -665,19 +698,19 @@ Only the sealed `continuation` is tamper-evident across
rounds; the per-round `a
### Configuring MRTR: `McpMrtrConfig`
-`McpMrtrConfig` is the adapter-owned configuration bean, placed exactly like
`McpCacheConfig` (v2-adapter-only, never on the neutral core). It carries the
`RequestStateCodec`, a `requestState` TTL (default 5 minutes), and a max-rounds
cap (default 10). Supply it via the servlet's `createMrtrConfig()` hook (or the
mixin's `mrtrConfig()`):
+`McpMrtrConfig` is the adapter-owned configuration bean, placed exactly like
`McpCacheConfig` (v2-adapter-only, never on the neutral core). It carries the
`RequestStateCodec`, a `requestState` TTL (default 5 minutes), and a max-rounds
cap (default 10). It's one of the nested configs on
[`McpOptions`](#configuring-the-endpoint-mcpoptions-mcp-2026-07-28) — mutate it
in place via the `mrtr(Consumer<McpMrtrConfig>)` configure-block:
```java
@Override
-protected McpMrtrConfig createMrtrConfig() {
- return new McpMrtrConfig()
+protected McpOptions createMcpOptions() {
+ return new McpOptions().mrtr(m -> m
.setCodec(new AeadRequestStateCodec()) // or a shared/rotating-key
implementation
.setTtlMs(5 * 60 * 1000L)
- .setMaxRounds(10);
+ .setMaxRounds(10));
}
```
-The config is memoized at binding time and treated as read-only afterward
(each `AeadRequestStateCodec` holds a distinct random key, so exactly one
instance must be published per binding).
+`McpOptions` (and hence `mrtr`) is memoized once per binding and treated as
read-only afterward (each `AeadRequestStateCodec` holds a distinct random key,
so exactly one instance must be published per binding — the mixin path gets its
own per-binding key too, with no sharing across separate endpoint instances).
### Error codes
diff --git a/pages/topics/11.05.JuneauRestClientMcp.md
b/pages/topics/11.05.JuneauRestClientMcp.md
index 5f7cb606b7..eb0ac42497 100644
--- a/pages/topics/11.05.JuneauRestClientMcp.md
+++ b/pages/topics/11.05.JuneauRestClientMcp.md
@@ -31,24 +31,31 @@ The illustrative server-initiated method name used
elsewhere in this codebase's
## Elicitation (MCP `2026-07-28`, SEP-2322)
-**v2-only.** `org.apache.juneau.rest.client.mcp.v20260728.ElicitationAccess`
is a static helper for driving elicitation over `McpClient.callRaw(...)`'s raw
`Map<String,Object>` result — the typed `callTool`/`getPrompt`/`readResource`
methods cannot represent a paused `input_required` result or set
`requestState`/`inputResponses` on a resume call, so a caller must go through
`callRaw(...)` for the resumable leg of the loop.
+**v2-only.** Two static helper classes in
`org.apache.juneau.rest.client.mcp.v20260728` drive elicitation over
`McpClient.callRaw(...)`'s raw `Map<String,Object>` result — the typed
`callTool`/`getPrompt`/`readResource` methods cannot represent a paused
`input_required` result or set `requestState`/`inputResponses` on a resume
call, so a caller must go through `callRaw(...)` for the resumable leg of the
loop:
+
+| Helper | Purpose |
+|---|---|
+| `ElicitationRequests` | Reads the server's `input_required` pause out of a
raw result: `isInputRequired`, `requests` (`Map<String, ElicitRequest>`),
`requestState`. |
+| `ElicitationResponses` | Encodes the client's answers back into a resume
call: `toInputResponse`/`toInputResponses`. |
+
+This mirrors the server-side `ElicitationRequests`/`ElicitationResponses` pair
(see
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#elicitation-mcp-2026-07-28-sep-2322))
— same class names, same direction-pair scheme, disambiguated by package: the
client *reads* requests / *writes* responses, the server *writes* requests /
*reads* responses.
```java
import org.apache.juneau.bean.mcp.v20260728.*;
import org.apache.juneau.rest.client.mcp.v20260728.*;
var paused = client.callRaw(McpMethods.TOOLS_CALL, new
CallToolRequest().setName("confirm").setArguments(Map.of()));
-if (ElicitationAccess.isInputRequired(paused)) {
- var questions = ElicitationAccess.requests(paused); // Map<String,
ElicitRequest>
+if (ElicitationRequests.isInputRequired(paused)) {
+ var questions = ElicitationRequests.requests(paused); // Map<String,
ElicitRequest>
// ... show questions.get("confirm").getMessage() to the end user, collect
an answer ...
var answer = new
ElicitResult().setAction(ElicitAction.ACCEPT).putContent("confirm", true);
var completed = client.callRaw(McpMethods.TOOLS_CALL, new
CallToolRequest().setName("confirm")
- .setRequestState(ElicitationAccess.requestState(paused))
- .setInputResponses(ElicitationAccess.toInputResponse("confirm",
answer)));
+ .setRequestState(ElicitationRequests.requestState(paused))
+ .setInputResponses(ElicitationResponses.toInputResponse("confirm",
answer)));
}
```
-`ElicitationAccess` works at the raw map/JSON level rather than exposing typed
overloads per concrete request bean, because
`CallToolRequest`/`GetPromptRequest`/`ReadResourceRequest` share no common
"has-`inputResponses`-and-`requestState`" interface — a caller resuming a
specific one of the three makes its own final
`.setInputResponses(...).setRequestState(...)` call on the concrete bean it
already knows it holds.
`ElicitationAccess.toInputResponses(Map<String,ElicitResult>)` encodes se [...]
+Both helpers work at the raw map/JSON level rather than exposing typed
overloads per concrete request bean, because
`CallToolRequest`/`GetPromptRequest`/`ReadResourceRequest` share no common
"has-`inputResponses`-and-`requestState`" interface — a caller resuming a
specific one of the three makes its own final
`.setInputResponses(...).setRequestState(...)` call on the concrete bean it
already knows it holds.
`ElicitationResponses.toInputResponses(Map<String,ElicitResult>)` encodes
several [...]
See
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#elicitation-mcp-2026-07-28-sep-2322)
for the server-side helper half of this loop.