mcpField
M
ModelContextProtocol (MCP) Java SDK v0.8.0 Specification

ModelContextProtocol (MCP) Java SDK v0.8.0 Specification

ローカル
github.com/jayessdeesea開発ツール084 週間前に更新

ModelContextProtocol (MCP) Java SDK v0.8.0 Specification について

このドキュメントは、Java製MCPクライアントとサーバーのAI支援開発向けに、MCP Java SDK 0.8.0を解説します。クライアントとサーバー、トランスポート、ツール、リソース、プロンプト、エラー処理を扱います。

主な機能

  1. 01クライアントとサーバーの実装
  2. 02同期・非同期API
  3. 03Stdioとカスタムトランスポート
  4. 04ツール、リソース、プロンプト
  5. 05プロトコル型とエラー処理

活用シーン

  1. 01Java製MCPクライアントコードの生成
  2. 02同期または非同期MCPサーバーの構築
  3. 03トランスポートとリソース処理の設定

MCP 対応

MCPサーバーと通信するクライアント、およびクライアントにツールやリソースを公開するサーバーを実装するJava SDKの仕様です。

設定

ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。

インストール方法は未掲載です

このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。

リポジトリ

ツール

ツール一覧はまだ取得されていません

ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。

詳細

ModelContextProtocol (MCP) Java SDK v0.8.0 仕様

はじめに

Model Context Protocol(MCP)は、AI モデルと外部のツールやリソース間の通信を標準化するプロトコルです。Java SDK は、このプロトコルを堅牢に実装しており、AI モデルにツールやリソースを公開する MCP サーバーと、それらのサーバーと通信する MCP クライアントを Java アプリケーションで作成できます。

このドキュメントは、MCP クライアントおよびサーバーの AI 支援コード生成を目的とした、MCP Java SDK バージョン 0.8.0 の包括的な仕様です。

アーキテクチャ

MCP Java SDK は、関心事を明確に分離したモジュール式アーキテクチャを採用しています。

graph TD
    Client[Client] --> Transport[Transport Layer]
    Server[Server] --> Transport
    Transport --> Protocol[Protocol Layer]
    Protocol --> JSON[JSON Schema]
    Client --> Resources[Resources]
    Client --> Tools[Tools]
    Server --> Resources
    Server --> Tools
    Server --> ErrorHandling[Error Handling]
    Client --> ErrorHandling
コアコンポーネント
  1. クライアント - MCP サーバーと連携して、リソースやツールにアクセスします
  2. サーバー - MCP クライアントにリソースやツールを公開します
  3. トランスポート層 - クライアントとサーバー間の通信を処理します
  4. プロトコル層 - MCP プロトコル仕様を実装します
  5. リソース - サーバーが公開する静的または動的なデータです
  6. ツール - サーバーが公開する実行可能な関数です
パッケージ構成

SDK は、次の主要なパッケージで構成されています。

  • io.modelcontextprotocol.client - クライアントの実装(McpClient)
  • io.modelcontextprotocol.server - サーバーの実装(McpServer、McpSyncServer、McpAsyncServer)
  • io.modelcontextprotocol.client.transport - クライアントのトランスポート実装
  • io.modelcontextprotocol.server.transport - サーバーのトランスポート実装およびプロバイダー
  • io.modelcontextprotocol.spec - コアプロトコル仕様およびスキーマクラス
  • io.modelcontextprotocol.transport - トランスポート層のインターフェースおよび実装
  • io.modelcontextprotocol.types - MCP プロトコルの型定義
  • io.modelcontextprotocol.errors - エラー処理クラスおよびユーティリティ

インストール

Maven 依存関係

すべてのコンポーネントで互換性のあるバージョンを使用するため、MCP BOM(部品表)をプロジェクトに追加します。

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>io.modelcontextprotocol.sdk</groupId>
            <artifactId>mcp-bom</artifactId>
            <version>0.8.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

次に、必要な依存関係を追加します。

<dependencies>
    
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp</artifactId>
    </dependency>
    
    
    <dependency>
        <groupId>io.modelcontextprotocol.sdk</groupId>
        <artifactId>mcp-test</artifactId>
    </dependency>
    
    
    <dependency>
        <groupId>jakarta.servlet</groupId>
        <artifactId>jakarta.servlet-api</artifactId>
        <version>5.0.0</version>
        <scope>provided</scope>
    </dependency>
</dependencies>

クライアントの実装

ツールを使用する同期クライアント
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;

import java.util.HashMap;
import java.util.Map;

