Add McpTransportContext to McpSyncClient (#522)
* McpSyncClient: introduce McpTransportContext - McpSyncClient should be considered thread-agnostic, and therefore consumers cannot rely on thread locals to propagate "context", e.g. pass down the Servlet request reference in a server context. - This PR introduces a mechanism for populating an McpTransportContext before executing client operations, and reworks the HTTP request customizers to leverage that McpTransportContext. - Move McpTransportContext from server to common package for shared client/server usage - Make McpTransportContext immutable by removing put() and copy() methods - Add static create() factory method for creating contexts with predefined data - Update McpTransportContextExtractor to return context instead of modifying one - Replace DefaultMcpTransportContext mutable implementation with immutable version - Update all transport implementations to use McpTransportContext.EMPTY as default - Rename *HttpRequestCustomizer -> *HttpClientRequestCustomizer - Add end-to-end McpTransportContextIntegrationTests - This PR introduces a breaking change to the Sync/Async request customizers. Signed-off-by: Daniel Garnier-Moiroux <git@garnier.wf>
This commit is contained in:
parent
95ba8e77ec
commit
629464b1d6
10 changed files with 746 additions and 327 deletions
|
|
@ -12,8 +12,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.server.DefaultMcpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContext;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -201,7 +200,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
public WebFluxSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint, Duration keepAliveInterval) {
|
||||
this(objectMapper, baseUrl, messageEndpoint, sseEndpoint, keepAliveInterval,
|
||||
(serverRequest, context) -> context);
|
||||
(serverRequest) -> McpTransportContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -344,7 +343,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).bodyValue("Server is shutting down");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
return ServerResponse.ok()
|
||||
.contentType(MediaType.TEXT_EVENT_STREAM)
|
||||
|
|
@ -401,7 +400,7 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
.bodyValue(new McpError("Session not found: " + request.queryParam("sessionId").get()));
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
return request.bodyToMono(String.class).flatMap(body -> {
|
||||
try {
|
||||
|
|
@ -491,7 +490,8 @@ public class WebFluxSseServerTransportProvider implements McpServerTransportProv
|
|||
|
||||
private Duration keepAliveInterval;
|
||||
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (serverRequest, context) -> context;
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (
|
||||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
/**
|
||||
* Sets the ObjectMapper to use for JSON serialization/deserialization of MCP
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@
|
|||
package io.modelcontextprotocol.server.transport;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpStatelessServerHandler;
|
||||
import io.modelcontextprotocol.server.DefaultMcpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpStatelessServerTransport;
|
||||
import io.modelcontextprotocol.server.McpTransportContext;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -97,7 +96,7 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).bodyValue("Server is shutting down");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
List<MediaType> acceptHeaders = request.headers().asHttpHeaders().getAccept();
|
||||
if (!(acceptHeaders.contains(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -151,7 +150,8 @@ public class WebFluxStatelessServerTransport implements McpStatelessServerTransp
|
|||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (serverRequest, context) -> context;
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (
|
||||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
private Builder() {
|
||||
// used by a static method
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ package io.modelcontextprotocol.server.transport;
|
|||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.server.DefaultMcpTransportContext;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.HttpHeaders;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
|
|
@ -15,7 +15,6 @@ import io.modelcontextprotocol.spec.McpStreamableServerSession;
|
|||
import io.modelcontextprotocol.spec.McpStreamableServerTransport;
|
||||
import io.modelcontextprotocol.spec.McpStreamableServerTransportProvider;
|
||||
import io.modelcontextprotocol.spec.ProtocolVersions;
|
||||
import io.modelcontextprotocol.server.McpTransportContext;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import io.modelcontextprotocol.util.KeepAliveScheduler;
|
||||
|
||||
|
|
@ -166,7 +165,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).bodyValue("Server is shutting down");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
return Mono.defer(() -> {
|
||||
List<MediaType> acceptHeaders = request.headers().asHttpHeaders().getAccept();
|
||||
|
|
@ -221,7 +220,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).bodyValue("Server is shutting down");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
List<MediaType> acceptHeaders = request.headers().asHttpHeaders().getAccept();
|
||||
if (!(acceptHeaders.contains(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -309,7 +308,7 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).bodyValue("Server is shutting down");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
return Mono.defer(() -> {
|
||||
if (!request.headers().asHttpHeaders().containsKey(HttpHeaders.MCP_SESSION_ID)) {
|
||||
|
|
@ -402,7 +401,8 @@ public class WebFluxStreamableServerTransportProvider implements McpStreamableSe
|
|||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (serverRequest, context) -> context;
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (
|
||||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
private boolean disallowDelete;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
package io.modelcontextprotocol;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
|
@ -20,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpServer;
|
||||
import io.modelcontextprotocol.server.McpServer.AsyncSpecification;
|
||||
import io.modelcontextprotocol.server.McpServer.SingleSessionSyncSpecification;
|
||||
|
|
@ -42,10 +44,8 @@ class WebFluxSseIntegrationTests extends AbstractMcpClientServerIntegrationTests
|
|||
|
||||
private WebFluxSseServerTransportProvider mcpServerTransportProvider;
|
||||
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = (r, tc) -> {
|
||||
tc.put("important", "value");
|
||||
return tc;
|
||||
};
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = (r) -> McpTransportContext
|
||||
.create(Map.of("important", "value"));
|
||||
|
||||
@Override
|
||||
protected void prepareClients(int port, String mcpEndpoint) {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
package io.modelcontextprotocol;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
|
@ -20,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
|||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpServer;
|
||||
import io.modelcontextprotocol.server.McpServer.AsyncSpecification;
|
||||
import io.modelcontextprotocol.server.McpServer.SyncSpecification;
|
||||
|
|
@ -40,10 +42,8 @@ class WebFluxStreamableIntegrationTests extends AbstractMcpClientServerIntegrati
|
|||
|
||||
private WebFluxStreamableServerTransportProvider mcpStreamableServerTransportProvider;
|
||||
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = (r, tc) -> {
|
||||
tc.put("important", "value");
|
||||
return tc;
|
||||
};
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = (r) -> McpTransportContext
|
||||
.create(Map.of("important", "value"));
|
||||
|
||||
@Override
|
||||
protected void prepareClients(int port, String mcpEndpoint) {
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.server.DefaultMcpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContext;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
|
|
@ -192,7 +191,7 @@ public class WebMvcSseServerTransportProvider implements McpServerTransportProvi
|
|||
public WebMvcSseServerTransportProvider(ObjectMapper objectMapper, String baseUrl, String messageEndpoint,
|
||||
String sseEndpoint, Duration keepAliveInterval) {
|
||||
this(objectMapper, baseUrl, messageEndpoint, sseEndpoint, keepAliveInterval,
|
||||
(serverRequest, context) -> context);
|
||||
(serverRequest) -> McpTransportContext.EMPTY);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -397,8 +396,7 @@ public class WebMvcSseServerTransportProvider implements McpServerTransportProvi
|
|||
}
|
||||
|
||||
try {
|
||||
final McpTransportContext transportContext = this.contextExtractor.extract(request,
|
||||
new DefaultMcpTransportContext());
|
||||
final McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
String body = request.body(String.class);
|
||||
McpSchema.JSONRPCMessage message = McpSchema.deserializeJsonRpcMessage(objectMapper, body);
|
||||
|
|
@ -553,7 +551,8 @@ public class WebMvcSseServerTransportProvider implements McpServerTransportProvi
|
|||
|
||||
private Duration keepAliveInterval;
|
||||
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (serverRequest, context) -> context;
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (
|
||||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
/**
|
||||
* Sets the JSON object mapper to use for message serialization/deserialization.
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@
|
|||
package io.modelcontextprotocol.server.transport;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpStatelessServerHandler;
|
||||
import io.modelcontextprotocol.server.DefaultMcpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
import io.modelcontextprotocol.spec.McpSchema;
|
||||
import io.modelcontextprotocol.spec.McpStatelessServerTransport;
|
||||
import io.modelcontextprotocol.server.McpTransportContext;
|
||||
import io.modelcontextprotocol.util.Assert;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -101,7 +100,7 @@ public class WebMvcStatelessServerTransport implements McpStatelessServerTranspo
|
|||
return ServerResponse.status(HttpStatus.SERVICE_UNAVAILABLE).body("Server is shutting down");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
List<MediaType> acceptHeaders = request.headers().asHttpHeaders().getAccept();
|
||||
if (!(acceptHeaders.contains(MediaType.APPLICATION_JSON)
|
||||
|
|
@ -176,7 +175,8 @@ public class WebMvcStatelessServerTransport implements McpStatelessServerTranspo
|
|||
|
||||
private String mcpEndpoint = "/mcp";
|
||||
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (serverRequest, context) -> context;
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (
|
||||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
private Builder() {
|
||||
// used by a static method
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@ import org.springframework.web.servlet.function.ServerResponse.SseBuilder;
|
|||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import io.modelcontextprotocol.server.DefaultMcpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContext;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpTransportContextExtractor;
|
||||
import io.modelcontextprotocol.spec.HttpHeaders;
|
||||
import io.modelcontextprotocol.spec.McpError;
|
||||
|
|
@ -238,7 +237,7 @@ public class WebMvcStreamableServerTransportProvider implements McpStreamableSer
|
|||
return ServerResponse.badRequest().body("Invalid Accept header. Expected TEXT_EVENT_STREAM");
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
if (!request.headers().asHttpHeaders().containsKey(HttpHeaders.MCP_SESSION_ID)) {
|
||||
return ServerResponse.badRequest().body("Session ID required in mcp-session-id header");
|
||||
|
|
@ -322,7 +321,7 @@ public class WebMvcStreamableServerTransportProvider implements McpStreamableSer
|
|||
.body(new McpError("Invalid Accept headers. Expected TEXT_EVENT_STREAM and APPLICATION_JSON"));
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
try {
|
||||
String body = request.body(String.class);
|
||||
|
|
@ -431,7 +430,7 @@ public class WebMvcStreamableServerTransportProvider implements McpStreamableSer
|
|||
return ServerResponse.status(HttpStatus.METHOD_NOT_ALLOWED).build();
|
||||
}
|
||||
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request, new DefaultMcpTransportContext());
|
||||
McpTransportContext transportContext = this.contextExtractor.extract(request);
|
||||
|
||||
if (!request.headers().asHttpHeaders().containsKey(HttpHeaders.MCP_SESSION_ID)) {
|
||||
return ServerResponse.badRequest().body("Session ID required in mcp-session-id header");
|
||||
|
|
@ -604,7 +603,8 @@ public class WebMvcStreamableServerTransportProvider implements McpStreamableSer
|
|||
|
||||
private boolean disallowDelete = false;
|
||||
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (serverRequest, context) -> context;
|
||||
private McpTransportContextExtractor<ServerRequest> contextExtractor = (
|
||||
serverRequest) -> McpTransportContext.EMPTY;
|
||||
|
||||
private Duration keepAliveInterval;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package io.modelcontextprotocol.server;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
|
|
@ -26,6 +27,7 @@ import io.modelcontextprotocol.AbstractMcpClientServerIntegrationTests;
|
|||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientSseClientTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebFluxSseClientTransport;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpServer.AsyncSpecification;
|
||||
import io.modelcontextprotocol.server.McpServer.SingleSessionSyncSpecification;
|
||||
import io.modelcontextprotocol.server.transport.WebMvcSseServerTransportProvider;
|
||||
|
|
@ -40,10 +42,8 @@ class WebMvcSseIntegrationTests extends AbstractMcpClientServerIntegrationTests
|
|||
|
||||
private WebMvcSseServerTransportProvider mcpServerTransportProvider;
|
||||
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = (r, tc) -> {
|
||||
tc.put("important", "value");
|
||||
return tc;
|
||||
};
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = r -> McpTransportContext
|
||||
.create(Map.of("important", "value"));
|
||||
|
||||
@Override
|
||||
protected void prepareClients(int port, String mcpEndpoint) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ package io.modelcontextprotocol.server;
|
|||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
|
|
@ -26,6 +27,7 @@ import io.modelcontextprotocol.AbstractMcpClientServerIntegrationTests;
|
|||
import io.modelcontextprotocol.client.McpClient;
|
||||
import io.modelcontextprotocol.client.transport.HttpClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.client.transport.WebClientStreamableHttpTransport;
|
||||
import io.modelcontextprotocol.common.McpTransportContext;
|
||||
import io.modelcontextprotocol.server.McpServer.AsyncSpecification;
|
||||
import io.modelcontextprotocol.server.McpServer.SyncSpecification;
|
||||
import io.modelcontextprotocol.server.transport.WebMvcStreamableServerTransportProvider;
|
||||
|
|
@ -40,10 +42,8 @@ class WebMvcStreamableIntegrationTests extends AbstractMcpClientServerIntegratio
|
|||
|
||||
private WebMvcStreamableServerTransportProvider mcpServerTransportProvider;
|
||||
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = (r, tc) -> {
|
||||
tc.put("important", "value");
|
||||
return tc;
|
||||
};
|
||||
static McpTransportContextExtractor<ServerRequest> TEST_CONTEXT_EXTRACTOR = r -> McpTransportContext
|
||||
.create(Map.of("important", "value"));
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
|
|
|
|||
Loading…
Reference in a new issue