Skip to main content

FsMcp

Build MCP servers and clients in F# with typed cancellation, explicit errors, secure hosting composition, and honest runtime boundaries.

FsMcp wraps Microsoft's ModelContextProtocol .NET SDK with an idiomatic F# API.

type GreetArgs = { name: string; greeting: string option }

let server = mcpServer {
name "MyServer"
version "1.0.0"

tool (TypedTool.define<GreetArgs> "greet" "Greets" (fun args cancellationToken -> task {
cancellationToken.ThrowIfCancellationRequested()
let g = args.greeting |> Option.defaultValue "Hello"
return Ok [ Content.text $"{g}, {args.name}!" ]
}) |> unwrapResult)
}

Server.run server |> fun t -> t.GetAwaiter().GetResult()

Packages

PackageInstallDescription
FsMcp.Coredotnet add package FsMcp.CoreDomain types, validation, serialization
FsMcp.Serverdotnet add package FsMcp.ServerServer builder CE, cancellable typed handlers, stdio
FsMcp.Clientdotnet add package FsMcp.ClientTyped client and enterprise-managed authorization
FsMcp.Testingdotnet add package FsMcp.TestingTestServer, assertions, FsCheck generators
FsMcp.TaskApidotnet add package FsMcp.TaskApiFsToolkit.ErrorHandling pipeline
FsMcp.Server.Httpdotnet add package FsMcp.Server.HttpStreamable HTTP and ASP.NET Core composition
FsMcp.Samplingdotnet add package FsMcp.SamplingSampling types and explicit test helpers

Why FsMcp?

  • mcpServer { } CE — declare tools, resources, prompts in one block
  • TypedTool.define<'T> — F# record as input, JSON Schema auto-generated via TypeShape
  • Result<'T, McpError> — typed errors, no exceptions in expected paths
  • Smart constructorsToolName.create validates at construction, not at runtime
  • Request cancellation — the SDK request token reaches every primary handler
  • Secure composition — caller-owned DI, SDK filters, and ASP.NET authorization
  • Enterprise-managed authorization — validated ID-JAG client flow with bounded refresh/retry
  • Fail-closed compatibility — disconnected 1.x runtime surfaces no longer pretend to work

FsMcp 2.0 is a breaking release. McpClient.readResource returns the complete ResourceContents list, handler signatures take a final CancellationToken, and transport selection belongs to Server.run or FsMcp.Server.Http, not the server computation expression.