public class SyncClientStdioToolsExample {
    public static void main(String[] args) throws Exception {
        // Create client info
        McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
        
        // Create server parameters
        ServerParameters serverParams = ServerParameters.builder("example-server-command")
            .build();
        
        // Create transport with server parameters
        StdioClientTransport transport = new StdioClientTransport(serverParams);
        
        // Create the client using the builder pattern
        McpSyncClient client = McpClient.sync(transport)
            .clientInfo(clientInfo)
            .build();
        
        try {
            // Read a resource
            McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("example://resource");
            McpSchema.ReadResourceResult result = client.readResource(request);
            
            // Access the resource contents
            if (result.contents() != null && !result.contents().isEmpty()) {
                McpSchema.ResourceContents contents = result.contents().get(0);
                if (contents instanceof McpSchema.TextResourceContents textContents) {
                    System.out.println("Resource content: " + textContents.text());
                }
            }
            
            // Call a tool with a Map of arguments
            Map<String, Object> toolArgs = new HashMap<>();
            toolArgs.put("param1", "value1");
            toolArgs.put("param2", 42);
            
            McpSchema.CallToolRequest toolRequest = new McpSchema.CallToolRequest("example-tool", toolArgs);
            McpSchema.CallToolResult toolResponse = client.callTool(toolRequest);
            
            // Access the tool response content
            if (toolResponse.content() != null && !toolResponse.content().isEmpty()) {
                McpSchema.Content content = toolResponse.content().get(0);
                if (content instanceof McpSchema.TextContent textContent) {
                    System.out.println("Tool response: " + textContent.text());
                }
            }
        } finally {
            // Close the client
            client.close();
        }
    }
}
プロンプトを使用する同期クライアント
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpSyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SyncClientStdioPromptsExample {
    public static void main(String[] args) throws Exception {
        // Create client info
        McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
        
        // Create server parameters
        ServerParameters serverParams = ServerParameters.builder("example-server-command")
            .build();
        
        // Create transport with server parameters
        StdioClientTransport transport = new StdioClientTransport(serverParams);
        
        // Create the client using the builder pattern
        McpSyncClient client = McpClient.sync(transport)
            .clientInfo(clientInfo)
            .build();
        
        try {
            // List available prompts
            ListPromptsResult promptsResult = client.listPrompts();
            
            if (promptsResult.prompts() != null && !promptsResult.prompts().isEmpty()) {
                System.out.println("Available prompts:");
                for (Prompt prompt : promptsResult.prompts()) {
                    System.out.println("- " + prompt.name() + ": " + prompt.description());
                }
                
                // Get a specific prompt
                String promptName = promptsResult.prompts().get(0).name();
                
                // Create arguments for the prompt if needed
                Map<String, Object> promptArgs = new HashMap<>();
                promptArgs.put("language", "Java");
                promptArgs.put("code", "public class Example { public static void main(String[] args) { } }");
                
                GetPromptRequest promptRequest = new GetPromptRequest(promptName, promptArgs);
                GetPromptResult promptResult = client.getPrompt(promptRequest);
                
                // Process the prompt result
                if (promptResult.messages() != null && !promptResult.messages().isEmpty()) {
                    System.out.println("Prompt messages:");
                    for (PromptMessage message : promptResult.messages()) {
                        System.out.println("Role: " + message.role());
                        System.out.println("Content: " + message.content());
                    }
                }
            } else {
                System.out.println("No prompts available from the server.");
            }
        } finally {
            // Close the client
            client.close();
        }
    }
}
ツールを使用する非同期クライアント
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.Map;

public class AsyncClientStdioToolsExample {

