Skip to content
// EFFECT DAYS 2026

McpClient

Connects to MCP servers with scoped Effect clients.

Clients discover tools, prompts, resources and Agent Skills using the protocol revision selected by their transport. callTool returns tool-reported errors as results; supplying a schema turns them into a ToolError reason that retains the original result. Transport and protocol failures fail the Effect. Interactive server requests, subscriptions, OAuth and retries are not included.

14 exports Since v4.0.6 Source

Constructors

Since v4.0.6

Creates a Streamable HTTP transport with request-owned JSON or SSE responses.

Signature

declare const http: (options: {
readonly headers?: Readonly<Record<string, string>>;
readonly maxMessageBytes?: ByteSize.Input;
readonly protocol: McpProtocol.ProtocolAdapter<ProtocolVersion>;
readonly url: string | URL;
}) => Effect.Effect<Transport, McpClientError, HttpClient.HttpClient | Scope.Scope>
Since v4.0.6

Constructs and connects a client using the supplied MCP transport service and its protocol adapter.

Details

name, version and the optional title, description, websiteUrl and icons identify the client to the server. timeout defaults to 60 seconds and bounds initialization and each complete listTools, listPrompts, listResources, listSkills or readResourceDirectory scan. discoveryLimits sets the default scan limits of 100 pages and 10,000 items. callTool, getPrompt, readResource, getSkill and readSkillResource have no deadline unless their own timeout option is supplied.

extensions selects the protocol extensions the client declares. With skills: true it declares the Skills extension (SEP-2640) and enables listSkills, getSkill, readResourceDirectory and readSkillResource; without it they fail with a ConfigurationError. They run only against a server that declares the extension too, and skill entries are checked against its rules. readSkillResource checks digests with SHA-256 on crypto.subtle. Schema decoding requires the schema's services from the caller.

Signature

declare const make: (options: {
readonly description?: string;
readonly discoveryLimits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly extensions?: {
readonly skills?: boolean;
};
readonly icons?: ReadonlyArray<McpSchema.Icon>;
readonly name: string;
readonly timeout?: Duration.Input;
readonly title?: string;
readonly version: string;
readonly websiteUrl?: string;
}) => Effect.Effect<McpClient, McpClientError, Scope.Scope | Transport>
Since v4.0.6

Starts a scoped subprocess using newline-delimited JSON-RPC.

Signature

declare const stdio: (options: {
readonly command: ChildProcess.Command;
readonly maxMessageBytes?: ByteSize.Input;
readonly protocol: McpProtocol.ProtocolAdapter<ProtocolVersion>;
}) => Effect.Effect<Transport, McpClientError, ChildProcessSpawner | Scope.Scope>
Since v4.0.6

Binds remote tools using the standard Toolkit implementation.

Details

Pass a prefix such as "reports__" or an options object. Tools are discovered unless an approved tools snapshot is supplied. Remote JSON Schemas are advertised as-is, and model tool names must be 1โ€“64 ASCII letters, digits, underscores or hyphens. Build a new toolkit to pick up remote changes.

By default results are text and failures fail the Effect. resultMode: "complete" returns the full CallToolResult and sends its content to the model as text and file parts. failureMode: "return" returns typed failures, including transport errors, to the model; ToolError keeps the failed result. Type arguments that select a non-default mode require the matching option.

timeout bounds each tool call. trustAnnotations copies server hints into tool annotations but never sets approval. transformTool receives each annotated tool before binding and must return a tool derived from it, e.g. with setNeedsApproval, annotate or addDependency, keeping its name, schemas and failure mode.

Signature

declare function toolkit(client: McpClient, prefix?: string): Effect<WithHandler<Record<string, Tool<string, {
readonly failure: typeof McpClientError;
readonly failureMode: "error";
readonly parameters: Unknown;
readonly success: String;
}, never, Execution>>>, McpClientError>
declare function toolkit<ResultMode extends "text" | "complete" = "text", FailureMode extends FailureMode = "error", Requirements = never>(client: McpClient, options: {
readonly prefix?: string;
readonly timeout?: Input;
readonly tools?: readonly Array<Tool>;
readonly transformTool?: (tool: RemoteTool<ResultMode, FailureMode>, descriptor: Tool) => RemoteTool<ResultMode, FailureMode, Requirements>;
readonly trustAnnotations?: boolean;
} & [ResultMode] extends ["text"] ? {
readonly resultMode?: "text";
} : {
readonly resultMode: ResultMode;
} & [FailureMode] extends ["error"] ? {
readonly failureMode?: "error";
} : {
readonly failureMode: FailureMode;
}): Effect<WithHandler<Record<string, RemoteTool<ResultMode, FailureMode, Requirements>>>, McpClientError>

Guards

Returns whether a value is an MCP client.

Signature

declare function isMcpClient(value: unknown): value is McpClient

Layers

Provides a connected MCP client over Streamable HTTP using the HTTP client.

Details

The layer scope owns the client and connection. The options are those of make and http.

See

Signature

declare const layerHttp: (options: {
readonly description?: string;
readonly discoveryLimits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly extensions?: {
readonly skills?: boolean;
};
readonly headers?: Readonly<Record<string, string>>;
readonly icons?: ReadonlyArray<McpSchema.Icon>;
readonly maxMessageBytes?: ByteSize.Input;
readonly name: string;
readonly protocol: McpProtocol.ProtocolAdapter<ProtocolVersion>;
readonly timeout?: Duration.Input;
readonly title?: string;
readonly url: string | URL;
readonly version: string;
readonly websiteUrl?: string;
}) => Layer.Layer<McpClient, McpClientError, HttpClient.HttpClient>

Example Providing an HTTP client connection

import { Layer } from "effect"
import { McpClient, McpProtocol } from "effect/ai"
import { FetchHttpClient } from "effect/http"
const ClientLayer = McpClient.layerHttp({
name: "report-workflow",
version: "1.0.0",
protocol: McpProtocol.v2026_07_28,
url: "http://localhost:3000/mcp"
}).pipe(Layer.provide(FetchHttpClient.layer))

Provides a connected MCP client over stdio using the child process spawner.

Details

The layer scope owns the client and subprocess. The options are those of make and stdio.

See

Signature

declare const layerStdio: (options: {
readonly command: ChildProcess.Command;
readonly description?: string;
readonly discoveryLimits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly extensions?: {
readonly skills?: boolean;
};
readonly icons?: ReadonlyArray<McpSchema.Icon>;
readonly maxMessageBytes?: ByteSize.Input;
readonly name: string;
readonly protocol: McpProtocol.ProtocolAdapter<ProtocolVersion>;
readonly timeout?: Duration.Input;
readonly title?: string;
readonly version: string;
readonly websiteUrl?: string;
}) => Layer.Layer<McpClient, McpClientError, ChildProcessSpawner>

Models

McpClient

interface
Since v4.0.6

A scoped connection to one MCP server.

Signature

