Class AbstractMcpClient

java.lang.Object
org.apache.juneau.rest.client.mcp.AbstractMcpClient
All Implemented Interfaces:
Closeable, AutoCloseable
Direct Known Subclasses:
McpClient, McpClient

public abstract class AbstractMcpClient extends Object implements Closeable
Revision-neutral base class for Model Context Protocol (MCP) clients.

Wraps a single configured RestClient and executes raw JSON-RPC 2.0 request/response round trips against one endpoint in JSON response mode. A generic RestCallInterceptor passthrough is provided on the builder so per-revision facades can layer auth and other cross-cutting concerns without changing this core.

send(JsonRpcRequest) returns the complete JsonRpcResponse envelope untouched, including error responses - it does not throw McpException on a JSON-RPC error. Typed facades are responsible for translating a response with a non-null error into a thrown McpException.

Instances are thread-safe for concurrent reuse: RestClient and endpoint are final, and each send(JsonRpcRequest) creates a fresh request/response scope. Builders are single-use value assemblers: calling build() twice creates two clients and both use the same explicitly configured transport instance.

Since:
10.0.0
  • Constructor Details

    • AbstractMcpClient

      Constructor.
      Parameters:
      builder - The builder supplying this client's configuration. Must not be null.
      Throws:
      IllegalArgumentException - If builder is null, or its endpoint is null/blank or is not a syntactically valid absolute http/https URL (see validateEndpoint(String)).
  • Method Details

    • send

      Sends a raw JSON-RPC request and returns the raw JSON-RPC response envelope.

      A request with a null id is a notification: this method still sends it over the wire, but always returns null without attempting to read a response body, per the JSON-RPC 2.0 notification contract (the server sends no response body for a notification).

      Parameters:
      request - The JSON-RPC request to send. Must not be null.
      Returns:
      The JSON-RPC response envelope, or null if request is a notification.
      Throws:
      IOException - If a transport-level or (de)serialization error occurs.
    • send

      public JsonRpcResponse send(JsonRpcRequest request, Map<String,String> httpHeaders) throws IOException
      Sends a raw JSON-RPC request and returns the raw JSON-RPC response envelope.

      A request with a null id is a notification: this method still sends it over the wire, but always returns null without attempting to read a response body, per the JSON-RPC 2.0 notification contract (the server sends no response body for a notification).

      Note: for a notification, this method returns null immediately after the transport call completes, without ever inspecting RestResponse.getStatusCode(). A non-2xx HTTP status on a notification is therefore silently swallowed - the caller sees no indication that the server rejected it. This is intentional per the notification contract above (there is no response envelope to report an error through), but it does mean transport-level failures on notifications are otherwise invisible to callers.

      Parameters:
      request - The JSON-RPC request to send. Must not be null.
      httpHeaders - Optional additional HTTP headers to add on this request. Can be null.
      Returns:
      The JSON-RPC response envelope, or null if request is a notification.
      Throws:
      IOException - If a transport-level or (de)serialization error occurs.
    • openEventStream

      Opens a Server-Sent-Events stream on the configured endpoint, for revision-specific facades that support a duplex (server-initiated) channel alongside the request/response send(org.apache.juneau.bean.jsonrpc.JsonRpcRequest) calls.
      Returns:
      A reader over the opened event stream. Never null. Callers are responsible for closing it.
      Throws:
      IOException - If a transport-level error occurs opening the stream.
    • openEventStream

      Opens a Server-Sent-Events stream on the configured endpoint by first POSTing request as the request body — for a revision-specific method (e.g. subscriptions/listen) whose held-open SSE response is itself the answer to one specific JSON-RPC request, as opposed to openEventStream()'s body-less open used by the duplex server-push channel.
      Parameters:
      request - The JSON-RPC request to POST as the body that opens the stream. Must not be null.
      Returns:
      A reader over the opened event stream. Never null. Callers are responsible for closing it.
      Throws:
      IOException - If a transport-level or (de)serialization error occurs opening the stream.
    • openEventStream

      protected SseEventReader openEventStream(JsonRpcRequest request, Map<String,String> httpHeaders) throws IOException
      Opens a Server-Sent-Events stream on the configured endpoint by first POSTing request as the request body, with additional HTTP headers on the opening request — for a revision-specific method whose held-open SSE response must agree with a header-based method/name contract (e.g. SEP-2243's Mcp-Method/ Mcp-Name) the same way send(JsonRpcRequest, Map) already does for the ordinary request/response path.

      Unlike the body-less openEventStream(), this opening POST is itself the answer to one specific JSON-RPC request, so the server may reject it with a JSON-RPC error envelope instead of opening the stream (e.g. a capability, Accept-header, or over-limit gate) — on any HTTP status, not just 2xx. Rather than handing that envelope to an SseEventReader (which would see zero events and eventually look like an indistinguishable transport failure), this checks the response Content-Type first: only a body reporting text/event-stream is opened as a stream. Anything else is parsed as a JsonRpcResponse; a non-null error is thrown synchronously as an McpException carrying the server's code/message/data, matching the way mid-stream JSON-RPC errors are already surfaced to a stream's listener. A response that is neither text/event-stream nor a JSON-RPC error envelope still fails as a plain IOException (or the underlying RestCallException from a non-2xx status), never silently masquerading as an opened stream.

      Parameters:
      request - The JSON-RPC request to POST as the body that opens the stream. Must not be null.
      httpHeaders - Optional additional HTTP headers to add on this request. Can be null.
      Returns:
      A reader over the opened event stream. Never null. Callers are responsible for closing it.
      Throws:
      IOException - If a transport-level or (de)serialization error occurs opening the stream, or the response was neither an SSE stream nor a JSON-RPC error envelope.
      McpException - If the server rejected request with a JSON-RPC error instead of opening the stream.
    • close

      public void close() throws IOException
      Specified by:
      close in interface AutoCloseable
      Specified by:
      close in interface Closeable
      Throws:
      IOException