    public static void main(String[] args) throws Exception {
        // Create client info
        McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
        
        // Create server parameters
        ServerParameters serverParams = ServerParameters.builder("example-server-command")
            .build();
        
        // Create transport with server parameters
        StdioClientTransport transport = new StdioClientTransport(serverParams);
        
        // Create the client using the builder pattern
        McpAsyncClient client = McpClient.async(transport)
            .clientInfo(clientInfo)
            .build();
        
        try {
            // Initialize the client (connects to the server)
            client.initialize().block(); // Block until initialization completes
            
            // Read a resource
            McpSchema.ReadResourceRequest request = new McpSchema.ReadResourceRequest("example://resource");
            McpSchema.ReadResourceResult result = client.readResource(request).block();
            
            // Access the resource contents
            if (result.contents() != null && !result.contents().isEmpty()) {
                McpSchema.ResourceContents contents = result.contents().get(0);
                if (contents instanceof McpSchema.TextResourceContents textContents) {
                    System.out.println("Resource content: " + textContents.text());
                }
            }
            
            // Call a tool with a Map of arguments
            Map<String, Object> toolArgs = new HashMap<>();
            toolArgs.put("param1", "value1");
            toolArgs.put("param2", 42);
            
            McpSchema.CallToolRequest toolRequest = new McpSchema.CallToolRequest("example-tool", toolArgs);
            McpSchema.CallToolResult toolResponse = client.callTool(toolRequest).block();
            
            // Access the tool response content
            if (toolResponse.content() != null && !toolResponse.content().isEmpty()) {
                McpSchema.Content content = toolResponse.content().get(0);
                if (content instanceof McpSchema.TextContent textContent) {
                    System.out.println("Tool response: " + textContent.text());
                }
            }
        } catch (Exception e) {
            if (e.getCause() instanceof McpError) {
                McpError mcpError = (McpError) e.getCause();
                System.err.println("MCP Error: " + mcpError.getMessage());
            } else {
                System.err.println("Error: " + e.getMessage());
            }
        } finally {
            // Close the client
            client.close();
        }
    }
}
プロンプトを使用する非同期クライアント
import io.modelcontextprotocol.client.McpClient;
import io.modelcontextprotocol.client.McpAsyncClient;
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;
import io.modelcontextprotocol.spec.McpSchema.ListPromptsResult;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import io.modelcontextprotocol.spec.McpError;

import java.util.HashMap;
import java.util.Map;

public class AsyncClientStdioPromptsExample {

    public static void main(String[] args) throws Exception {
        // Create client info
        McpSchema.Implementation clientInfo = new McpSchema.Implementation("example-client", "1.0.0");
        
        // Create server parameters
        ServerParameters serverParams = ServerParameters.builder("example-server-command")
            .build();
        
        // Create transport with server parameters
        StdioClientTransport transport = new StdioClientTransport(serverParams);
        
        // Create the client using the builder pattern
        McpAsyncClient client = McpClient.async(transport)
            .clientInfo(clientInfo)
            .build();
        
        try {
            // Initialize the client (connects to the server)
            client.initialize().block(); // Block until initialization completes
            
            // List available prompts
            ListPromptsResult promptsResult = client.listPrompts().block();
            
            if (promptsResult.prompts() != null && !promptsResult.prompts().isEmpty()) {
                System.out.println("Available prompts:");
                for (Prompt prompt : promptsResult.prompts()) {
                    System.out.println("- " + prompt.name() + ": " + prompt.description());
                }
                
                // Get a specific prompt
                String promptName = promptsResult.prompts().get(0).name();
                
                // Create arguments for the prompt if needed
                Map<String, Object> promptArgs = new HashMap<>();
                promptArgs.put("language", "Java");
                promptArgs.put("code", "public class Example { public static void main(String[] args) { } }");
                
                GetPromptRequest promptRequest = new GetPromptRequest(promptName, promptArgs);
                GetPromptResult promptResult = client.getPrompt(promptRequest).block();
                
                // Process the prompt result
                if (promptResult.messages() != null && !promptResult.messages().isEmpty()) {
                    System.out.println("Prompt messages:");
                    for (PromptMessage message : promptResult.messages()) {
                        System.out.println("Role: " + message.role());
                        System.out.println("Content: " + message.content());
                    }
                }
            } else {
                System.out.println("No prompts available from the server.");
            }
        } catch (Exception e) {
            if (e.getCause() instanceof McpError) {
                McpError mcpError = (McpError) e.getCause();
                System.err.println("MCP Error: " + mcpError.getMessage());
            } else {
                System.err.println("Error: " + e.getMessage());
            }
        } finally {
            // Close the client
            client.close();
        }
    }
}

サーバーの実装

