Skills mcp-csharp-publish
git clone https://github.com/dotnet/skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/dotnet/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/dotnet-ai/skills/mcp-csharp-publish" ~/.claude/skills/dotnet-skills-mcp-csharp-publish && rm -rf "$T"
plugins/dotnet-ai/skills/mcp-csharp-publish/SKILL.mdC# MCP Server Publishing
Publish and deploy MCP servers to their target platforms. stdio servers are distributed as NuGet tool packages. HTTP servers are containerized and deployed to Azure or other container hosts. Both can optionally be listed in the official MCP Registry.
When to Use
- Packaging a stdio MCP server for NuGet distribution
- Creating a Docker container for an HTTP MCP server
- Deploying to Azure Container Apps or App Service
- Publishing to the official MCP Registry for discoverability
- Setting up
metadata for the MCP Registryserver.json
Stop Signals
- Server not tested yet? → Use
firstmcp-csharp-test - Server not working locally? → Use
mcp-csharp-debug - No server project yet? → Use
mcp-csharp-create - Publishing a non-MCP NuGet package? → Use
insteadnuget-trusted-publishing
Inputs
| Input | Required | Description |
|---|---|---|
| Transport type | Yes | → NuGet path, → Docker/Azure path |
| Target destination | Yes | NuGet.org, Docker registry, Azure Container Apps, Azure App Service, MCP Registry |
| Project path | Yes | Path to the file |
| Package ID / server name | Required for publishing | NuGet or MCP Registry name |
Workflow
Step 1: Choose the publishing path
| Transport | Primary Destination | Users Run With |
|---|---|---|
| stdio | NuGet.org | |
| HTTP | Docker → Azure | Container URL |
Both paths can optionally publish to the MCP Registry for discoverability.
Step 2a: NuGet publishing (stdio servers)
- Configure
with package properties:.csproj
<PropertyGroup> <PackAsTool>true</PackAsTool> <ToolCommandName>mymcpserver</ToolCommandName> <PackageId>YourUsername.MyMcpServer</PackageId> <Version>1.0.0</Version> <Authors>Your Name</Authors> <Description>MCP server for interacting with MyService</Description> <PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageTags>mcp;modelcontextprotocol;ai;llm</PackageTags> <PackageReadmeFile>README.md</PackageReadmeFile> </PropertyGroup> <ItemGroup> <None Include="README.md" Pack="true" PackagePath="\" /> </ItemGroup>
- Build and pack:
dotnet build -c Release dotnet pack -c Release
- Test locally before publishing:
dotnet tool install --global --add-source bin/Release/ YourUsername.MyMcpServer mymcpserver --help # verify it runs dotnet tool uninstall --global YourUsername.MyMcpServer
- Push to NuGet.org:
dotnet nuget push bin/Release/*.nupkg \ --api-key YOUR_NUGET_API_KEY \ --source https://api.nuget.org/v3/index.json
- Verify — users configure in
:mcp.json
{ "servers": { "MyMcpServer": { "type": "stdio", "command": "dnx", "args": ["YourUsername.MyMcpServer@1.0.0", "--yes"] } } }
For detailed NuGet packaging and trusted publishing setup, see references/nuget-packaging.md.
Step 2b: Docker containerization (HTTP servers)
- Create Dockerfile:
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY *.csproj ./ RUN dotnet restore COPY . ./ RUN dotnet publish -c Release -o /app FROM mcr.microsoft.com/dotnet/aspnet:10.0 WORKDIR /app COPY --from=build /app . # Non-root user for security RUN adduser --disabled-password --gecos '' appuser USER appuser ENV ASPNETCORE_URLS=http://+:8080 EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \ CMD curl -f http://localhost:8080/health || exit 1 ENTRYPOINT ["dotnet", "MyMcpServer.dll"]
- Build and test locally:
docker build -t mymcpserver:latest . docker run -d -p 3001:8080 -e API_KEY=test-key --name mymcpserver mymcpserver:latest curl http://localhost:3001/health
- Push to container registry:
# Docker Hub docker tag mymcpserver:latest <yourusername>/<mymcpserver>:1.0.0 docker push <yourusername>/<mymcpserver>:1.0.0 # Azure Container Registry az acr login --name yourregistry docker tag mymcpserver:latest <yourregistry>.azurecr.io/<mymcpserver>:1.0.0 docker push <yourregistry>.azurecr.io/<mymcpserver>:1.0.0
Step 3: Deploy to Azure (HTTP servers)
Azure Container Apps (recommended — serverless with auto-scaling):
az containerapp create \ --name mymcpserver \ --resource-group mygroup \ --environment myenvironment \ --image <yourregistry>.azurecr.io/<mymcpserver>:1.0.0 \ --target-port 8080 \ --ingress external \ --min-replicas 0 \ --max-replicas 10 \ --secrets api-key=my-actual-api-key \ --env-vars API_KEY=secretref:api-key
Azure App Service (traditional web hosting):
az webapp create \ --name mymcpserver \ --resource-group mygroup \ --plan myplan \ --deployment-container-image-name <yourregistry>.azurecr.io/<mymcpserver>:1.0.0
For detailed Azure deployment, see references/docker-azure.md.
Step 4: Publish to MCP Registry (optional)
List your server in the official MCP Registry for discoverability.
- Install
:mcp-publisher
# macOS/Linux brew install mcp-publisher # Or download from https://github.com/modelcontextprotocol/registry/releases
- Create
(or run.mcp/server.json
to generate interactively):mcp-publisher init
{ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.username/servername", "description": "Your server description", "version": "1.0.0", "packages": [{ "registryType": "nuget", "registryBaseUrl": "https://api.nuget.org", "identifier": "YourUsername.MyMcpServer", "version": "1.0.0", "transport": { "type": "stdio" } }], "repository": { "url": "https://github.com/username/repo", "source": "github" } }
Version consistency (critical): The root
,version, andpackages[].versionin<Version>must all match. A mismatch causes registry validation failures or users downloading the wrong version..csproj
- Authenticate and publish:
mcp-publisher login github # name must be io.github.<username>/... for GitHub auth mcp-publisher publish
- Verify:
curl "https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.<username>/<servername>"
For Registry details (namespace conventions, environment variables, CI/CD automation), see references/mcp-registry.md.
Step 5: Security checklist
- No hardcoded secrets — use environment variables or Key Vault
- HTTPS enabled for HTTP transport in production
- Health check endpoint implemented
- Input validation on all tool parameters
- Rate limiting considered for HTTP servers
Validation
- NuGet: Package installs and runs via
dnx PackageId@version - Docker: Container starts and health check passes
- Azure: Server is reachable and tools respond
- MCP Registry: Server appears at
registry.modelcontextprotocol.io - MCP client can connect and call tools on the deployed server
Common Pitfalls
| Pitfall | Solution |
|---|---|
| NuGet package doesn't run as a tool | Missing in |
Version mismatch between and | Keep , root , and in sync |
| Docker container exits immediately | Check entrypoint DLL name matches project output. Run for errors |
| Azure Container App returns 502 | Target port mismatch. Ensure matches port in the container |
| MCP Registry rejects publish | Name must follow namespace convention: for GitHub auth |
| API keys leaked in Docker image | Use multi-stage builds. Never files. Pass secrets via at runtime |
Related Skills
— Create a new MCP server projectmcp-csharp-create
— Running and interactive debuggingmcp-csharp-debug
— Automated tests and evaluationsmcp-csharp-test
Reference Files
- references/nuget-packaging.md — Complete NuGet
configuration,.csproj
for MCP, NuGet.org push, testing withserver.json
, version management. Load when: publishing a stdio server to NuGet.dnx - references/docker-azure.md — Production Dockerfile patterns, ACR setup, Azure Container Apps full configuration, App Service with Key Vault, secrets management. Load when: deploying an HTTP server to Docker or Azure.
- references/mcp-registry.md —
CLI installation,mcp-publisher
schema, namespace conventions (GitHub vs DNS auth), CI/CD automation. Load when: publishing to the official MCP Registry.server.json
More Info
- NuGet publishing — NuGet.org publishing guide
- Azure Container Apps — Serverless container hosting
- MCP Registry — Official MCP server registry