From c45939225042e59183c605e50d380095ca76dc98 Mon Sep 17 00:00:00 2001 From: john-mckillip Date: Tue, 10 Mar 2026 19:40:02 -0500 Subject: [PATCH] Add Docker deployment concept doc and docs cross-links Document how to run ASP.NET Core MCP servers in Docker using Streamable HTTP, including a baseline server example, multi-stage Dockerfile, build/run commands, environment variable configuration, and deployment notes for health checks and reverse proxies. Improve discoverability by adding Docker deployment to conceptual navigation and linking it from transports and getting started docs. Fixes #147 --- docs/concepts/deployment/docker.md | 115 +++++++++++++++++++++++++ docs/concepts/getting-started.md | 14 +-- docs/concepts/index.md | 48 ++++++----- docs/concepts/toc.yml | 88 ++++++++++--------- docs/concepts/transports/transports.md | 53 ++++++------ 5 files changed, 224 insertions(+), 94 deletions(-) create mode 100644 docs/concepts/deployment/docker.md diff --git a/docs/concepts/deployment/docker.md b/docs/concepts/deployment/docker.md new file mode 100644 index 000000000..a3f49cd47 --- /dev/null +++ b/docs/concepts/deployment/docker.md @@ -0,0 +1,115 @@ +--- +title: Docker Deployment +author: jeffhandley +description: How to run ASP.NET Core MCP servers in Docker containers using Streamable HTTP transport. +uid: docker-deployment +--- + +## Docker deployment for MCP servers + +Docker is a practical way to package and run MCP servers consistently across development, CI, and production environments. For HTTP-based MCP servers, use ASP.NET Core hosting with Streamable HTTP. + +This guide assumes you already have an ASP.NET Core MCP server configured with `ModelContextProtocol.AspNetCore`, `WithHttpTransport()`, and `MapMcp()`. + + + +> [!TIP] +> For local, process-based integrations where the client launches the server directly, stdio is often simpler. For remote and containerized deployments, Streamable HTTP is the recommended transport. + +### Baseline server + +A minimal HTTP-based MCP server looks like this: + +```csharp +using ModelContextProtocol.Server; + +var builder = WebApplication.CreateBuilder(args); + +builder.Services.AddMcpServer() + .WithHttpTransport() + .WithToolsFromAssembly(); + +var app = builder.Build(); + +app.MapMcp("/mcp"); +app.Run(); +``` + +### Dockerfile + +Use a multi-stage Docker build so SDK tooling stays in the build stage and only runtime dependencies are shipped in the final image. + +```dockerfile +# Build stage +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /src + +COPY . . +RUN dotnet restore +RUN dotnet publish -c Release -o /app/publish + +# Runtime stage +FROM mcr.microsoft.com/dotnet/aspnet:10.0 AS runtime +WORKDIR /app + +COPY --from=build /app/publish . + +# MCP HTTP endpoint listens on 8080 inside container +ENV ASPNETCORE_URLS=http://+:8080 +EXPOSE 8080 + +ENTRYPOINT ["dotnet", "MyMcpServer.dll"] +``` + +Replace `MyMcpServer.dll` with your server assembly output name. + +### Build and run + +Build the image: + +```bash +docker build -t my-mcp-server:latest . +``` + +Run the container and map host port `3001` to container port `8080`: + +```bash +docker run --rm -p 3001:8080 my-mcp-server:latest +``` + +With the baseline route above (`app.MapMcp("/mcp")`), clients connect to: + +- Streamable HTTP: `http://localhost:3001/mcp` +- Legacy SSE endpoint (if needed): `http://localhost:3001/mcp/sse` + +### Configuration and secrets + +Pass configuration through environment variables rather than baking secrets into the image: + +```bash +docker run --rm -p 3001:8080 \ + -e ASPNETCORE_ENVIRONMENT=Production \ + -e MYAPP__APIKEY=example \ + my-mcp-server:latest +``` + +ASP.NET Core binds `MYAPP__APIKEY` to `MYAPP:APIKEY` in configuration. + + + +> [!IMPORTANT] +> Do not commit real tokens or credentials into Dockerfiles, compose files, or source code. Use runtime environment variables or an external secret store. + +### Health and readiness + +For container orchestrators, add an HTTP health endpoint and use it for readiness/liveness checks. Keep MCP traffic on your mapped MCP route and health probes on a separate route. + +### Reverse proxies and forwarded headers + +If your container is behind a reverse proxy (for example, ingress or load balancers), ensure forwarded headers are handled correctly so auth and origin metadata flow to the MCP server as expected. + +See also: + +- [Transports](../transports/transports.md) +- [Getting Started](../getting-started.md) +- [HTTP Context](../httpcontext/httpcontext.md) diff --git a/docs/concepts/getting-started.md b/docs/concepts/getting-started.md index 6e096d767..f7dceff6a 100644 --- a/docs/concepts/getting-started.md +++ b/docs/concepts/getting-started.md @@ -13,19 +13,21 @@ This guide walks you through installing the MCP C# SDK and building a minimal MC The SDK ships as three NuGet packages. Pick the one that matches your scenario: -| Package | Use when... | -| - | - | -| **[ModelContextProtocol.Core](https://www.nuget.org/packages/ModelContextProtocol.Core/absoluteLatest)** | You only need the client or low-level server APIs and want the **minimum set of dependencies**. | -| **[ModelContextProtocol](https://www.nuget.org/packages/ModelContextProtocol/absoluteLatest)** | You're building a client or a **stdio-based** server and want hosting, dependency injection, and attribute-based tool/prompt/resource discovery. References `ModelContextProtocol.Core`. **This is the right starting point for most projects.** | -| **[ModelContextProtocol.AspNetCore](https://www.nuget.org/packages/ModelContextProtocol.AspNetCore/absoluteLatest)** | You're building an **HTTP-based** MCP server hosted in ASP.NET Core. References `ModelContextProtocol`, so you get everything above plus the HTTP transport. | +| Package | Use when... | +| -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| **[ModelContextProtocol.Core](https://www.nuget.org/packages/ModelContextProtocol.Core/absoluteLatest)** | You only need the client or low-level server APIs and want the **minimum set of dependencies**. | +| **[ModelContextProtocol](https://www.nuget.org/packages/ModelContextProtocol/absoluteLatest)** | You're building a client or a **stdio-based** server and want hosting, dependency injection, and attribute-based tool/prompt/resource discovery. References `ModelContextProtocol.Core`. **This is the right starting point for most projects.** | +| **[ModelContextProtocol.AspNetCore](https://www.nuget.org/packages/ModelContextProtocol.AspNetCore/absoluteLatest)** | You're building an **HTTP-based** MCP server hosted in ASP.NET Core. References `ModelContextProtocol`, so you get everything above plus the HTTP transport. | + > [!TIP] > If you're unsure, start with the **ModelContextProtocol** package. You can always add **ModelContextProtocol.AspNetCore** later if you need HTTP transport support. ### Building an MCP server + > [!TIP] > You can also use the [MCP Server project template](https://learn.microsoft.com/dotnet/ai/quickstarts/build-mcp-server) to quickly scaffold a new MCP server project. @@ -152,4 +154,4 @@ var response = await chatClient.GetResponseAsync( ### Next steps -Explore the rest of the conceptual documentation to learn about [tools](tools/tools.md), [prompts](prompts/prompts.md), [resources](resources/resources.md), [transports](transports/transports.md), and more. You can also browse the [samples](https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples) directory for complete end-to-end examples. +Explore the rest of the conceptual documentation to learn about [tools](tools/tools.md), [prompts](prompts/prompts.md), [resources](resources/resources.md), [transports](transports/transports.md), and [Docker deployment](deployment/docker.md) for HTTP-based servers. You can also browse the [samples](https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples) directory for complete end-to-end examples. diff --git a/docs/concepts/index.md b/docs/concepts/index.md index 85d94492f..9607746f4 100644 --- a/docs/concepts/index.md +++ b/docs/concepts/index.md @@ -8,33 +8,39 @@ Welcome to the conceptual documentation for the Model Context Protocol SDK. Here Install the SDK and build your first MCP client and server. +### Deployment + +| Title | Description | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------- | +| [Docker deployment](deployment/docker.md) | Learn how to package and run ASP.NET Core MCP servers in Docker containers using Streamable HTTP transport. | + ### Base Protocol -| Title | Description | -| - | - | +| Title | Description | +| -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- | | [Capabilities](capabilities/capabilities.md) | Learn how client and server capabilities are negotiated during initialization, including protocol version negotiation. | -| [Transports](transports/transports.md) | Learn how to configure stdio, Streamable HTTP, and SSE transports for client-server communication. | -| [Ping](ping/ping.md) | Learn how to verify connection health using the ping mechanism. | -| [Progress tracking](progress/progress.md) | Learn how to track progress for long-running operations through notification messages. | -| [Cancellation](cancellation/cancellation.md) | Learn how to cancel in-flight MCP requests using cancellation tokens and notifications. | -| [Pagination](pagination/pagination.md) | Learn how to use cursor-based pagination when listing tools, prompts, and resources. | +| [Transports](transports/transports.md) | Learn how to configure stdio, Streamable HTTP, and SSE transports for client-server communication. | +| [Ping](ping/ping.md) | Learn how to verify connection health using the ping mechanism. | +| [Progress tracking](progress/progress.md) | Learn how to track progress for long-running operations through notification messages. | +| [Cancellation](cancellation/cancellation.md) | Learn how to cancel in-flight MCP requests using cancellation tokens and notifications. | +| [Pagination](pagination/pagination.md) | Learn how to use cursor-based pagination when listing tools, prompts, and resources. | ### Client Features -| Title | Description | -| - | - | -| [Sampling](sampling/sampling.md) | Learn how servers request LLM completions from the client using the sampling feature. | -| [Roots](roots/roots.md) | Learn how clients provide filesystem roots to servers for context-aware operations. | -| [Elicitation](elicitation/elicitation.md) | Learn how to request additional information from users during interactions. | +| Title | Description | +| ----------------------------------------- | ------------------------------------------------------------------------------------- | +| [Sampling](sampling/sampling.md) | Learn how servers request LLM completions from the client using the sampling feature. | +| [Roots](roots/roots.md) | Learn how clients provide filesystem roots to servers for context-aware operations. | +| [Elicitation](elicitation/elicitation.md) | Learn how to request additional information from users during interactions. | ### Server Features -| Title | Description | -| - | - | -| [Tools](tools/tools.md) | Learn how to implement and consume tools that return text, images, audio, and embedded resources. | -| [Resources](resources/resources.md) | Learn how to expose and consume data through MCP resources, including templates and subscriptions. | -| [Prompts](prompts/prompts.md) | Learn how to implement and consume reusable prompt templates with rich content types. | -| [Completions](completions/completions.md) | Learn how to implement argument auto-completion for prompts and resource templates. | -| [Logging](logging/logging.md) | Learn how to implement logging in MCP servers and how clients can consume log messages. | -| [HTTP Context](httpcontext/httpcontext.md) | Learn how to access the underlying `HttpContext` for a request. | -| [MCP Server Handler Filters](filters.md) | Learn how to add filters to the handler pipeline. Filters let you wrap the original handler with additional functionality. | +| Title | Description | +| ------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------- | +| [Tools](tools/tools.md) | Learn how to implement and consume tools that return text, images, audio, and embedded resources. | +| [Resources](resources/resources.md) | Learn how to expose and consume data through MCP resources, including templates and subscriptions. | +| [Prompts](prompts/prompts.md) | Learn how to implement and consume reusable prompt templates with rich content types. | +| [Completions](completions/completions.md) | Learn how to implement argument auto-completion for prompts and resource templates. | +| [Logging](logging/logging.md) | Learn how to implement logging in MCP servers and how clients can consume log messages. | +| [HTTP Context](httpcontext/httpcontext.md) | Learn how to access the underlying `HttpContext` for a request. | +| [MCP Server Handler Filters](filters.md) | Learn how to add filters to the handler pipeline. Filters let you wrap the original handler with additional functionality. | diff --git a/docs/concepts/toc.yml b/docs/concepts/toc.yml index d04eeb707..2361b245c 100644 --- a/docs/concepts/toc.yml +++ b/docs/concepts/toc.yml @@ -1,43 +1,47 @@ items: -- name: Overview - href: index.md -- name: Getting Started - uid: getting-started -- name: Base Protocol - items: - - name: Capabilities - uid: capabilities - - name: Transports - uid: transports - - name: Ping - uid: ping - - name: Progress - uid: progress - - name: Cancellation - uid: cancellation - - name: Pagination - uid: pagination - - name: Tasks - uid: tasks -- name: Client Features - items: - - name: Roots - uid: roots - - name: Elicitation - uid: elicitation -- name: Server Features - items: - - name: Tools - uid: tools - - name: Resources - uid: resources - - name: Prompts - uid: prompts - - name: Completions - uid: completions - - name: Logging - uid: logging - - name: HTTP Context - uid: httpcontext - - name: Filters - uid: filters \ No newline at end of file + - name: Overview + href: index.md + - name: Getting Started + uid: getting-started + - name: Deployment + items: + - name: Docker + uid: docker-deployment + - name: Base Protocol + items: + - name: Capabilities + uid: capabilities + - name: Transports + uid: transports + - name: Ping + uid: ping + - name: Progress + uid: progress + - name: Cancellation + uid: cancellation + - name: Pagination + uid: pagination + - name: Tasks + uid: tasks + - name: Client Features + items: + - name: Roots + uid: roots + - name: Elicitation + uid: elicitation + - name: Server Features + items: + - name: Tools + uid: tools + - name: Resources + uid: resources + - name: Prompts + uid: prompts + - name: Completions + uid: completions + - name: Logging + uid: logging + - name: HTTP Context + uid: httpcontext + - name: Filters + uid: filters diff --git a/docs/concepts/transports/transports.md b/docs/concepts/transports/transports.md index 55623d51a..7782c579f 100644 --- a/docs/concepts/transports/transports.md +++ b/docs/concepts/transports/transports.md @@ -19,7 +19,7 @@ The stdio transport communicates over standard input and output streams. It is b Use to launch a server process and communicate over its stdin/stdout. This example connects to the [NuGet MCP Server]: -[NuGet MCP Server]: https://learn.microsoft.com/nuget/concepts/nuget-mcp-server +[nuget mcp server]: https://learn.microsoft.com/nuget/concepts/nuget-mcp-server ```csharp var transport = new StdioClientTransport(new StdioClientTransportOptions @@ -34,15 +34,15 @@ await using var client = await McpClient.CreateAsync(transport); Key properties: -| Property | Description | -|----------|-------------| -| `Command` | The executable to launch (required) | -| `Arguments` | Command-line arguments for the process | -| `WorkingDirectory` | Working directory for the server process | +| Property | Description | +| ---------------------- | --------------------------------------------------------------------------- | +| `Command` | The executable to launch (required) | +| `Arguments` | Command-line arguments for the process | +| `WorkingDirectory` | Working directory for the server process | | `EnvironmentVariables` | Environment variables (merged with current; `null` values remove variables) | -| `ShutdownTimeout` | Graceful shutdown timeout (default: 5 seconds) | -| `StandardErrorLines` | Callback for stderr output from the server process | -| `Name` | Optional transport identifier for logging | +| `ShutdownTimeout` | Graceful shutdown timeout (default: 5 seconds) | +| `StandardErrorLines` | Callback for stderr output from the server process | +| `Name` | Optional transport identifier for logging | #### stdio server @@ -62,7 +62,7 @@ await builder.Build().RunAsync(); The [Streamable HTTP] transport uses HTTP for bidirectional communication with optional streaming. This is the recommended transport for remote servers. -[Streamable HTTP]: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http +[streamable http]: https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#streamable-http #### Streamable HTTP client @@ -95,7 +95,7 @@ var transport = new HttpClientTransport(new HttpClientTransportOptions #### Resuming sessions -Streamable HTTP supports session resumption. Save the session ID, server capabilities, and server info from the original session, then use to reconnect: +Streamable HTTP supports session resumption. Save the session ID, server capabilities, and server info from the original session, then use to reconnect: ```csharp var transport = new HttpClientTransport(new HttpClientTransportOptions @@ -113,7 +113,7 @@ await using var client = await McpClient.ResumeSessionAsync(transport, new Resum #### Streamable HTTP server (ASP.NET Core) -Use the `ModelContextProtocol.AspNetCore` package to host an MCP server over HTTP. The method maps the Streamable HTTP endpoint at the specified route (root by default). It also maps legacy SSE endpoints at `{route}/sse` and `{route}/message` for backward compatibility. +Use the `ModelContextProtocol.AspNetCore` package to host an MCP server over HTTP. The method maps the Streamable HTTP endpoint at the specified route (root by default). It also maps legacy SSE endpoints at `{route}/sse` and `{route}/message` for backward compatibility. ```csharp var builder = WebApplication.CreateBuilder(args); @@ -129,7 +129,7 @@ app.Run(); A custom route can be specified. For example, the [AspNetCoreMcpPerSessionTools] sample uses a route parameter: -[AspNetCoreMcpPerSessionTools]: https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples/AspNetCoreMcpPerSessionTools +[aspnetcoremcppersessiontools]: https://github.com/modelcontextprotocol/csharp-sdk/tree/main/samples/AspNetCoreMcpPerSessionTools ```csharp app.MapMcp("/mcp"); @@ -137,13 +137,16 @@ app.MapMcp("/mcp"); When using a custom route, Streamable HTTP clients should connect directly to that route (e.g., `https://host/mcp`), while SSE clients should connect to `{route}/sse` (e.g., `https://host/mcp/sse`). +For containerized deployments of ASP.NET Core servers, see [Docker deployment](../deployment/docker.md). + ### SSE transport (legacy) The [SSE (Server-Sent Events)] transport is a legacy mechanism that uses unidirectional server-to-client streaming with a separate HTTP endpoint for client-to-server messages. New implementations should prefer Streamable HTTP. -[SSE (Server-Sent Events)]: https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse +[sse (server-sent events)]: https://modelcontextprotocol.io/specification/2024-11-05/basic/transports#http-with-sse + > [!NOTE] > The SSE transport is considered legacy. The [Streamable HTTP](#streamable-http-transport) transport is the recommended approach for HTTP-based communication and supports bidirectional streaming. @@ -165,10 +168,10 @@ await using var client = await McpClient.CreateAsync(transport); SSE-specific configuration options: -| Property | Description | -|----------|-------------| -| `MaxReconnectionAttempts` | Maximum number of reconnection attempts on stream disconnect (default: 5) | -| `DefaultReconnectionInterval` | Wait time between reconnection attempts (default: 1 second) | +| Property | Description | +| ----------------------------- | ------------------------------------------------------------------------- | +| `MaxReconnectionAttempts` | Maximum number of reconnection attempts on stream disconnect (default: 5) | +| `DefaultReconnectionInterval` | Wait time between reconnection attempts (default: 1 second) | #### SSE server (ASP.NET Core) @@ -193,10 +196,10 @@ No additional configuration is needed. When a client connects using the SSE prot ### Transport mode comparison -| Feature | stdio | Streamable HTTP | SSE (Legacy) | -|---------|-------|----------------|--------------| -| Process model | Child process | Remote HTTP | Remote HTTP | -| Direction | Bidirectional | Bidirectional | Server→client stream + client→server POST | -| Session resumption | N/A | ✓ | ✗ | -| Authentication | Process-level | HTTP auth (OAuth, headers) | HTTP auth (OAuth, headers) | -| Best for | Local tools | Remote servers | Legacy compatibility | +| Feature | stdio | Streamable HTTP | SSE (Legacy) | +| ------------------ | ------------- | -------------------------- | ----------------------------------------- | +| Process model | Child process | Remote HTTP | Remote HTTP | +| Direction | Bidirectional | Bidirectional | Server→client stream + client→server POST | +| Session resumption | N/A | ✓ | ✗ | +| Authentication | Process-level | HTTP auth (OAuth, headers) | HTTP auth (OAuth, headers) | +| Best for | Local tools | Remote servers | Legacy compatibility |