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 2fcfc66d7d docs: MCP 2026-07-28 _meta / trace-context + Spring Boot 
setup (TODO-312c3)
2fcfc66d7d is described below

commit 2fcfc66d7d603626a24f4b75342e6ad7d1450f49
Author: James Bognar <[email protected]>
AuthorDate: Sat Aug 1 10:36:35 2026 -0400

    docs: MCP 2026-07-28 _meta / trace-context + Spring Boot setup (TODO-312c3)
    
    - Page 11 (juneau-rest-server-mcp): add "Running Under Spring Boot" 
(recommend
      SpringMcpRestServlet / the BasicSpringRestServlet + McpEndpoint mixin; 
caution
      that subclassing McpRestServlet under Spring Boot loses the 
SpringBeanStore
      bridge) and a Trace-Context Propagation section (params._meta carrier,
      _meta-wins precedence, result._meta echo, gen_ai.*/mcp.* attributes,
      recordRpcError mapping).
    - Page 05.07 (juneau-bean-mcp): document the reshaped v2 _meta beans
      (RequestParams/RequestMeta/Result/ResultMeta/Icon/PingResult, resultType,
      ServerDiscoverResult -> CacheableResult); fix a broken cache-hints anchor.
    - Page 10.40 (observability): neutral tracing seam + OTel bridge + pinned
      experimental semconv snapshot.
    - Release notes 10.0.0: MCP _meta reshape, trace-context propagation,
      SpringMcpRestServlet.
    
    Co-authored-by: Cursor <[email protected]>
---
 pages/release-notes/10.0.0.md                 |  10 ++
 pages/topics/05.07.JuneauBeanMcp.md           |  36 +++++-
 pages/topics/10.40.RestServerObservability.md | 100 ++++++++++++++++
 pages/topics/11.JuneauRestServerMcp.md        | 157 ++++++++++++++++++++++++++
 4 files changed, 301 insertions(+), 2 deletions(-)

diff --git a/pages/release-notes/10.0.0.md b/pages/release-notes/10.0.0.md
index 633feb1fa5..e39debca39 100644
--- a/pages/release-notes/10.0.0.md
+++ b/pages/release-notes/10.0.0.md
@@ -908,6 +908,16 @@ Building on the `resources/templates/list` endpoint above, 
10.0.0 makes register
 
 See 
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#resource-templates-reads-and-completions)
 and 
[juneau-bean-mcp-v20250618](/docs/topics/JuneauBeanMcp#completions-completioncomplete-new-in-1000)
 for the full topics.
 
+### MCP `2026-07-28` — `_meta` wire compliance + trace-context propagation + 
Spring Boot convenience class
+
+`2026-07-28`-only. Brings `juneau-bean-mcp-v20260728`'s per-request/per-result 
metadata into exact alignment with the MCP `2026-07-28` schema, adds 
distributed trace-context propagation through that same `_meta` carrier, and 
adds a Spring Boot convenience base class. `2025-06-18` is untouched by all 
three changes.
+
+- **`_meta` wire-compliance reshape.** The neutral JSON-RPC envelope beans 
(`JsonRpcRequest`/`JsonRpcResponse`) carry no `_meta` property; it now lives 
under `params._meta` (new `RequestMeta`, via a new `RequestParams<T>` CRTP base 
on 
`CallToolRequest`/`GetPromptRequest`/`ReadResourceRequest`/`CompleteRequest`, 
plus `RequestParamsOnly` for the metadata-only methods) with the exact 
`io.modelcontextprotocol/`-prefixed negotiation keys the schema mandates, and 
under `result._meta` (new `Res [...]
+- **Trace-context propagation.** `params._meta` may additionally carry bare 
(unprefixed) W3C `traceparent`/`tracestate`/`baggage` keys. When an active 
`TracerHook` is registered, an explicit `params._meta` value wins over the 
equivalent HTTP header (independently per field); the active trace context is 
echoed back into `result._meta` on success; and the OpenTelemetry bridge (when 
present) enriches the span with pinned, experimental `gen_ai.*`/`mcp.*` 
attributes and maps JSON-RPC errors ( [...]
+- **`SpringMcpRestServlet` convenience class (both revisions).** A new 
`SpringMcpRestServlet` 
(`org.apache.juneau.rest.server.mcp.v20250618.SpringMcpRestServlet` and 
`.v20260728.SpringMcpRestServlet`) combines `BasicSpringRestServlet` with the 
revision's `McpEndpoint` mixin — the simplest way to expose MCP from a Spring 
Boot resource with full Spring dependency-injection support in 
tool/prompt/resource handlers; implement only `getMcpConfig()`. **Don't** 
subclass the plain `McpRestServle [...]
+
+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.
+
 ### 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/05.07.JuneauBeanMcp.md 
b/pages/topics/05.07.JuneauBeanMcp.md
index 799cb4cb2c..f41750a501 100644
--- a/pages/topics/05.07.JuneauBeanMcp.md
+++ b/pages/topics/05.07.JuneauBeanMcp.md
@@ -265,7 +265,7 @@ String yaml = Yaml.of(r);
 
 Set `addBeanTypes` and the discriminator property names on the corresponding 
builders to round-trip polymorphic content correctly.
 
-## MCP `2026-07-28` — Cache Hints & Resource Templates
+## MCP `2026-07-28`: Cache Hints, Resource Templates
 
 The sibling `juneau-bean-mcp-v20260728` module (package 
`org.apache.juneau.bean.mcp.v20260728`) adds SEP-2549 cache hints and a 
`resources/templates/list` result to its own revision of the wire beans covered 
above. Both are opt-in, top-level, nullable fields/beans — omitted entirely 
from the wire when unset.
 
@@ -288,7 +288,39 @@ A compact example showing both features on the same result:
 
 ### `2026-07-28` completions (`completion/complete`, new in 10.0.0)
 
-`juneau-bean-mcp-v20260728` gained the same nine-bean completion family 
described above for `2025-06-18` — `CompleteRequest`, `CompletionReference` 
(with `PromptReference`/`ResourceTemplateReference` subtypes, 
`ref/prompt`/`ref/resource` discriminators), `CompletionArgument`, 
`CompletionContext`, `CompleteResult`, `Completion`, and `CompletionCapability` 
— as an independent copy in `org.apache.juneau.bean.mcp.v20260728`, with 
`McpMethods.COMPLETION_COMPLETE` (`"completion/complete"`). Fi [...]
+`juneau-bean-mcp-v20260728` gained the same nine-bean completion family 
described above for `2025-06-18` — `CompleteRequest`, `CompletionReference` 
(with `PromptReference`/`ResourceTemplateReference` subtypes, 
`ref/prompt`/`ref/resource` discriminators), `CompletionArgument`, 
`CompletionContext`, `CompleteResult`, `Completion`, and `CompletionCapability` 
— as an independent copy in `org.apache.juneau.bean.mcp.v20260728`, with 
`McpMethods.COMPLETION_COMPLETE` (`"completion/complete"`). Fi [...]
+
+## MCP `2026-07-28` Metadata and Trace-Context (`_meta`)
+
+10.0.0 also brings `juneau-bean-mcp-v20260728`'s per-request/per-result 
metadata into exact alignment with the MCP `2026-07-28` schema. This is a 
correction to the wire shape (an unreleased-10.0.0 fix, not a compatibility 
mode — there's no old-shape fallback) and is `2026-07-28`-only; `2025-06-18` 
has no `_meta` concept and is untouched by it.
+
+The neutral JSON-RPC envelope beans (`JsonRpcRequest`/`JsonRpcResponse` in 
[juneau-bean-jsonrpc](/docs/topics/JuneauBeanJsonRpc)) carry **no** `_meta` 
property. Per-request metadata instead lives one level down, under 
`params._meta`; per-result metadata lives under `result._meta`.
+
+| Bean | Purpose |
+|---|---|
+| `RequestParams<T>` | Abstract CRTP base for the four concrete request-params 
beans (`CallToolRequest`, `GetPromptRequest`, `ReadResourceRequest`, 
`CompleteRequest`), contributing the optional `_meta` (`RequestMeta`) property. 
|
+| `RequestParamsOnly` | Concrete params bean for the methods whose only member 
is `_meta` — `*/list`, `ping`, `server/discover`. |
+| `RequestMeta` | Per-request metadata: required 
`io.modelcontextprotocol/protocolVersion`, optional 
`io.modelcontextprotocol/clientInfo` (an `Implementation`), required 
`io.modelcontextprotocol/clientCapabilities`, deprecated-but-accepted 
`io.modelcontextprotocol/logLevel`, and bare (unprefixed) W3C trace-context 
keys `traceparent`/`tracestate`/`baggage`. Declares the wire-key names as 
`public static final String` constants (`KEY_PROTOCOL_VERSION`, 
`KEY_CLIENT_INFO`, `KEY_CLIENT_CAPABIL [...]
+| `Result<T>` | Abstract CRTP base for every successful result, contributing 
`resultType` (an open string; defaults to `"complete"`) and optional `_meta` 
(`ResultMeta`). `CacheableResult<T>` (see above) extends it, so the five 
cacheable results inherit it transitively; `CallToolResult`, `GetPromptResult`, 
`CompleteResult`, `PingResult`, and `ServerDiscoverResult` all extend it 
directly or transitively. |
+| `ResultMeta` | Per-result metadata: `io.modelcontextprotocol/serverInfo` (an 
`Implementation`, the server's own identity) plus bare 
`traceparent`/`tracestate`/`baggage`, populated when an active tracer echoes 
the request's trace context back to the caller. Declares `KEY_SERVER_INFO` as 
its wire-key constant; same extension-map shape as `RequestMeta`. |
+| `PingResult` | Typed, empty success result for `ping` (previously an untyped 
`JsonMap`). |
+| `Icon` | One entry of `Implementation.icons`: required `src`, optional 
`mimeType`, ordered `sizes`, and `theme` (`Icon.Theme`: `light`/`dark`). |
+
+`Implementation` gains optional `title`, `description`, and ordered `icons` 
(`List<Icon>`) alongside its existing `name`/`version`. `ClientCapabilities` 
and `ServerCapabilities` both gain a schema-defined `extensions` map (with a 
`put*Extensions(name, value)` convenience setter on each) — distinct from the 
pre-existing free-form `experimental` bag, which stays client-side only.
+
+`ServerDiscoverResult` (the `server/discover` result) now extends 
`CacheableResult<ServerDiscoverResult>`, inheriting `resultType`/`_meta`/cache 
hints, and adds required `supportedVersions` (`["2026-07-28"]`), 
`capabilities`, and optional `instructions`. Server identity moved off a 
top-level `serverInfo` field onto the inherited `_meta` 
(`ResultMeta.serverInfo`) — the same place every other result now carries it.
+
+A representative `tools/call` round trip showing the full `_meta` shape on 
both sides:
+
+```json
+// Request
+{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"echo","arguments":{"text":"hello"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientInfo":{"name":"my-client","version":"1.0"},"io.modelcontextprotocol/clientCapabilities":{}}}}
+
+// Response
+{"jsonrpc":"2.0","id":1,"result":{"resultType":"complete","_meta":{"io.modelcontextprotocol/serverInfo":{"name":"my-server","version":"1.0.0"}},"content":[{"type":"text","text":"hello"}]}}
+```
+
+Trace-context propagation (the `traceparent`/`tracestate`/`baggage` keys 
above) is a REST-server-adapter behavior, not a bean-level one — see 
[Trace-Context 
Propagation](/docs/topics/JuneauRestServerMcp#trace-context-propagation-mcp-2026-07-28)
 on the `juneau-rest-server-mcp` topic and 
[Observability](/docs/topics/RestServerObservability) for the full mechanism.
 
 ## Related Modules
 
diff --git a/pages/topics/10.40.RestServerObservability.md 
b/pages/topics/10.40.RestServerObservability.md
index b5d98c72a4..f6413ab30f 100644
--- a/pages/topics/10.40.RestServerObservability.md
+++ b/pages/topics/10.40.RestServerObservability.md
@@ -309,6 +309,106 @@ Set the `RestContext.responseTraceparent` environment / 
system property to `fals
 
 The default is `true` (on-when-tracer). A per-resource `@Rest`-annotation 
opt-out is tracked as a follow-on.
 
+## MCP Trace-Context Propagation (`2026-07-28`)
+
+MCP `2026-07-28` endpoints are ordinary `@RestOp`s — `POST /` on 
`McpRestServlet`, `POST /mcp` on `McpEndpoint` — so everything above (the 
off-by-default contract, `TracerHook`, the OpenTelemetry bridge, 
response-header injection) already applies to them with **no MCP-specific 
wiring**. This section documents the one MCP-specific extension: a second, 
non-HTTP place a trace context can travel — the JSON-RPC request's own 
`params._meta` — and the neutral seam that makes that possible witho [...]
+
+**v2-only.** Trace-context propagation is a `2026-07-28` feature; `2025-06-18` 
keeps its original HTTP-header-only tracing behavior unchanged — no `_meta`, no 
trace echo.
+
+### The neutral carrier seam
+
+`RestOpInvoker` already resolves every `@RestOp` handler argument before it 
asks the active `TracerHook` for a span. Three neutral types in 
`juneau-rest-server` let a non-HTTP argument (like a parsed MCP 
`JsonRpcRequest`) participate in that decision without OpenTelemetry — or any 
tracer implementation — knowing what MCP or JSON-RPC are:
+
+```java
+public interface TraceContextCarrier {
+    String get(String key);
+    Iterable<String> keys();
+    void set(String key, String value);
+}
+
+public interface TraceContextExtractor {
+    Optional<TraceContextCarrier> extract(RestRequest request, Object[] 
resolvedArguments);
+    default TraceOperation operation(RestRequest request, Object[] 
resolvedArguments) {
+        return TraceOperation.DEFAULT;
+    }
+}
+```
+
+- **`TraceContextCarrier`** is a read/write key-value view over W3C fields 
(`traceparent`/`tracestate`/`baggage`) from a source that need not be HTTP 
headers.
+- **`TraceContextExtractor`** is a bean an adapter (like the `2026-07-28` MCP 
binding) publishes; it inspects the already-resolved handler arguments and, if 
it recognizes one, hands back a carrier plus a **`TraceOperation`** — an 
immutable, low-cardinality span name and attribute set the bridge should use 
instead of its own HTTP-derived defaults.
+- **Extraction only happens when a non-no-op `TracerHook` is active.** A 
resource with no registered `TracerHook` never resolves a 
`TraceContextExtractor` either — the existing zero-allocation no-tracer fast 
path is unchanged.
+
+`TracerHook` gains two source-compatible default methods so every existing 
implementation — including a bare lambda implementing only 
`startSpan(RestRequest)` — keeps compiling unchanged:
+
+```java
+default Scope startSpan(RestRequest request, TraceContextCarrier carrier, 
TraceOperation operation) {
+    return startSpan(request); // ignores carrier/operation unless overridden
+}
+
+default void inject(TraceContextCarrier carrier) {
+    // no-op unless overridden
+}
+```
+
+`Scope` gains one more source-compatible default, for observing a 
JSON-RPC-level error on an already-HTTP-200 response (see below):
+
+```java
+default void recordRpcError(int code, String message) {
+    // no-op unless overridden
+}
+```
+
+### `params._meta` — a second carrier, not a new protocol
+
+The `2026-07-28` MCP adapter (`juneau-rest-server-mcp-v20260728`) publishes a 
stable `TraceContextExtractor` from both `McpRestServlet` and `McpEndpoint` (as 
a `@Bean mcpTraceContextExtractor()`). It recognizes the resolved 
`JsonRpcRequest` argument and reads its `params._meta`, which may carry the 
bare (unprefixed) W3C fields `traceparent`, `tracestate`, and `baggage` 
alongside the `io.modelcontextprotocol/`-prefixed negotiation keys. The 
extractor hands the bridge a **composite** carrier:
+
+```text
+lookup(key) = params._meta[key] if present, otherwise the HTTP header of the 
same name
+```
+
+**An explicit `params._meta` value wins over the equivalent HTTP header, 
independently for each of the three W3C fields.** An absent metadata key simply 
falls back to the HTTP header. The extractor also derives a `TraceOperation` 
naming the span after the MCP method/target (`"tools/call echo"`, `"prompts/get 
greet"`, bare `"resources/read"`, or the exact method otherwise) with 
`mcp.*`/`gen_ai.*` attributes — see 
[juneau-rest-server-mcp](/docs/topics/JuneauRestServerMcp#trace-context-prop 
[...]
+
+### How the OpenTelemetry bridge implements the composite
+
+`OtelTracerHook` overrides the three-argument `startSpan` overload above. It 
runs the configured `TextMapPropagator` twice against the same `Context`: first 
against ordinary HTTP headers, then — only when the extractor recognized a 
carrier — a second pass against that carrier. Per the propagator contract, 
extraction that finds nothing usable leaves the `Context` from the previous 
pass unchanged, so an explicit `params._meta` value wins while an 
absent/invalid one falls back to whatever t [...]
+
+The bridge also overrides `inject(TraceContextCarrier)` (backing the neutral 
`TraceContexts.inject(TracerHook, TraceContextCarrier)` helper below) using the 
same configured propagator against `Context.current()`.
+
+### Result `_meta` echo
+
+At span-start, the OTel bridge already stashes the rendered 
`traceparent`/`tracestate`/(non-empty) `baggage` as request attributes for 
`TraceContextResponseProcessor` to write as HTTP response headers (see above). 
Before returning any successful `2026-07-28` result, the MCP adapter reads 
those same request-scoped attributes and copies them into the result's own 
`_meta`, alongside the server identity every success already carries:
+
+```json
+{
+  "traceparent": "00-0af7651916cd43dd8448eb211c80319c-<server-span-id>-01",
+  "io.modelcontextprotocol/serverInfo": {"name": "my-server", "version": 
"1.0.0"}
+}
+```
+
+So an MCP client reading the JSON-RPC result body sees the same trace 
identifiers an HTTP-level observer reads off the response headers. JSON-RPC 
errors have no `result`, so there's no error-response echo.
+
+### JSON-RPC errors on an HTTP-200 response
+
+A dated MCP adapter always answers over HTTP `200`, even for a JSON-RPC-level 
error (an unknown tool, a malformed request) — so `Scope.setStatusCode(int)` 
never sees anything but the adapter's uniform success status for those cases. 
Before returning a JSON-RPC error response, `McpRevision` calls the neutral 
`Scope.recordRpcError(code, message)` default introduced above on the request's 
active tracing scope. `OtelTracerHook`'s override sets 
`rpc.response.status_code`, a low-cardinality `e [...]
+
+### Neutral injection helper
+
+A dependency-free static helper stamps the active tracer's current trace 
context into an arbitrary carrier, without the caller depending on 
OpenTelemetry:
+
+```java
+TraceContexts.inject(TracerHook tracer, TraceContextCarrier carrier);
+```
+
+This has no first-party MCP call site in 10.0.0 — it exists so a future MCP 
*client* (or any other non-HTTP caller) can inject the active trace context 
into whatever carrier it builds (for example a `RequestMeta` it's about to send 
as `params._meta`) using only this class and the installed `TracerHook`.
+
+### Pinned experimental semantic conventions
+
+The `gen_ai.*`/`mcp.*` span attribute names, the tool/prompt/resource 
span-naming rules, and the `error.type` mapping above are pinned to the 
OpenTelemetry GenAI semantic-conventions snapshot at commit 
[`c739977ae690961f36e435504e5c1febaef1f7f3`](https://github.com/open-telemetry/semantic-conventions-genai/tree/c739977ae690961f36e435504e5c1febaef1f7f3),
 plus core OpenTelemetry semantic conventions v1.43.0. **All of these 
attributes are experimental/development** — the dedicated GenAI sem [...]
+
+### `2025-06-18` is unaffected
+
+None of the above exists on `2025-06-18`: its wire beans have no 
`_meta`-carried trace fields, its adapter publishes no `TraceContextExtractor`, 
and it continues to rely solely on the HTTP-header propagation and 
response-header injection described earlier on this page.
+
 ## Custom `MetricsRecorder` / `TracerHook` implementations
 
 The SPIs are deliberately tiny — implement them directly when you need a 
backend the shipped bridges don't cover (Dropwizard Metrics, an internal 
time-series store, a structured-log appender, …):
diff --git a/pages/topics/11.JuneauRestServerMcp.md 
b/pages/topics/11.JuneauRestServerMcp.md
index 5c108c6868..7c9eb9ca72 100644
--- a/pages/topics/11.JuneauRestServerMcp.md
+++ b/pages/topics/11.JuneauRestServerMcp.md
@@ -95,6 +95,91 @@ public class MyResource extends BasicRestServlet implements 
McpEndpoint {
 
 The default `handleMcpRequest(...)` method on `McpEndpoint` (annotated 
`@RestPost("/mcp")`) takes care of dispatch, via 
`org.apache.juneau.rest.server.mcp.v20250618.McpEndpoint`'s `revision()` 
override.
 
+## Running Under Spring Boot
+
+Both dated adapters ship a Spring Boot convenience base class, 
`SpringMcpRestServlet` — 
`org.apache.juneau.rest.server.mcp.v20250618.SpringMcpRestServlet` and 
`org.apache.juneau.rest.server.mcp.v20260728.SpringMcpRestServlet` — combining 
the revision's `McpEndpoint` mixin with `BasicSpringRestServlet`. This is the 
simplest way to expose MCP from a Spring Boot resource with full Spring 
dependency-injection support inside your tool/prompt/resource handlers.
+
+### Recommended: extend `SpringMcpRestServlet`
+
+```java
+import org.apache.juneau.rest.server.*;
+import org.apache.juneau.rest.server.mcp.*;
+import org.apache.juneau.rest.server.mcp.v20260728.*;
+
+@Rest(path="/mcp")
+public class MyMcpResource extends SpringMcpRestServlet {
+
+    @Override
+    public McpServerConfig getMcpConfig() {
+        return new McpServerConfig().addTool(new MySpringAwareTool());
+    }
+}
+```
+
+You get MCP dispatch (`McpEndpoint`) plus the Spring bean-store bridge 
(`BasicSpringRestServlet`, backed by `SpringBeanStore`) in one class — just 
implement `getMcpConfig()`. A handler like `MySpringAwareTool` can then resolve 
Spring-managed beans via `BeanStore.getBean(MySpringService.class)`.
+
+### General mixin pattern
+
+If you already have your own Spring Boot base resource — one that already 
extends `BasicSpringRestServlet` (or a subclass of it) — compose the same mixin 
directly instead of going through `SpringMcpRestServlet`:
+
+```java
+@Rest(path="/api")
+public class MyResource extends BasicSpringRestServlet implements McpEndpoint {
+
+    @Override
+    public McpServerConfig getMcpConfig() {
+        return new McpServerConfig().addTool(new MySpringAwareTool());
+    }
+}
+```
+
+This is exactly the shape `SpringMcpRestServlet` uses internally — reach for 
it directly when your resource needs to extend some other Spring Boot base 
class.
+
+:::caution Don't subclass `McpRestServlet` under Spring Boot
+It's tempting to reuse the plain drop-in servlet (`extends McpRestServlet`, 
see "Drop-in servlet" above) from a Spring Boot app. **Don't.** `McpRestServlet 
extends BasicRestServlet` — a *sibling* of `SpringRestServlet`, not a subclass 
of it — so a class can never extend both, and even setting that aside, only the 
mixin path (`BasicSpringRestServlet implements McpEndpoint`) carries the Spring 
bean-store bridge MCP handlers rely on. A servlet that extends `McpRestServlet` 
inside a Spring B [...]
+:::
+
+### Maven dependencies
+
+```xml
+<dependency>
+    <groupId>org.apache.juneau</groupId>
+    <artifactId>juneau-rest-server-springboot</artifactId>
+    <version>${juneau.version}</version>
+</dependency>
+<dependency>
+    <groupId>org.apache.juneau</groupId>
+    <artifactId>juneau-rest-server-mcp-v20260728</artifactId>
+    <version>${juneau.version}</version>
+</dependency>
+<!-- and/or juneau-rest-server-mcp-v20250618, if you also need that revision 
-->
+```
+
+Which dated adapter you depend on — and therefore which 
`SpringMcpRestServlet`/`McpEndpoint` you extend/implement 
(`org.apache.juneau.rest.server.mcp.v20250618.*` or 
`org.apache.juneau.rest.server.mcp.v20260728.*`) — is a compile-time choice, 
exactly like every other MCP binding on this page. Both revisions ship the same 
convenience class.
+
+### Servlet registration
+
+Registration is standard Juneau-on-Spring-Boot — nothing MCP-specific. Either 
enable opt-in auto-registration:
+
+```properties
+juneau.rest.auto-register=true
+```
+
+or register explicitly with the self-declared-path helper:
+
+```java
+@Bean
+ServletRegistrationBean<?> mcpServlet(BeanStore beanStore) {
+    return JuneauServletRegistrations.forServlet(new MyMcpResource(), 
beanStore);
+}
+```
+
+See [REST Server — Self-Registration](/docs/topics/RestServerSelfRegistration) 
for the full mechanism (Jetty microservice and `web.xml` equivalents included) 
and [juneau-rest-server-springboot](/docs/topics/JuneauRestServerSpringboot) / 
[Spring Boot Overview](/docs/topics/SpringBootOverview) for the Spring 
bean-store bridge these classes build on.
+
+### Contrast: the Juneau Microservice runtime
+
+Under the Jetty-based Juneau Microservice runtime there is no Spring bean 
store at all, so the caveat above doesn't apply: `MyMcpServlet extends 
McpRestServlet` (see "Drop-in servlet" above) is the ordinary, correct recipe 
there — there's no second bean-resolution path to silently miss.
+
 ## Writing Handlers
 
 ### Raw tool handler
@@ -468,6 +553,78 @@ Registering resource templates through the neutral 
`McpServerConfig`/`McpResourc
 
 See 
[juneau-bean-mcp-v20260728](/docs/topics/JuneauBeanMcp#mcp-2026-07-28-cache-hints-resource-templates)
 for the wire-bean side of cache hints (`McpCacheScope`, `CacheableResult<T>`) 
and resource templates (`ResourceTemplate`, `ListResourceTemplatesResult`).
 
+## Trace-Context Propagation (MCP `2026-07-28`)
+
+**v2-only.** Every `2026-07-28` MCP request participates in distributed 
tracing exactly the way any other `@RestOp` invocation does — there is no 
MCP-specific wiring to turn on. This section covers the MCP-specific *carrier*: 
how `params._meta` interacts with HTTP trace-context headers, and how the 
result echoes the active trace back to the caller. For the framework-level seam 
(`TraceContextExtractor`, `TraceContextCarrier`, `TraceOperation`, 
`TracerHook`, the OpenTelemetry bridge), see  [...]
+
+### `params._meta` as a second trace-context carrier
+
+Per the `2026-07-28` schema, `params._meta` may carry the bare (unprefixed) 
W3C fields `traceparent`, `tracestate`, and `baggage` alongside the 
`io.modelcontextprotocol/`-prefixed negotiation keys:
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 1,
+  "method": "tools/call",
+  "params": {
+    "name": "echo",
+    "arguments": {"text": "hi"},
+    "_meta": {
+      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
+      "io.modelcontextprotocol/clientInfo": {"name": "my-client", "version": 
"1.0"},
+      "io.modelcontextprotocol/clientCapabilities": {},
+      "traceparent": "00-0af7651916cd43dd8448eb211c80319c-b7ad6b7169203331-01"
+    }
+  }
+}
+```
+
+Both `McpRestServlet` and `McpEndpoint` publish this revision's stable 
`TraceContextExtractor` (a `@Bean mcpTraceContextExtractor()`), which — only 
when an active `TracerHook` is registered — recognizes the resolved 
`JsonRpcRequest` argument before the span opens and builds a composite carrier 
over `params._meta`:
+
+```text
+lookup(key) = params._meta[key] if present, otherwise the HTTP header of the 
same name
+```
+
+**An explicit `params._meta` value wins over the equivalent HTTP header — 
independently for `traceparent`, `tracestate`, and `baggage`.** An absent 
metadata key simply falls back to the HTTP header, letting an MCP client 
propagate its own trace context even when the transport-level HTTP headers 
belong to some other hop (a gateway, a load balancer, etc.). With no tracer 
registered, this extraction never runs at all — the same zero-allocation 
no-tracer fast path described on the observabil [...]
+
+### Result `_meta` echo
+
+Before returning any successful result, the adapter copies the active trace 
context — whatever the `TracerHook` bridge rendered at span-start, whether that 
came from `params._meta` or the HTTP fallback — into the result's own `_meta`, 
alongside the server identity every success already carries:
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 1,
+  "result": {
+    "resultType": "complete",
+    "_meta": {
+      "io.modelcontextprotocol/serverInfo": {"name": "my-server", "version": 
"1.0.0"},
+      "traceparent": "00-0af7651916cd43dd8448eb211c80319c-<server-span-id>-01"
+    },
+    "content": [{"type": "text", "text": "hi"}]
+  }
+}
+```
+
+The same values also reach the ordinary HTTP `traceparent`/`tracestate` 
response headers (see the observability page) — an MCP client and an HTTP-level 
observer read the identical trace identifiers, whichever surface they look at. 
`tracestate`/`baggage` are only added when non-empty. JSON-RPC errors have no 
`result`, so there is no error-response echo — see below for how an error is 
still observed on the span.
+
+### Span naming, attributes, and JSON-RPC errors
+
+When the OpenTelemetry bridge (`juneau-rest-server-tracing-otel`) is active as 
the `TracerHook`, it enriches the span with pinned, **experimental** 
`gen_ai.*`/`mcp.*` attributes derived from the request, and names the span 
after the MCP operation rather than the bare HTTP method:
+
+| Method | Span name | Notable attributes |
+|---|---|---|
+| `tools/call` (tool `echo`) | `"tools/call echo"` | `gen_ai.tool.name=echo`, 
`gen_ai.operation.name=execute_tool` |
+| `prompts/get` (prompt `greet`) | `"prompts/get greet"` | 
`gen_ai.prompt.name=greet` |
+| `resources/read` | `"resources/read"` (the URI stays an attribute, never a 
span-name suffix) | `mcp.resource.uri=<uri>` |
+| everything else | the exact method, e.g. `"tools/list"` | — |
+
+Every span additionally carries `mcp.method.name`, `mcp.protocol.version`, and 
(when present) `jsonrpc.request.id`.
+
+Because a dated MCP adapter always answers over HTTP `200` — even for a 
JSON-RPC-level error like an unknown tool — the HTTP status alone can never 
mark a span failed. Before returning a JSON-RPC error response, `McpRevision` 
calls a neutral `Scope.recordRpcError(code, message)` on the request's active 
tracing scope; the OpenTelemetry bridge maps that into 
`rpc.response.status_code`, a low-cardinality `error.type` category, and 
`StatusCode.ERROR` with the JSON-RPC message as the status d [...]
+
+All of the above attribute names and span-naming choices are pinned to a 
specific, **experimental** OpenTelemetry GenAI semantic-conventions snapshot — 
see [Observability — Micrometer + 
OpenTelemetry](/docs/topics/RestServerObservability#mcp-trace-context-propagation-2026-07-28)
 for the exact pin, the full attribute reference, and the neutral seam these 
classes are built on.
+
 ## Related Modules
 
 - **[juneau-bean-mcp-v20250618](/docs/topics/JuneauBeanMcp)** — The 
`2025-06-18` wire beans consumed by the adapter module, plus the 
revision-neutral JSON-RPC envelope beans (`juneau-bean-jsonrpc`) both modules 
build on.

Reply via email to