ツールを使用する同期サーバー
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SyncServerStdioToolsExample {

    public static void main(String[] args) throws Exception {
        // Create server info
        McpSchema.Implementation serverInfo = new McpSchema.Implementation("example-server", "1.0.0");
        
        // Create transport provider
        StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
        
        // Create server using the builder pattern
        McpSyncServer server = McpServer.sync(transportProvider)
            .serverInfo(serverInfo)
            .tool(
                new McpSchema.Tool(
                    "example-tool",
                    "An example tool",
                    createToolSchema()
                ),
                (exchange, toolArgs) -> {
                    String param1 = (String) toolArgs.get("param1");
                    Number param2 = (Number) toolArgs.get("param2");
                    
                    List<McpSchema.Content> content = new ArrayList<>();
                    content.add(new McpSchema.TextContent(
                        null,
                        null,
                        "Tool executed with param1=" + param1 + ", param2=" + param2
                    ));
                    
                    return new McpSchema.CallToolResult(content, false);
                }
            )
            .build();
            
        System.err.println("Server started");
    }
    
    /**
     * Creates the JSON schema for the example tool.
     */
    private static McpSchema.JsonSchema createToolSchema() {
        // Create input schema for the tool
        Map<String, Object> properties = new HashMap<>();
        
        Map<String, Object> param1 = new HashMap<>();
        param1.put("type", "string");
        param1.put("description", "A string parameter");
        
        Map<String, Object> param2 = new HashMap<>();
        param2.put("type", "number");
        param2.put("description", "A numeric parameter");
        
        properties.put("param1", param1);
        properties.put("param2", param2);
        
        List<String> required = List.of("param1");
        
        return new McpSchema.JsonSchema("object", properties, required, null);
    }
}
プロンプトを使用する同期サーバー
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpSyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SyncServerStdioPromptsExample {

    public static void main(String[] args) throws Exception {
        // Create server info
        McpSchema.Implementation serverInfo = new McpSchema.Implementation("prompts-example-server", "1.0.0");
        
        // Create transport provider
        StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
        
        // Create a code analysis prompt
        List<PromptArgument> codeAnalysisArgs = new ArrayList<>();
        codeAnalysisArgs.add(new PromptArgument(
            "language",
            "The programming language of the code",
            true
        ));
        codeAnalysisArgs.add(new PromptArgument(
            "code",
            "The code to analyze",
            true
        ));
        
        Prompt codeAnalysisPrompt = new Prompt(
            "code-analysis",
            "Analyzes code for potential issues and improvements",
            codeAnalysisArgs
        );
        
        // Create server using the builder pattern
        McpSyncServer server = McpServer.sync(transportProvider)
            .serverInfo(serverInfo)
            .prompt(
                codeAnalysisPrompt,
                (exchange, request) -> {
                    // Extract arguments from the request
                    String language = (String) request.arguments().get("language");
                    String code = (String) request.arguments().get("code");
                    
                    // Create prompt messages
                    List<PromptMessage> messages = new ArrayList<>();
                    
                    // System message
                    messages.add(new PromptMessage(
                        "system",
                        "You are a code analysis assistant that helps identify issues and suggest improvements."
                    ));
                    
                    // User message with the code
                    messages.add(new PromptMessage(
                        "user",
                        "Please analyze this " + language + " code:\n\n```" + language + "\n" + code + "\n```"
                    ));
                    
                    // Assistant message with the analysis
                    messages.add(new PromptMessage(
                        "assistant",
                        "Here's my analysis of your " + language + " code:\n\n" +
                        "1. The code is very minimal and doesn't do anything yet.\n" +
                        "2. Consider adding some functionality to the main method.\n" +
                        "3. Add comments to explain the purpose of the class."
                    ));
                    
                    // Return the prompt result
                    return new GetPromptResult(
                        "Code analysis for " + language,
                        messages
                    );
                }
            )
            .build();
            
        System.err.println("Prompts server started");
    }
}
ツールを使用する非同期サーバー
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpAsyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Mono;

public class AsyncServerStdioToolsExample {

    public static void main(String[] args) {
        try {
            // Create server info
            McpSchema.Implementation serverInfo = new McpSchema.Implementation("example-server", "1.0.0");
            
            // Create transport provider
            StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
            
            // Create server using the builder pattern
            McpAsyncServer server = McpServer.async(transportProvider)
                .serverInfo(serverInfo)
                .tool(
                    new McpSchema.Tool(
                        "example-tool",
                        "An example tool",
                        createToolSchema()
                    ),
                    (exchange, toolArgs) -> {
                        String param1 = (String) toolArgs.get("param1");
                        Number param2 = (Number) toolArgs.get("param2");
                        
                        List<McpSchema.Content> content = new ArrayList<>();
                        content.add(new McpSchema.TextContent(
                            null,
                            null,
                            "Tool executed with param1=" + param1 + ", param2=" + param2
                        ));
                        
                        return Mono.just(new McpSchema.CallToolResult(content, false));
                    }
                )
                .build();
                
            System.err.println("Server started");
        } catch (Exception e) {
            System.err.println("Failed to start server: " + e.getMessage());
        }
    }
    
