diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..5eb30737a --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,27 @@ +name: Deploy Documentation + +on: + push: + branches: + - main + paths: + - 'docs/**' + - 'mkdocs.yml' + workflow_dispatch: + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: 3.x + + - run: pip install mkdocs-material + + - run: mkdocs gh-deploy --force diff --git a/.gitignore b/.gitignore index 50425e205..1fc975c0a 100644 --- a/.gitignore +++ b/.gitignore @@ -57,6 +57,9 @@ node_modules/ package-lock.json package.json +### MkDocs ### +site/ + ### Other ### .antlr/ .profiler/ diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100644 index 000000000..3199dd51f --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,106 @@ +--- +title: Contributing +description: How to contribute to the MCP Java SDK +--- + +# Contributing + +Thank you for your interest in contributing to the Model Context Protocol Java SDK! +This guide outlines how to contribute to this project. + +## Prerequisites + +!!! info "Required Software" + - **Java 17** or above + - **Docker** + - **npx** + +## Getting Started + +1. Fork the repository +2. Clone your fork: + + ```bash + git clone https://github.com/YOUR-USERNAME/java-sdk.git + cd java-sdk + ``` + +3. Build from source: + + ```bash + ./mvnw clean install -DskipTests # skip the tests + ./mvnw test # run tests + ``` + +## Reporting Issues + +Please create an issue in the repository if you discover a bug or would like to +propose an enhancement. Bug reports should have a reproducer in the form of a code +sample or a repository attached that the maintainers or contributors can work with to +address the problem. + +## Making Changes + +1. Create a new branch: + + ```bash + git checkout -b feature/your-feature-name + ``` + +2. Make your changes. + +3. Validate your changes: + + ```bash + ./mvnw clean test + ``` + +### Change Proposal Guidelines + +#### Principles of MCP + +1. **Simple + Minimal**: It is much easier to add things to the codebase than it is to + remove them. To maintain simplicity, we keep a high bar for adding new concepts and + primitives as each addition requires maintenance and compatibility consideration. +2. **Concrete**: Code changes need to be based on specific usage and implementation + challenges and not on speculative ideas. Most importantly, the SDK is meant to + implement the MCP specification. + +## Submitting Changes + +1. For non-trivial changes, please clarify with the maintainers in an issue whether + you can contribute the change and the desired scope of the change. +2. For trivial changes (for example a couple of lines or documentation changes) there + is no need to open an issue first. +3. Push your changes to your fork. +4. Submit a pull request to the main repository. +5. Follow the pull request template. +6. Wait for review. +7. For any follow-up work, please add new commits instead of force-pushing. This will + allow the reviewer to focus on incremental changes instead of having to restart the + review process. + +## Code of Conduct + +This project follows a Code of Conduct. Please review it in +[CODE_OF_CONDUCT.md](https://github.com/modelcontextprotocol/java-sdk/blob/main/CODE_OF_CONDUCT.md). + +## Questions + +If you have questions, please create a discussion in the repository. + +## License + +By contributing, you agree that your contributions will be licensed under the MIT +License. + +## Security + +This SDK is maintained by [Anthropic](https://www.anthropic.com/) as part of the Model Context Protocol project. + +The security of our systems and user data is Anthropic's top priority. We appreciate the work of security researchers acting in good faith in identifying and reporting potential vulnerabilities. + +!!! warning "Reporting Security Vulnerabilities" + Do **not** report security vulnerabilities through public GitHub issues. Instead, report them through our HackerOne [submission form](https://hackerone.com/anthropic-vdp/reports/new?type=team&report_type=vulnerability). + +Our Vulnerability Disclosure Program guidelines are defined on our [HackerOne program page](https://hackerone.com/anthropic-vdp). diff --git a/docs/client.md b/docs/client.md new file mode 100644 index 000000000..29cfcc3b7 --- /dev/null +++ b/docs/client.md @@ -0,0 +1,424 @@ +--- +title: MCP Client +description: Learn how to use the Model Context Protocol (MCP) client to interact with MCP servers +--- + +# MCP Client + +The MCP Client is a key component in the Model Context Protocol (MCP) architecture, responsible for establishing and managing connections with MCP servers. It implements the client-side of the protocol, handling: + +- Protocol version negotiation to ensure compatibility with servers +- Capability negotiation to determine available features +- Message transport and JSON-RPC communication +- Tool discovery and execution with optional schema validation +- Resource access and management +- Prompt system interactions +- Optional features like roots management, sampling, and elicitation support +- Progress tracking for long-running operations + +!!! tip + The core `io.modelcontextprotocol.sdk:mcp` module provides STDIO, SSE, and Streamable HTTP client transport implementations without requiring external web frameworks. + + Spring-specific transport implementations are available as an **optional** dependency `io.modelcontextprotocol.sdk:mcp-spring-webflux` for [Spring Framework](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) users. + +The client provides both synchronous and asynchronous APIs for flexibility in different application contexts. + +=== "Sync API" + + ```java + // Create a sync client with custom configuration + McpSyncClient client = McpClient.sync(transport) + .requestTimeout(Duration.ofSeconds(10)) + .capabilities(ClientCapabilities.builder() + .roots(true) // Enable roots capability + .sampling() // Enable sampling capability + .elicitation() // Enable elicitation capability + .build()) + .sampling(request -> new CreateMessageResult(response)) + .elicitation(request -> new ElicitResult(ElicitResult.Action.ACCEPT, content)) + .build(); + + // Initialize connection + client.initialize(); + + // List available tools + ListToolsResult tools = client.listTools(); + + // Call a tool + CallToolResult result = client.callTool( + new CallToolRequest("calculator", + Map.of("operation", "add", "a", 2, "b", 3)) + ); + + // List and read resources + ListResourcesResult resources = client.listResources(); + ReadResourceResult resource = client.readResource( + new ReadResourceRequest("resource://uri") + ); + + // List and use prompts + ListPromptsResult prompts = client.listPrompts(); + GetPromptResult prompt = client.getPrompt( + new GetPromptRequest("greeting", Map.of("name", "Spring")) + ); + + // Add/remove roots + client.addRoot(new Root("file:///path", "description")); + client.removeRoot("file:///path"); + + // Close client + client.closeGracefully(); + ``` + +=== "Async API" + + ```java + // Create an async client with custom configuration + McpAsyncClient client = McpClient.async(transport) + .requestTimeout(Duration.ofSeconds(10)) + .capabilities(ClientCapabilities.builder() + .roots(true) // Enable roots capability + .sampling() // Enable sampling capability + .elicitation() // Enable elicitation capability + .build()) + .sampling(request -> Mono.just(new CreateMessageResult(response))) + .elicitation(request -> Mono.just(new ElicitResult(ElicitResult.Action.ACCEPT, content))) + .toolsChangeConsumer(tools -> Mono.fromRunnable(() -> { + logger.info("Tools updated: {}", tools); + })) + .resourcesChangeConsumer(resources -> Mono.fromRunnable(() -> { + logger.info("Resources updated: {}", resources); + })) + .promptsChangeConsumer(prompts -> Mono.fromRunnable(() -> { + logger.info("Prompts updated: {}", prompts); + })) + .progressConsumer(progress -> Mono.fromRunnable(() -> { + logger.info("Progress: {}", progress); + })) + .build(); + + // Initialize connection and use features + client.initialize() + .flatMap(initResult -> client.listTools()) + .flatMap(tools -> { + return client.callTool(new CallToolRequest( + "calculator", + Map.of("operation", "add", "a", 2, "b", 3) + )); + }) + .flatMap(result -> { + return client.listResources() + .flatMap(resources -> + client.readResource(new ReadResourceRequest("resource://uri")) + ); + }) + .flatMap(resource -> { + return client.listPrompts() + .flatMap(prompts -> + client.getPrompt(new GetPromptRequest( + "greeting", + Map.of("name", "Spring") + )) + ); + }) + .flatMap(prompt -> { + return client.addRoot(new Root("file:///path", "description")) + .then(client.removeRoot("file:///path")); + }) + .doFinally(signalType -> { + client.closeGracefully().subscribe(); + }) + .subscribe(); + ``` + +## Client Transport + +The transport layer handles the communication between MCP clients and servers, providing different implementations for various use cases. The client transport manages message serialization, connection establishment, and protocol-specific communication patterns. + +=== "STDIO" + + Creates transport for process-based communication using stdin/stdout: + + ```java + ServerParameters params = ServerParameters.builder("npx") + .args("-y", "@modelcontextprotocol/server-everything", "dir") + .build(); + McpTransport transport = new StdioClientTransport(params); + ``` + +=== "SSE (HttpClient)" + + Creates a framework-agnostic (pure Java API) SSE client transport. Included in the core `mcp` module: + + ```java + McpTransport transport = new HttpClientSseClientTransport("http://your-mcp-server"); + ``` + +=== "Streamable HTTP" + + Creates a Streamable HTTP client transport for efficient bidirectional communication. Included in the core `mcp` module: + + ```java + McpTransport transport = HttpClientStreamableHttpTransport + .builder("http://your-mcp-server") + .endpoint("/mcp") + .build(); + ``` + + The Streamable HTTP transport supports: + + - Resumable streams for connection recovery + - Configurable connect timeout + - Custom HTTP request customization + - Multiple protocol version negotiation + +=== "SSE (WebFlux)" + + Creates WebFlux-based SSE client transport. Requires the `mcp-spring-webflux` dependency: + + ```java + WebClient.Builder webClientBuilder = WebClient.builder() + .baseUrl("http://your-mcp-server"); + McpTransport transport = new WebFluxSseClientTransport(webClientBuilder); + ``` + +## Client Capabilities + +The client can be configured with various capabilities: + +```java +var capabilities = ClientCapabilities.builder() + .roots(true) // Enable filesystem roots support with list changes notifications + .sampling() // Enable LLM sampling support + .elicitation() // Enable elicitation support (form and URL modes) + .build(); +``` + +You can also configure elicitation with specific mode support: + +```java +var capabilities = ClientCapabilities.builder() + .elicitation(true, false) // Enable form-based elicitation, disable URL-based + .build(); +``` + +### Roots Support + +Roots define the boundaries of where servers can operate within the filesystem: + +```java +// Add a root dynamically +client.addRoot(new Root("file:///path", "description")); + +// Remove a root +client.removeRoot("file:///path"); + +// Notify server of roots changes +client.rootsListChangedNotification(); +``` + +The roots capability allows servers to: + +- Request the list of accessible filesystem roots +- Receive notifications when the roots list changes +- Understand which directories and files they have access to + +### Sampling Support + +Sampling enables servers to request LLM interactions ("completions" or "generations") through the client: + +```java +// Configure sampling handler +Function samplingHandler = request -> { + // Sampling implementation that interfaces with LLM + return new CreateMessageResult(response); +}; + +// Create client with sampling support +var client = McpClient.sync(transport) + .capabilities(ClientCapabilities.builder() + .sampling() + .build()) + .sampling(samplingHandler) + .build(); +``` + +This capability allows: + +- Servers to leverage AI capabilities without requiring API keys +- Clients to maintain control over model access and permissions +- Support for both text and image-based interactions +- Optional inclusion of MCP server context in prompts + +### Elicitation Support + +Elicitation enables servers to request additional information or user input through the client. This is useful when a server needs clarification or confirmation during an operation: + +```java +// Configure elicitation handler +Function elicitationHandler = request -> { + // Present the request to the user and collect their response + // The request contains a message and a schema describing the expected input + Map userResponse = collectUserInput(request.message(), request.requestedSchema()); + return new ElicitResult(ElicitResult.Action.ACCEPT, userResponse); +}; + +// Create client with elicitation support +var client = McpClient.sync(transport) + .capabilities(ClientCapabilities.builder() + .elicitation() + .build()) + .elicitation(elicitationHandler) + .build(); +``` + +The `ElicitResult` supports three actions: + +- `ACCEPT` - The user accepted and provided the requested information +- `DECLINE` - The user declined to provide the information +- `CANCEL` - The operation was cancelled + +### Logging Support + +The client can register a logging consumer to receive log messages from the server and set the minimum logging level to filter messages: + +```java +var mcpClient = McpClient.sync(transport) + .loggingConsumer(notification -> { + System.out.println("Received log message: " + notification.data()); + }) + .build(); + +mcpClient.initialize(); + +mcpClient.setLoggingLevel(McpSchema.LoggingLevel.INFO); + +// Call the tool that sends logging notifications +CallToolResult result = mcpClient.callTool(new CallToolRequest("logging-test", Map.of())); +``` + +Clients can control the minimum logging level they receive through the `mcpClient.setLoggingLevel(level)` request. Messages below the set level will be filtered out. +Supported logging levels (in order of increasing severity): DEBUG (0), INFO (1), NOTICE (2), WARNING (3), ERROR (4), CRITICAL (5), ALERT (6), EMERGENCY (7) + +### Progress Notifications + +The client can register a progress consumer to track the progress of long-running operations: + +```java +var mcpClient = McpClient.sync(transport) + .progressConsumer(progress -> { + System.out.println("Progress: " + progress.progress() + "/" + progress.total()); + }) + .build(); +``` + +## Using MCP Clients + +### Tool Execution + +Tools are server-side functions that clients can discover and execute. The MCP client provides methods to list available tools and execute them with specific parameters. Each tool has a unique name and accepts a map of parameters. + +=== "Sync API" + + ```java + // List available tools + ListToolsResult tools = client.listTools(); + + // Call a tool with a CallToolRequest + CallToolResult result = client.callTool( + new CallToolRequest("calculator", Map.of( + "operation", "add", + "a", 1, + "b", 2 + )) + ); + ``` + +=== "Async API" + + ```java + // List available tools asynchronously + client.listTools() + .doOnNext(tools -> tools.tools().forEach(tool -> + System.out.println(tool.name()))) + .subscribe(); + + // Call a tool asynchronously + client.callTool(new CallToolRequest("calculator", Map.of( + "operation", "add", + "a", 1, + "b", 2 + ))) + .subscribe(); + ``` + +### Tool Schema Validation and Caching + +The client supports optional JSON schema validation for tool call results and automatic schema caching: + +```java +var client = McpClient.sync(transport) + .jsonSchemaValidator(myValidator) // Enable schema validation + .enableCallToolSchemaCaching(true) // Cache tool schemas + .build(); +``` + +### Resource Access + +Resources represent server-side data sources that clients can access using URI templates. The MCP client provides methods to discover available resources and retrieve their contents through a standardized interface. + +=== "Sync API" + + ```java + // List available resources + ListResourcesResult resources = client.listResources(); + + // Read a resource + ReadResourceResult resource = client.readResource( + new ReadResourceRequest("resource://uri") + ); + ``` + +=== "Async API" + + ```java + // List available resources asynchronously + client.listResources() + .doOnNext(resources -> resources.resources().forEach(resource -> + System.out.println(resource.name()))) + .subscribe(); + + // Read a resource asynchronously + client.readResource(new ReadResourceRequest("resource://uri")) + .subscribe(); + ``` + +### Prompt System + +The prompt system enables interaction with server-side prompt templates. These templates can be discovered and executed with custom parameters, allowing for dynamic text generation based on predefined patterns. + +=== "Sync API" + + ```java + // List available prompt templates + ListPromptsResult prompts = client.listPrompts(); + + // Get a prompt with parameters + GetPromptResult prompt = client.getPrompt( + new GetPromptRequest("greeting", Map.of("name", "World")) + ); + ``` + +=== "Async API" + + ```java + // List available prompt templates asynchronously + client.listPrompts() + .doOnNext(prompts -> prompts.prompts().forEach(prompt -> + System.out.println(prompt.name()))) + .subscribe(); + + // Get a prompt asynchronously + client.getPrompt(new GetPromptRequest("greeting", Map.of("name", "World"))) + .subscribe(); + ``` diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 000000000..e00c7268b --- /dev/null +++ b/docs/development.md @@ -0,0 +1,75 @@ +--- +title: Documentation +description: How to contribute to the MCP Java SDK documentation +--- + +# Documentation Development + +This guide covers how to set up and preview the MCP Java SDK documentation locally. + +!!! info "Prerequisites" + - Python 3.x + - pip (Python package manager) + +## Setup + +Install mkdocs-material: + +```bash +pip install mkdocs-material +``` + +## Preview Locally + +From the project root directory, run: + +```bash +mkdocs serve +``` + +A local preview of the documentation will be available at `http://localhost:8000`. + +### Custom Ports + +By default, mkdocs uses port 8000. You can customize the port with the `-a` flag: + +```bash +mkdocs serve -a localhost:3333 +``` + +## Building + +To build the static site for deployment: + +```bash +mkdocs build +``` + +The built site will be output to the `site/` directory. + +## Project Structure + +``` +docs/ +├── index.md # Overview page +├── quickstart.md # Quickstart guide +├── client.md # MCP Client documentation +├── server.md # MCP Server documentation +├── contributing.md # Contributing guide +├── development.md # This page +├── images/ # Images and diagrams +└── stylesheets/ # Custom CSS +mkdocs.yml # MkDocs configuration +``` + +## Writing Guidelines + +- Documentation pages use standard Markdown with [mkdocs-material extensions](https://squidfunk.github.io/mkdocs-material/reference/) +- Use content tabs (`=== "Tab Label"`) for Maven/Gradle or Sync/Async code examples +- Use admonitions (`!!! tip`, `!!! info`, `!!! warning`) for callouts +- All code blocks should specify a language for syntax highlighting +- Images go in the `docs/images/` directory + +## IDE Support + +We suggest using extensions on your IDE to recognize and format Markdown. If you're a VSCode user, consider the [Markdown All in One](https://marketplace.visualstudio.com/items?itemName=yzhang.markdown-all-in-one) extension for enhanced Markdown support, and [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) for code formatting. diff --git a/docs/images/favicon.svg b/docs/images/favicon.svg new file mode 100644 index 000000000..fe5edb725 --- /dev/null +++ b/docs/images/favicon.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + diff --git a/docs/images/java-mcp-client-architecture.jpg b/docs/images/java-mcp-client-architecture.jpg new file mode 100644 index 000000000..688a2b4ad Binary files /dev/null and b/docs/images/java-mcp-client-architecture.jpg differ diff --git a/docs/images/java-mcp-server-architecture.jpg b/docs/images/java-mcp-server-architecture.jpg new file mode 100644 index 000000000..4b05ca139 Binary files /dev/null and b/docs/images/java-mcp-server-architecture.jpg differ diff --git a/docs/images/java-mcp-uml-classdiagram.svg b/docs/images/java-mcp-uml-classdiagram.svg new file mode 100644 index 000000000..f83a586e7 --- /dev/null +++ b/docs/images/java-mcp-uml-classdiagram.svg @@ -0,0 +1 @@ +McpTransportMono<Void> connect(Function<Mono<JSONRPCMessage>, Mono<JSONRPCMessage>> handler)Mono<Void> sendMessage(JSONRPCMessage message)void close()Mono<Void> closeGracefully()<T> T unmarshalFrom(Object data, TypeReference<T> typeRef)McpSession<T> Mono<T> sendRequest(String method, Object requestParams, TypeReference<T> typeRef)Mono<Void> sendNotification(String method, Map<String, Object> params)Mono<Void> closeGracefully()void close()DefaultMcpSessioninterface RequestHandlerinterface NotificationHandlerMcpClientBuilder using(ClientMcpTransport transport)McpAsyncClientMono<InitializeResult> initialize()ServerCapabilities getServerCapabilities()Implementation getServerInfo()ClientCapabilities getClientCapabilities()Implementation getClientInfo()void close()Mono<Void> closeGracefully()Mono<Object> ping()Mono<Void> addRoot(Root root)Mono<Void> removeRoot(String rootUri)Mono<Void> rootsListChangedNotification()Mono<CallToolResult> callTool(CallToolRequest request)Mono<ListToolsResult> listTools()Mono<ListResourcesResult> listResources()Mono<ReadResourceResult> readResource(ReadResourceRequest request)Mono<ListResourceTemplatesResult> listResourceTemplates()Mono<Void> subscribeResource(SubscribeRequest request)Mono<Void> unsubscribeResource(UnsubscribeRequest request)Mono<ListPromptsResult> listPrompts()Mono<GetPromptResult> getPrompt(GetPromptRequest request)Mono<Void> setLoggingLevel(LoggingLevel level)McpSyncClientInitializeResult initialize()ServerCapabilities getServerCapabilities()Implementation getServerInfo()ClientCapabilities getClientCapabilities()Implementation getClientInfo()void close()boolean closeGracefully()Object ping()void addRoot(Root root)void removeRoot(String rootUri)void rootsListChangedNotification()CallToolResult callTool(CallToolRequest request)ListToolsResult listTools()ListResourcesResult listResources()ReadResourceResult readResource(ReadResourceRequest request)ListResourceTemplatesResult listResourceTemplates()void subscribeResource(SubscribeRequest request)void unsubscribeResource(UnsubscribeRequest request)ListPromptsResult listPrompts()GetPromptResult getPrompt(GetPromptRequest request)void setLoggingLevel(LoggingLevel level)McpServerBuilder using(ServerMcpTransport transport)McpAsyncServerServerCapabilities getServerCapabilities()Implementation getServerInfo()ClientCapabilities getClientCapabilities()Implementation getClientInfo()void close()Mono<Void> closeGracefully() Mono<Void> addTool(ToolRegistration toolRegistration)Mono<Void> removeTool(String toolName)Mono<Void> notifyToolsListChanged() Mono<Void> addResource(ResourceRegistration resourceHandler)Mono<Void> removeResource(String resourceUri)Mono<Void> notifyResourcesListChanged() Mono<Void> addPrompt(PromptRegistration promptRegistration)Mono<Void> removePrompt(String promptName)Mono<Void> notifyPromptsListChanged() Mono<Void> loggingNotification(LoggingMessageNotification notification) Mono<CreateMessageResult> createMessage(CreateMessageRequest request)McpSyncServerMcpAsyncServer getAsyncServer() ServerCapabilities getServerCapabilities()Implementation getServerInfo()ClientCapabilities getClientCapabilities()Implementation getClientInfo()void close()void closeGracefully() void addTool(ToolRegistration toolHandler)void removeTool(String toolName)void notifyToolsListChanged() void addResource(ResourceRegistration resourceHandler)void removeResource(String resourceUri)void notifyResourcesListChanged() void addPrompt(PromptRegistration promptRegistration)void removePrompt(String promptName)void notifyPromptsListChanged() void loggingNotification(LoggingMessageNotification notification) CreateMessageResult createMessage(CreateMessageRequest request)StdioClientTransportvoid setErrorHandler(Consumer<String> errorHandler)Sinks.Many<String> getErrorSink()ClientMcpTransportStdioServerTransportServerMcpTransportHttpServletSseServerTransportHttpClientSseClientTransportWebFluxSseClientTransportWebFluxSseServerTransportRouterFunction<?> getRouterFunction()WebMvcSseServerTransportRouterFunction<?> getRouterFunction()McpSchemaclass ErrorCodesinterface Requestinterface JSONRPCMessageinterface ResourceContentsinterface Contentinterface ServerCapabilitiesJSONRPCMessage deserializeJsonRpcMessage()McpErrorcreatescreatesdelegates tocreatescreatesusesthrows \ No newline at end of file diff --git a/docs/images/logo-dark.svg b/docs/images/logo-dark.svg new file mode 100644 index 000000000..03d9f85d3 --- /dev/null +++ b/docs/images/logo-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/docs/images/logo-light.svg b/docs/images/logo-light.svg new file mode 100644 index 000000000..fe5edb725 --- /dev/null +++ b/docs/images/logo-light.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + diff --git a/docs/images/mcp-stack.svg b/docs/images/mcp-stack.svg new file mode 100644 index 000000000..3847eaa8d --- /dev/null +++ b/docs/images/mcp-stack.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..71dcecfa1 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,131 @@ +--- +title: Overview +description: Introduction to the Model Context Protocol (MCP) Java SDK +--- + +# MCP Java SDK + +Java SDK for the [Model Context Protocol](https://modelcontextprotocol.io/docs/concepts/architecture) +enables standardized integration between AI models and tools. + +## Features + +- MCP Client and MCP Server implementations supporting: + - Protocol [version compatibility negotiation](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle#initialization) with multiple protocol versions + - [Tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) discovery, execution, list change notifications, and structured output with schema validation + - [Resources](https://modelcontextprotocol.io/specification/2025-11-25/server/resources) management with URI templates + - [Roots](https://modelcontextprotocol.io/specification/2025-11-25/client/roots) list management and notifications + - [Prompts](https://modelcontextprotocol.io/specification/2025-11-25/server/prompts) handling and management + - [Sampling](https://modelcontextprotocol.io/specification/2025-11-25/client/sampling) support for AI model interactions + - [Elicitation](https://modelcontextprotocol.io/specification/2025-11-25/client/elicitation) support for requesting user input from servers + - [Completions](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/completion) for argument autocompletion suggestions + - [Progress](https://modelcontextprotocol.io/specification/2025-11-25/basic/utilities/progress) - progress notifications for tracking long-running operations + - [Logging](https://modelcontextprotocol.io/specification/2025-11-25/server/utilities/logging) - structured logging with configurable severity levels +- Multiple transport implementations: + - Default transports (included in core `mcp` module, no external web frameworks required): + - [STDIO](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#stdio)-based transport for process-based communication + - Java HttpClient-based SSE client transport for HTTP SSE Client-side streaming + - Servlet-based SSE server transport for HTTP SSE Server streaming + - [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http) transport for efficient bidirectional communication (client and server) + - Optional Spring-based transports (convenience if using Spring Framework): + - WebFlux SSE client and server transports for reactive HTTP streaming + - WebFlux Streamable HTTP server transport + - WebMVC SSE server transport for servlet-based HTTP streaming + - WebMVC Streamable HTTP server transport + - WebMVC Stateless server transport +- Supports Synchronous and Asynchronous programming paradigms +- Pluggable JSON serialization (Jackson 2.x and Jackson 3.x) +- Pluggable authorization hooks for server security +- DNS rebinding protection with Host/Origin header validation + +!!! tip + The core `io.modelcontextprotocol.sdk:mcp` module provides default STDIO, SSE, and Streamable HTTP client and server transport implementations without requiring external web frameworks. + + Spring-specific transports are available as optional dependencies for convenience when using the [MCP Client Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) and [MCP Server Boot Starter](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-server-boot-starter-docs.html). + Also consider the [MCP Annotations](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-annotations-overview.html) and [MCP Security](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-security.html). + +## Architecture + +The SDK follows a layered architecture with clear separation of concerns: + +![MCP Stack Architecture](images/mcp-stack.svg) + +- **Client/Server Layer (McpClient/McpServer)**: Both use McpSession for sync/async operations, + with McpClient handling client-side protocol operations and McpServer managing server-side protocol operations. +- **Session Layer (McpSession)**: Manages communication patterns and state. +- **Transport Layer (McpTransport)**: Handles JSON-RPC message serialization/deserialization via: + - StdioTransport (stdin/stdout) in the core module + - HTTP SSE transports in dedicated transport modules (Java HttpClient, Spring WebFlux, Spring WebMVC) + - Streamable HTTP transports for efficient bidirectional communication + +The MCP Client is a key component in the Model Context Protocol (MCP) architecture, responsible for establishing and managing connections with MCP servers. +It implements the client-side of the protocol. + +![Java MCP Client Architecture](images/java-mcp-client-architecture.jpg) + +The MCP Server is a foundational component in the Model Context Protocol (MCP) architecture that provides tools, resources, and capabilities to clients. +It implements the server-side of the protocol. + +![Java MCP Server Architecture](images/java-mcp-server-architecture.jpg) + +Key Interactions: + +- **Client/Server Initialization**: Transport setup, protocol compatibility check, capability negotiation, and implementation details exchange. +- **Message Flow**: JSON-RPC message handling with validation, type-safe response processing, and error handling. +- **Resource Management**: Resource discovery, URI template-based access, subscription system, and content retrieval. + +## Module Structure + +The SDK is organized into modules to separate concerns and allow adopters to bring in only what they need: + +| Module | Artifact ID | Purpose | +|--------|------------|---------| +| `mcp-bom` | `mcp-bom` | Bill of Materials for dependency management | +| `mcp-core` | `mcp-core` | Core reference implementation (STDIO, JDK HttpClient, Servlet, Streamable HTTP) | +| `mcp-json-jackson2` | `mcp-json-jackson2` | Jackson 2.x JSON serialization implementation | +| `mcp-json-jackson3` | `mcp-json-jackson3` | Jackson 3.x JSON serialization implementation | +| `mcp` | `mcp` | Convenience bundle (`mcp-core` + `mcp-json-jackson3`) | +| `mcp-test` | `mcp-test` | Shared testing utilities and integration tests | +| `mcp-spring-webflux` | `mcp-spring-webflux` | Spring WebFlux integration (SSE and Streamable HTTP) | +| `mcp-spring-webmvc` | `mcp-spring-webmvc` | Spring WebMVC integration (SSE and Streamable HTTP) | + +!!! tip + A minimal adopter may depend only on `mcp` (core + Jackson 3), while a Spring-based application can add `mcp-spring-webflux` or `mcp-spring-webmvc` for deeper framework integration. + +## Next Steps + +
+ +- :rocket:{ .lg .middle } **Quickstart** + + --- + + Get started with dependencies and BOM configuration. + + [:octicons-arrow-right-24: Quickstart](quickstart.md) + +- :material-monitor:{ .lg .middle } **MCP Client** + + --- + + Learn how to create and configure MCP clients. + + [:octicons-arrow-right-24: Client](client.md) + +- :material-server:{ .lg .middle } **MCP Server** + + --- + + Learn how to implement and configure MCP servers. + + [:octicons-arrow-right-24: Server](server.md) + +- :fontawesome-brands-github:{ .lg .middle } **GitHub** + + --- + + View the source code and contribute. + + [:octicons-arrow-right-24: Repository](https://github.com/modelcontextprotocol/java-sdk) + +
diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 000000000..4c43c07f3 --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,160 @@ +--- +title: Quickstart +description: Get started with the MCP Java SDK dependencies and configuration +--- + +# Quickstart + +## Dependencies + +Add the following dependency to your project: + +=== "Maven" + + The convenience `mcp` module bundles `mcp-core` with Jackson 3.x JSON serialization: + + ```xml + + io.modelcontextprotocol.sdk + mcp + + ``` + + This includes default STDIO, SSE, and Streamable HTTP transport implementations without requiring external web frameworks. + + If you need only the core module without a JSON implementation (e.g., to bring your own): + + ```xml + + io.modelcontextprotocol.sdk + mcp-core + + ``` + + For Jackson 2.x instead of Jackson 3.x: + + ```xml + + io.modelcontextprotocol.sdk + mcp-core + + + io.modelcontextprotocol.sdk + mcp-json-jackson2 + + ``` + + If you're using the Spring Framework and want Spring-specific transport implementations, add one of the following optional dependencies: + + ```xml + + + io.modelcontextprotocol.sdk + mcp-spring-webflux + + + + + io.modelcontextprotocol.sdk + mcp-spring-webmvc + + ``` + +=== "Gradle" + + The convenience `mcp` module bundles `mcp-core` with Jackson 3.x JSON serialization: + + ```groovy + dependencies { + implementation "io.modelcontextprotocol.sdk:mcp" + } + ``` + + This includes default STDIO, SSE, and Streamable HTTP transport implementations without requiring external web frameworks. + + If you need only the core module without a JSON implementation (e.g., to bring your own): + + ```groovy + dependencies { + implementation "io.modelcontextprotocol.sdk:mcp-core" + } + ``` + + For Jackson 2.x instead of Jackson 3.x: + + ```groovy + dependencies { + implementation "io.modelcontextprotocol.sdk:mcp-core" + implementation "io.modelcontextprotocol.sdk:mcp-json-jackson2" + } + ``` + + If you're using the Spring Framework and want Spring-specific transport implementations, add one of the following optional dependencies: + + ```groovy + // Optional: Spring WebFlux-based SSE and Streamable HTTP client and server transport + dependencies { + implementation "io.modelcontextprotocol.sdk:mcp-spring-webflux" + } + + // Optional: Spring WebMVC-based SSE and Streamable HTTP server transport + dependencies { + implementation "io.modelcontextprotocol.sdk:mcp-spring-webmvc" + } + ``` + +## Bill of Materials (BOM) + +The Bill of Materials (BOM) declares the recommended versions of all the dependencies used by a given release. +Using the BOM from your application's build script avoids the need for you to specify and maintain the dependency versions yourself. +Instead, the version of the BOM you're using determines the utilized dependency versions. +It also ensures that you're using supported and tested versions of the dependencies by default, unless you choose to override them. + +Add the BOM to your project: + +=== "Maven" + + ```xml + + + + io.modelcontextprotocol.sdk + mcp-bom + 0.17.2 + pom + import + + + + ``` + +=== "Gradle" + + ```groovy + dependencies { + implementation platform("io.modelcontextprotocol.sdk:mcp-bom:0.17.2") + //... + } + ``` + + Gradle users can also leverage Gradle (5.0+) native support for declaring dependency constraints using a Maven BOM. + This is implemented by adding a 'platform' dependency handler method to the dependencies section of your Gradle build script. + As shown in the snippet above this can then be followed by version-less declarations of the dependencies. + +Replace the version number with the latest version from [Maven Central](https://central.sonatype.com/artifact/io.modelcontextprotocol.sdk/mcp). + +## Available Dependencies + +The following dependencies are available and managed by the BOM: + +- **Core Dependencies** + - `io.modelcontextprotocol.sdk:mcp-core` - Core MCP library providing the base functionality, APIs, and default transport implementations (STDIO, SSE, Streamable HTTP). JSON binding is abstracted for pluggability. + - `io.modelcontextprotocol.sdk:mcp` - Convenience bundle that combines `mcp-core` with `mcp-json-jackson3` for out-of-the-box usage. +- **JSON Serialization** + - `io.modelcontextprotocol.sdk:mcp-json-jackson3` - Jackson 3.x JSON serialization implementation (included in `mcp` bundle). + - `io.modelcontextprotocol.sdk:mcp-json-jackson2` - Jackson 2.x JSON serialization implementation for projects that require Jackson 2.x compatibility. +- **Optional Transport Dependencies** (convenience if using Spring Framework) + - `io.modelcontextprotocol.sdk:mcp-spring-webflux` - WebFlux-based SSE and Streamable HTTP transport implementation for reactive applications. + - `io.modelcontextprotocol.sdk:mcp-spring-webmvc` - WebMVC-based SSE and Streamable HTTP transport implementation for servlet-based applications. +- **Testing Dependencies** + - `io.modelcontextprotocol.sdk:mcp-test` - Testing utilities and support for MCP-based applications. diff --git a/docs/server.md b/docs/server.md new file mode 100644 index 000000000..3c05aee30 --- /dev/null +++ b/docs/server.md @@ -0,0 +1,755 @@ +--- +title: MCP Server +description: Learn how to implement and configure a Model Context Protocol (MCP) server +--- + +# MCP Server + +## Overview + +The MCP Server is a foundational component in the Model Context Protocol (MCP) architecture that provides tools, resources, and capabilities to clients. It implements the server-side of the protocol, responsible for: + +- Exposing tools that clients can discover and execute +- Managing resources with URI-based access patterns and resource templates +- Providing prompt templates and handling prompt requests +- Supporting capability negotiation with clients +- Providing argument autocompletion suggestions (completions) +- Implementing server-side protocol operations +- Managing concurrent client connections +- Providing structured logging and notifications + +!!! tip + The core `io.modelcontextprotocol.sdk:mcp` module provides STDIO, SSE, and Streamable HTTP server transport implementations without requiring external web frameworks. + + Spring-specific transport implementations are available as **optional** dependencies `io.modelcontextprotocol.sdk:mcp-spring-webflux`, `io.modelcontextprotocol.sdk:mcp-spring-webmvc` for [Spring Framework](https://docs.spring.io/spring-ai/reference/api/mcp/mcp-client-boot-starter-docs.html) users. + +The server supports both synchronous and asynchronous APIs, allowing for flexible integration in different application contexts. + +=== "Sync API" + + ```java + // Create a server with custom configuration + McpSyncServer syncServer = McpServer.sync(transportProvider) + .serverInfo("my-server", "1.0.0") + .capabilities(ServerCapabilities.builder() + .resources(false, true) // Enable resource support with list changes + .tools(true) // Enable tool support with list changes + .prompts(true) // Enable prompt support with list changes + .completions() // Enable completions support + .logging() // Enable logging support + .build()) + .build(); + + // Register tools, resources, and prompts + syncServer.addTool(syncToolSpecification); + syncServer.addResource(syncResourceSpecification); + syncServer.addPrompt(syncPromptSpecification); + + // Close the server when done + syncServer.close(); + ``` + +=== "Async API" + + ```java + // Create an async server with custom configuration + McpAsyncServer asyncServer = McpServer.async(transportProvider) + .serverInfo("my-server", "1.0.0") + .capabilities(ServerCapabilities.builder() + .resources(false, true) // Enable resource support with list changes + .tools(true) // Enable tool support with list changes + .prompts(true) // Enable prompt support with list changes + .completions() // Enable completions support + .logging() // Enable logging support + .build()) + .build(); + + // Register tools, resources, and prompts + asyncServer.addTool(asyncToolSpecification) + .doOnSuccess(v -> logger.info("Tool registered")) + .subscribe(); + + asyncServer.addResource(asyncResourceSpecification) + .doOnSuccess(v -> logger.info("Resource registered")) + .subscribe(); + + asyncServer.addPrompt(asyncPromptSpecification) + .doOnSuccess(v -> logger.info("Prompt registered")) + .subscribe(); + + // Close the server when done + asyncServer.close() + .doOnSuccess(v -> logger.info("Server closed")) + .subscribe(); + ``` + +### Server Types + +The SDK supports multiple server creation patterns depending on your transport requirements: + +```java +// Single-session server with SSE transport provider +McpSyncServer server = McpServer.sync(sseTransportProvider).build(); + +// Streamable HTTP server +McpSyncServer server = McpServer.sync(streamableTransportProvider).build(); + +// Stateless server (no session management) +McpSyncServer server = McpServer.sync(statelessTransport).build(); +``` + +## Server Transport Providers + +The transport layer in the MCP SDK is responsible for handling the communication between clients and servers. +It provides different implementations to support various communication protocols and patterns. +The SDK includes several built-in transport provider implementations: + +=== "STDIO" + + Create process-based transport using stdin/stdout: + + ```java + StdioServerTransportProvider transportProvider = + new StdioServerTransportProvider(new ObjectMapper()); + ``` + + Provides bidirectional JSON-RPC message handling over standard input/output streams with non-blocking message processing, serialization/deserialization, and graceful shutdown support. + + Key features: + + - Bidirectional communication through stdin/stdout + - Process-based integration support + - Simple setup and configuration + - Lightweight implementation + +=== "Streamable HTTP (Servlet)" + + Creates a Servlet-based Streamable HTTP server transport. Included in the core `mcp` module: + + ```java + HttpServletStreamableServerTransportProvider transportProvider = + HttpServletStreamableServerTransportProvider.builder() + .jsonMapper(jsonMapper) + .mcpEndpoint("/mcp") + .build(); + ``` + + To use with a Spring Web application, register it as a Servlet bean: + + ```java + @Configuration + @EnableWebMvc + public class McpServerConfig implements WebMvcConfigurer { + + @Bean + public HttpServletStreamableServerTransportProvider transportProvider(McpJsonMapper jsonMapper) { + return HttpServletStreamableServerTransportProvider.builder() + .jsonMapper(jsonMapper) + .mcpEndpoint("/mcp") + .build(); + } + + @Bean + public ServletRegistrationBean mcpServlet( + HttpServletStreamableServerTransportProvider transportProvider) { + return new ServletRegistrationBean<>(transportProvider); + } + } + ``` + + Key features: + + - Efficient bidirectional HTTP communication + - Session management for multiple client connections + - Configurable keep-alive intervals + - Security validation support + - Graceful shutdown support + +=== "Streamable HTTP (WebFlux)" + + Creates WebFlux-based Streamable HTTP server transport. Requires the `mcp-spring-webflux` dependency: + + ```java + @Configuration + class McpConfig { + @Bean + WebFluxStreamableServerTransportProvider transportProvider(McpJsonMapper jsonMapper) { + return WebFluxStreamableServerTransportProvider.builder() + .jsonMapper(jsonMapper) + .messageEndpoint("/mcp") + .build(); + } + + @Bean + RouterFunction mcpRouterFunction( + WebFluxStreamableServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); + } + } + ``` + + Key features: + + - Reactive HTTP streaming with WebFlux + - Concurrent client connections + - Configurable keep-alive intervals + - Security validation support + +=== "Streamable HTTP (WebMvc)" + + Creates WebMvc-based Streamable HTTP server transport. Requires the `mcp-spring-webmvc` dependency: + + ```java + @Configuration + @EnableWebMvc + class McpConfig { + @Bean + WebMvcStreamableServerTransportProvider transportProvider(McpJsonMapper jsonMapper) { + return WebMvcStreamableServerTransportProvider.builder() + .jsonMapper(jsonMapper) + .mcpEndpoint("/mcp") + .build(); + } + + @Bean + RouterFunction mcpRouterFunction( + WebMvcStreamableServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); + } + } + ``` + +=== "SSE (WebFlux)" + + Creates WebFlux-based SSE server transport. Requires the `mcp-spring-webflux` dependency: + + ```java + @Configuration + class McpConfig { + @Bean + WebFluxSseServerTransportProvider webFluxSseServerTransportProvider(ObjectMapper mapper) { + return new WebFluxSseServerTransportProvider(mapper, "/mcp/message"); + } + + @Bean + RouterFunction mcpRouterFunction(WebFluxSseServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); + } + } + ``` + + Implements the MCP HTTP with SSE transport specification, providing: + + - Reactive HTTP streaming with WebFlux + - Concurrent client connections through SSE endpoints + - Message routing and session management + - Graceful shutdown capabilities + +=== "SSE (WebMvc)" + + Creates WebMvc-based SSE server transport. Requires the `mcp-spring-webmvc` dependency: + + ```java + @Configuration + @EnableWebMvc + class McpConfig { + @Bean + WebMvcSseServerTransportProvider webMvcSseServerTransportProvider(ObjectMapper mapper) { + return new WebMvcSseServerTransportProvider(mapper, "/mcp/message"); + } + + @Bean + RouterFunction mcpRouterFunction( + WebMvcSseServerTransportProvider transportProvider) { + return transportProvider.getRouterFunction(); + } + } + ``` + + Implements the MCP HTTP with SSE transport specification, providing: + + - Server-side event streaming + - Integration with Spring WebMVC + - Support for traditional web applications + - Synchronous operation handling + +=== "SSE (Servlet)" + + Creates a Servlet-based SSE server transport. Included in the core `mcp` module. + The `HttpServletSseServerTransportProvider` can be used with any Servlet container. + To use it with a Spring Web application, you can register it as a Servlet bean: + + ```java + @Configuration + @EnableWebMvc + public class McpServerConfig implements WebMvcConfigurer { + + @Bean + public HttpServletSseServerTransportProvider servletSseServerTransportProvider() { + return new HttpServletSseServerTransportProvider(new ObjectMapper(), "/mcp/message"); + } + + @Bean + public ServletRegistrationBean customServletBean( + HttpServletSseServerTransportProvider transportProvider) { + return new ServletRegistrationBean<>(transportProvider); + } + } + ``` + + Implements the MCP HTTP with SSE transport specification using the traditional Servlet API, providing: + + - Asynchronous message handling using Servlet 6.0 async support + - Session management for multiple client connections + - Two types of endpoints: + - SSE endpoint (`/sse`) for server-to-client events + - Message endpoint (configurable) for client-to-server requests + - Error handling and response formatting + - Graceful shutdown support + +## Server Capabilities + +The server can be configured with various capabilities: + +```java +var capabilities = ServerCapabilities.builder() + .resources(false, true) // Resource support (subscribe, listChanged) + .tools(true) // Tool support with list changes notifications + .prompts(true) // Prompt support with list changes notifications + .completions() // Enable completions support + .logging() // Enable logging support + .build(); +``` + +### Tool Specification + +The Model Context Protocol allows servers to [expose tools](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/tools/) that can be invoked by language models. +The Java SDK allows implementing Tool Specifications with their handler functions. +Tools enable AI models to perform calculations, access external APIs, query databases, and manipulate files. + +The recommended approach is to use the builder pattern and `CallToolRequest` as the handler parameter: + +=== "Sync" + + ```java + // Sync tool specification using builder + var syncToolSpecification = SyncToolSpecification.builder() + .tool(Tool.builder() + .name("calculator") + .description("Basic calculator") + .inputSchema(schema) + .build()) + .callHandler((exchange, request) -> { + // Access arguments via request.arguments() + String operation = (String) request.arguments().get("operation"); + int a = (int) request.arguments().get("a"); + int b = (int) request.arguments().get("b"); + // Tool implementation + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Result: " + result))) + .build(); + }) + .build(); + ``` + +=== "Async" + + ```java + // Async tool specification using builder + var asyncToolSpecification = AsyncToolSpecification.builder() + .tool(Tool.builder() + .name("calculator") + .description("Basic calculator") + .inputSchema(schema) + .build()) + .callHandler((exchange, request) -> { + // Access arguments via request.arguments() + String operation = (String) request.arguments().get("operation"); + int a = (int) request.arguments().get("a"); + int b = (int) request.arguments().get("b"); + // Tool implementation + return Mono.just(CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Result: " + result))) + .build()); + }) + .build(); + ``` + +The Tool specification includes a Tool definition with `name`, `description`, and `inputSchema` followed by a call handler that implements the tool's logic. +The handler receives `McpSyncServerExchange`/`McpAsyncServerExchange` for client interaction and a `CallToolRequest` containing the tool arguments. + +You can also register tools directly on the server builder using the `toolCall` convenience method: + +```java +var server = McpServer.sync(transportProvider) + .toolCall( + Tool.builder().name("echo").description("Echoes input").inputSchema(schema).build(), + (exchange, request) -> CallToolResult.builder() + .content(List.of(new McpSchema.TextContent(request.arguments().get("text").toString()))) + .build() + ) + .build(); +``` + +### Resource Specification + +Specification of a resource with its handler function. +Resources provide context to AI models by exposing data such as: File contents, Database records, API responses, System information, Application state. + +=== "Sync" + + ```java + // Sync resource specification + var syncResourceSpecification = new McpServerFeatures.SyncResourceSpecification( + Resource.builder() + .uri("custom://resource") + .name("name") + .description("description") + .mimeType("text/plain") + .build(), + (exchange, request) -> { + // Resource read implementation + return new ReadResourceResult(contents); + } + ); + ``` + +=== "Async" + + ```java + // Async resource specification + var asyncResourceSpecification = new McpServerFeatures.AsyncResourceSpecification( + Resource.builder() + .uri("custom://resource") + .name("name") + .description("description") + .mimeType("text/plain") + .build(), + (exchange, request) -> { + // Resource read implementation + return Mono.just(new ReadResourceResult(contents)); + } + ); + ``` + +### Resource Template Specification + +Resource templates allow servers to expose parameterized resources using URI templates: + +```java +// Resource template specification +var resourceTemplateSpec = new McpServerFeatures.SyncResourceTemplateSpecification( + ResourceTemplate.builder() + .uriTemplate("file://{path}") + .name("File Resource") + .description("Access files by path") + .mimeType("application/octet-stream") + .build(), + (exchange, request) -> { + // Read the file at the requested URI + return new ReadResourceResult(contents); + } +); +``` + +### Prompt Specification + +As part of the [Prompting capabilities](https://spec.modelcontextprotocol.io/specification/2024-11-05/server/prompts/), MCP provides a standardized way for servers to expose prompt templates to clients. +The Prompt Specification is a structured template for AI model interactions that enables consistent message formatting, parameter substitution, context injection, response formatting, and instruction templating. + +=== "Sync" + + ```java + // Sync prompt specification + var syncPromptSpecification = new McpServerFeatures.SyncPromptSpecification( + new Prompt("greeting", "description", List.of( + new PromptArgument("name", "description", true) + )), + (exchange, request) -> { + // Prompt implementation + return new GetPromptResult(description, messages); + } + ); + ``` + +=== "Async" + + ```java + // Async prompt specification + var asyncPromptSpecification = new McpServerFeatures.AsyncPromptSpecification( + new Prompt("greeting", "description", List.of( + new PromptArgument("name", "description", true) + )), + (exchange, request) -> { + // Prompt implementation + return Mono.just(new GetPromptResult(description, messages)); + } + ); + ``` + +The prompt definition includes name (identifier for the prompt), description (purpose of the prompt), and list of arguments (parameters for templating). +The handler function processes requests and returns formatted templates. +The first argument is `McpSyncServerExchange`/`McpAsyncServerExchange` for client interaction, and the second argument is a `GetPromptRequest` instance. + +### Completion Specification + +Completions allow servers to provide argument autocompletion suggestions for prompts and resources: + +=== "Sync" + + ```java + // Sync completion specification + var syncCompletionSpec = new McpServerFeatures.SyncCompletionSpecification( + new McpSchema.PromptReference("greeting"), // Reference to a prompt + (exchange, request) -> { + String argName = request.argument().name(); + String partial = request.argument().value(); + // Return matching suggestions + List suggestions = findMatches(partial); + return new McpSchema.CompleteResult( + new McpSchema.CompleteResult.CompleteCompletion(suggestions, suggestions.size(), false) + ); + } + ); + ``` + +=== "Async" + + ```java + // Async completion specification + var asyncCompletionSpec = new McpServerFeatures.AsyncCompletionSpecification( + new McpSchema.PromptReference("greeting"), + (exchange, request) -> { + String argName = request.argument().name(); + String partial = request.argument().value(); + List suggestions = findMatches(partial); + return Mono.just(new McpSchema.CompleteResult( + new McpSchema.CompleteResult.CompleteCompletion(suggestions, suggestions.size(), false) + )); + } + ); + ``` + +Completions can be registered for both `PromptReference` and `ResourceReference` types. + +### Using Sampling from a Server + +To use [Sampling capabilities](https://spec.modelcontextprotocol.io/specification/2024-11-05/client/sampling/), connect to a client that supports sampling. +No special server configuration is needed, but verify client sampling support before making requests. +Learn about [client sampling support](client.md#sampling-support). + +Once connected to a compatible client, the server can request language model generations: + +=== "Sync API" + + ```java + // Create a server + McpSyncServer server = McpServer.sync(transportProvider) + .serverInfo("my-server", "1.0.0") + .build(); + + // Define a tool that uses sampling + var calculatorTool = SyncToolSpecification.builder() + .tool(Tool.builder() + .name("ai-calculator") + .description("Performs calculations using AI") + .inputSchema(schema) + .build()) + .callHandler((exchange, request) -> { + // Check if client supports sampling + if (exchange.getClientCapabilities().sampling() == null) { + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Client does not support AI capabilities"))) + .build(); + } + + // Create a sampling request + CreateMessageRequest samplingRequest = CreateMessageRequest.builder() + .messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("Calculate: " + request.arguments().get("expression"))))) + .modelPreferences(McpSchema.ModelPreferences.builder() + .hints(List.of( + McpSchema.ModelHint.of("claude-3-sonnet"), + McpSchema.ModelHint.of("claude") + )) + .intelligencePriority(0.8) + .speedPriority(0.5) + .build()) + .systemPrompt("You are a helpful calculator assistant. Provide only the numerical answer.") + .maxTokens(100) + .build(); + + // Request sampling from the client + CreateMessageResult result = exchange.createMessage(samplingRequest); + + // Process the result + String answer = ((McpSchema.TextContent) result.content()).text(); + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent(answer))) + .build(); + }) + .build(); + + // Add the tool to the server + server.addTool(calculatorTool); + ``` + +=== "Async API" + + ```java + // Create a server + McpAsyncServer server = McpServer.async(transportProvider) + .serverInfo("my-server", "1.0.0") + .build(); + + // Define a tool that uses sampling + var calculatorTool = AsyncToolSpecification.builder() + .tool(Tool.builder() + .name("ai-calculator") + .description("Performs calculations using AI") + .inputSchema(schema) + .build()) + .callHandler((exchange, request) -> { + // Check if client supports sampling + if (exchange.getClientCapabilities().sampling() == null) { + return Mono.just(CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Client does not support AI capabilities"))) + .build()); + } + + // Create a sampling request + CreateMessageRequest samplingRequest = CreateMessageRequest.builder() + .messages(List.of(new McpSchema.SamplingMessage(McpSchema.Role.USER, + new McpSchema.TextContent("Calculate: " + request.arguments().get("expression"))))) + .modelPreferences(McpSchema.ModelPreferences.builder() + .hints(List.of( + McpSchema.ModelHint.of("claude-3-sonnet"), + McpSchema.ModelHint.of("claude") + )) + .intelligencePriority(0.8) + .speedPriority(0.5) + .build()) + .systemPrompt("You are a helpful calculator assistant. Provide only the numerical answer.") + .maxTokens(100) + .build(); + + // Request sampling from the client + return exchange.createMessage(samplingRequest) + .map(result -> { + String answer = ((McpSchema.TextContent) result.content()).text(); + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent(answer))) + .build(); + }); + }) + .build(); + + // Add the tool to the server + server.addTool(calculatorTool) + .subscribe(); + ``` + +The `CreateMessageRequest` object allows you to specify: `Content` - the input text or image for the model, +`Model Preferences` - hints and priorities for model selection, `System Prompt` - instructions for the model's behavior and +`Max Tokens` - maximum length of the generated response. + +### Using Elicitation from a Server + +Servers can request user input from connected clients that support elicitation: + +```java +var tool = SyncToolSpecification.builder() + .tool(Tool.builder() + .name("confirm-action") + .description("Confirms an action with the user") + .inputSchema(schema) + .build()) + .callHandler((exchange, request) -> { + // Check if client supports elicitation + if (exchange.getClientCapabilities().elicitation() == null) { + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Client does not support elicitation"))) + .build(); + } + + // Request user confirmation + ElicitRequest elicitRequest = ElicitRequest.builder() + .message("Do you want to proceed with this action?") + .requestedSchema(Map.of( + "type", "object", + "properties", Map.of("confirmed", Map.of("type", "boolean")) + )) + .build(); + + ElicitResult result = exchange.elicit(elicitRequest); + + if (result.action() == ElicitResult.Action.ACCEPT) { + // User accepted + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Action confirmed"))) + .build(); + } else { + return CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Action declined"))) + .build(); + } + }) + .build(); +``` + +### Logging Support + +The server provides structured logging capabilities that allow sending log messages to clients with different severity levels. +Log notifications can only be sent from within an existing client session, such as tools, resources, and prompts calls. + +The server can send log messages using the `McpAsyncServerExchange`/`McpSyncServerExchange` object in the tool/resource/prompt handler function: + +```java +var tool = new McpServerFeatures.AsyncToolSpecification( + Tool.builder().name("logging-test").description("Test logging notifications").inputSchema(emptyJsonSchema).build(), + null, + (exchange, request) -> { + + exchange.loggingNotification( // Use the exchange to send log messages + McpSchema.LoggingMessageNotification.builder() + .level(McpSchema.LoggingLevel.DEBUG) + .logger("test-logger") + .data("Debug message") + .build()) + .block(); + + return Mono.just(CallToolResult.builder() + .content(List.of(new McpSchema.TextContent("Logging test completed"))) + .build()); + }); + +var mcpServer = McpServer.async(mcpServerTransportProvider) + .serverInfo("test-server", "1.0.0") + .capabilities( + ServerCapabilities.builder() + .logging() // Enable logging support + .tools(true) + .build()) + .tools(tool) + .build(); +``` + +On the client side, you can register a logging consumer to receive log messages from the server: + +```java +var mcpClient = McpClient.sync(transport) + .loggingConsumer(notification -> { + System.out.println("Received log message: " + notification.data()); + }) + .build(); + +mcpClient.initialize(); +mcpClient.setLoggingLevel(McpSchema.LoggingLevel.INFO); +``` + +Clients can control the minimum logging level they receive through the `mcpClient.setLoggingLevel(level)` request. Messages below the set level will be filtered out. +Supported logging levels (in order of increasing severity): DEBUG (0), INFO (1), NOTICE (2), WARNING (3), ERROR (4), CRITICAL (5), ALERT (6), EMERGENCY (7) + +## Error Handling + +The SDK provides comprehensive error handling through the McpError class, covering protocol compatibility, transport communication, JSON-RPC messaging, tool execution, resource management, prompt handling, timeouts, and connection issues. This unified error handling approach ensures consistent and reliable error management across both synchronous and asynchronous operations. diff --git a/docs/stylesheets/extra.css b/docs/stylesheets/extra.css new file mode 100644 index 000000000..20fba9276 --- /dev/null +++ b/docs/stylesheets/extra.css @@ -0,0 +1,13 @@ +:root { + --md-primary-fg-color: #16A34A; + --md-primary-fg-color--light: #07C983; + --md-primary-fg-color--dark: #15803D; + --md-accent-fg-color: #07C983; +} + +[data-md-color-scheme="slate"] { + --md-primary-fg-color: #07C983; + --md-primary-fg-color--light: #07C983; + --md-primary-fg-color--dark: #15803D; + --md-accent-fg-color: #07C983; +} diff --git a/migration-0.8.0.md b/migration-0.8.0.md deleted file mode 100644 index 3ba29a10b..000000000 --- a/migration-0.8.0.md +++ /dev/null @@ -1,328 +0,0 @@ -# MCP Java SDK Migration Guide: 0.7.0 to 0.8.0 - -This document outlines the breaking changes and provides guidance on how to migrate your code from version 0.7.0 to 0.8.0. - -The 0.8.0 refactoring introduces a session-based architecture for server-side MCP implementations. -It improves the SDK's ability to handle multiple concurrent client connections and provides an API better aligned with the MCP specification. -The main changes include: - -1. Introduction of a session-based architecture -2. New transport provider abstraction -3. Exchange objects for client interaction -4. Renamed and reorganized interfaces -5. Updated handler signatures - -## Breaking Changes - -### 1. Interface Renaming - -Several interfaces have been renamed to better reflect their roles: - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `ClientMcpTransport` | `McpClientTransport` | -| `ServerMcpTransport` | `McpServerTransport` | -| `DefaultMcpSession` | `McpClientSession`, `McpServerSession` | - -### 2. New Server Transport Architecture - -The most significant change is the introduction of the `McpServerTransportProvider` interface, which replaces direct usage of `ServerMcpTransport` when creating servers. This new pattern separates the concerns of: - -1. **Transport Provider**: Manages connections with clients and creates individual transports for each connection -2. **Server Transport**: Handles communication with a specific client connection - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `ServerMcpTransport` | `McpServerTransportProvider` + `McpServerTransport` | -| Direct transport usage | Session-based transport usage | - -#### Before (0.7.0): - -```java -// Create a transport -ServerMcpTransport transport = new WebFluxSseServerTransport(objectMapper, "/mcp/message"); - -// Create a server with the transport -McpServer.sync(transport) - .serverInfo("my-server", "1.0.0") - .build(); -``` - -#### After (0.8.0): - -```java -// Create a transport provider -McpServerTransportProvider transportProvider = new WebFluxSseServerTransportProvider(objectMapper, "/mcp/message"); - -// Create a server with the transport provider -McpServer.sync(transportProvider) - .serverInfo("my-server", "1.0.0") - .build(); -``` - -### 3. Handler Method Signature Changes - -Tool, resource, and prompt handlers now receive an additional `exchange` parameter that provides access to client capabilities and methods to interact with the client: - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `(args) -> result` | `(exchange, args) -> result` | - -The exchange objects (`McpAsyncServerExchange` and `McpSyncServerExchange`) provide context for the current session and access to session-specific operations. - -#### Before (0.7.0): - -```java -// Tool handler -.tool(calculatorTool, args -> new CallToolResult("Result: " + calculate(args))) - -// Resource handler -.resource(fileResource, req -> new ReadResourceResult(readFile(req))) - -// Prompt handler -.prompt(analysisPrompt, req -> new GetPromptResult("Analysis prompt")) -``` - -#### After (0.8.0): - -```java -// Tool handler -.tool(calculatorTool, (exchange, args) -> new CallToolResult("Result: " + calculate(args))) - -// Resource handler -.resource(fileResource, (exchange, req) -> new ReadResourceResult(readFile(req))) - -// Prompt handler -.prompt(analysisPrompt, (exchange, req) -> new GetPromptResult("Analysis prompt")) -``` - -### 4. Registration vs. Specification - -The naming convention for handlers has changed from "Registration" to "Specification": - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `AsyncToolRegistration` | `AsyncToolSpecification` | -| `SyncToolRegistration` | `SyncToolSpecification` | -| `AsyncResourceRegistration` | `AsyncResourceSpecification` | -| `SyncResourceRegistration` | `SyncResourceSpecification` | -| `AsyncPromptRegistration` | `AsyncPromptSpecification` | -| `SyncPromptRegistration` | `SyncPromptSpecification` | - -### 5. Roots Change Handler Updates - -The roots change handlers now receive an exchange parameter: - -#### Before (0.7.0): - -```java -.rootsChangeConsumers(List.of( - roots -> { - // Process roots - } -)) -``` - -#### After (0.8.0): - -```java -.rootsChangeHandlers(List.of( - (exchange, roots) -> { - // Process roots with access to exchange - } -)) -``` - -### 6. Server Creation Method Changes - -The `McpServer` factory methods now accept `McpServerTransportProvider` instead of `ServerMcpTransport`: - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `McpServer.async(ServerMcpTransport)` | `McpServer.async(McpServerTransportProvider)` | -| `McpServer.sync(ServerMcpTransport)` | `McpServer.sync(McpServerTransportProvider)` | - -The method names for creating servers have been updated: - -Root change handlers now receive an exchange object: - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `rootsChangeConsumers(List>>)` | `rootsChangeHandlers(List>>)` | -| `rootsChangeConsumer(Consumer>)` | `rootsChangeHandler(BiConsumer>)` | - -### 7. Direct Server Methods Moving to Exchange - -Several methods that were previously available directly on the server are now accessed through the exchange object: - -| 0.7.0 (Old) | 0.8.0 (New) | -|-------------|-------------| -| `server.listRoots()` | `exchange.listRoots()` | -| `server.createMessage()` | `exchange.createMessage()` | -| `server.getClientCapabilities()` | `exchange.getClientCapabilities()` | -| `server.getClientInfo()` | `exchange.getClientInfo()` | - -The direct methods are deprecated and will be removed in 0.9.0: - -- `McpSyncServer.listRoots()` -- `McpSyncServer.getClientCapabilities()` -- `McpSyncServer.getClientInfo()` -- `McpSyncServer.createMessage()` -- `McpAsyncServer.listRoots()` -- `McpAsyncServer.getClientCapabilities()` -- `McpAsyncServer.getClientInfo()` -- `McpAsyncServer.createMessage()` - -## Deprecation Notices - -The following components are deprecated in 0.8.0 and will be removed in 0.9.0: - -- `ClientMcpTransport` interface (use `McpClientTransport` instead) -- `ServerMcpTransport` interface (use `McpServerTransport` instead) -- `DefaultMcpSession` class (use `McpClientSession` instead) -- `WebFluxSseServerTransport` class (use `WebFluxSseServerTransportProvider` instead) -- `WebMvcSseServerTransport` class (use `WebMvcSseServerTransportProvider` instead) -- `StdioServerTransport` class (use `StdioServerTransportProvider` instead) -- All `*Registration` classes (use corresponding `*Specification` classes instead) -- Direct server methods for client interaction (use exchange object instead) - -## Migration Examples - -### Example 1: Creating a Server - -#### Before (0.7.0): - -```java -// Create a transport -ServerMcpTransport transport = new WebFluxSseServerTransport(objectMapper, "/mcp/message"); - -// Create a server with the transport -var server = McpServer.sync(transport) - .serverInfo("my-server", "1.0.0") - .tool(calculatorTool, args -> new CallToolResult("Result: " + calculate(args))) - .rootsChangeConsumers(List.of( - roots -> System.out.println("Roots changed: " + roots) - )) - .build(); - -// Get client capabilities directly from server -ClientCapabilities capabilities = server.getClientCapabilities(); -``` - -#### After (0.8.0): - -```java -// Create a transport provider -McpServerTransportProvider transportProvider = new WebFluxSseServerTransportProvider(objectMapper, "/mcp/message"); - -// Create a server with the transport provider -var server = McpServer.sync(transportProvider) - .serverInfo("my-server", "1.0.0") - .tool(calculatorTool, (exchange, args) -> { - // Get client capabilities from exchange - ClientCapabilities capabilities = exchange.getClientCapabilities(); - return new CallToolResult("Result: " + calculate(args)); - }) - .rootsChangeHandlers(List.of( - (exchange, roots) -> System.out.println("Roots changed: " + roots) - )) - .build(); -``` - -### Example 2: Implementing a Tool with Client Interaction - -#### Before (0.7.0): - -```java -McpServerFeatures.SyncToolRegistration tool = new McpServerFeatures.SyncToolRegistration( - new Tool("weather", "Get weather information", schema), - args -> { - String location = (String) args.get("location"); - // Cannot interact with client from here - return new CallToolResult("Weather for " + location + ": Sunny"); - } -); - -var server = McpServer.sync(transport) - .tools(tool) - .build(); - -// Separate call to create a message -CreateMessageResult result = server.createMessage(new CreateMessageRequest(...)); -``` - -#### After (0.8.0): - -```java -McpServerFeatures.SyncToolSpecification tool = new McpServerFeatures.SyncToolSpecification( - new Tool("weather", "Get weather information", schema), - (exchange, args) -> { - String location = (String) args.get("location"); - - // Can interact with client directly from the tool handler - CreateMessageResult result = exchange.createMessage(new CreateMessageRequest(...)); - - return new CallToolResult("Weather for " + location + ": " + result.content()); - } -); - -var server = McpServer.sync(transportProvider) - .tools(tool) - .build(); -``` - -### Example 3: Converting Existing Registration Classes - -If you have custom implementations of the registration classes, you can convert them to the new specification classes: - -#### Before (0.7.0): - -```java -McpServerFeatures.AsyncToolRegistration toolReg = new McpServerFeatures.AsyncToolRegistration( - tool, - args -> Mono.just(new CallToolResult("Result")) -); - -McpServerFeatures.AsyncResourceRegistration resourceReg = new McpServerFeatures.AsyncResourceRegistration( - resource, - req -> Mono.just(new ReadResourceResult(List.of())) -); -``` - -#### After (0.8.0): - -```java -// Option 1: Create new specification directly -McpServerFeatures.AsyncToolSpecification toolSpec = new McpServerFeatures.AsyncToolSpecification( - tool, - (exchange, args) -> Mono.just(new CallToolResult("Result")) -); - -// Option 2: Convert from existing registration (during transition) -McpServerFeatures.AsyncToolRegistration oldToolReg = /* existing registration */; -McpServerFeatures.AsyncToolSpecification toolSpec = oldToolReg.toSpecification(); - -// Similarly for resources -McpServerFeatures.AsyncResourceSpecification resourceSpec = new McpServerFeatures.AsyncResourceSpecification( - resource, - (exchange, req) -> Mono.just(new ReadResourceResult(List.of())) -); -``` - -## Architecture Changes - -### Session-Based Architecture - -In 0.8.0, the MCP Java SDK introduces a session-based architecture where each client connection has its own session. This allows for better isolation between clients and more efficient resource management. - -The `McpServerTransportProvider` is responsible for creating `McpServerTransport` instances for each session, and the `McpServerSession` manages the communication with a specific client. - -### Exchange Objects - -The new exchange objects (`McpAsyncServerExchange` and `McpSyncServerExchange`) provide access to client-specific information and methods. They are passed to handler functions as the first parameter, allowing handlers to interact with the specific client that made the request. - -## Conclusion - -The changes in version 0.8.0 represent a significant architectural improvement to the MCP Java SDK. While they require some code changes, the new design provides a more flexible and maintainable foundation for building MCP applications. - -For assistance with migration or to report issues, please open an issue on the GitHub repository. diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 000000000..845df82d6 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,88 @@ +site_name: MCP Java SDK +site_url: https://modelcontextprotocol.github.io/java-sdk/ +site_description: Java SDK for the Model Context Protocol - standardized integration between AI models and tools +repo_url: https://github.com/modelcontextprotocol/java-sdk +repo_name: modelcontextprotocol/java-sdk +edit_uri: edit/main/docs/ + +theme: + name: material + favicon: images/favicon.svg + logo: images/logo-light.svg + palette: + - scheme: default + primary: green + accent: green + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: green + accent: green + toggle: + icon: material/brightness-4 + name: Switch to light mode + features: + - navigation.instant + - navigation.instant.progress + - navigation.tabs + - navigation.tabs.sticky + - navigation.sections + - navigation.top + - navigation.path + - navigation.indexes + - toc.follow + - search.suggest + - search.highlight + - content.code.copy + - content.code.annotate + - content.tabs.link + +nav: + - Getting Started: + - Overview: index.md + - Quickstart: quickstart.md + - MCP Components: + - MCP Client: client.md + - MCP Server: server.md + - Contributing: + - Contributing Guide: contributing.md + - Documentation: development.md + - API Reference: https://javadoc.io/doc/io.modelcontextprotocol.sdk/mcp-core/latest + +markdown_extensions: + - admonition + - pymdownx.details + - pymdownx.superfences + - pymdownx.tabbed: + alternate_style: true + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.mark + - pymdownx.critic + - pymdownx.caret + - pymdownx.keys + - pymdownx.tilde + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - attr_list + - md_in_html + - tables + - toc: + permalink: true + +plugins: + - search + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/modelcontextprotocol/java-sdk + generator: false + +extra_css: + - stylesheets/extra.css