Skip to content
5 changes: 5 additions & 0 deletions .changeset/mcp-protocol-versions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"effect": patch
---

MCP servers now support the 2024-11-05 and 2025-03-26 RPC revisions through version-specific protocol adapters.
10 changes: 7 additions & 3 deletions packages/effect/MCP.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,13 @@ The server exposes three main parts:
The part layers are merged into one layer that has a MCP server implementation as dependency.
`McpServer.layerStdio` is used to create a standard I/O–based MCP server identified by its name and
version. Its ordered, non-empty `protocols` declaration names implemented protocol adapters rather
than arbitrary version strings. This release supports `McpProtocol.v2025_06_18`. Because of the
layer architecture the server implementation can be easily exchanged with an HTTP-based implementation
with `McpServer.layerHttp`. Finally, a logging layer is added with
than arbitrary version strings. This release supports `McpProtocol.v2024_11_05`,
`McpProtocol.v2025_03_26`, and `McpProtocol.v2025_06_18`. The `v2024_11_05` adapter implements that
revision's RPC schemas and stdio framing, including its batch policy. It does not implement the
historical two-endpoint HTTP+SSE transport. `McpServer.layerHttp` instead offers the 2024 RPC schema
through the same single-endpoint HTTP compatibility transport used by the 2025 adapters. Because of
the layer architecture the server implementation can be easily exchanged with this HTTP-based
implementation. Finally, a logging layer is added with
`Logger.layer([Logger.consolePretty({ stderr: true })])`, ensuring logs are written to `stderr`.
This is essential when using stdio, as any output to `stdout` would interfere with the protocol
communication.
Expand Down
139 changes: 114 additions & 25 deletions packages/effect/src/unstable/ai/McpProtocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,135 @@
*
* @since 4.0.0
*/
import type * as Effect from "../../Effect.ts"
import type * as Schema from "../../Schema.ts"
import type * as Scope from "../../Scope.ts"
import type * as Rpc from "../rpc/Rpc.ts"
import type * as RpcClient from "../rpc/RpcClient.ts"
import type * as RpcGroup from "../rpc/RpcGroup.ts"
import * as Internal from "./internal/mcpProtocol.ts"
import * as McpSchema from "./McpSchema.ts"
import { protocol as protocol2024_11_05 } from "./internal/mcpProtocol/v2024_11_05.ts"
import { protocol as protocol2025_03_26 } from "./internal/mcpProtocol/v2025_03_26.ts"
import { protocol as protocol2025_06_18 } from "./internal/mcpProtocol/v2025_06_18.ts"
import type * as McpSchema from "./McpSchema.ts"

/**
* The MCP 2025-06-18 protocol implementation.
* The MCP protocol versions implemented by this release.
*
* @category protocols
* @category models
* @since 4.0.0
*/
export const v2025_06_18: ProtocolAdapter = Internal.make({
protocolVersion: "2025-06-18",
transport: {
acceptsJsonRpcBatches: false,
requiresVersionHeader: true
},
clientRpcs: McpSchema.ClientRpcs,
clientNotificationRpcs: McpSchema.ClientNotificationRpcs,
serverRequestRpcs: McpSchema.ServerRequestRpcs,
serverNotificationRpcs: McpSchema.ServerNotificationRpcs
})
export type ProtocolVersion = "2024-11-05" | "2025-03-26" | "2025-06-18"

/**
* An implemented MCP protocol that can be supplied to `McpServer`.
* Payload codecs used by a protocol adapter.
*
* @category models
* @since 4.0.0
*/
export type ProtocolAdapter = Internal.ProtocolAdapter<
"2025-06-18",
RpcGroup.Rpcs<typeof McpSchema.ClientRpcs>,
RpcGroup.Rpcs<typeof McpSchema.ClientNotificationRpcs>,
RpcGroup.Rpcs<typeof McpSchema.ServerRequestRpcs>,
RpcGroup.Rpcs<typeof McpSchema.ServerNotificationRpcs>
>
export interface PayloadCodecs {
readonly decode: (input: unknown) => Effect.Effect<unknown, Schema.SchemaError>
readonly encode: (input: unknown) => Effect.Effect<unknown, Schema.SchemaError>
}

/**
* The MCP protocol versions implemented by this release.
* A notification projected into a protocol-specific payload.
*
* @category models
* @since 4.0.0
*/
export interface ProjectedNotification {
readonly tag: string
readonly payload: unknown
}

/**
* The operations required from an RPC group after its RPC union is erased.
*
* @category models
* @since 4.0.0
*/
export interface ErasedRpcGroup<RpcType extends Rpc.Any = Rpc.Any> {
readonly requests: ReadonlyMap<string, RpcType>
}

/**
* The additional operation required from the complete client RPC group.
*
* @category models
* @since 4.0.0
*/
export interface ErasedClientRpcGroup extends ErasedRpcGroup {
readonly prefix: (prefix: string) => RpcGroup.RpcGroup<any>
}

/**
* The operational shape shared by protocol adapters.
*
* @category models
* @since 4.0.0
*/
export interface AnyProtocolAdapter<out Version extends string = string, HandlerRequirements = unknown> {
readonly protocolVersion: Version
readonly transport: {
readonly acceptsJsonRpcBatches: boolean
readonly requiresVersionHeader: boolean
}
readonly clientRpcs: ErasedClientRpcGroup
readonly clientNotificationRpcs: ErasedRpcGroup
readonly serverRequestRpcs: RpcGroup.Any
readonly serverNotificationRpcs: ErasedRpcGroup<Rpc.AnyWithProps>
readonly payloadCodecs: (rpc: Rpc.AnyWithProps) => PayloadCodecs
readonly installHandlers: (
core: any,
lifecycle: any,
target: any
) => Effect.Effect<void, never, HandlerRequirements>
readonly makeReverseClient: (
profile: any
) => Effect.Effect<McpSchema.McpReverseClient, never, RpcClient.Protocol | Scope.Scope>
readonly projectNotification: (
notification: any
) => Effect.Effect<ProjectedNotification | undefined, any>
readonly normalizeCancellation: (payload: unknown) => Effect.Effect<any, unknown>
}

/**
* An MCP protocol adapter that can be supplied to `McpServer`.
*
* @category models
* @since 4.0.0
*/
export type ProtocolVersion = ProtocolAdapter["protocolVersion"]
export interface ProtocolAdapter<out Version extends ProtocolVersion = ProtocolVersion>
extends AnyProtocolAdapter<Version>
{}

/**
* The MCP 2025-06-18 protocol implementation.
*
* @category protocols
* @since 4.0.0
*/
export const v2025_06_18: ProtocolAdapter<"2025-06-18"> = protocol2025_06_18

/**
* The MCP 2025-03-26 protocol implementation.
*
* @category protocols
* @since 4.0.0
*/
export const v2025_03_26: ProtocolAdapter<"2025-03-26"> = protocol2025_03_26

/**
* The MCP 2024-11-05 protocol implementation.
*
* **Details**
*
* It provides the dated schema and stdio behavior. When supplied to
* `McpServer.layerHttp`, the server uses its single-endpoint Streamable HTTP
* compatibility transport; it does not implement the historical two-endpoint
* HTTP+SSE transport.
*
* @category protocols
* @since 4.0.0
*/
export const v2024_11_05: ProtocolAdapter<"2024-11-05"> = protocol2024_11_05
Loading