Skip to content

Commit 19c28ad

Browse files
committed
Add first draft of publishing a local NuGet MCP Server to the MCP Registry
1 parent 184fa3e commit 19c28ad

File tree

2 files changed

+314
-0
lines changed

2 files changed

+314
-0
lines changed
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
---
2+
title: Quickstart - Publish a .NET MCP Server to the MCP Registry
3+
description: Learn to create a minimal MCP client and connect it to an MCP server using .NET
4+
ms.date: 11/17/2025
5+
ms.topic: quickstart
6+
author: joelverhagen
7+
zone_pivot_groups: operating-systems-set-one
8+
---
9+
10+
# Publish an MCP Server on NuGet.org to the Official MCP Registry
11+
12+
In this quickstart, you will publish your NuGet-based local MCP Server to the [Official MCP Registry](https://github.com/modelcontextprotocol/registry/blob/main/docs/explanations/ecosystem-vision.md).
13+
14+
## Prerequisites
15+
16+
- A [GitHub account](https://github.com/join)
17+
- [Visual Studio Code](https://code.visualstudio.com/)
18+
- Your MCP Server is packaged with NuGet and published to NuGet.org ([quickstart](./build-mcp-server.md)).
19+
20+
## Create a server.json manifest file
21+
22+
*If you used the NuGet MCP Server quickstart and `mcpserver` project template, you can skip this step.*
23+
24+
1. Navigate to your MCP server's source directory and create a new `server.json` file.
25+
::: zone pivot="os-windows"
26+
27+
```powershell
28+
cd path\my\project
29+
30+
# create and open the server.json file
31+
code .mcp\server.json
32+
```
33+
34+
::: zone-end
35+
::: zone pivot="os-linux"
36+
37+
```bash
38+
cd path/my/project
39+
40+
# create and open the server.json file
41+
code .mcp/server.json
42+
```
43+
44+
::: zone-end
45+
::: zone pivot="os-macos"
46+
47+
```bash
48+
cd path/my/project
49+
50+
# create and open the server.json file
51+
code .mcp/server.json
52+
```
53+
54+
::: zone-end
55+
2. Use this content to start with and fill in the placeholders.
56+
:::code language="json" source="snippets/mcp-registry/server.json":::
57+
3. Save the file.
58+
59+
Use this reference to understand more about the fields:
60+
61+
| Property | Example | Purpose |
62+
| ------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
63+
| name | `io.github.contoso/data-mcp` | Unique identifier for the MCP Server, namespaced using reverse DNS names, **case sensitive** |
64+
| version | `0.1.0-beta` | Version of the MCP Server listing<br>Consider using the same version as the MCP Server package on NuGet.org |
65+
| description | `Access Contoso data in your AI agent` | Description of your MCP Server, up to 100 characters |
66+
| title | `Contoso Data` | Optional: short human readable title, up to 100 characters |
67+
| websiteUrl | `https://contoso.com/docs/mcp` | Optional: URL to the server's homepage, documentation, or project website |
68+
| packages identifier | `Contoso.Data.Mcp` | The ID of your MCP Server package on NuGet.org |
69+
| packages version | `0.1.0-beta` | The version of your MCP Server package on NuGet.org |
70+
| repository url | `https://github.com/contoso/data-mcp` | Optional: GitHub repository URL |
71+
72+
The `name` field has two parts, separated by a forward slash `/`. The first part is a namespace based off of a reverse DNS name. The authentication method you use in later steps will give you access to a specific namespace. For example, using GitHub-based authentication will give you access to `io.github.<your GitHub username>/*`. The second part, after the forward slash, is a custom identifier for your server within the namespace. Think of this much like a NuGet package ID. It should be unchanging and descriptive of your MCP server. Using your GitHub repository name is a reasonable option if you only have one MCP Server published from that repository.
73+
74+
## Update your package README
75+
76+
The Official MCP Registry verifies that your MCP Server package references the `name` specified in your `server.json` file.
77+
78+
1. If you haven't already, add a README to your MCP Server NuGet package. See [how to do this in your project file](/nuget/reference/msbuild-targets#packagereadmefile).
79+
2. Open the README.md used by your NuGet package.
80+
::: zone pivot="os-windows"
81+
82+
```powershell
83+
code path\to\README.md
84+
```
85+
86+
::: zone-end
87+
::: zone pivot="os-linux"
88+
89+
```bash
90+
code path/to/README.md
91+
```
92+
93+
::: zone-end
94+
::: zone pivot="os-macos"
95+
96+
```bash
97+
code path/to/README.md
98+
```
99+
100+
::: zone-end
101+
3. Add the following line to your README. It can be anywhere, since it will be invisible (an HTML comment).
102+
103+
```markdown
104+
<!-- mcp-name: [name property from the server.json] -->
105+
```
106+
107+
Example:
108+
109+
```markdown
110+
<!-- mcp-name: io.github.contoso/data-mcp -->
111+
```
112+
113+
4. Save the README file.
114+
115+
## Publish your MCP Server package to NuGet.org
116+
117+
Because your README now has an `mcp-name` declared in it, publish the latest package to NuGet.org.
118+
119+
1. If needed, update your package version and the respective version strings in your `server.json`.
120+
2. Pack your project so the latest README version is contained.
121+
122+
```bash
123+
dotnet pack
124+
```
125+
126+
3. Push it to NuGet.org either [via the website](https://www.nuget.org/packages/manage/upload) or using the CLI:
127+
::: zone pivot="os-windows"
128+
129+
```powershell
130+
dotnet push bin\Release\*.nupkg -k <API key here> -s https://api.nuget.org/v3/index.json
131+
```
132+
133+
::: zone-end
134+
::: zone pivot="os-linux"
135+
136+
```bash
137+
dotnet push bin/Release/*.nupkg -k <API key here> -s https://api.nuget.org/v3/index.json
138+
```
139+
140+
::: zone-end
141+
::: zone pivot="os-macos"
142+
143+
```bash
144+
dotnet push bin/Release/*.nupkg -k <API key here> -s https://api.nuget.org/v3/index.json
145+
```
146+
147+
::: zone-end
148+
149+
## Wait for your package to become available
150+
151+
NuGet.org performs validations against your package before making it available.
152+
153+
Wait for your package to become available. This can either be done by refreshing the package details page on NuGet.org until the validating message disappears, or by using this simple PowerShell script to poll for availability.
154+
155+
```powershell
156+
$id = "<your NuGet package ID here>".ToLowerInvariant()
157+
$version = "<your NuGet package version here>".ToLowerInvariant()
158+
$url = "https://api.nuget.org/v3-flatcontainer/$id/$version/readme"
159+
$elapsed = 0; $interval = 10; $timeout = 300
160+
Write-Host "Checking for package README of $id $version."
161+
while ($true) {
162+
if ($elapsed -gt $timeout) {
163+
Write-Error "Package README is not available after $elapsed seconds. URL: $url"
164+
exit 1
165+
}
166+
try {
167+
Invoke-WebRequest -Uri $url -ErrorAction Stop | Out-Null
168+
Write-Host "Package README is now available."
169+
break
170+
} catch {
171+
Write-Host "Package README is not yet available. Elapsed time: $elapsed seconds."
172+
Start-Sleep -Seconds $interval; $elapsed += $interval
173+
continue
174+
}
175+
}
176+
```
177+
178+
This script can be leveraged in a CI/CD pipeline to ensure the next step (publishing to the Official MCP Registry) does not happen before the NuGet package is available.
179+
180+
## Download the MCP Publisher tool
181+
182+
1. Download the `mcp-publisher-*.tar.gz` file from the Official MCP Registry GitHub repository that matches your CPU architecture.
183+
::: zone pivot="os-windows"
184+
- Windows x64: [mcp-publisher_windows_amd64.tar.gz](https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_windows_amd64.tar.gz)
185+
- Windows Arm64: [mcp-publisher_windows_arm64.tar.gz](https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_windows_amd64.tar.gz)
186+
::: zone-end
187+
::: zone pivot="os-linux"
188+
- Linux x64: [mcp-publisher_linux_amd64.tar.gz](https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz)
189+
- Linux Arm64: [mcp-publisher_linux_amd64.tar.gz](https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz)
190+
::: zone-end
191+
::: zone pivot="os-macos"
192+
- macOS x64: [mcp-publisher_darwin_amd64.tar.gz](https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_darwin_amd64.tar.gz)
193+
- macOS Arm64: [mcp-publisher_darwin_amd64.tar.gz](https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_darwin_amd64.tar.gz)
194+
::: zone-end
195+
See the full list of assets in the [latest release](https://github.com/modelcontextprotocol/registry/releases/latest).
196+
2. Extract the downloaded .tar.gz to the current directory.
197+
::: zone pivot="os-windows"
198+
199+
```powershell
200+
# For Windows x64
201+
tar xf 'mcp-publisher_windows_amd64.tar.gz'
202+
203+
# For Windows ARM64
204+
tar xf 'mcp-publisher_windows_arm64.tar.gz'
205+
```
206+
207+
::: zone-end
208+
::: zone pivot="os-linux"
209+
210+
```bash
211+
# For Linux x64
212+
tar xf 'mcp-publisher_linux_amd64.tar.gz'
213+
214+
# For Linux ARM64
215+
tar xf 'mcp-publisher_linux_arm64.tar.gz'
216+
```
217+
218+
::: zone-end
219+
::: zone pivot="os-macos"
220+
221+
```bash
222+
# For macOS x64
223+
tar xf 'mcp-publisher_darwin_amd64.tar.gz'
224+
225+
# For macOS ARM64
226+
tar xf 'mcp-publisher_darwin_amd64.tar.gz'
227+
```
228+
229+
::: zone-end
230+
231+
## Publish to the Official MCP Registry
232+
233+
The MCP Registry has different authentication mechanisms based on the namespace MCP Server's `name`. In this guide, we are using a namespace based on GitHub (`io.github.<your GitHub username>/*`) so GitHub authentication must be used. See the [registry documentation for information on other authentication modes](https://github.com/modelcontextprotocol/registry/blob/main/docs/modelcontextprotocol-io/authentication.mdx) which unlock other namespaces.
234+
235+
1. Log in using GitHub interactive authentication.
236+
::: zone pivot="os-windows"
237+
238+
```powershell
239+
.\mcp-publisher.exe login github
240+
```
241+
242+
::: zone-end
243+
::: zone pivot="os-linux"
244+
245+
```bash
246+
./mcp-publisher login github
247+
```
248+
249+
::: zone-end
250+
::: zone pivot="os-macos"
251+
252+
```bash
253+
./mcp-publisher login github
254+
```
255+
256+
::: zone-end
257+
Follow the instructions provided by the tool. You will provide a code to GitHub in your web browser to complete the flow.
258+
259+
Once the flow is complete, you will be able to publish `server.json` files to the `io.github.<your GitHub username>/*` namespace.
260+
261+
2. Publish your `server.json` file to the Official MCP Registry.
262+
::: zone pivot="os-windows"
263+
264+
```powershell
265+
.\mcp-publisher.exe publish path\to\.mcp\server.json
266+
```
267+
268+
::: zone-end
269+
::: zone pivot="os-linux"
270+
271+
```bash
272+
./mcp-publisher publish path/to/.mcp/server.json
273+
```
274+
275+
::: zone-end
276+
::: zone pivot="os-macos"
277+
278+
```bash
279+
./mcp-publisher publish path/to/.mcp/server.json
280+
```
281+
282+
::: zone-end
283+
3. When the command succeeds, you can verify that your MCP Server is published by going to the [registry home page](https://registry.modelcontextprotocol.io/) and searching for your server name.
284+
285+
## Related content
286+
287+
- [Build and publish an MCP Server to NuGet.org](./build-mcp-server.md)
288+
- [Publish a NuGet package](/nuget/nuget-org/publish-a-package)
289+
- [Conceptual: MCP Servers in NuGet Packages](/nuget/concepts/nuget-mcp)
290+
- [Get started with .NET AI and the Model Context Protocol](../get-started-mcp.md)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
3+
"name": "io.github.<your GitHub username here>/<your server name here>",
4+
"version": "<your package version here>",
5+
"description": "<your server description here>",
6+
"title": "<optional: human readable title>",
7+
"websiteUrl": "<optional: URL to a landing page or documentation site>",
8+
"packages": [
9+
{
10+
"registryType": "nuget",
11+
"identifier": "<your package ID here>",
12+
"version": "<your package version here>",
13+
"transport": {
14+
"type": "stdio"
15+
},
16+
"packageArguments": [],
17+
"environmentVariables": []
18+
}
19+
],
20+
"repository": {
21+
"url": "https://github.com/<your GitHub username here>/<your repo name here>",
22+
"source": "github"
23+
}
24+
}

0 commit comments

Comments
 (0)