MCP server for tangled
1# publishing to mcp registry
2
3this document explains how we set up automated publishing to the [MCP registry](https://github.com/modelcontextprotocol/registry) and the lessons learned along the way.
4
5## overview
6
7the MCP registry is Anthropic's official directory of Model Context Protocol servers. publishing makes your server discoverable and installable through Claude Desktop and other MCP clients.
8
9## setup
10
11### required files
12
131. **`server.json`** - registry metadata
14 - must match PyPI package version exactly
15 - uses namespace format: `io.github.username/server-name`
16 - validated against https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json
17
182. **`README.md`** - must contain `mcp-name:` line
19 - format: `mcp-name: io.github.username/server-name`
20 - can appear anywhere in the file (we put it at the bottom)
21 - validation uses simple `strings.Contains()` check
22
233. **`.github/workflows/publish-mcp.yml`** - automation workflow
24 - triggers on version tags (e.g., `v0.0.6`)
25 - publishes to PyPI first, then MCP registry
26 - uses GitHub OIDC for authentication (no secrets needed)
27
28### github secrets
29
30only one secret required:
31- `PYPI_API_TOKEN` - from https://pypi.org/manage/account/token/
32
33## workflow
34
35when you push a version tag:
36
37```bash
38git tag v0.0.6
39git push origin v0.0.6
40```
41
42the workflow automatically:
431. runs tests
442. builds the package with `uv build`
453. publishes to PyPI with `uv publish`
464. installs `mcp-publisher` binary (v1.2.3)
475. authenticates using GitHub OIDC
486. publishes to MCP registry
49
50## cutting a release
51
52to cut a new release:
53
541. **update server.json version** (both fields must match the version you're releasing)
55 ```json
56 {
57 "version": "0.0.9",
58 "packages": [{
59 "version": "0.0.9"
60 }]
61 }
62 ```
63
642. **run pre-commit checks**
65 ```bash
66 just check
67 ```
68
693. **commit and push your changes**
70 ```bash
71 git add .
72 git commit -m "your commit message"
73 git push origin main
74 ```
75
764. **create and push the version tag**
77 ```bash
78 git tag v0.0.9
79 git push origin v0.0.9
80 ```
81
825. **verify the release**
83 - workflow: https://github.com/zzstoatzz/tangled-mcp/actions/workflows/publish-mcp.yml
84 - pypi: https://pypi.org/project/tangled-mcp/
85 - mcp registry: `https://registry.modelcontextprotocol.io/v0/servers/io.github.zzstoatzz%2Ftangled-mcp/versions/X.Y.Z`
86
87## key learnings
88
89### mcp-publisher installation
90
91the official docs suggest using a "latest" URL that doesn't actually work:
92
93```bash
94# ❌ doesn't work - 404s
95curl -L "https://github.com/modelcontextprotocol/registry/releases/download/latest/..."
96
97# ✅ use specific version
98curl -L "https://github.com/modelcontextprotocol/registry/releases/download/v1.2.3/mcp-publisher_1.2.3_linux_amd64.tar.gz"
99```
100
101the publisher is a Go binary, not an npm package. don't try `npm install`.
102
103### version synchronization
104
105`server.json` version must match the PyPI package version:
106
107```json
108{
109 "version": "0.0.6",
110 "packages": [{
111 "version": "0.0.6"
112 }]
113}
114```
115
116if they don't match, registry validation fails with:
117```
118PyPI package 'tangled-mcp' not found (status: 404)
119```
120
121### readme validation
122
123the `mcp-name:` line just needs to exist somewhere in the README content. the validator uses:
124
125```go
126strings.Contains(description, "mcp-name: io.github.username/server-name")
127```
128
129so you can place it wherever looks best aesthetically. we put it at the bottom after a horizontal rule.
130
131### authentication
132
133GitHub OIDC is the recommended method for CI/CD:
134
135```yaml
136permissions:
137 id-token: write
138 contents: read
139
140steps:
141 - name: login to mcp registry (github oidc)
142 run: mcp-publisher login github-oidc
143```
144
145no need for additional tokens or secrets - GitHub handles it automatically.
146
147## common errors
148
149### "PyPI package not found (status: 404)"
150
151**cause**: version mismatch between `server.json` and actual PyPI package
152
153**fix**: ensure `server.json` versions match the git tag and PyPI will build that version
154
155### "ownership validation failed"
156
157**cause**: missing or incorrect `mcp-name:` in README
158
159**fix**: add `mcp-name: io.github.username/server-name` anywhere in README.md
160
161### "failed to install mcp-publisher"
162
163**cause**: wrong download URL or npm package attempt
164
165**fix**: use specific version binary download from GitHub releases
166
167## resources
168
169- [MCP registry docs](https://github.com/modelcontextprotocol/registry/tree/main/docs)
170- [MCP publisher source](https://github.com/modelcontextprotocol/registry)
171- [our workflow](.github/workflows/publish-mcp.yml)
172- [our server.json](server.json)