|
| 1 | +# Maintaining and publishing |
| 2 | + |
| 3 | +Notes for template maintainers: how to change, test and publish the template. This file isn't part of the NuGet |
| 4 | +package. |
| 5 | + |
| 6 | +## Repository layout |
| 7 | + |
| 8 | +```text |
| 9 | +dotnet-mcp-server-template/ |
| 10 | +├── README.md public readme (also shown on nuget.org) |
| 11 | +├── CHANGELOG.md template version history |
| 12 | +├── nuget-publish.md this guide |
| 13 | +├── LICENSE |
| 14 | +├── TemplatePack.csproj packs the template into a NuGet package |
| 15 | +├── assets/ README screenshots (loaded from GitHub, not packed) |
| 16 | +├── .github/workflows/ |
| 17 | +│ ├── template-ci.yml creates a sample project, builds, tests, packs; checks UI bundles (push, PR) |
| 18 | +│ └── publish.yml publishes to nuget.org (version tags or manual run) |
| 19 | +└── templates/ |
| 20 | + └── DotnetMcpTemplate/ the template itself (everything a new project gets) |
| 21 | + ├── .template.config/template.json |
| 22 | + ├── DotnetMcpTemplate.sln |
| 23 | + └── src/ tests/ ui/ docker/ docs/ .github/ ... |
| 24 | +``` |
| 25 | + |
| 26 | +The `.github/workflows` inside `templates/DotnetMcpTemplate` belong to generated projects. They don't run in this |
| 27 | +repository. |
| 28 | + |
| 29 | +## Rules |
| 30 | + |
| 31 | +- Keep `DotnetMcpTemplate` as the placeholder name everywhere (`sourceName`). Never rename it. |
| 32 | +- Keep `dotnetmcptemplate-slug` where a lowercase, dash-only name is needed (Docker image, Compose, `ui/package.json`). |
| 33 | +- Set NuGet package versions only in `templates/DotnetMcpTemplate/Directory.Packages.props`. |
| 34 | +- After changing anything in `templates/DotnetMcpTemplate/ui/`, run `pnpm run build` there and commit the updated |
| 35 | + bundles in `src/DotnetMcpTemplate/ui_dist/`. CI fails when they are stale. |
| 36 | +- Never commit or pack `.env`. It's git-ignored and excluded in `TemplatePack.csproj`, and CI and `publish` fail if a |
| 37 | + `.env` ends up in the package. `.env.example` is the committed one. |
| 38 | +- Never create projects inside this repository. |
| 39 | + |
| 40 | +## Install from source |
| 41 | + |
| 42 | +```bash |
| 43 | +dotnet new install ./templates/DotnetMcpTemplate # first time |
| 44 | +dotnet new install ./templates/DotnetMcpTemplate --force # after changes |
| 45 | +dotnet new uninstall ./templates/DotnetMcpTemplate # remove |
| 46 | +dotnet new list code4mk-mcp # check |
| 47 | +``` |
| 48 | + |
| 49 | +## Workflow for a change |
| 50 | + |
| 51 | +1. Create a branch and edit files under `templates/DotnetMcpTemplate`. |
| 52 | +2. Test the template in place (it builds and runs as a normal solution): |
| 53 | + |
| 54 | + ```bash |
| 55 | + cd templates/DotnetMcpTemplate |
| 56 | + dotnet build && dotnet test |
| 57 | + cd ui && pnpm install && pnpm run build # when ui/ changed |
| 58 | + ``` |
| 59 | + |
| 60 | +3. Test a generated project, outside the repository: |
| 61 | + |
| 62 | + ```bash |
| 63 | + dotnet new install ./templates/DotnetMcpTemplate --force |
| 64 | + cd .. |
| 65 | + dotnet new code4mk-mcp -n Test.Mcp -o test-mcp |
| 66 | + cd test-mcp && dotnet build && dotnet test |
| 67 | + grep -rIi --exclude-dir=bin --exclude-dir=obj --exclude-dir=node_modules dotnetmcptemplate . || echo "no placeholders left" |
| 68 | + cd .. && rm -rf test-mcp |
| 69 | + ``` |
| 70 | + |
| 71 | +4. Add an entry to `CHANGELOG.md` under a new version. |
| 72 | +5. Open a pull request. `template-ci` runs automatically. |
| 73 | +6. After merging, publish the new version. |
| 74 | + |
| 75 | +## Publishing to nuget.org |
| 76 | + |
| 77 | +Packages are published under the nuget.org account **Code4mk** as `Code4mk.McpServer.Template`. |
| 78 | + |
| 79 | +Before every publish: |
| 80 | + |
| 81 | +1. `main` is pushed. The README's screenshots and CI badge load from GitHub, so they break on nuget.org otherwise. |
| 82 | +2. `CHANGELOG.md` has the new version and date. |
| 83 | +3. `template-ci` is green on `main`. |
| 84 | + |
| 85 | +### From your machine |
| 86 | + |
| 87 | +```bash |
| 88 | +dotnet pack TemplatePack.csproj -c Release -o artifacts -p:PackageVersion=1.0.0 |
| 89 | + |
| 90 | +# check the contents: only .env.example, no .env, bin/, obj/ or node_modules/ |
| 91 | +unzip -l artifacts/Code4mk.McpServer.Template.1.0.0.nupkg | grep -E "\.env|/bin/|/obj/|node_modules" |
| 92 | + |
| 93 | +# macOS / Linux |
| 94 | +export NUGET_API_KEY="your-key" |
| 95 | +dotnet nuget push artifacts/Code4mk.McpServer.Template.1.0.0.nupkg \ |
| 96 | + --source https://api.nuget.org/v3/index.json --api-key $NUGET_API_KEY |
| 97 | + |
| 98 | +# Windows PowerShell |
| 99 | +$env:NUGET_API_KEY = "your-key" |
| 100 | +dotnet nuget push artifacts\Code4mk.McpServer.Template.1.0.0.nupkg ` |
| 101 | + --source https://api.nuget.org/v3/index.json --api-key $env:NUGET_API_KEY |
| 102 | +``` |
| 103 | + |
| 104 | +Then tag the release so the repository matches the package: `git tag v1.0.0 && git push origin v1.0.0`. |
| 105 | +If `NUGET_API_KEY` is also set as a repository secret, that tag starts `publish` too; it skips the version that |
| 106 | +already exists (`--skip-duplicate`), so this is harmless. |
| 107 | + |
| 108 | +### From GitHub Actions |
| 109 | + |
| 110 | +1. Add the nuget.org API key as the repository secret `NUGET_API_KEY` (Settings → Secrets and variables → Actions). |
| 111 | +2. Either push a version tag: `git tag v1.1.0 && git push origin v1.1.0`, |
| 112 | + or open Actions → `publish` → **Run workflow** and enter the version (e.g. `1.1.0`). |
| 113 | + |
| 114 | +The workflow validates the version, packs the template with it, checks the package for `.env` files and pushes it. |
| 115 | + |
| 116 | +### Notes |
| 117 | + |
| 118 | +- Create the API key on nuget.org (username → API Keys) with the **Push** scope and glob pattern `Code4mk.*`. |
| 119 | + Give it an expiry and don't paste it into files or commits. |
| 120 | +- New versions appear on nuget.org after validation and indexing, usually within 15 to 30 minutes. |
| 121 | +- Every publish needs a new version number. A broken version can be unlisted but never deleted or replaced. |
| 122 | +- Pre-releases use a suffix (`1.1.0-preview.1`); `dotnet new install` only picks them when asked for explicitly. |
| 123 | +- `README.md` is packed into the package and shown on nuget.org: keep its links and images absolute (GitHub URLs, |
| 124 | + images from `raw.githubusercontent.com` or `img.shields.io`). |
| 125 | +- Users update with `dotnet new install Code4mk.McpServer.Template` (installs the latest) or |
| 126 | + `dotnet new update`. |
| 127 | +
|
| 128 | +## Troubleshooting |
| 129 | +
|
| 130 | +| Problem | Fix | |
| 131 | +| --- | --- | |
| 132 | +| `No templates found matching: 'code4mk-mcp'` | Install the template and check `dotnet new list code4mk-mcp` | |
| 133 | +| Namespaces like `my_app.Mcp` | Dashes were used in `-n`. Use PascalCase in `-n` and dashes only in `-o` | |
| 134 | +| New project contains another project | `dotnet new` ran inside the template repo. Delete it and run from another folder | |
| 135 | +| `template-ci` fails on "Committed bundles match the source" | Run `pnpm run build` in `templates/DotnetMcpTemplate/ui` and commit `ui_dist/` | |
| 136 | +| `publish` fails on "Package contains no local-only files" | A `.env` got into the package: check the excludes in `TemplatePack.csproj` | |
| 137 | +| README images missing on nuget.org | Push `main` (images load from GitHub); nuget.org caches the README per version | |
| 138 | +| `409 Conflict` on push | That version already exists on nuget.org: bump the version | |
| 139 | +| `403 Forbidden` on push | The API key expired, lacks the Push scope, or its glob doesn't match `Code4mk.*` | |
0 commit comments