Request customizers can't tell which connection a request belongs to
Maintainer antworten meist innerhalb von 3 Tagen
@Kehrlann arbeitet bereits daran.
Seit 07.8.2026.
Bewertung
Dieses Issue wurde noch nicht bewertet.
Beschreibung
Expected Behavior
A request customizer should be able to find out which configured connection the request it is customizing belongs to.
The cheaper option is a well-known key in the transport context, seeded by the transport, so no signature changes:
Publisher<HttpRequest.Builder> customize(HttpRequest.Builder builder, String method, URI endpoint,
String body, McpTransportContext context) {
String connection = (String) context.get(McpTransportContext.CONNECTION_NAME);
builder.setHeader("Authorization", tokenFor(connection));
return Mono.just(builder);
}
The transport already knows the name when it is built, so it would set it once in the builder and merge it into whatever context the caller supplied.
The other option is to put it in the signature:
Publisher<HttpRequest.Builder> customize(String connectionName, HttpRequest.Builder builder, String method,
URI endpoint, String body, McpTransportContext context);
This is breaking, but it lines up with McpClientCustomizer#customize(String name, T spec) in Spring AI, which already takes the name first. If the interface is going to change shape at some point anyway, that's the more consistent end state.
Current Behavior
A request customizer runs for every outbound HTTP request on a transport, but isn't told which connection the request belongs to. On main at fd00498:
// McpAsyncHttpClientRequestCustomizer:27
Publisher<HttpRequest.Builder> customize(HttpRequest.Builder builder, String method, URI endpoint,
@Nullable String body, McpTransportContext context);
The only discriminator available is the endpoint URI. There is no connection name in the context either: nothing in mcp-core defines or sets one, and the transport passes the caller's context through untouched. HttpClientStreamableHttpTransport reads it the same way on all four request paths, at lines 205, 291, 430, and 514:
var transportContext = ctx.getOrDefault(McpTransportContext.KEY, McpTransportContext.EMPTY);
return Mono.from(this.httpRequestCustomizer.customize(builder, "POST", uri, jsonBody, transportContext));
So a customizer that needs per-connection behavior has to build its own URL-to-name map and reverse-match on the endpoint for every request. That map has to be assembled by re-reading the same configuration that the framework already parsed, and the match breaks as soon as a URL is templated, redirected, or differs by a trailing slash.
The name is known at the point the customizer is installed, since the transport is built per connection. It just isn't carried through to the call.
Context
Callers configure connections by name. In Spring AI, for example:
spring.ai.mcp.client.streamable-http.connections:
first-server:
url: https://...
second-server:
url: https://...
Anything per-connection needs that name: a different credential or audience per server, per-connection metrics, per-connection logging. We hit this with credentials, where each MCP server is a distinct audience, and the token must be minted for the correct one.
Alternatives considered:
- One customizer instance per connection, closing over the name, installed by whoever builds the transport. This is what we do today. It works, but it only works for the party that owns the builder, and it interacts badly with the single-customizer-slot problem (https://github.com/modelcontextprotocol/java-sdk/issues/1073).
- A URL to name map inside the customizer, reverse-matched on
endpoint. Fragile for the reasons above, and it duplicates configuration parsing. - Putting the name into the caller's context at the call site. Requires every caller to know which connection a given client operation will reach, which they generally don't.
Is there a reason the connection name was deliberately omitted from the customizer contract? I might be missing something.
- Vorherrschende Sprache
- Java
- Sterne
- 3.7k
- Forks
- 1.1k
- Ø Merge
- 2 T. 5 Std.
- Gemergte PRs (30 T.)
- 4
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus modelcontextprotocol/java-sdk
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 86/100
modelcontextprotocol/java-sdk#1155 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
area/client bug P2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
modelcontextprotocol/java-sdk#1124 · 5 Kommentare ·
Maintainer antworten meist innerhalb von 3 Tagen
-
ServerCapabilities.logging is added unconditionally, overriding the caller's explicit capabilitiesOffenbug P2 ready for work
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
modelcontextprotocol/java-sdk#1086 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
enhancement good first issue P3
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
modelcontextprotocol/java-sdk#1067 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
bug P2 ready for work
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 74/100
modelcontextprotocol/java-sdk#898 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
Alle Issues in modelcontextprotocol/java-sdk
Ähnliche Issues
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
apache/rocketmq-dashboard#5358 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
area:cpan-port area:database bug
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
fglock/PerlOnJava#1605 ·
Maintainer antworten meist innerhalb von 1 Tag
-
1.0.0-rc2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
wso2/dpdp-accelerator#377 ·
Maintainer antworten meist innerhalb von 1 Tag
-
area/dependencies backport/26.4 kind/cve severity/high source/scan-dependencies status/triage
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 1 Tag