    /**
     * Creates the JSON schema for the example tool.
     */
    private static McpSchema.JsonSchema createToolSchema() {
        // Create input schema for the tool
        Map<String, Object> properties = new HashMap<>();
        
        Map<String, Object> param1 = new HashMap<>();
        param1.put("type", "string");
        param1.put("description", "A string parameter");
        
        Map<String, Object> param2 = new HashMap<>();
        param2.put("type", "number");
        param2.put("description", "A numeric parameter");
        
        properties.put("param1", param1);
        properties.put("param2", param2);
        
        List<String> required = List.of("param1");
        
        return new McpSchema.JsonSchema("object", properties, required, null);
    }
}
リソースを使用する非同期サーバー
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpAsyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
import reactor.core.publisher.Mono;

public class AsyncServerStdioResourcesExample {

    // Pattern for matching resource URIs
    private static final Pattern RESOURCE_PATTERN = Pattern.compile("data://users/(.+)");

    public static void main(String[] args) {
        try {
            // Create server info
            McpSchema.Implementation serverInfo = new McpSchema.Implementation("async-resources-example", "1.0.0");
            
            // Create transport provider
            StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
            
            // Create server using the builder pattern
            McpAsyncServer server = McpServer.async(transportProvider)
                .serverInfo(serverInfo)
                .resourceTemplate(
                    new McpSchema.ResourceTemplate(
                        "data://users/{userId}",
                        "User Data",
                        "Data for a specific user",
                        "application/json",
                        null
                    ),
                    (exchange, request) -> {
                        String uri = request.uri();
                        
                        // Parse the URI to extract parameters
                        Matcher matcher = RESOURCE_PATTERN.matcher(uri);
                        
                        if (matcher.matches()) {
                            String userId = matcher.group(1);
                            
                            // Simulate an asynchronous database lookup
                            return Mono.fromCallable(() -> {
                                // In a real implementation, this would be a database query
                                // For this example, we'll just generate some data
                                String userData = String.format(
                                    "{\"id\":\"%s\",\"name\":\"User %s\",\"email\":\"user%[email protected]\",\"created\":\"2025-03-24\"}",
                                    userId, userId, userId
                                );
                                
                                List<McpSchema.ResourceContents> contents = new ArrayList<>();
                                contents.add(new McpSchema.TextResourceContents(
                                    uri,
                                    "application/json",
                                    userData
                                ));
                                
                                return new McpSchema.ReadResourceResult(contents);
                            });
                        }
                        
                        return Mono.error(new McpError(
                            new McpSchema.JSONRPCResponse.JSONRPCError(
                                McpSchema.ErrorCodes.RESOURCE_NOT_FOUND,
                                "Resource not found: " + uri,
                                null
                            )
                        ));
                    }
                )
                .build();
                
            System.err.println("Async resources server started");
        } catch (Exception e) {
            System.err.println("Failed to start server: " + e.getMessage());
        }
    }
}
プロンプトを使用する非同期サーバー
import io.modelcontextprotocol.server.McpServer;
import io.modelcontextprotocol.server.McpAsyncServer;
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpSchema.Prompt;
import io.modelcontextprotocol.spec.McpSchema.PromptArgument;
import io.modelcontextprotocol.spec.McpSchema.PromptMessage;
import io.modelcontextprotocol.spec.McpSchema.GetPromptRequest;
import io.modelcontextprotocol.spec.McpSchema.GetPromptResult;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import reactor.core.publisher.Mono;

public class AsyncServerStdioPromptsExample {

    public static void main(String[] args) {
        try {
            // Create server info
            McpSchema.Implementation serverInfo = new McpSchema.Implementation("async-prompts-example", "1.0.0");
            
            // Create transport provider
            StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
            
            // Create a code analysis prompt
            List<PromptArgument> codeAnalysisArgs = new ArrayList<>();
            codeAnalysisArgs.add(new PromptArgument(
                "language",
                "The programming language of the code",
                true
            ));
            codeAnalysisArgs.add(new PromptArgument(
                "code",
                "The code to analyze",
                true
            ));
            
            Prompt codeAnalysisPrompt = new Prompt(
                "code-analysis",
                "Analyzes code for potential issues and improvements",
                codeAnalysisArgs
            );
            
            // Create server using the builder pattern
            McpAsyncServer server = McpServer.async(transportProvider)
                .serverInfo(serverInfo)
                .prompt(
                    codeAnalysisPrompt,
                    (exchange, request) -> {
                        // Extract arguments from the request
                        String language = (String) request.arguments().get("language");
                        String code = (String) request.arguments().get("code");
                        
                        // Simulate an asynchronous operation (e.g., calling an external API)
                        return Mono.fromCallable(() -> {
                            // Create prompt messages
                            List<PromptMessage> messages = new ArrayList<>();
                            
                            // System message
                            messages.add(new PromptMessage(
                                "system",
                                "You are a code analysis assistant that helps identify issues and suggest improvements."
                            ));
                            
                            // User message with the code
                            messages.add(new PromptMessage(
                                "user",
                                "Please analyze this " + language + " code:\n\n```" + language + "\n" + code + "\n```"
                            ));
                            
                            // Assistant message with the analysis
                            messages.add(new PromptMessage(
                                "assistant",
                                "Here's my analysis of your " + language + " code:\n\n" +
                                "1. The code is very minimal and doesn't do anything yet.\n" +
                                "2. Consider adding some functionality to the main method.\n" +
                                "3. Add comments to explain the purpose of the class."
                            ));
                            
                            // Return the prompt result
                            return new GetPromptResult(
                                "Code analysis for " + language,
                                messages
                            );
                        });
                    }
                )
                .build();
                
            System.err.println("Async prompts server started");
        } catch (Exception e) {
            System.err.println("Failed to start server: " + e.getMessage());
        }
    }
}

