MCPClientImpl

org.llm4s.mcp.MCPClientImpl
See theMCPClientImpl companion object
class MCPClientImpl(config: MCPServerConfig) extends MCPClient

MCPClient implementation that connects to an MCP server over JSON-RPC.

== Transport auto-detection == For HTTP-based server configs (StreamableHTTPTransport or SSETransport), this client first attempts to connect using the MCP 2025-06-18 Streamable HTTP protocol. If the server responds with HTTP 404 or 405, it automatically falls back to the older 2024-11-05 HTTP+SSE protocol. Stdio servers always use the 2024-11-05 protocol.

== Failures in getTools == getTools() returns a Left for any failure during tool discovery (network error, JSON-RPC error, unreadable listing, missing transport), so "the server has no tools" (Right(Seq.empty)) is distinct from "the server could not be reached". An interrupted call returns Left(CancelledError) with the thread's interrupt flag still set (design section 4.4).

== Thread safety == This class is not thread-safe. Concurrent calls to initialize, getTools, or close from different threads require external synchronisation.

Value parameters

config

Server configuration including transport type, URL/command, and timeout.

Attributes

Companion
object
Graph
Supertypes
trait MCPClient
class Object
trait Matchable
class Any

Members list

Value members

Concrete methods

override def close(): Unit

Closes the MCP client connection and releases resources. Should be called when done with the client.

Closes the MCP client connection and releases resources. Should be called when done with the client.

Attributes

Definition Classes
override def getToolHints(): Map[String, ToolHints]

The hints each tool declares through its MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), by tool name, as of the last successful getTools; empty before that, and empty again as soon as a listing fails or the client is closed, so a tool the server no longer advertises never keeps its old hints. A tool that carries no annotations has the specification's conservative defaults.

The hints each tool declares through its MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), by tool name, as of the last successful getTools; empty before that, and empty again as soon as a listing fails or the client is closed, so a tool the server no longer advertises never keeps its old hints. A tool that carries no annotations has the specification's conservative defaults.

'''Trust.''' Hints are advisory: they say what a server claims, not what its tool does, and the MCP specification requires a client to treat annotations from an untrusted server as untrusted. They are therefore reported only for a server configured with MCPServerConfig.trustAnnotations = true; for any other the map is empty, which leaves ToolHints.default in force (approval required). Otherwise a server could mark a destructive tool readOnlyHint = true and have ApprovalMiddleware.unlessReadOnly run it unapproved.

Attach hints to the tool a middleware will see with AgentTool.fromToolFunction(tool, hints) in llm4s-agent.

Attributes

Definition Classes
override def getTools(): Result[Seq[ToolFunction[_, _]]]

Retrieves all tools advertised by the MCP server, converting them to ToolFunction instances that the agent framework can invoke.

Retrieves all tools advertised by the MCP server, converting them to ToolFunction instances that the agent framework can invoke.

Calls initialize() automatically if not already connected. Any error during transport initialisation, tool listing, or JSON parsing is logged and returned as a Left; Right(Seq.empty) means the server advertises no tools. A call that is interrupted returns Left(CancelledError), with the thread's interrupt flag still set.

A tool entry that cannot be read is skipped and logged, and the tools that can be read are returned; a listing that cannot be read at all, or none of whose entries can, is a Left.

A listing that fails clears the hints recorded by the last one (see getToolHints), so a server that is down or sends a list that cannot be read leaves no stale hints behind.

Attributes

Returns

the tools the server advertises, or the Left that stopped the listing

Definition Classes
override def initialize(): Result[Unit]

Initializes the MCP connection with handshake protocol. Must be called before other operations.

Initializes the MCP connection with handshake protocol. Must be called before other operations.

Attributes

Returns

the error that stopped the handshake, or successful initialization; Left(CancelledError), with the thread's interrupt flag still set, if the call was interrupted

Definition Classes
def trySendingRequest(transportImpl: MCPTransportImpl): Result[Seq[ToolFunction[_, _]]]