MCP Client SDK

MCP Server SDK

Misc

MCP Client SDK Setup

Install the Dependency

Add the AJ MCP client dependency:


<dependency>
    <groupId>com.ajaxjs</groupId>
    <artifactId>aj-mcp-client</artifactId>
    <version>1.3</version>
</dependency>

We can find the latest version: Maven Central

Concepts

The client SDK implementation consists of two main components:

To use the client, first create an appropriate transport and then build an McpClient with that transport. The client supports different transport mechanisms, primarily Server-Sent Events (SSE) and standard I/O (stdio).

Setup the Transport

First, we need to create the transport. There are two types of transport you can choose from for your application, depending on the type of your MCP server.

Stdio Transport

Stdio stands for standard input/output. In this transport, the client launches a local MCP server subprocess and exchanges one JSON-RPC message per line through its standard streams.

// The MCP server is a Java program that communicates over stdio.
McpTransport transport = StdioTransport.builder()
    .command(Arrays.asList("java", "-jar", "C:\\app\\my-app-jar-with-dependencies.jar"))
    .logEvents(true)
    .build();

Here is an example using a .exe program:

// The MCP server is a native executable that communicates over stdio.
McpTransport transport = StdioTransport.builder()
    .command(Arrays.asList("C:\\app\\my-app.exe", "-token", "dd4df2sx32ds"))
    .logEvents(true)
    .build();

Set logEvents to true to log outgoing protocol messages while debugging. The transport also consumes stderr so that a child process cannot block on a full error pipe.

SSE Transport

The SSE Transport enables bidirectional communication between MCP clients and servers using the HTTP protocol with Server-Sent Events. This transport method is particularly useful for web-based applications.

McpTransport transport = HttpMcpTransport.builder()
    .sseUrl("http://localhost:8080/sse")
    .logRequests(true)
    .logResponses(true)
    .build();

The sseUrl is required. It specifies the URL of the SSE endpoint where the MCP server is listening for incoming connections.

McpClient

The MCP Client serves as a bridge between local applications and remote tool implementations.

McpClient mcpClient = McpClient.builder()
        .clientName("my-host")
        .clientVersion("1.2")
        .transport(transport)
        .build();

Usually, you should set the clientName and clientVersion properties. The clientName property is used to identify the client to the MCP server, while the clientVersion property is used to indicate the version of the client.

All properties are listing below:

Property Note Type of value Example of value
clientName Sets the name that the client will use to identify itself to the MCP server in the initialization message. String myapp/foo-app
clientVersion Sets the version string that the client will use to identify itself to the MCP server in the initialization message. The default value is "1.0". String 1.0/2.1.2
protocolVersion Sets the protocol version that the client will advertise in the initialization message. The default value right now is "2024-11-05", but will change over time in later versions. String 2024-11-05
requestTimeout Timeout applied to every request, including initialization and health checks. The default is 60 seconds; zero means wait indefinitely, and negative values are rejected. Duration Duration.ofSeconds(60)

Please note that after creating the McpClient, you should call mcpClient.initialize(); right away. The next section describes protocol initialization.

McpClient mcpClient = McpClient.builder()
        .clientName("my-host")
        .clientVersion("1.2")
        .transport(sseTransport)
        .build();
        
mcpClient.initialize();

Close the client when it is no longer needed. Closing the transport releases HTTP/SSE requests or the stdio subprocess and completes outstanding requests exceptionally.

try (IMcpClient mcpClient2 = McpClient.builder().transport(transport).build()) {
    mcpClient2.initialize();
    ...
} catch (Exception e) {
   throw new RuntimeException(e);
}

The MCP Client follows a layered architecture with a clean separation between the interface definition and its implementation. The client relies on the transport layer for actual communication with the server, abstracting the communication details to support different transport mechanisms.