FsMcp.Server
1.0.1
dotnet add package FsMcp.Server --version 1.0.1
NuGet\Install-Package FsMcp.Server -Version 1.0.1
<PackageReference Include="FsMcp.Server" Version="1.0.1" />
<PackageVersion Include="FsMcp.Server" Version="1.0.1" />
<PackageReference Include="FsMcp.Server" />
paket add FsMcp.Server --version 1.0.1
#r "nuget: FsMcp.Server, 1.0.1"
#:package FsMcp.Server@1.0.1
#addin nuget:?package=FsMcp.Server&version=1.0.1
#tool nuget:?package=FsMcp.Server&version=1.0.1
FsMcp
FsMcp is an idiomatic F# toolkit for building Model Context Protocol (MCP) servers and clients. It wraps the official Microsoft ModelContextProtocol .NET SDK with computation expressions, typed tool handlers, Result-based error handling, and composable middleware — so you can build MCP servers in F# with type safety and zero boilerplate.
type GreetArgs = { name: string; greeting: string option }
let server = mcpServer {
name "MyServer"
version "1.0.0"
tool (TypedTool.define<GreetArgs> "greet" "Greets a person" (fun args -> task {
let greeting = args.greeting |> Option.defaultValue "Hello"
return Ok [ Content.text $"{greeting}, {args.name}!" ]
}) |> unwrapResult)
useStdio
}
Server.run server |> fun t -> t.GetAwaiter().GetResult()
// Input schema auto-generated: name=required, greeting=optional
Install
dotnet add package FsMcp.Server # server builder + stdio transport
dotnet add package FsMcp.Client # typed client wrapper
dotnet add package FsMcp.Testing # test helpers + FsCheck generators
dotnet add package FsMcp.TaskApi # FsToolkit.ErrorHandling pipeline
dotnet add package FsMcp.Server.Http # HTTP/SSE transport (opt-in ASP.NET)
dotnet add package FsMcp.Sampling # LLM sampling from server tools
Why FsMcp?
mcpServer { }CE — declare tools, resources, prompts in a single blockTypedTool.define<'T>— F# record as input, JSON Schema auto-generated via TypeShapeResult<'T, McpError>— no exceptions in expected paths, typed errors everywhere- Smart constructors —
ToolName.createvalidates at construction, not at runtime - Composable middleware — logging, validation, telemetry via
Middleware.pipeline - 306 tests — Expecto + FsCheck property tests on every domain type
Quick Start
Server with typed tools
open FsMcp.Core
open FsMcp.Core.Validation
open FsMcp.Server
type CalcArgs = { a: float; b: float }
let server = mcpServer {
name "Calculator"
version "1.0.0"
tool (TypedTool.define<CalcArgs> "add" "Add two numbers" (fun args -> task {
return Ok [ Content.text $"{args.a + args.b}" ]
}) |> unwrapResult)
tool (TypedTool.define<CalcArgs> "divide" "Divide a by b" (fun args -> task {
if args.b = 0.0 then return Error (TransportError "Division by zero")
else return Ok [ Content.text $"{args.a / args.b}" ]
}) |> unwrapResult)
useStdio
}
Server.run server |> fun t -> t.GetAwaiter().GetResult()
HTTP transport
dotnet add package FsMcp.Server.Http
open FsMcp.Server.Http
HttpServer.run server (Some "/mcp") "http://localhost:3001"
|> fun t -> t.GetAwaiter().GetResult()
Client
open FsMcp.Core.Validation
open FsMcp.Client
let demo () = task {
let config = {
Transport = ClientTransport.stdio "dotnet" ["run"; "--project"; "../Calculator"]
Name = "TestClient"
ShutdownTimeout = None
}
let! client = McpClient.connect config
let! tools = McpClient.listTools client
let toolName = ToolName.create "add" |> unwrapResult
let args = Map.ofList [
"a", System.Text.Json.JsonDocument.Parse("10").RootElement
"b", System.Text.Json.JsonDocument.Parse("20").RootElement
]
let! result = McpClient.callTool client toolName args
// result : Result<Content list, McpError>
}
Testing
open FsMcp.Testing
// Direct handler invocation — no network, no process spawning
let result =
TestServer.callTool serverConfig "add"
(Map.ofList ["a", jsonEl 10; "b", jsonEl 20])
|> Async.AwaitTask |> Async.RunSynchronously
result |> Expect.mcpHasTextContent "30" "addition works"
Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Your F# Code │
│ mcpServer { tool ...; resource ...; prompt ... } │
├──────────────┬──────────────────────────────┬───────────────────┤
│ FsMcp.Server │ FsMcp.Core │ FsMcp.Client │
│ │ │ │
│ CE builder Types (DUs, records) │ Typed wrapper │
│ TypedHandlers Validation (smart ctors) │ Async module │
│ Middleware Serialization (JSON) │ │
│ Streaming Interop (internal) │ │
│ Telemetry │ │
├──────────────┴──────────────────────────────┴───────────────────┤
│ Microsoft ModelContextProtocol SDK │
├─────────────────────────────────────────────────────────────────┤
│ .NET 10 Runtime │
└─────────────────────────────────────────────────────────────────┘
Packages
| Package | What it does |
|---|---|
| FsMcp.Core | Domain types, smart constructors, JSON serialization |
| FsMcp.Server | mcpServer { } CE, typed handlers, middleware, stdio transport |
| FsMcp.Server.Http | HTTP/SSE transport via ASP.NET Core (opt-in) |
| FsMcp.Client | Typed client with Result<'T, McpError> |
| FsMcp.Testing | TestServer.callTool, Expect.mcp*, FsCheck generators |
| FsMcp.TaskApi | taskResult { } pipeline via FsToolkit.ErrorHandling |
| FsMcp.Sampling | Server-side LLM invocation via MCP sampling |
Features
- Typed tool handlers —
TypedTool.define<'T>with TypeShape-powered JSON Schema + caching - Nested CE —
mcpTool { toolName "..."; typedHandler ... } - Streaming tools —
StreamingTool.definewithIAsyncEnumerable<Content> - Notifications —
ContextualTool.definewith progress + log callbacks - Validation middleware — auto-validates args against schema before handler
- Telemetry —
Telemetry.tracing()(Activity/OTel) +MetricsCollector - Hot reload —
DynamicServer.addTool/removeToolat runtime - Error handling —
FsToolkit.ErrorHandlingintegration viaFsMcp.TaskApi
Build & Test
dotnet build # 7 packages
dotnet test # 306 tests (Expecto + FsCheck)
Examples
See examples/ for runnable MCP servers:
- EchoServer — echo + reverse tools, resource, prompt
- Calculator — add/subtract/multiply/divide
- FileServer — read_file, list_directory, file_info
Design Principles
- Wrap, don't reimplement — protocol concerns stay in Microsoft SDK
- Idiomatic F# — DUs, Result, CEs, pipe-friendly
- Type safety — private constructors, no
objin public API - Test-first — Expecto + FsCheck on every function
- Composable — middleware, function handlers, no inheritance
Contributing
See CONTRIBUTING.md. Issues and PRs welcome.
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- FSharp.Core (>= 10.1.201)
- FsMcp.Core (>= 1.0.1)
- Microsoft.Extensions.Hosting (>= 10.0.5)
- Microsoft.Extensions.Logging.Console (>= 10.0.5)
- ModelContextProtocol (>= 1.2.0)
- TypeShape (>= 10.0.0)
NuGet packages (3)
Showing the top 3 NuGet packages that depend on FsMcp.Server:
| Package | Downloads |
|---|---|
|
FsMcp.Testing
Testing utilities for MCP servers: assertions, FsCheck generators, and in-process test server |
|
|
FsMcp.Server.Http
HTTP/SSE transport for FsMcp MCP servers via ASP.NET Core |
|
|
FsMcp.Sampling
MCP Sampling support — let server-side tools invoke LLM reasoning via the client |
GitHub repositories
This package is not used by any popular GitHub repositories.