Class AbstractMcpClient
- All Implemented Interfaces:
Closeable,AutoCloseable
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-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
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic classFluent, self-typed builder forAbstractMcpClientsubclasses. -
Constructor Summary
ConstructorsModifierConstructorDescriptionprotectedAbstractMcpClient(AbstractMcpClient.Builder<?> builder) Constructor. -
Method Summary
Modifier and TypeMethodDescriptionvoidclose()protected SseEventReaderOpens a Server-Sent-Events stream on the configured endpoint, for revision-specific facades that support a duplex (server-initiated) channel alongside the request/responsesend(org.apache.juneau.bean.jsonrpc.JsonRpcRequest)calls.protected SseEventReaderopenEventStream(JsonRpcRequest request) Opens a Server-Sent-Events stream on the configured endpoint by first POSTingrequestas the request body — for a revision-specific method (e.g.protected SseEventReaderopenEventStream(JsonRpcRequest request, Map<String, String> httpHeaders) Opens a Server-Sent-Events stream on the configured endpoint by first POSTingrequestas 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.send(JsonRpcRequest request) Sends a raw JSON-RPC request and returns the raw JSON-RPC response envelope.send(JsonRpcRequest request, Map<String, String> httpHeaders) Sends a raw JSON-RPC request and returns the raw JSON-RPC response envelope.
-
Constructor Details
-
AbstractMcpClient
Constructor.- Parameters:
builder- The builder supplying this client's configuration. Must not benull .- Throws:
IllegalArgumentException- Ifbuilderisnull , or its endpoint isnull /blank or is not a syntactically valid absolutehttp/httpsURL (seevalidateEndpoint(String)).
-
-
Method Details
-
send
Sends a raw JSON-RPC request and returns the raw JSON-RPC response envelope.A request with a
null idis a notification: this method still sends it over the wire, but always returnsnull 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 benull .- Returns:
- The JSON-RPC response envelope, or
null ifrequestis a notification. - Throws:
IOException- If a transport-level or (de)serialization error occurs.
-
send
public JsonRpcResponse send(JsonRpcRequest request, Map<String, String> httpHeaders) throws IOExceptionSends a raw JSON-RPC request and returns the raw JSON-RPC response envelope.A request with a
null idis a notification: this method still sends it over the wire, but always returnsnull 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 inspectingRestResponse.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 benull .httpHeaders- Optional additional HTTP headers to add on this request. Can benull .- Returns:
- The JSON-RPC response envelope, or
null ifrequestis 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/responsesend(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 POSTingrequestas 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 toopenEventStream()'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 benull .- 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 IOExceptionOpens a Server-Sent-Events stream on the configured endpoint by first POSTingrequestas 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'sMcp-Method/Mcp-Name) the same waysend(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 anSseEventReader(which would see zero events and eventually look like an indistinguishable transport failure), this checks the responseContent-Typefirst: only a body reportingtext/event-streamis opened as a stream. Anything else is parsed as aJsonRpcResponse; a non-null erroris thrown synchronously as anMcpExceptioncarrying 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 neithertext/event-streamnor a JSON-RPC error envelope still fails as a plainIOException(or the underlyingRestCallExceptionfrom 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 benull .httpHeaders- Optional additional HTTP headers to add on this request. Can benull .- 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 rejectedrequestwith a JSON-RPC error instead of opening the stream.
-
close
- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceCloseable- Throws:
IOException
-