Packaging & Distribution
A Repl app is a standard .NET console application — it packages like any other. The main distribution channels are global tools (NuGet), MCP server registry, and self-contained binaries.
.NET Global Tool
Section titled “.NET Global Tool”The most common distribution model for developer-facing tools. Users install once with dotnet tool install and your app is available globally.
-
Configure the project
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net10.0</TargetFramework><PackAsTool>true</PackAsTool><ToolCommandName>myapp</ToolCommandName><PackageId>MyCompany.MyApp</PackageId><Version>1.0.0</Version></PropertyGroup> -
Pack
Terminal window dotnet pack -c Release -
Install locally for testing
Terminal window dotnet tool install --global --add-source ./nupkg MyCompany.MyAppmyapp --version -
Publish to NuGet.org
Terminal window dotnet nuget push ./nupkg/MyCompany.MyApp.1.0.0.nupkg \--api-key $NUGET_API_KEY \--source https://api.nuget.org/v3/index.json
User install:
dotnet tool install -g MyCompany.MyAppMCP Server distribution
Section titled “MCP Server distribution”If your app exposes MCP (app.UseMcpServer()), set PackageType=McpServer so NuGet.org and MCP-aware clients like VS Code can discover and install it automatically.
Project configuration
Section titled “Project configuration”<PropertyGroup> <PackAsTool>true</PackAsTool> <ToolCommandName>myapp</ToolCommandName> <PackageType>McpServer</PackageType></PropertyGroup>Server manifest — .mcp/server.json
Section titled “Server manifest — .mcp/server.json”This file lives at .mcp/server.json in your repository. It tells registries and clients how to discover and invoke the server. The schema has evolved significantly — use the current version:
{ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json", "name": "io.github.myorg/myapp", "version": "1.0.0", "description": "Contacts management MCP server.", "title": "MyApp", "websiteUrl": "https://myorg.github.io/myapp", "repository": { "url": "https://github.com/myorg/myapp", "source": "github" }, "packages": [ { "registryType": "nuget", "registryBaseUrl": "https://api.nuget.org", "identifier": "MyOrg.MyApp", "version": "1.0.0", "runtimeHint": "dnx", "transport": { "type": "stdio" }, "packageArguments": [ { "type": "positional", "value": "mcp" }, { "type": "positional", "value": "serve" } ] } ]}Required: name (reverse-DNS format org/repo), description, version; inside packages[]: registryType, identifier, transport.
runtimeHint: "dnx" — clients invoke the tool via dnx MyOrg.MyApp@1.0.0 --yes rather than the installed global tool name. This works without a prior dotnet tool install.
packageArguments — positional args appended to the invocation. Repl activates stdio MCP mode when it receives mcp serve.
If your server requires secrets (API keys, connection strings), declare them so clients can prompt the user at install time:
"environmentVariables": [ { "name": "MYAPP_API_KEY", "description": "API key for the backing service.", "isRequired": true, "isSecret": true }]Include the manifest in the package
Section titled “Include the manifest in the package”<ItemGroup> <None Include=".mcp/server.json" Pack="true" PackagePath=".mcp/" /></ItemGroup>After publishing, NuGet.org generates a Connect snippet for VS Code under the MCP tab on your package page — clients can install the server in one click.
Self-contained binary
Section titled “Self-contained binary”For shipping to machines without .NET installed:
dotnet publish -c Release \ -r win-x64 \ --self-contained \ -p:PublishSingleFile=true \ -p:PublishTrimmed=true| Platform | Runtime ID |
|---|---|
| Windows x64 | win-x64 |
| macOS ARM | osx-arm64 |
| Linux x64 | linux-x64 |
Versioning
Section titled “Versioning”Repl Toolkit itself uses Nerdbank.GitVersioning — version numbers are derived from git history automatically. The same approach works well for your apps:
dotnet add package Nerdbank.GitVersioningversion.json:
{ "version": "1.0", "publicReleaseRefSpec": ["^refs/heads/main$", "^refs/heads/release/.*$"]}Version is then 1.0.{commit-height} on release branches, 1.0.0-dev.{height} on other branches.
CI/CD pipeline
Section titled “CI/CD pipeline”A minimal GitHub Actions release workflow:
name: Releaseon: push: branches: [main, 'release/**']
jobs: release: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 # needed for Nerdbank.GitVersioning
- uses: actions/setup-dotnet@v4 with: dotnet-version: '10.x'
- run: dotnet pack -c Release -o ./nupkg
- name: Publish to NuGet if: startsWith(github.ref, 'refs/heads/release/') run: | dotnet nuget push ./nupkg/*.nupkg \ --api-key ${{ secrets.NUGET_API_KEY }} \ --source https://api.nuget.org/v3/index.json \ --skip-duplicateWhat to include in the package
Section titled “What to include in the package”| Asset | Purpose |
|---|---|
.mcp/server.json | MCP registry discovery |
README.md | NuGet landing page |
Icon (.png) | NuGet gallery icon |
CHANGELOG.md | Release notes |
| Shell completion note in README | Guide users to run myapp completion install |
Distribution checklist
Section titled “Distribution checklist”-
PackAsTool = trueandToolCommandNameset - Version sourced from git (or explicit)
-
README.mdhas a quick-start snippet -
dotnet tool install -g <pkg>tested clean on a fresh machine -
myapp --helpworks after global install -
myapp completion installworks for your target shells - If MCP:
myapp mcp servestarts without error,.mcp/server.jsonis present - NuGet API key stored in CI secrets, not in source