トランスポートの設定

MCP Java SDK は、クライアントとサーバー間の通信に複数のトランスポート方式をサポートしています。

StdioTransport

標準入出力ストリームを介して通信します。サブプロセス間の通信に便利です。

// Server-side
import io.modelcontextprotocol.server.transport.StdioServerTransportProvider;

StdioServerTransportProvider transportProvider = new StdioServerTransportProvider();
McpSyncServer server = new McpSyncServer(transportProvider, features);

// Client-side
import io.modelcontextprotocol.client.transport.ServerParameters;
import io.modelcontextprotocol.client.transport.StdioClientTransport;

ServerParameters serverParams = new ServerParameters.Builder().build();
StdioClientTransport transport = new StdioClientTransport(serverParams);
client.connect(transport);
カスタムトランスポート

適切なトランスポートプロバイダーインターフェースを実装することで、カスタムトランスポートを実装できます。

import io.modelcontextprotocol.transport.Transport;
import io.modelcontextprotocol.transport.ReceiveHandler;
import io.modelcontextprotocol.server.transport.McpServerTransportProvider;
import io.modelcontextprotocol.client.transport.McpClientTransport;

// Server-side custom transport provider
public class CustomServerTransportProvider implements McpServerTransportProvider {
    @Override
    public Transport createTransport() {
        // Implement transport creation logic
        return new CustomServerTransport();
    }
}

// Client-side custom transport
public class CustomClientTransport implements Transport {
    @Override
    public void send(String message) {
        // Implement sending logic
    }
    
    @Override
    public void setReceiveHandler(ReceiveHandler handler) {
        // Implement receiving logic
    }
    
    @Override
    public void close() {
        // Implement closing logic
    }
}

リソースの実装

MCP におけるリソースは、クライアントがアクセスできるデータを表します。静的(事前定義)または動的(要求に応じて生成)にできます。

静的リソース
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;

import java.util.ArrayList;
import java.util.List;

// Define static resources in server features
features.resourceHandler = (exchange, request) -> {
    if (request instanceof McpSchema.ListResourcesRequest) {
        List<McpSchema.Resource> resources = new ArrayList<>();
        resources.add(new McpSchema.Resource("data://example/static"));
        
        return new McpSchema.ListResourcesResult(resources, null);
    } else if (request instanceof McpSchema.ReadResourceRequest) {
        McpSchema.ReadResourceRequest readRequest = (McpSchema.ReadResourceRequest) request;
        String uri = readRequest.uri();
        
        if ("data://example/static".equals(uri)) {
            List<McpSchema.ResourceContents> contents = new ArrayList<>();
            contents.add(new McpSchema.TextResourceContents(
                uri,
                "application/json",
                "{\"name\":\"Example\",\"value\":42}"
            ));
            
            return new McpSchema.ReadResourceResult(contents);
        }
        
        throw new McpError(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND, "Resource not found: " + uri);
    }
    
    return null;
};
動的リソース(リソーステンプレート)
import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

