From 19dc0fc1223c58b94883e0991df03a50430831cf Mon Sep 17 00:00:00 2001 From: Zachary Lee Date: Thu, 30 Jan 2025 11:05:16 -0500 Subject: [PATCH 1/6] Base for Java docs --- development/updates.mdx | 3 +++ introduction.mdx | 2 +- sdk/java/overview.mdx | 31 +++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 sdk/java/overview.mdx diff --git a/development/updates.mdx b/development/updates.mdx index f7fc2d4..b80da76 100644 --- a/development/updates.mdx +++ b/development/updates.mdx @@ -3,6 +3,9 @@ title: "What's New" description: 'The latest updates and improvements to MCP' --- + + - We now have a [Java SDK](https://github.com/modelcontextprotocol/java-sdk)! + - Simplified, express-like API in the [TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk) - Added 8 new clients to the [clients page](https://modelcontextprotocol.io/clients) diff --git a/introduction.mdx b/introduction.mdx index 8620277..b9b01d8 100644 --- a/introduction.mdx +++ b/introduction.mdx @@ -3,7 +3,7 @@ title: Introduction description: 'Get started with the Model Context Protocol (MCP)' --- -Kotlin SDK released! Check out [what else is new.](/development/updates) +Java SDK released! Check out [what else is new.](/development/updates) MCP is an open protocol that standardizes how applications provide context to LLMs. Think of MCP like a USB-C port for AI applications. Just as USB-C provides a standardized way to connect your devices to various peripherals and accessories, MCP provides a standardized way to connect AI models to different data sources and tools. diff --git a/sdk/java/overview.mdx b/sdk/java/overview.mdx new file mode 100644 index 0000000..b00f817 --- /dev/null +++ b/sdk/java/overview.mdx @@ -0,0 +1,31 @@ +--- +title: Overview +description: Introduction to the Model Context Protocol (MCP) Java SDK +--- + +# MCP Java SDK + +Java SDK for the [Model Context Protocol](https://modelcontextprotocol.org/docs/concepts/architecture), enabling standardized interaction with AI models and tools through both synchronous and asynchronous communication. + +![Java MCP Client Architecture](/images/java-mcp-client-architecture.jpg) +![Java MCP Server Architecture](/images/java-mcp-server-architecture.jpg) + +## Getting Started + + + +```xml + + + org.modelcontextprotocol.sdk + mcp + + + + + org.modelcontextprotocol.sdk + mcp-spring-webflux + +``` + + \ No newline at end of file From c267635cd312560681b8ccc7a55095f999535d74 Mon Sep 17 00:00:00 2001 From: Christian Tzolov Date: Mon, 3 Feb 2025 15:01:49 +0100 Subject: [PATCH 2/6] docs(java): Migrate Java-SDK/docs Add visual documentation for Java SDK architecture: - PlantUML class diagrams showing core components and relationships - Client and server architecture diagrams - Stack architecture overview - Generated UML class diagram with detailed implementation structure --- images/java/class-diagrams.puml | 282 ++++++++++++++ images/java/java-mcp-client-architecture.jpg | Bin 0 -> 676694 bytes images/java/java-mcp-server-architecture.jpg | Bin 0 -> 859935 bytes images/java/java-mcp-uml-classdiagram.svg | 1 + images/java/mcp-stack.svg | 197 ++++++++++ sdk/java/mcp-client.mdx | 322 ++++++++++++++++ sdk/java/mcp-overview.mdx | 162 ++++++++ sdk/java/mcp-server.mdx | 369 +++++++++++++++++++ sdk/java/overview.mdx | 31 -- 9 files changed, 1333 insertions(+), 31 deletions(-) create mode 100644 images/java/class-diagrams.puml create mode 100644 images/java/java-mcp-client-architecture.jpg create mode 100644 images/java/java-mcp-server-architecture.jpg create mode 100644 images/java/java-mcp-uml-classdiagram.svg create mode 100644 images/java/mcp-stack.svg create mode 100644 sdk/java/mcp-client.mdx create mode 100644 sdk/java/mcp-overview.mdx create mode 100644 sdk/java/mcp-server.mdx delete mode 100644 sdk/java/overview.mdx diff --git a/images/java/class-diagrams.puml b/images/java/class-diagrams.puml new file mode 100644 index 0000000..5b08c73 --- /dev/null +++ b/images/java/class-diagrams.puml @@ -0,0 +1,282 @@ +@startuml Core Components + +' Core Interfaces +interface McpTransport { + +Mono connect(Function, Mono> handler) + +Mono sendMessage(JSONRPCMessage message) + +void close() + +Mono closeGracefully() + + T unmarshalFrom(Object data, TypeReference typeRef) +} + +interface McpSession { + + Mono sendRequest(String method, Object requestParams, TypeReference typeRef) + +Mono sendNotification(String method, Map params) + +Mono closeGracefully() + +void close() +} + +' Core Implementation Classes +class DefaultMcpSession { + +interface RequestHandler + +interface NotificationHandler +} + +' Client Classes +class McpClient { + +{static} Builder using(ClientMcpTransport transport) +} + +class McpAsyncClient { + +Mono initialize() + +ServerCapabilities getServerCapabilities() + +Implementation getServerInfo() + +ClientCapabilities getClientCapabilities() + +Implementation getClientInfo() + +void close() + +Mono closeGracefully() + +Mono ping() + +Mono addRoot(Root root) + +Mono removeRoot(String rootUri) + +Mono rootsListChangedNotification() + +Mono callTool(CallToolRequest request) + +Mono listTools() + +Mono listResources() + +Mono readResource(ReadResourceRequest request) + +Mono listResourceTemplates() + +Mono subscribeResource(SubscribeRequest request) + +Mono unsubscribeResource(UnsubscribeRequest request) + +Mono listPrompts() + +Mono getPrompt(GetPromptRequest request) + +Mono setLoggingLevel(LoggingLevel level) +} + +class McpSyncClient { + +InitializeResult 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) +} + +' Server Classes +class McpServer { + +{static} Builder using(ServerMcpTransport transport) +} + +class McpAsyncServer { + + +ServerCapabilities getServerCapabilities() + +Implementation getServerInfo() + +ClientCapabilities getClientCapabilities() + +Implementation getClientInfo() + +void close() + +Mono closeGracefully() + + ' Tool Management + +Mono addTool(ToolRegistration toolRegistration) + +Mono removeTool(String toolName) + +Mono notifyToolsListChanged() + + ' Resource Management + +Mono addResource(ResourceRegistration resourceHandler) + +Mono removeResource(String resourceUri) + +Mono notifyResourcesListChanged() + + ' Prompt Management + +Mono addPrompt(PromptRegistration promptRegistration) + +Mono removePrompt(String promptName) + +Mono notifyPromptsListChanged() + + ' Logging + +Mono loggingNotification(LoggingMessageNotification notification) + + ' Sampling + +Mono createMessage(CreateMessageRequest request) +} + +class McpSyncServer { + +McpAsyncServer getAsyncServer() + + +ServerCapabilities getServerCapabilities() + +Implementation getServerInfo() + +ClientCapabilities getClientCapabilities() + +Implementation getClientInfo() + +void close() + +void closeGracefully() + + ' Tool Management + +void addTool(ToolRegistration toolHandler) + +void removeTool(String toolName) + +void notifyToolsListChanged() + + ' Resource Management + +void addResource(ResourceRegistration resourceHandler) + +void removeResource(String resourceUri) + +void notifyResourcesListChanged() + + ' Prompt Management + +void addPrompt(PromptRegistration promptRegistration) + +void removePrompt(String promptName) + +void notifyPromptsListChanged() + + ' Logging + +void loggingNotification(LoggingMessageNotification notification) + + ' Sampling + +CreateMessageResult createMessage(CreateMessageRequest request) +} + +' Transport Implementations +class StdioClientTransport implements ClientMcpTransport { + +void setErrorHandler(Consumer errorHandler) + +Sinks.Many getErrorSink() +} + +class StdioServerTransport implements ServerMcpTransport { +} + + +class HttpServletSseServerTransport implements ServerMcpTransport { +} + + +class HttpClientSseClientTransport implements ClientMcpTransport { +} + + +class WebFluxSseClientTransport implements ClientMcpTransport { +} + + +class WebFluxSseServerTransport implements ServerMcpTransport { + +RouterFunction getRouterFunction() +} + +class WebMvcSseServerTransport implements ServerMcpTransport { + +RouterFunction getRouterFunction() +} + + +' Schema and Error Classes +class McpSchema { + +class ErrorCodes + +interface Request + +interface JSONRPCMessage + +interface ResourceContents + +interface Content + +interface ServerCapabilities + +{static} JSONRPCMessage deserializeJsonRpcMessage() +} + +class McpError { +} + +' Relationships +McpTransport <|.. ClientMcpTransport +McpTransport <|.. ServerMcpTransport + +McpSession <|.. DefaultMcpSession +DefaultMcpSession --o McpAsyncClient +DefaultMcpSession --o McpAsyncServer + +McpClient ..> McpAsyncClient : creates +McpClient ..> McpSyncClient : creates +McpSyncClient --> McpAsyncClient : delegates to + +McpServer ..> McpAsyncServer : creates +McpServer ..> McpSyncServer : creates +McpSyncServer o-- McpAsyncServer + +DefaultMcpSession o-- McpTransport +McpSchema <.. McpSession : uses +McpError ..> McpSession : throws + +@enduml + +@startuml Message Flow + +package "MCP Schema" { + interface JSONRPCMessage { + +String jsonrpc() + } + + interface Request { + } + + class InitializeRequest + class CallToolRequest + class ListToolsRequest + class ListResourcesRequest + class ReadResourceRequest + class ListResourceTemplatesRequest + class ListPromptsRequest + class GetPromptRequest +} + +package "Resource Types" { + interface ResourceContents { + +String uri() + +String mimeType() + } + + class TextResourceContents + class BlobResourceContents + + interface Content { + +String type() + } + + class TextContent + class ImageContent + class EmbeddedResource + + interface Annotated { + +Annotations annotations() + } + + interface PromptOrResourceReference { + +String type() + } + + class PromptReference + class ResourceReference +} + +JSONRPCMessage <|.. Request +Request <|.. InitializeRequest +Request <|.. CallToolRequest +Request <|.. ListToolsRequest +Request <|.. ListResourcesRequest +Request <|.. ReadResourceRequest +Request <|.. ListResourceTemplatesRequest +Request <|.. ListPromptsRequest +Request <|.. GetPromptRequest + +ResourceContents <|.. TextResourceContents +ResourceContents <|.. BlobResourceContents + +Content <|.. TextContent +Content <|.. ImageContent +Content <|.. EmbeddedResource + +PromptOrResourceReference <|.. PromptReference +PromptOrResourceReference <|.. ResourceReference + +@enduml diff --git a/images/java/java-mcp-client-architecture.jpg b/images/java/java-mcp-client-architecture.jpg new file mode 100644 index 0000000000000000000000000000000000000000..688a2b4ad0f92090bf0033ab5eb3b20fce1a8484 GIT binary patch literal 676694 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