Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 98 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
name: Release

# Phase-6 publish workflow per AI-discoverability-plan.md §7 Phase 6.
# Fires on a v* tag push. Three artifacts ship in order:
# 1. The wheel is attached to the GitHub Release (Phase-4 path; backup
# install channel for environments that can't reach PyPI).
# 2. The same wheel is published to PyPI under the `m-dev-tools-mcp`
# name via Trusted Publisher OIDC (no stored token).
# 3. The MCP registry record at registry.modelcontextprotocol.io is
# updated via `mcp-publisher` with GitHub OIDC auth.
#
# Manual prereqs the maintainer must do once:
# * PyPI: configure m-dev-tools-mcp as a Trusted Publisher pointing
# at this workflow (PyPI project settings → Publishing).
# * MCP registry: nothing — first publish auto-claims the
# io.github.m-dev-tools/* namespace via the GitHub OIDC token.

on:
push:
tags:
- 'v*'

permissions:
contents: write # GitHub Release creation
id-token: write # PyPI Trusted Publisher + mcp-publisher OIDC

jobs:
release:
runs-on: ubuntu-latest
environment: release
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: '3.12'

- name: Install build deps
run: pip install --upgrade pip build

- name: Build wheel
run: python -m build --wheel

- name: Create GitHub Release with wheel attached
# `gh release create` is idempotent on already-existing tags
# (re-running fails harmlessly), so a manual run won't clobber
# a previously cut release.
run: |
gh release create "${GITHUB_REF_NAME}" \
dist/*.whl \
--title "${GITHUB_REF_NAME}" \
--generate-notes
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Publish to PyPI (Trusted Publisher OIDC)
uses: pypa/gh-action-pypi-publish@release/v1
# No password / API token — Trusted Publisher uses the
# `id-token: write` permission to mint an OIDC token PyPI
# exchanges for a short-lived publish credential. Configured
# once on PyPI's side.

- name: Install mcp-publisher
# Pulled fresh on every release; the CLI is small (single Go
# binary). Homebrew/apt are out of the question on the
# GitHub-Actions runner.
run: |
curl -L --fail \
"https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz" \
| tar -xz mcp-publisher
chmod +x mcp-publisher
./mcp-publisher --help

- name: Update server.json version to match the tag
# server.json's `version` and `packages[0].version` are pinned
# to the release tag at publish time. The committed copy is a
# template; CI rewrites both fields before mcp-publisher
# publish.
run: |
tag="${GITHUB_REF_NAME#v}"
python3 - <<PY
import json, pathlib
p = pathlib.Path("server.json")
d = json.loads(p.read_text())
d["version"] = "${tag}"
d["packages"][0]["version"] = "${tag}"
p.write_text(json.dumps(d, indent=2) + "\n")
print(p.read_text())
PY

- name: Publish to MCP registry
# GitHub OIDC mode — mcp-publisher exchanges the workflow's
# OIDC token for a short-lived registry credential bound to
# the `io.github.m-dev-tools/*` namespace. First run claims
# the namespace; subsequent runs update the record.
run: |
./mcp-publisher login github-oidc
./mcp-publisher publish
18 changes: 14 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,20 @@ Install via `uvx --from git+https://github.com/m-dev-tools/m-dev-tools-mcp@v<X.Y

## Status

**Track A** (this scaffold): repo skeleton + Phase-0 contract + CI. Tool
bodies raise `NotImplementedError`. **Track B** lands real behavior.
**Tracks C / D / E** add Claude Code integration smoke, the v0.1.0
release wheel, and Phase 4 exit evidence.
Phase 4 closed 2026-05-11 — v0.1.0 release wheel shipped, `route_intent` / `describe` / `verify` all real-agent tested. Phase 6 ships PyPI + the official MCP registry listing (`io.github.m-dev-tools/m-dev-tools-mcp`); see [`AI-discoverability-plan.md` §7 Phase 6](https://github.com/m-dev-tools/.github/blob/main/docs/ai-discoverability/AI-discoverability-plan.md). `server.json` at the repo root + `.github/workflows/release.yml` automate both publishes on every `v*` tag.

## Release process

1. Bump `pyproject.toml` `version` (and `__version__` in `src/m_dev_tools_mcp/__init__.py`).
2. Bump `server.json`'s `version` + `packages[0].version` to match.
3. Open + merge a release PR.
4. Tag `vX.Y.Z` on `main`; push the tag.
5. `.github/workflows/release.yml` fires: builds the wheel, attaches it to the GitHub Release, publishes to PyPI via Trusted Publisher OIDC, then `mcp-publisher publish` updates the MCP registry record via GitHub OIDC.

Manual prereq (one-time, by a maintainer):

- **PyPI**: configure `m-dev-tools-mcp` as a [Trusted Publisher](https://docs.pypi.org/trusted-publishers/) pointing at this repo's `release.yml` workflow. No API token gets stored anywhere.
- **MCP registry**: nothing — first `mcp-publisher publish` auto-claims the `io.github.m-dev-tools/*` namespace via the runner's GitHub OIDC token.

## Setup

Expand Down
24 changes: 24 additions & 0 deletions server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.m-dev-tools/m-dev-tools-mcp",
"description": "MCP server for the m-dev-tools org catalog — exposes route_intent, describe, and verify as first-class agent tools.",
"title": "m-dev-tools",
"websiteUrl": "https://github.com/m-dev-tools/m-dev-tools-mcp",
"repository": {
"url": "https://github.com/m-dev-tools/m-dev-tools-mcp",
"source": "github"
},
"version": "0.1.0",
"packages": [
{
"registryType": "pypi",
"registryBaseUrl": "https://pypi.org",
"identifier": "m-dev-tools-mcp",
"version": "0.1.0",
"runtimeHint": "uvx",
"transport": {
"type": "stdio"
}
}
]
}
Loading