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.6</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 three transport mechanisms: standard I/O (STDIO), the legacy two-endpoint HTTP/SSE transport, and Streamable HTTP.

Setup the Transport

First, create the transport that matches the 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.

Legacy HTTP/SSE Transport

The legacy transport uses an SSE endpoint for server-to-client messages and a server-advertised POST endpoint for client requests. It is useful when connecting to older MCP servers.

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.

Streamable HTTP (2025-03-26 / 2025-06-18)

Newer revisions use one HTTP endpoint:

McpTransport transport = StreamableHttpTransport.builder()
        .endpointUrl("http://localhost:8080/mcp")
        .openEventStream(true)
        .build();

McpClient client = McpClient.builder()
        .transport(transport)
        .protocolVersion("2025-06-18")
        .build();
client.

initialize();

For OAuth, pass an Authorization Bearer token through requestHeaders. The SDK retains the returned session ID and automatically sends the negotiated MCP-Protocol-Version on subsequent requests.

Set openEventStream(true) when the client advertises Roots, Sampling, or Elicitation handlers. Those server-initiated requests are received through the optional GET event stream, which opens asynchronously after initialization.

Current limitations: request-scoped streaming over a POST text/event-stream response is buffered rather than processed incrementally; use ordinary JSON POST responses. The optional GET event stream has no reconnect/resumption policy, and initialization does not wait for that stream to become ready. Do not rely on incremental POST progress or server requests delivered through a POST response until this limitation is removed.

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.