Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
112 changes: 112 additions & 0 deletions docs/concepts/deployment/docker.md
Original file line number Diff line number Diff line change
@@ -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()`.

<!-- mlc-disable-next-line -->
> [!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.

<!-- mlc-disable-next-line -->
> [!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)
2 changes: 1 addition & 1 deletion docs/concepts/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
6 changes: 6 additions & 0 deletions docs/concepts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
4 changes: 4 additions & 0 deletions docs/concepts/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions docs/concepts/transports/transports.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down