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
Resource access and management
Prompt system interactions
Optional features like roots management and sampling support
The core io.modelcontextprotocol.sdk:mcp module provides STDIO and SSE 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 users.
The client provides both synchronous and asynchronous APIs for flexibility in different application contexts.
Copy
// Create a sync client with custom configurationMcpSyncClient client = McpClient.sync(transport) .requestTimeout(Duration.ofSeconds(10)) .capabilities(ClientCapabilities.builder() .roots(true) // Enable roots capability .sampling() // Enable sampling capability .build()) .sampling(request -> new CreateMessageResult(response)) .build();// Initialize connectionclient.initialize();// List available toolsListToolsResult tools = client.listTools();// Call a toolCallToolResult result = client.callTool( new CallToolRequest("calculator", Map.of("operation", "add", "a", 2, "b", 3)));// List and read resourcesListResourcesResult resources = client.listResources();ReadResourceResult resource = client.readResource( new ReadResourceRequest("resource://uri"));// List and use promptsListPromptsResult prompts = client.listPrompts();GetPromptResult prompt = client.getPrompt( new GetPromptRequest("greeting", Map.of("name", "Spring")));// Add/remove rootsclient.addRoot(new Root("file:///path", "description"));client.removeRoot("file:///path");// Close clientclient.closeGracefully();
Copy
// Create a sync client with custom configurationMcpSyncClient client = McpClient.sync(transport) .requestTimeout(Duration.ofSeconds(10)) .capabilities(ClientCapabilities.builder() .roots(true) // Enable roots capability .sampling() // Enable sampling capability .build()) .sampling(request -> new CreateMessageResult(response)) .build();// Initialize connectionclient.initialize();// List available toolsListToolsResult tools = client.listTools();// Call a toolCallToolResult result = client.callTool( new CallToolRequest("calculator", Map.of("operation", "add", "a", 2, "b", 3)));// List and read resourcesListResourcesResult resources = client.listResources();ReadResourceResult resource = client.readResource( new ReadResourceRequest("resource://uri"));// List and use promptsListPromptsResult prompts = client.listPrompts();GetPromptResult prompt = client.getPrompt( new GetPromptRequest("greeting", Map.of("name", "Spring")));// Add/remove rootsclient.addRoot(new Root("file:///path", "description"));client.removeRoot("file:///path");// Close clientclient.closeGracefully();
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.
Creates transport for in-process based communication
Copy
ServerParameters params = ServerParameters.builder("npx") .args("-y", "@modelcontextprotocol/server-everything", "dir") .build();McpTransport transport = new StdioClientTransport(params);
Creates transport for in-process based communication
Copy
ServerParameters params = ServerParameters.builder("npx") .args("-y", "@modelcontextprotocol/server-everything", "dir") .build();McpTransport transport = new StdioClientTransport(params);
Creates a framework agnostic (pure Java API) SSE client transport. Included in the core mcp module.
Copy
McpTransport transport = new HttpClientSseClientTransport("http://your-mcp-server");
Creates WebFlux-based SSE client transport. Requires the mcp-webflux-sse-transport dependency.
Copy
WebClient.Builder webClientBuilder = WebClient.builder() .baseUrl("http://your-mcp-server");McpTransport transport = new WebFluxSseClientTransport(webClientBuilder);
The client can be configured with various capabilities:
Copy
var capabilities = ClientCapabilities.builder() .roots(true) // Enable filesystem roots support with list changes notifications .sampling() // Enable LLM sampling support .build();
Roots define the boundaries of where servers can operate within the filesystem:
Copy
// Add a root dynamicallyclient.addRoot(new Root("file:///path", "description"));// Remove a rootclient.removeRoot("file:///path");// Notify server of roots changesclient.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
The client can register a logging consumer to receive log messages from the server and set the minimum logging level to filter messages:
Copy
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 can sends logging notificationsCallToolResult result = mcpClient.callTool(new McpSchema.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)
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.
Copy
// List available tools and their namesvar tools = client.listTools();tools.forEach(tool -> System.out.println(tool.getName()));// Execute a tool with parametersvar result = client.callTool("calculator", Map.of( "operation", "add", "a", 1, "b", 2));
Copy
// List available tools and their namesvar tools = client.listTools();tools.forEach(tool -> System.out.println(tool.getName()));// Execute a tool with parametersvar result = client.callTool("calculator", Map.of( "operation", "add", "a", 1, "b", 2));
Copy
// List available tools asynchronouslyclient.listTools() .doOnNext(tools -> tools.forEach(tool -> System.out.println(tool.getName()))) .subscribe();// Execute a tool asynchronouslyclient.callTool("calculator", Map.of( "operation", "add", "a", 1, "b", 2 )) .subscribe();
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.
Copy
// List available resources and their namesvar resources = client.listResources();resources.forEach(resource -> System.out.println(resource.getName()));// Retrieve resource content using a URI templatevar content = client.getResource("file", Map.of( "path", "/path/to/file.txt"));
Copy
// List available resources and their namesvar resources = client.listResources();resources.forEach(resource -> System.out.println(resource.getName()));// Retrieve resource content using a URI templatevar content = client.getResource("file", Map.of( "path", "/path/to/file.txt"));
Copy
// List available resources asynchronouslyclient.listResources() .doOnNext(resources -> resources.forEach(resource -> System.out.println(resource.getName()))) .subscribe();// Retrieve resource content asynchronouslyclient.getResource("file", Map.of( "path", "/path/to/file.txt" )) .subscribe();
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.
Copy
// List available prompt templatesvar prompts = client.listPrompts();prompts.forEach(prompt -> System.out.println(prompt.getName()));// Execute a prompt template with parametersvar response = client.executePrompt("echo", Map.of( "text", "Hello, World!"));
Copy
// List available prompt templatesvar prompts = client.listPrompts();prompts.forEach(prompt -> System.out.println(prompt.getName()));// Execute a prompt template with parametersvar response = client.executePrompt("echo", Map.of( "text", "Hello, World!"));
Copy
// List available prompt templates asynchronouslyclient.listPrompts() .doOnNext(prompts -> prompts.forEach(prompt -> System.out.println(prompt.getName()))) .subscribe();// Execute a prompt template asynchronouslyclient.executePrompt("echo", Map.of( "text", "Hello, World!" )) .subscribe();
As part of the Completion capabilities, MCP provides a provides a standardized way for servers to offer argument autocompletion suggestions for prompts and resource URIs.
On the client side, the MCP client provides methods to request auto-completions:
Copy
CompleteRequest request = new CompleteRequest( new PromptReference("code_review"), new CompleteRequest.CompleteArgument("language", "py"));CompleteResult result = syncMcpClient.completeCompletion(request);
Copy
CompleteRequest request = new CompleteRequest( new PromptReference("code_review"), new CompleteRequest.CompleteArgument("language", "py"));CompleteResult result = syncMcpClient.completeCompletion(request);
Copy
CompleteRequest request = new CompleteRequest( new PromptReference("code_review"), new CompleteRequest.CompleteArgument("language", "py"));Mono<CompleteResult> result = mcpClient.completeCompletion(request);