interface McpClient {
readonly "~effect/ai/McpClient": "~effect/ai/McpClient";
readonly callTool: {
(params: {
readonly arguments?: {
[key: string]: any;
};
readonly schema?: undefined;
readonly tool: Tool;
}, options?: {
readonly timeout?: Input;
}): Effect<CallToolResult, McpClientError>;
<S extends Top>(params: {
readonly arguments?: {
[key: string]: any;
};
readonly schema: S;
readonly tool: Tool;
}, options?: {
readonly timeout?: Input;
}): Effect<S["Type"], McpClientError, S["DecodingServices"]>;
<S extends Top = never>(params: {
readonly arguments?: {
[key: string]: any;
};
readonly schema?: S;
readonly tool: Tool;
}, options?: {
readonly timeout?: Input;
}): Effect<CallToolResult | S["Type"], McpClientError, S["DecodingServices"]>;
};
readonly capabilities: ServerCapabilities;
readonly getPrompt: (params: {
readonly arguments?: {
[key: string]: string;
};
readonly prompt: Prompt;
}, options?: {
readonly timeout?: Input;
}) => Effect<GetPromptResult, McpClientError>;
readonly getSkill: (params: {
readonly uri: string;
}, options?: {
readonly timeout?: Input;
}) => Effect<Skill, McpClientError>;
readonly instructions?: string;
readonly listPrompts: (options?: {
readonly limits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly timeout?: Input;
}) => Effect<readonly Array<Prompt>, McpClientError>;
readonly listResources: (options?: {
readonly limits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly timeout?: Input;
}) => Effect<readonly Array<Resource>, McpClientError>;
readonly listSkills: (options?: {
readonly limits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly onInvalidSkill?: (invalid: {
readonly entry: unknown;
readonly error: McpClientError;
}) => Effect<void>;
readonly timeout?: Input;
}) => Effect<readonly Array<Skill>, McpClientError>;
readonly listTools: (options?: {
readonly limits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly timeout?: Input;
}) => Effect<readonly Array<Tool>, McpClientError>;
readonly protocolVersion: ProtocolVersion;
readonly readResource: (params: {
readonly uri: string;
}, options?: {
readonly timeout?: Input;
}) => Effect<ReadResourceResult, McpClientError>;
readonly readResourceDirectory: (params: {
readonly uri: string;
}, options?: {
readonly limits?: {
readonly maxItems?: number;
readonly maxPages?: number;
};
readonly timeout?: Input;
}) => Effect<readonly Array<Resource>, McpClientError>;
readonly readSkillResource: (params: {
readonly skill: Skill;
readonly uri: string;
}, options?: {
readonly timeout?: Input;
}) => Effect<ReadResourceResult, McpClientError>;
readonly serverInfo: Implementation | undefined;
}
Since v4.0.6

Supported MCP wire protocol revisions.

Signature

type ProtocolVersion = "2025-11-25" | "2026-07-28"
Since v4.1.1

Native tool bound to a remote MCP descriptor with configurable result and failure modes.

Signature

type RemoteTool<ResultMode extends "text" | "complete" = "text", FailureMode extends Tool.FailureMode = "error", Requirements = never> = FailureMode extends Tool.FailureMode ? Tool.Tool<string, {
readonly failure: typeof McpClientError;
readonly failureMode: FailureMode;
readonly parameters: typeof Schema.Unknown;
readonly success: {
readonly complete: typeof McpSchema.CallToolResult;
readonly text: typeof Schema.String;
}[ResultMode];
}, Requirements> : never

Transport

interface
Since v4.0.6

Exchanges JSON-RPC messages with one MCP server using its protocol adapter.

Signature

interface Transport {
readonly "~effect/ai/McpClient/Transport": "~effect/ai/McpClient/Transport";
readonly isCallable: (tool: Tool) => boolean;
readonly notify: (message: JsonRpcNotification) => Effect<void, McpClientError>;
readonly protocol: ProtocolAdapter<ProtocolVersion>;
readonly request: (message: {
readonly id: string | number;
readonly jsonrpc: "2.0";
readonly method: string;
readonly params?: {
[key: string]: unknown;
};
}, tool?: Tool) => Effect<JsonRpcResponse, McpClientError>;
}

Services

Service tag for applications that provide one default MCP connection.

Signature

declare const McpClient: Context.Service<McpClient, McpClient>

Annotation containing the remote descriptor used to bind an MCP tool.

Details

The descriptor is server-provided and should be treated as untrusted.

Signature

declare class ToolDescriptor extends Shape<"effect/ai/McpClient/ToolDescriptor", Tool, this> {
constructor(_: never);
}

Service supplied by the built-in MCP transport constructors and layers.

Details

Transport construction owns cleanup through its Effect scope.

Signature

declare const Transport: Context.Service<Transport, Transport>