diff --git a/docs/concepts/deployment/docker.md b/docs/concepts/deployment/docker.md new file mode 100644 index 000000000..8a6fa2719 --- /dev/null +++ b/docs/concepts/deployment/docker.md @@ -0,0 +1,112 @@ +--- +title: Docker Deployment +author: john-mckillip +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 the Streamable HTTP endpoint at `http://localhost:3001/mcp`. + +Streamable HTTP is the recommended transport for containerized MCP servers. The legacy SSE endpoints (`/mcp/sse` and `/mcp/message`) are not mapped by default, and the option to enable them is obsolete. See [Transports](../transports/transports.md) for details. + +### 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 c6096aa60..a770f062e 100644 --- a/docs/concepts/getting-started.md +++ b/docs/concepts/getting-started.md @@ -172,4 +172,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 3e763be4f..c5c452f4b 100644 --- a/docs/concepts/index.md +++ b/docs/concepts/index.md @@ -8,6 +8,12 @@ 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 | diff --git a/docs/concepts/toc.yml b/docs/concepts/toc.yml index 1b4999531..574bface6 100644 --- a/docs/concepts/toc.yml +++ b/docs/concepts/toc.yml @@ -3,6 +3,10 @@ items: href: index.md - name: Getting Started uid: getting-started +- name: Deployment + items: + - name: Docker + uid: docker-deployment - name: Base Protocol items: - name: Capabilities diff --git a/docs/concepts/transports/transports.md b/docs/concepts/transports/transports.md index 8fb2af0c7..e76693a48 100644 --- a/docs/concepts/transports/transports.md +++ b/docs/concepts/transports/transports.md @@ -261,6 +261,8 @@ 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 (when [legacy SSE is enabled](xref:stateless#legacy-sse-transport)) 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.