Skip to content

Instantly share code, notes, and snippets.

@Thorium
Created September 29, 2025 10:45
Show Gist options
  • Save Thorium/46d683453517ca0567f035e78d758449 to your computer and use it in GitHub Desktop.
Save Thorium/46d683453517ca0567f035e78d758449 to your computer and use it in GitHub Desktop.
ModelContextProtocol with FSharp (MCP with F#)
#r "nuget: ModelContextProtocol,0.4.0-preview.1"
open ModelContextProtocol.Client
open ModelContextProtocol.Protocol
open System
open System.Threading.Tasks
module McpClient =
let clientTransport =
StdioClientTransport(
StdioClientTransportOptions(
Name = "Everything",
Command = "npx",
Arguments =
[| "-y"; "@modelcontextprotocol/server-everything" |]))
// Print the list of tools available from the server.
let listTools =
task {
let! client = McpClient.CreateAsync clientTransport
let! tools = client.ListToolsAsync()
let res =
tools
|> Seq.toArray
|> Array.map(fun tool ->
$"{tool.Name} ({tool.Description})")
do! client.DisposeAsync()
res |> Array.iter Console.WriteLine
return ()
}
// Execute a tool (this would normally be driven by LLM tool invocations).
let executeTool =
task {
let! client = McpClient.CreateAsync clientTransport
let! result = client.CallToolAsync(
"echo",
readOnlyDict [| "message", ("Hello MCP!" :> obj) |],
cancellationToken = System.Threading.CancellationToken.None
)
// echo always returns one and only one text content object
let content =
result.Content
|> Seq.toArray
|> Array.find(fun c -> c.Type = "text")
:?> TextContentBlock
|> _.Text
do! client.DisposeAsync()
Console.WriteLine content
return ()
}
[| McpClient.listTools; McpClient.executeTool |]
|> Array.map(fun t -> t :> Task)
|> Task.WaitAll
{
"servers": {
"MyServer": {
"type": "stdio",
"command": "dotnet",
"args": [
"fsi",
"C:\\git\\mcp\\Server.fsx"
]
}
},
"inputs": []
}
#r "nuget: ModelContextProtocol,0.4.0-preview.1"
#r "nuget: Microsoft.Extensions.Hosting"
open Microsoft.Extensions.DependencyInjection
open Microsoft.Extensions.Hosting
open Microsoft.Extensions.Logging
open ModelContextProtocol.Server
open System
open System.ComponentModel
[<McpServerToolType>]
type EchoTool =
[<McpServerTool;
Description "Echoes the message back to the client.">]
static member Echo (message:string) = $"Hello from F#: {message}"
// Define your urls whatever .NET Core style you like....
let args = [|"--urls \"http://localhost:5000\""|]
let builder = Host.CreateApplicationBuilder args
builder.Logging.AddConsole(fun consoleLogOptions ->
// Configure all logs to go to stderr
consoleLogOptions.LogToStandardErrorThreshold <- LogLevel.Trace
)
builder.Services
.AddMcpServer(fun opts ->
opts.ServerInfo <- ModelContextProtocol.Protocol.Implementation(
Name = "MyServer", Version = "1.0",
Title = "My echo server"
)
)
.WithStdioServerTransport()
.WithToolsFromAssembly()
builder.Build().RunAsync()
|> System.Threading.Tasks.Task.WaitAny
// Test in VSCode CoPilot:
// Create .vscode\mcp.json file, you can make it like this:
// VSCode: Press Ctrl + Shift + P -> Command (stdio), Command to run:
// dotnet fsi c:\mypath\Server.fsx
// Then Ctrl + Alt + I -> Agents mode, should be available now.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment