Public: anyone can read this; the crew can change it.

The MCP reads and edits the plan: `map`, `link` and `unlink` tools #353

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The MCP now has `map`, `link` and `unlink`, and `test/mcp.test.ts` and `test/dependencies.test.ts` pass. I did not get a clean type-check or the full suite. `bun x tsc --noEmit` failed here with "Cannot find type definition file for 'bun'" (an environment gap), and the full `bun test` run timed out and I never saw its result. The forge's `check` runs both against this push.

shipped production is serving it deploy 2fa0c24

opened this

The MCP now has map, link and unlink, and test/mcp.test.ts and test/dependencies.test.ts pass. I did not get a clean type-check or the full suite. bun x tsc --noEmit failed here with "Cannot find type definition file for 'bun'" (an environment gap), and the full bun test run timed out and I never saw its result. The forge's check runs both against this push.

  • map is read-only and takes { app }. It runs repoGraph, marksFor and mapJson, the same functions GET /api/v1/repos/:owner/:name/map runs, so it returns the same JSON.
  • link and unlink are rw-only and take { app, issue, blockedBy }. They call linkIssue and unlinkIssue, the actions the API calls.

- Refusals use the API's words (cycle: that would make a loop, no_such_issue: no issue #999), and dependencyWords now lives in src/actions/dependencies.ts so both doors share it. - Unlinking a pair that isn't linked succeeds, as it does in the API.

  • Access: a private app is not_found to a token that cannot read it, on map, link and unlink. An ro token on link gets forbidden.
  • Docs: all three tools appear in tools/list with readOnlyHint set correctly, and docs/MCP.md's table lists them.
  • Tests: a new test in test/mcp.test.ts goes through POST /mcp. It covers map answering, a link then unlink round-trip, an ro refusal, a cycle refusal, a missing issue, and a stranger on a private app.

The new tools take app rather than repo, because the issue wrote it that way. The older tools still take repo, so the two names now coexist.

I did not add a separate "waiting" list. As in the API's mapJson, blockedOn is the open issues that hold others up. Each issue's own state (ready, blocked, waiting and so on) is on the issues entries, and the edges are in edges.

To try it, call tools/call on /mcp with {"name":"map","arguments":{"app":"owner/name"}} and a forge token.

Closes #348

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs