├── .config
└── dotnet-tools.json
├── .editorconfig
├── .github
├── pull_request_template.md
└── workflows
│ └── ci.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── GitVersion.yml
├── LICENSE
├── README.MD
├── SECURITY.md
├── TODO.md
├── build.cake
├── build.ps1
├── build.sh
├── mcpdotnet.sln
├── samples
├── AspNetCoreSseServer
│ ├── AspNetCoreSseServer.csproj
│ ├── McpEndpointRouteBuilderExtensions.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── SseServerStreamTransport.cs
│ ├── Tools
│ │ ├── EchoTool.cs
│ │ └── SampleLlmTool.cs
│ ├── appsettings.Development.json
│ └── appsettings.json
├── README.md
├── TestServerWithHosting
│ ├── Program.cs
│ ├── TestServerWithHosting.csproj
│ └── Tools
│ │ ├── EchoTool.cs
│ │ └── SampleLlmTool.cs
├── anthropic
│ └── tools
│ │ └── ToolsConsole
│ │ ├── AnthropicToolsConsole.csproj
│ │ ├── McpToolExtensions.cs
│ │ ├── Program.cs
│ │ └── Properties
│ │ └── launchSettings.json
└── microsoft.extensions.ai
│ └── tools
│ └── ToolsConsole
│ ├── MEAIToolsConsole.csproj
│ ├── Program.cs
│ └── Properties
│ └── launchSettings.json
├── src
├── Common
│ └── Polyfills
│ │ └── System
│ │ ├── Collections
│ │ └── Generic
│ │ │ └── CollectionExtensions.cs
│ │ ├── Diagnostics
│ │ ├── CodeAnalysis
│ │ │ ├── DynamicallyAccessedMemberTypes.cs
│ │ │ ├── DynamicallyAccessedMembersAttribute.cs
│ │ │ ├── NullableAttributes.cs
│ │ │ ├── RequiresDynamicCodeAttribute.cs
│ │ │ ├── RequiresUnreferencedCode.cs
│ │ │ ├── SetsRequiredMembersAttribute.cs
│ │ │ └── UnconditionalSuppressMessageAttribute.cs
│ │ └── ProcessExtensions.cs
│ │ ├── IO
│ │ ├── TextReaderExtensions.cs
│ │ └── TextWriterExtensions.cs
│ │ ├── Net
│ │ └── Http
│ │ │ └── HttpClientExtensions.cs
│ │ ├── Runtime
│ │ └── CompilerServices
│ │ │ ├── CallerArgumentExpressionAttribute.cs
│ │ │ ├── CompilerFeatureRequiredAttribute.cs
│ │ │ ├── IsExternalInit.cs
│ │ │ └── RequiredMemberAttribute.cs
│ │ └── Threading
│ │ ├── CancellationTokenSourceExtensions.cs
│ │ └── Tasks
│ │ └── TaskExtensions.cs
├── McpDotNet.Extensions.AI
│ ├── McpDotNet.Extensions.AI.csproj
│ └── README.md
└── mcpdotnet
│ ├── Client
│ ├── IMcpClient.cs
│ ├── McpClient.cs
│ ├── McpClientException.cs
│ ├── McpClientExtensions.cs
│ ├── McpClientFactory.cs
│ └── McpClientOptions.cs
│ ├── Configuration
│ ├── DefaultMcpServerBuilder.cs
│ ├── IMcpServerBuilder.cs
│ ├── McpServerBuilderExtensions.Handler.cs
│ ├── McpServerBuilderExtensions.Tools.cs
│ ├── McpServerBuilderExtensions.Transports.cs
│ ├── McpServerConfig.cs
│ ├── McpServerOptionsSetup.cs
│ └── McpServerServiceCollectionExtension.cs
│ ├── Hosting
│ └── McpServerHostedService.cs
│ ├── Logging
│ └── Log.cs
│ ├── Protocol
│ ├── Messages
│ │ ├── ErrorCodes.cs
│ │ ├── IJsonRpcMessage.cs
│ │ ├── IJsonRpcMessageWithId.cs
│ │ ├── JsonRpcError.cs
│ │ ├── JsonRpcErrorDetail.cs
│ │ ├── JsonRpcMessage.cs
│ │ ├── JsonRpcNotification.cs
│ │ ├── JsonRpcResponse.cs
│ │ ├── NotificationMethods.cs
│ │ ├── OperationNames.cs
│ │ ├── PaginatedResult.cs
│ │ ├── RequestId.cs
│ │ └── RequestIdConverter.cs
│ ├── Transport
│ │ ├── HttpListenerServerProvider.cs
│ │ ├── HttpListenerSseServerTransport.cs
│ │ ├── IClientTransport.cs
│ │ ├── IServerTransport.cs
│ │ ├── ITransport.cs
│ │ ├── McpTransportException.cs
│ │ ├── SseClientTransport.cs
│ │ ├── SseClientTransportOptions.cs
│ │ ├── StdioClientTransport.cs
│ │ ├── StdioClientTransportOptions.cs
│ │ ├── StdioServerTransport.cs
│ │ ├── TransportBase.cs
│ │ └── TransportTypes.cs
│ └── Types
│ │ ├── Annotations.cs
│ │ ├── Argument.cs
│ │ ├── CallToolRequestParams.cs
│ │ ├── CallToolResponse.cs
│ │ ├── Capabilities.cs
│ │ ├── CompleteRequestParams.cs
│ │ ├── CompleteResult.cs
│ │ ├── Completion.cs
│ │ ├── Content.cs
│ │ ├── ContextInclusion.cs
│ │ ├── CreateMessageRequestParams.cs
│ │ ├── CreateMessageResult.cs
│ │ ├── EmptyResult.cs
│ │ ├── GetPromptRequestParams.cs
│ │ ├── GetPromptResult.cs
│ │ ├── Implementation.cs
│ │ ├── InitializeRequestParams.cs
│ │ ├── InitializeResult.cs
│ │ ├── JsonSchema.cs
│ │ ├── JsonSchemaProperty.cs
│ │ ├── ListPromptsRequestParams.cs
│ │ ├── ListPromptsResult.cs
│ │ ├── ListResourcesRequestParams.cs
│ │ ├── ListResourcesResult.cs
│ │ ├── ListRootsRequestParams.cs
│ │ ├── ListRootsResult.cs
│ │ ├── ListToolsRequestParams.cs
│ │ ├── ListToolsResult.cs
│ │ ├── ModelHint.cs
│ │ ├── ModelPreferences.cs
│ │ ├── PingResult.cs
│ │ ├── Prompt.cs
│ │ ├── PromptArgument.cs
│ │ ├── PromptMessage.cs
│ │ ├── ReadResourceRequestParams.cs
│ │ ├── ReadResourceResult.cs
│ │ ├── Reference.cs
│ │ ├── ResourceContents.cs
│ │ ├── ResourceUpdatedNotificationParams.cs
│ │ ├── Resources.cs
│ │ ├── Role.cs
│ │ ├── Root.cs
│ │ ├── SamplingMessage.cs
│ │ ├── ServerCapabilities.cs
│ │ ├── SubscribeRequestParams.cs
│ │ ├── Tool.cs
│ │ ├── UnsubscribeFromResourceRequestParams.cs
│ │ └── UnsubscribeRequestParams.cs
│ ├── Server
│ ├── IMcpServer.cs
│ ├── McpServer.cs
│ ├── McpServerException.cs
│ ├── McpServerExtensions.cs
│ ├── McpServerFactory.cs
│ ├── McpServerHandlers.cs
│ ├── McpServerOptions.cs
│ ├── McpToolAttribute.cs
│ ├── McpToolTypeAttribute.cs
│ └── RequestContext.cs
│ ├── Shared
│ └── McpJsonRpcEndpoint.cs
│ ├── Utils
│ ├── Json
│ │ ├── JsonRpcMessageConverter.cs
│ │ └── JsonSerializerOptionsExtensions.cs
│ ├── ProcessHelper.cs
│ └── Throw.cs
│ └── mcpdotnet.csproj
└── tests
├── mcpdotnet.TestServer
├── Program.cs
└── mcpdotnet.TestServer.csproj
├── mcpdotnet.TestSseServer
├── Program.cs
└── mcpdotnet.TestSseServer.csproj
└── mcpdotnet.Tests
├── Client
└── McpClientFactoryTests.cs
├── ClientIntegrationTestFixture.cs
├── ClientIntegrationTests.cs
├── Configuration
├── McpServerBuilderExtensionsHandlerTests.cs
├── McpServerBuilderExtensionsToolsTests.cs
└── McpServerBuilderExtensionsTransportsTests.cs
├── EverythingSseServerFixture.cs
├── GlobalUsings.cs
├── Server
├── McpServerDelegatesTests.cs
├── McpServerFactoryTests.cs
└── McpServerTests.cs
├── SseIntegrationTests.cs
├── SseServerIntegrationTestFixture.cs
├── SseServerIntegrationTests.cs
├── Transport
├── SseClientTransportTests.cs
└── StdioServerTransportTests.cs
├── Utils
├── InMemoryTestSseServer.cs
├── MockHttpHandler.cs
└── TestServerTransport.cs
└── mcpdotnet.Tests.csproj
/.config/dotnet-tools.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": 1,
3 | "isRoot": true,
4 | "tools": {
5 | "cake.tool": {
6 | "version": "5.0.0",
7 | "commands": [
8 | "dotnet-cake"
9 | ],
10 | "rollForward": false
11 | }
12 | }
13 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories
2 | root = true
3 |
4 | # C# files
5 | [*.cs]
6 |
7 | # Code Analysis
8 | dotnet_diagnostic.CA1002.severity = none # CA1002: Do not expose generic lists
9 | dotnet_diagnostic.CA1031.severity = none # CA1031: Do not catch general exception types
10 | dotnet_diagnostic.CA1054.severity = none # CA1054: URI-like parameters should not be strings
11 | dotnet_diagnostic.CA1056.severity = none # CA1056: URI-like properties should not be strings
12 | dotnet_diagnostic.CA1062.severity = suggestion # CA1062: Validate arguments of public methods
13 | dotnet_diagnostic.CA1510.severity = suggestion # CA1510: Use ArgumentNullException throw helper
14 | dotnet_diagnostic.CA1849.severity = suggestion # CA1849: Call async methods when in an async method
15 | dotnet_diagnostic.CA2000.severity = suggestion # CA2000: Dispose objects before losing scope
16 | dotnet_diagnostic.CA2227.severity = suggestion # CA2227: Collection properties should be read only
17 | dotnet_diagnostic.CA2249.severity = suggestion # CA2249: Use 'string.Contains' instead of 'string.IndexOf'
18 | dotnet_diagnostic.CA1819.severity = suggestion # CA1819: Properties should not return arrays
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | # Pull Request
2 |
3 | ## Description of Changes
4 |
5 |
6 | ## Related Issue(s)
7 |
8 | - Fixes #
9 |
10 | ## Testing Done
11 |
12 | - [ ] Unit tests added/updated
13 | - [ ] Integration tests added/updated
14 | - [ ] Manual testing performed
15 |
16 | ## Breaking Changes
17 |
18 | None
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: .NET Build, Test and publish
2 |
3 | on:
4 | push:
5 | branches: [ "main", "master" ]
6 | pull_request:
7 | branches: [ "main", "master" ]
8 | release:
9 | types: [published,edited]
10 |
11 | # Allows you to run this workflow manually from the Actions tab
12 | workflow_dispatch:
13 |
14 | jobs:
15 | build:
16 |
17 | runs-on: ubuntu-latest
18 |
19 | steps:
20 | - uses: actions/checkout@v4
21 | with:
22 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
23 |
24 | - name: Setup .NET
25 | uses: actions/setup-dotnet@v2
26 | with:
27 | dotnet-version: |
28 | 8.0.x
29 | 9.0.x
30 |
31 | - name: Setup Mono
32 | run: sudo apt-get install -y mono-devel
33 |
34 | - name: Set up Node.js
35 | uses: actions/setup-node@v3
36 | with:
37 | node-version: '20'
38 |
39 | - name: Install dependencies for tests
40 | run: npm install @modelcontextprotocol/server-everything
41 |
42 | - name: Install dependencies for tests
43 | run: npm install @modelcontextprotocol/server-memory
44 |
45 | - name: Run Cake script
46 | uses: cake-build/cake-action@v1
47 | with:
48 | verbosity: Diagnostic
49 | env:
50 | NUGET_API_KEY: ${{ secrets.NUGET_API_KEY}}
51 | SONAR_LOGIN: ${{ secrets.SONAR_LOGIN }}
52 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Cake tools
2 | /[Tt]ools/
3 |
4 | # Build output
5 | [Bb]uildArtifacts/
6 | # Build results
7 | [Dd]ebug/
8 | [Rr]elease/
9 | x64/
10 | x86/
11 | [Aa][Rr][Mm]/
12 | [Aa][Rr][Mm]64/
13 | bld/
14 | [Bb]in/
15 | [Oo]bj/
16 | [Ll]og/
17 | [Ll]ogs/
18 |
19 | # Visual Studio files
20 | .vs/
21 | *.user
22 | *.userosscache
23 | *.sln.docstates
24 | *.userprefs
25 |
26 | # ReSharper
27 | _ReSharper*/
28 | *.[Rr]e[Ss]harper
29 | *.DotSettings.user
30 |
31 | # NuGet
32 | *.nupkg
33 | *.snupkg
34 | **/packages/*
35 | !**/packages/build/
36 |
37 | # MSTest test Results
38 | [Tt]est[Rr]esult*/
39 | [Bb]uild[Ll]og.*
40 |
41 | # .NET Core
42 | project.lock.json
43 | project.fragment.lock.json
44 | artifacts/
45 |
46 | # VS Code files
47 | .vscode/*
48 | !.vscode/settings.json
49 | !.vscode/tasks.json
50 | !.vscode/launch.json
51 | !.vscode/extensions.json
52 | *.code-workspace
53 |
54 | # Local History for Visual Studio Code
55 | .history/
56 |
57 | # Windows image file caches
58 | Thumbs.db
59 | ehthumbs.db
60 |
61 | # Folder config file
62 | Desktop.ini
63 |
64 | # Recycle Bin used on file shares
65 | $RECYCLE.BIN/
66 |
67 | # DotCover is a Code Coverage Tool
68 | *.dotCover
69 |
70 | # NCrunch
71 | _NCrunch_*
72 | .*crunch*.local.xml
73 | nCrunchTemp_*
74 | /mcpdotnet.v3.ncrunchsolution
75 | /.NCrunch_mcpdotnet
76 | *.ncrunchproject
77 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to mcpdotnet
2 |
3 | Thank you for your interest in contributing to mcpdotnet! This project is in its early stages, and we welcome contributions from the community.
4 |
5 | ## Getting Started
6 |
7 | 1. Fork the repository
8 | 2. Clone your fork: `git clone https://github.com/yourusername/mcpdotnet.git`
9 | 3. Create a branch: `git checkout -b your-feature-name`
10 |
11 | ## Prerequisites
12 |
13 | - .NET 8.0 SDK or later
14 | - Your favorite IDE (Visual Studio 2022, VS Code, Rider, etc.)
15 |
16 | ## Development Process
17 |
18 | 1. Write your code
19 | 2. Add tests for your changes
20 | 3. Ensure all tests pass
21 | 4. Update documentation if needed
22 | 5. Submit a pull request
23 |
24 | ## Coding Guidelines
25 |
26 | - Follow standard C# coding conventions
27 | - Use meaningful variable and method names
28 | - Write XML documentation comments for public APIs
29 | - Keep methods focused and concise
30 |
31 | ## Pull Request Process
32 |
33 | 1. Update the README.md with details of changes if needed
34 | 2. Follow the PR template
35 | 3. Wait for review from maintainers
36 |
37 | ## Code of Conduct
38 |
39 | Please note that this project adheres to a Code of Conduct. By participating, you agree to uphold this code.
40 |
41 | ## Questions?
42 |
43 | Feel free to open an issue for any questions or concerns.
--------------------------------------------------------------------------------
/GitVersion.yml:
--------------------------------------------------------------------------------
1 | mode: ContinuousDeployment
2 | commit-message-incrementing: Disabled
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Peder Holdgaard Pedersen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | # Security Policy
2 |
3 | The mcpdotnet team takes security vulnerabilities seriously. We appreciate your efforts to responsibly disclose your findings, and will make every effort to acknowledge your contributions.
4 |
5 | To report a security issue, please use the GitHub Security Advisory ["Report a Vulnerability"](https://github.com/PederHP/mcpdotnet/security/advisories/new) tab.
6 |
7 | **Please do not report security vulnerabilities through public issues, discussions, or change requests.**
8 |
9 | ## Supported Versions
10 |
11 | Please note that mcpdotnet is currently in Early Development and versions are pre-release. We strongly advise against including mcpdotnet in production systems at this time.
12 |
13 | We will list supported versions here once the project is further along in development.
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | # TODOs for mcpdotnet
2 |
3 | ## Integration Testing
4 | - Add comprehensive Roots feature testing once reference servers implement support
5 | - Consider using everything server adding `listRoots` tool)
6 | - Add integration tests similar to Sampling tests
7 | - Verify roots notification handling
8 | - Expand SSE test server to support all features or use a reference SSE server if one becomes available
9 |
10 | ## Future Improvements
11 | - [X] Add HTTPS/SSE transport support
12 | - [ ] Add more example applications showing different capabilities
13 | - [ ] Add comprehensive documentation for advanced scenarios
14 | - [ ] Profile and optimize performance
15 | - [ ] Linux support in stdio transport
16 |
17 | ## Code Improvements
18 | - [ ] Consolidate notification handling in McpClient to reduce duplication between SendNotificationAsync overloads
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | $ErrorActionPreference = 'Stop'
2 |
3 | Set-Location -LiteralPath $PSScriptRoot
4 |
5 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE = '1'
6 | $env:DOTNET_CLI_TELEMETRY_OPTOUT = '1'
7 | $env:DOTNET_NOLOGO = '1'
8 |
9 | dotnet tool restore
10 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
11 |
12 | dotnet cake @args
13 | if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
14 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | set -euox pipefail
3 |
4 | cd "$(dirname "${BASH_SOURCE[0]}")"
5 |
6 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
7 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
8 | export DOTNET_NOLOGO=1
9 |
10 | dotnet tool restore
11 |
12 | dotnet cake "$@"
13 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/AspNetCoreSseServer.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net9.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/McpEndpointRouteBuilderExtensions.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet.Protocol.Messages;
2 | using McpDotNet.Server;
3 | using McpDotNet.Utils.Json;
4 | using Microsoft.Extensions.Options;
5 |
6 | namespace AspNetCoreSseServer;
7 |
8 | public static class McpEndpointRouteBuilderExtensions
9 | {
10 | public static IEndpointConventionBuilder MapMcpSse(this IEndpointRouteBuilder endpoints)
11 | {
12 | IMcpServer? server = null;
13 | SseServerStreamTransport? transport = null;
14 | var loggerFactory = endpoints.ServiceProvider.GetRequiredService();
15 | var mcpServerOptions = endpoints.ServiceProvider.GetRequiredService>();
16 |
17 | var routeGroup = endpoints.MapGroup("");
18 |
19 | routeGroup.MapGet("/sse", async (HttpResponse response, CancellationToken requestAborted) =>
20 | {
21 | await using var localTransport = transport = new SseServerStreamTransport(response.Body);
22 | await using var localServer = server = McpServerFactory.Create(transport, mcpServerOptions.Value, loggerFactory, endpoints.ServiceProvider);
23 |
24 | await localServer.StartAsync(requestAborted);
25 |
26 | response.Headers.ContentType = "text/event-stream";
27 | response.Headers.CacheControl = "no-cache";
28 |
29 | try
30 | {
31 | await transport.RunAsync(requestAborted);
32 | }
33 | catch (OperationCanceledException) when (requestAborted.IsCancellationRequested)
34 | {
35 | // RequestAborted always triggers when the client disconnects before a complete response body is written,
36 | // but this is how SSE connections are typically closed.
37 | }
38 | });
39 |
40 | routeGroup.MapPost("/message", async (HttpContext context) =>
41 | {
42 | if (transport is null)
43 | {
44 | await Results.BadRequest("Connect to the /sse endpoint before sending messages.").ExecuteAsync(context);
45 | return;
46 | }
47 |
48 | var message = await context.Request.ReadFromJsonAsync(JsonSerializerOptionsExtensions.DefaultOptions, context.RequestAborted);
49 | if (message is null)
50 | {
51 | await Results.BadRequest("No message in request body.").ExecuteAsync(context);
52 | return;
53 | }
54 |
55 | await transport.OnMessageReceivedAsync(message, context.RequestAborted);
56 | context.Response.StatusCode = StatusCodes.Status202Accepted;
57 | await context.Response.WriteAsync("Accepted");
58 | });
59 |
60 | return routeGroup;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/Program.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet;
2 | using AspNetCoreSseServer;
3 |
4 | var builder = WebApplication.CreateBuilder(args);
5 | builder.Services.AddMcpServer().WithTools();
6 | var app = builder.Build();
7 |
8 | app.MapGet("/", () => "Hello World!");
9 | app.MapMcpSse();
10 |
11 | app.Run();
12 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/launchsettings.json",
3 | "profiles": {
4 | "http": {
5 | "commandName": "Project",
6 | "dotnetRunMessages": true,
7 | "launchBrowser": true,
8 | "applicationUrl": "http://localhost:3001",
9 | "environmentVariables": {
10 | "ASPNETCORE_ENVIRONMENT": "Development"
11 | }
12 | },
13 | "https": {
14 | "commandName": "Project",
15 | "dotnetRunMessages": true,
16 | "launchBrowser": true,
17 | "applicationUrl": "https://localhost:7133;http://localhost:3001",
18 | "environmentVariables": {
19 | "ASPNETCORE_ENVIRONMENT": "Development"
20 | }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/SseServerStreamTransport.cs:
--------------------------------------------------------------------------------
1 | using System.Buffers;
2 | using System.Net.ServerSentEvents;
3 | using System.Text.Json;
4 | using System.Threading.Channels;
5 | using McpDotNet.Protocol.Messages;
6 | using McpDotNet.Protocol.Transport;
7 | using McpDotNet.Utils.Json;
8 |
9 | namespace AspNetCoreSseServer;
10 |
11 | public class SseServerStreamTransport(Stream sseResponseStream) : ITransport
12 | {
13 | private readonly Channel _incomingChannel = CreateSingleItemChannel();
14 | private readonly Channel> _outgoingSseChannel = CreateSingleItemChannel>();
15 |
16 | private Task? _sseWriteTask;
17 | private Utf8JsonWriter? _jsonWriter;
18 |
19 | public bool IsConnected => _sseWriteTask?.IsCompleted == false;
20 |
21 | public Task RunAsync(CancellationToken cancellationToken)
22 | {
23 | void WriteJsonRpcMessageToBuffer(SseItem item, IBufferWriter writer)
24 | {
25 | if (item.EventType == "endpoint")
26 | {
27 | writer.Write("/message"u8);
28 | return;
29 | }
30 |
31 | JsonSerializer.Serialize(GetUtf8JsonWriter(writer), item.Data, JsonSerializerOptionsExtensions.DefaultOptions);
32 | }
33 |
34 | // The very first SSE event isn't really an IJsonRpcMessage, but there's no API to write a single item of a different type,
35 | // so we fib and special-case the "endpoint" event type in the formatter.
36 | _outgoingSseChannel.Writer.TryWrite(new SseItem(null, "endpoint"));
37 |
38 | var sseItems = _outgoingSseChannel.Reader.ReadAllAsync(cancellationToken);
39 | return _sseWriteTask = SseFormatter.WriteAsync(sseItems, sseResponseStream, WriteJsonRpcMessageToBuffer, cancellationToken);
40 | }
41 |
42 | public ChannelReader MessageReader => _incomingChannel.Reader;
43 |
44 | public ValueTask DisposeAsync()
45 | {
46 | _incomingChannel.Writer.TryComplete();
47 | _outgoingSseChannel.Writer.TryComplete();
48 | return new ValueTask(_sseWriteTask ?? Task.CompletedTask);
49 | }
50 |
51 | public Task SendMessageAsync(IJsonRpcMessage message, CancellationToken cancellationToken = default) =>
52 | _outgoingSseChannel.Writer.WriteAsync(new SseItem(message), cancellationToken).AsTask();
53 |
54 | public Task OnMessageReceivedAsync(IJsonRpcMessage message, CancellationToken cancellationToken)
55 | {
56 | if (!IsConnected)
57 | {
58 | throw new McpTransportException("Transport is not connected");
59 | }
60 |
61 | return _incomingChannel.Writer.WriteAsync(message, cancellationToken).AsTask();
62 | }
63 |
64 | private static Channel CreateSingleItemChannel() =>
65 | Channel.CreateBounded(new BoundedChannelOptions(1)
66 | {
67 | SingleReader = true,
68 | SingleWriter = false,
69 | });
70 |
71 | private Utf8JsonWriter GetUtf8JsonWriter(IBufferWriter writer)
72 | {
73 | if (_jsonWriter is null)
74 | {
75 | _jsonWriter = new Utf8JsonWriter(writer);
76 | }
77 | else
78 | {
79 | _jsonWriter.Reset(writer);
80 | }
81 |
82 | return _jsonWriter;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/Tools/EchoTool.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet.Server;
2 | using System.ComponentModel;
3 |
4 | namespace TestServerWithHosting.Tools;
5 |
6 | [McpToolType]
7 | public static class EchoTool
8 | {
9 | [McpTool, Description("Echoes the input back to the client.")]
10 | public static string Echo(string message)
11 | {
12 | return "hello " + message;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/Tools/SampleLlmTool.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet.Protocol.Types;
2 | using McpDotNet.Server;
3 | using System.ComponentModel;
4 |
5 | namespace TestServerWithHosting.Tools;
6 |
7 | ///
8 | /// This tool uses depenency injection and async method
9 | ///
10 | [McpToolType]
11 | public class SampleLlmTool
12 | {
13 | private readonly IMcpServer _server;
14 |
15 | public SampleLlmTool(IMcpServer server)
16 | {
17 | _server = server ?? throw new ArgumentNullException(nameof(server));
18 | }
19 |
20 | [McpTool("sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")]
21 | public async Task SampleLLM(
22 | [Description("The prompt to send to the LLM")] string prompt,
23 | [Description("Maximum number of tokens to generate")] int maxTokens,
24 | CancellationToken cancellationToken)
25 | {
26 | var samplingParams = CreateRequestSamplingParams(prompt ?? string.Empty, "sampleLLM", maxTokens);
27 | var sampleResult = await _server.RequestSamplingAsync(samplingParams, cancellationToken);
28 |
29 | return $"LLM sampling result: {sampleResult.Content.Text}";
30 | }
31 |
32 | private static CreateMessageRequestParams CreateRequestSamplingParams(string context, string uri, int maxTokens = 100)
33 | {
34 | return new CreateMessageRequestParams()
35 | {
36 | Messages = [new SamplingMessage()
37 | {
38 | Role = Role.User,
39 | Content = new Content()
40 | {
41 | Type = "text",
42 | Text = $"Resource {uri} context: {context}"
43 | }
44 | }],
45 | SystemPrompt = "You are a helpful test server.",
46 | MaxTokens = maxTokens,
47 | Temperature = 0.7f,
48 | IncludeContext = ContextInclusion.ThisServer
49 | };
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/samples/AspNetCoreSseServer/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft.AspNetCore": "Warning"
6 | }
7 | },
8 | "AllowedHosts": "*"
9 | }
10 |
--------------------------------------------------------------------------------
/samples/README.md:
--------------------------------------------------------------------------------
1 | # Samples
2 |
3 | This directory contains example projects demonstrating how to use mcpdotnet with different LLM SDKs and platforms.
4 |
5 | ## Environment Setup
6 |
7 | Before running the samples, you'll need to set up the following environment variables:
8 |
9 | - `ANTHROPIC_API_KEY` - Required for the Anthropic sample
10 | - `OPENAI_API_KEY` - Required for the MEAI/OpenAI sample
11 |
12 | ## Sample Projects
13 |
14 | ### Anthropic Integration
15 |
16 | Located in `samples/anthropic`, this sample demonstrates integration with Anthropic's Claude API using mcpdotnet. The example shows how to:
17 | - Configure an MCP client for use with Anthropic
18 | - Map between MCP protocol types and Anthropic SDK types
19 | - Handle tool invocations and responses
20 |
21 | ### Microsoft.Extensions.AI Integration
22 |
23 | Located in `samples/microsoft.extensions.ai`, this sample shows how to use mcpdotnet with Microsoft's AI SDK. It demonstrates:
24 | - Setting up an MCP client with MEAI
25 | - Mapping MCP tools to MEAI function calls
26 | - Handling streaming responses and tool invocations
27 |
28 | ## Implementation Notes
29 |
30 | Each sample focuses on the mapping between MCP types and SDK-specific types, which is the primary integration point when working with different LLM SDKs. The samples provide reusable mapping code that can serve as a starting point for your own implementations.
31 |
32 | The complexity of this mapping varies depending on how closely the SDK's design aligns with typical LLM APIs. The provided samples demonstrate best practices for both straightforward and more complex mapping scenarios.
33 |
34 | ## Running the Samples
35 |
36 | 1. Clone the repository
37 | 2. Set up the required environment variables
38 | 3. Navigate to the desired sample directory
39 | 4. Run `dotnet run` to execute the sample
40 |
41 | For more detailed examples of mcpdotnet usage, you can also refer to the integration tests in the `tests/McpDotNet.IntegrationTests` project.
--------------------------------------------------------------------------------
/samples/TestServerWithHosting/Program.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet;
2 | using Microsoft.Extensions.Hosting;
3 | using Serilog;
4 |
5 | Log.Logger = new LoggerConfiguration()
6 | .MinimumLevel.Verbose() // Capture all log levels
7 | .WriteTo.File(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs", "TestServer_.log"),
8 | rollingInterval: RollingInterval.Day,
9 | outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}")
10 | .WriteTo.Debug()
11 | .WriteTo.Console(standardErrorFromLevel: Serilog.Events.LogEventLevel.Verbose)
12 | .CreateLogger();
13 |
14 | try
15 | {
16 | Log.Information("Starting server...");
17 |
18 | var builder = Host.CreateApplicationBuilder(args);
19 | builder.Services.AddSerilog();
20 | builder.Services.AddMcpServer()
21 | .WithStdioServerTransport()
22 | .WithTools();
23 |
24 | var app = builder.Build();
25 |
26 | await app.RunAsync();
27 | return 0;
28 | }
29 | catch (Exception ex)
30 | {
31 | Log.Fatal(ex, "Host terminated unexpectedly");
32 | return 1;
33 | }
34 | finally
35 | {
36 | await Log.CloseAndFlushAsync();
37 | }
--------------------------------------------------------------------------------
/samples/TestServerWithHosting/TestServerWithHosting.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net9.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/samples/TestServerWithHosting/Tools/EchoTool.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet.Server;
2 | using System.ComponentModel;
3 |
4 | namespace TestServerWithHosting.Tools;
5 |
6 | [McpToolType]
7 | public static class EchoTool
8 | {
9 | [McpTool, Description("Echoes the input back to the client.")]
10 | public static string Echo(string message)
11 | {
12 | return "hello " + message;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/samples/TestServerWithHosting/Tools/SampleLlmTool.cs:
--------------------------------------------------------------------------------
1 | using McpDotNet.Protocol.Types;
2 | using McpDotNet.Server;
3 | using System.ComponentModel;
4 |
5 | namespace TestServerWithHosting.Tools;
6 |
7 | ///
8 | /// This tool uses depenency injection and async method
9 | ///
10 | [McpToolType]
11 | public class SampleLlmTool
12 | {
13 | private readonly IMcpServer _server;
14 |
15 | public SampleLlmTool(IMcpServer server)
16 | {
17 | _server = server ?? throw new ArgumentNullException(nameof(server));
18 | }
19 |
20 | [McpTool("sampleLLM"), Description("Samples from an LLM using MCP's sampling feature")]
21 | public async Task SampleLLM(
22 | [Description("The prompt to send to the LLM")] string prompt,
23 | [Description("Maximum number of tokens to generate")] int maxTokens,
24 | CancellationToken cancellationToken)
25 | {
26 | var samplingParams = CreateRequestSamplingParams(prompt ?? string.Empty, "sampleLLM", maxTokens);
27 | var sampleResult = await _server.RequestSamplingAsync(samplingParams, cancellationToken);
28 |
29 | return $"LLM sampling result: {sampleResult.Content.Text}";
30 | }
31 |
32 | private static CreateMessageRequestParams CreateRequestSamplingParams(string context, string uri, int maxTokens = 100)
33 | {
34 | return new CreateMessageRequestParams()
35 | {
36 | Messages = [new SamplingMessage()
37 | {
38 | Role = Role.User,
39 | Content = new Content()
40 | {
41 | Type = "text",
42 | Text = $"Resource {uri} context: {context}"
43 | }
44 | }],
45 | SystemPrompt = "You are a helpful test server.",
46 | MaxTokens = maxTokens,
47 | Temperature = 0.7f,
48 | IncludeContext = ContextInclusion.ThisServer
49 | };
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/samples/anthropic/tools/ToolsConsole/AnthropicToolsConsole.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net8.0
6 | enable
7 | enable
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/samples/anthropic/tools/ToolsConsole/McpToolExtensions.cs:
--------------------------------------------------------------------------------
1 | using Anthropic.SDK.Common;
2 | using System.Text.Json;
3 | using System.Text.Json.Nodes;
4 |
5 | namespace McpDotNet;
6 |
7 | public static class McpToolExtensions
8 | {
9 | public static IList ToAnthropicTools(this IEnumerable tools)
10 | {
11 | if (tools is null)
12 | {
13 | throw new ArgumentNullException(nameof(tools));
14 | }
15 |
16 | List result = [];
17 | foreach (var tool in tools)
18 | {
19 | var function = tool.InputSchema == null
20 | ? new Function(tool.Name, tool.Description)
21 | : new Function(tool.Name, tool.Description, JsonSerializer.Serialize(tool.InputSchema));
22 | result.Add(function);
23 | }
24 | return result;
25 | }
26 |
27 | public static Dictionary? ToMCPArguments(this JsonNode jsonNode)
28 | {
29 | if (jsonNode == null)
30 | return null;
31 |
32 | // Convert JsonNode to Dictionary
33 | return jsonNode.AsObject()
34 | .ToDictionary(
35 | prop => prop.Key,
36 | prop => JsonSerializer.Deserialize