// Define resource templates in server features
features.resourceHandler = (exchange, request) -> {
    if (request instanceof McpSchema.ListResourceTemplatesRequest) {
        List<McpSchema.ResourceTemplate> templates = new ArrayList<>();
        
        // Define a resource template
        templates.add(new McpSchema.ResourceTemplate(
            "data://users/{userId}",
            "User Data",
            "application/json",
            "Data for a specific user",
            null
        ));
        
        return new McpSchema.ListResourceTemplatesResult(templates, null);
    } else if (request instanceof McpSchema.ReadResourceRequest) {
        McpSchema.ReadResourceRequest readRequest = (McpSchema.ReadResourceRequest) request;
        String uri = readRequest.uri();
        
        // Parse the URI to extract parameters
        Pattern pattern = Pattern.compile("data://users/(.+)");
        Matcher matcher = pattern.matcher(uri);
        
        if (matcher.matches()) {
            String userId = matcher.group(1);
            
            // Generate dynamic content based on the userId
            String userData = String.format("{\"id\":\"%s\",\"name\":\"User %s\",\"email\":\"user%[email protected]\"}", 
                                           userId, userId, userId);
            
            List<McpSchema.ResourceContents> contents = new ArrayList<>();
            contents.add(new McpSchema.TextResourceContents(
                uri,
                "application/json",
                userData
            ));
            
            return new McpSchema.ReadResourceResult(contents);
        }
        
        throw new McpError(McpSchema.ErrorCodes.RESOURCE_NOT_FOUND, "Resource not found: " + uri);
    }
    
    return null;
};

ツールの実装

MCP におけるツールは、クライアントから呼び出せる実行可能な関数を表します。

import io.modelcontextprotocol.server.McpServerFeatures;
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.types.CallToolRequestSchema;
import io.modelcontextprotocol.types.ErrorCode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// Define tools in server features
features.toolHandler = (exchange, request) -> {
    if (request instanceof McpSchema.ListToolsRequest) {
        List<McpSchema.Tool> tools = new ArrayList<>();
        
        // Define a calculator tool
        Map<String, Object> properties = new HashMap<>();
        
        Map<String, Object> operation = new HashMap<>();
        operation.put("type", "string");
        operation.put("description", "Operation to perform (add, subtract, multiply, divide)");
        operation.put("enum", List.of("add", "subtract", "multiply", "divide"));
        
        Map<String, Object> a = new HashMap<>();
        a.put("type", "number");
        a.put("description", "First operand");
        
        Map<String, Object> b = new HashMap<>();
        b.put("type", "number");
        b.put("description", "Second operand");
        
        properties.put("operation", operation);
        properties.put("a", a);
        properties.put("b", b);
        
        Map<String, Object> inputSchema = new HashMap<>();
        inputSchema.put("type", "object");
        inputSchema.put("properties", properties);
        inputSchema.put("required", List.of("operation", "a", "b"));
        
        tools.add(new McpSchema.Tool(
            "calculator",
            "Performs basic arithmetic operations",
            new McpSchema.JsonSchema(inputSchema),
            null
        ));
        
        return new McpSchema.ListToolsResult(tools, null);
    } else if (request instanceof McpSchema.CallToolRequest) {
        McpSchema.CallToolRequest callRequest = (McpSchema.CallToolRequest) request;
        String name = callRequest.name();
        
        if ("calculator".equals(name)) {
            Map<String, Object> arguments = callRequest.arguments();
            String operation = (String) arguments.get("operation");
            Number a = (Number) arguments.get("a");
            Number b = (Number) arguments.get("b");
            
            double result;
            switch (operation) {
                case "add":
                    result = a.doubleValue() + b.doubleValue();
                    break;
                case "subtract":
                    result = a.doubleValue() - b.doubleValue();
                    break;
                case "multiply":
                    result = a.doubleValue() * b.doubleValue();
                    break;
                case "divide":
                    if (b.doubleValue() == 0) {
                        throw new McpError(ErrorCode.INVALID_PARAMS, "Division by zero");
                    }
                    result = a.doubleValue() / b.doubleValue();
                    break;
                default:
                    throw new McpError(ErrorCode.INVALID_PARAMS, "Unknown operation: " + operation);
            }
            
            List<McpSchema.Content> content = new ArrayList<>();
            content.add(new McpSchema.TextContent(String.valueOf(result)));
            
            return new McpSchema.CallToolResult(content, false);
        }
        
        throw new McpError(ErrorCode.METHOD_NOT_FOUND, "Tool not found: " + name);
    }
    
    return null;
};

エラー処理

MCP Java SDK は、McpError クラスを使用する標準化されたエラー処理方法を提供します。

エラーコード

SDK は、McpSchema.ErrorCodes クラスで標準エラーコードを定義しています。

  • PARSE_ERROR - 無効な JSON を受信しました
  • INVALID_REQUEST - リクエストが無効です
  • METHOD_NOT_FOUND - 要求されたメソッドが存在しません
  • INVALID_PARAMS - メソッドのパラメーターが無効です
  • INTERNAL_ERROR - サーバー内部エラーです
  • RESOURCE_NOT_FOUND - 要求されたリソースが存在しません
エラーのスロー
import io.modelcontextprotocol.spec.McpSchema;
import io.modelcontextprotocol.spec.McpError;
import io.modelcontextprotocol.types.ErrorCode;

// In a request handler
if (someCondition) {
    throw new McpError(ErrorCode.INVALID_PARAMS, "Parameter 'x' must be positive");
}
エラーの処理
// Synchronous error handling
try {
    client.callTool(toolRequest);
} catch (McpError e) {
    System.err.println("MCP Error: " + e.getMessage());
}

// Asynchronous error handling
client.callTool(toolRequest)
    .thenAccept(response -> {
        // Handle success
    })
    .exceptionally(e -> {
        if (e.getCause() instanceof McpError) {
            McpError mcpError = (McpError) e.getCause();
            System.err.println("MCP Error: " + mcpError.getCode() + ": " + mcpError.getMessage());
        } else {
            System.err.println("Error: " + e.getMessage());
        }
        return null;
    });
サーバー側のエラー処理
// Set a request handler for specific requests
server.setRequestHandler(CallToolRequestSchema, (request) -> {
    // Handle the request
    return new McpSchema.CallToolResult(content, false);
});

// Set an error handler for specific error types
server.setErrorHandler(error -> {
    // Handle the error
    System.err.println("Server error: " + error.getMessage());
});

// Set a global error handler in server features
features.errorHandler = error -> {
    System.err.println("Server error: " + error.getMessage());
    // Log the error, send metrics, etc.
};

ベストプラクティス

全般
  1. BOMを使用する - すべてのコンポーネントの互換性を確保するため、必ずMCP BOMを使用してください。
  2. 接続を閉じる - クライアントとサーバーが不要になったら、必ず閉じてください。
  3. エラーを処理する - すべてのMCP操作に適切なエラー処理を実装してください。
  4. 入力を検証する - 処理する前に、すべての入力を検証してください。
  5. 適切なトランスポートを使用する - ユースケースに応じて、適切なトランスポート機構を選択してください。
クライアント側
  1. クライアントを再利用する - クライアントインスタンスを1つ作成し、複数の操作で再利用してください。
  2. 切断に対処する - ネットワークトランスポートでは、再接続のロジックを実装してください。
  3. レスポンスを検証する - サーバーからのすべてのレスポンスを、使用する前に検証してください。
サーバー側
  1. リソースとツールを文書化する - すべてのリソースとツールについて、明確な説明を記載してください。
  2. 適切なエラー処理を実装する - 適切なエラーコードとメッセージを返してください。
  3. リクエストパラメーターを検証する - 処理する前に、すべてのリクエストパラメーターを検証してください。
  4. リソーステンプレートを使用する - 動的リソースにはリソーステンプレートを使用してください。

参考資料

クラスリファレンス

クライアントクラス
  • McpClient - MCPクライアントを作成するファクトリー
  • McpSyncClient - 同期MCPクライアントの実装
  • McpAsyncClient - 非同期MCPクライアントの実装
  • McpSchema.Implementation - 接続初期化用のクライアント情報
サーバークラス
  • McpServer - MCPサーバーを作成するファクトリー
  • McpSyncServer - 同期MCPサーバーの実装
  • McpAsyncServer - 非同期MCPサーバーの実装
  • McpSchema.Implementation - 接続初期化用のサーバー情報
トランスポートクラス
  • StdioClientTransport - 標準入出力を介したクライアントトランスポート
  • StdioServerTransport - 標準入出力を介したサーバートランスポート
  • Transport - すべてのトランスポートの基底インターフェース
  • ReceiveHandler - メッセージ受信のハンドラー
コンテンツクラス
  • McpSchema.ResourceContents - リソースコンテンツのインターフェース
  • McpSchema.TextResourceContents - テキスト形式のリソースコンテンツ
  • McpSchema.Content - ツールコンテンツのインターフェース
  • McpSchema.TextContent - テキスト形式のツールコンテンツ
  • McpSchema.CallToolResult - ツール実行からのレスポンス
エラー処理
  • McpError - MCPプロトコルエラー用のエラークラス
  • McpSchema.ErrorCodes - エラーコード定数
  • ErrorCode - typesパッケージ内のエラーコード定数

コメント

MCP は初めてですか?

プロトコルの概要から最初のサーバーの導入まで、よくある疑問にまとめて答えます。

AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。