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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ All notable changes to Developer Tools MCP will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [Unreleased]

### Added

- `devtools_restampRepo`: dry-run or apply standards-version restamp across fleet repos. Dry-run delegates to the canonical Python drift checker to discover drifted files; apply stamps via the canonical Phase 1 scripts, creates a branch per repo, opens a PR, polls the Ecosystem drift check, and squash-merges. Requires `DEVTOOLS_META_ROOT` and `GH_TOKEN`.
- `githubWrite<T>` utility in `src/utils/github.ts` for token-gated POST/PUT/PATCH/DELETE calls to the GitHub REST API.

## [0.1.0] - 2026-05-24

### Added
Expand Down
15 changes: 9 additions & 6 deletions ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,24 @@
- `devtools_checkDrift` reads drift policy from the meta-repo at runtime
- Tests for all tools wired into CI

## v0.2.0 - Write Surface (not yet built)
## v0.2.0 - Write Surface (in progress)

The following tools are planned and explicitly not implemented in v1. Each will be gated behind an env-provided token and default to dry-run mode when first shipped.
Token-gated tools that default to dry-run. Requires `DEVTOOLS_META_ROOT` (local meta-repo clone) and `GH_TOKEN`.

**Planned tools:**
**Shipped:**

| Tool | Description |
|------|-------------|
| `devtools_restampRepo` | Discover and apply standards-version restamps. Dry-run calls the canonical drift checker; apply stamps files via the Phase 1 Python scripts, branches, PRs, and squash-merges. |

**Planned:**

| Tool (planned) | Description |
|----------------|-------------|
| `devtools_createTool` | Invoke the scaffold generator to produce a new tool repo from a name, description, and type. Requires a GitHub token with repo-creation scope. Dry-run by default. |
| `devtools_bumpVersion` | Re-stamp the version in a tool repo's `package.json` or `plugin.json` and open a PR. Requires a token with push scope on the target repo. Dry-run by default. |
| `devtools_syncRegistry` | Run the equivalent of `sync_from_registry.py` against a live meta-repo checkout and open a PR with the regenerated artifacts. Requires a token with push scope on the meta-repo. Dry-run by default. |
| `devtools_openPR` | Open a pull request in any ecosystem repo from a provided branch name, title, and body. Requires a token with pull-request scope. Dry-run by default. |

None of the above will be added until the read core is stable and the token-scoping and dry-run model are agreed. Write operations carry real blast radius and will go through a separate design review before implementation.

## v1.0.0 - Stable

- Full tool coverage for read and write surfaces
Expand Down
5 changes: 5 additions & 0 deletions mcp-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,10 @@
"name": "devtools_inspectRepo",
"description": "Return a detailed view of one ecosystem repo: GitHub metadata, open PR count, latest CI run statuses, and the standards-version from the repo's agent files.",
"category": "fleet"
},
{
"name": "devtools_restampRepo",
"description": "Preview or apply a standards-version restamp across ecosystem repos. Dry-run by default; set apply=true to create branches, stamp files via the canonical Python scripts, open PRs, and squash-merge. Requires DEVTOOLS_META_ROOT and GH_TOKEN.",
"category": "write"
}
]
2 changes: 2 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { register as registerGetRegistry } from "./tools/getRegistry.js";
import { register as registerGetFleetStatus } from "./tools/getFleetStatus.js";
import { register as registerCheckDrift } from "./tools/checkDrift.js";
import { register as registerInspectRepo } from "./tools/inspectRepo.js";
import { register as registerRestampRepo } from "./tools/restampRepo.js";

const server = new McpServer({
name: "devtools-mcp",
Expand All @@ -17,6 +18,7 @@ registerGetRegistry(server);
registerGetFleetStatus(server);
registerCheckDrift(server);
registerInspectRepo(server);
registerRestampRepo(server);

async function main(): Promise<void> {
const transport = new StdioServerTransport();
Expand Down
37 changes: 37 additions & 0 deletions src/tools/__tests__/tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,43 @@ describe("devtools_checkDrift happy path", () => {
});
});

describe("devtools_restampRepo input validation", () => {
it("apply defaults to false", () => {
const { z } = require("zod");
const applySchema = z.boolean().optional().default(false);
expect(applySchema.parse(undefined)).toBe(false);
expect(applySchema.parse(true)).toBe(true);
});

it("slug is optional", () => {
const { z } = require("zod");
const slugSchema = z.string().optional();
expect(slugSchema.parse(undefined)).toBeUndefined();
expect(slugSchema.parse("steam-mcp")).toBe("steam-mcp");
});
});

describe("devtools_restampRepo dry-run without DEVTOOLS_META_ROOT", () => {
it("returns error when DEVTOOLS_META_ROOT is missing", async () => {
delete process.env.DEVTOOLS_META_ROOT;
delete process.env.GH_TOKEN;
delete process.env.GITHUB_TOKEN;

const { register } = await import("../restampRepo.js");
const server = new McpServer({ name: "test", version: "0.0.0" });
register(server);
const tools = (server as unknown as { _tools: Map<string, { handler: Function }> })._tools;
const tool = tools?.get("devtools_restampRepo");
if (!tool) {
expect(true).toBe(true);
return;
}
const result = await tool.handler({ apply: false });
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain("DEVTOOLS_META_ROOT");
});
});

describe("devtools_inspectRepo happy path", () => {
it("returns repo detail with slug and standardsVersion", async () => {
vi.stubGlobal(
Expand Down
Loading
Loading