@anyforge/mcp-server 2.5.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,10 +9,28 @@ The server is a thin client over AnyForge's key-authenticated control
9
9
  API (`/api/v1/control/*`). It holds no business logic and never needs a
10
10
  Firebase login.
11
11
 
12
- > **User-facing setup guide:** [Drive AnyForge from Claude CLI](https://anyforge.ai/docs/mcp-server)
12
+ > **User-facing setup guide:** [Connect AnyForge to Claude, Cursor and VS Code](https://anyforge.ai/docs?page=mcp-server)
13
13
  > (`apps/www/content/docs/mcp-server.md`). This README is the in-repo
14
14
  > developer reference; the docs page is the canonical install walkthrough.
15
15
 
16
+ ## Platform guide for connected agents
17
+
18
+ The server advertises a static `anyforge-platform` guide without tenant data or
19
+ extra authority. MCP clients can load it on demand with the `platform_guide`
20
+ prompt or the `anyforge://guide/platform` resource. The resource also exposes
21
+ the guide's three reference files.
22
+
23
+ For an Agent Skills-compatible local host, install the same guide with:
24
+
25
+ ```bash
26
+ npx @anyforge/control skill install anyforge-platform
27
+ ```
28
+
29
+ The default is the project-local `.agents/skills/anyforge-platform/` directory.
30
+ Use `--scope user --client claude` or `--scope user --client codex` for the
31
+ corresponding user-level directory. Existing files are preserved unless
32
+ `--force` is explicit.
33
+
16
34
  ## 1. Authorise this machine (once)
17
35
 
18
36
  ```bash
@@ -61,28 +79,146 @@ Use the equivalent stdio MCP config (`command: npx`, `args: ["tsx",
61
79
  | `anyforge_submit_approval` | approve | Approve or reject a HIL (resumes the crew) |
62
80
  | `anyforge_list_programs` | read | List programs |
63
81
  | `anyforge_get_program` | read | Get a program |
64
- | `anyforge_list_initiatives` | read | List initiatives with progress + spend |
65
- | `anyforge_get_initiative` | read | Initiative + crews + burn-down |
82
+ | `anyforge_get_program_brief_context` | read | Read a program's structured Brief, version history, legacy mirror, and ICE readiness |
83
+ | `anyforge_save_program_brief_version` | write | Save a complete structured Brief version; archives the prior active version and replaces the retired free-form writer |
84
+ | `anyforge_update_program` | write | Update a program's name / status / owner / target date / coverage goal / tags |
85
+ | `anyforge_delete_program` | write | Delete a program; `deleteChildren: true` also deletes child initiatives + work items (else they're detached) |
86
+ | `anyforge_update_program_initiative` | write | Enrich one existing program initiative and return changed fields or a structured no-op |
87
+ | `anyforge_close_program_initiative` | write | Preview then close one program initiative with a supported close reason |
88
+ | `anyforge_close_program_work_items_as_fixed` | write | Preview then batch-close non-terminal program work items fixed outside AnyForge |
89
+ | `anyforge_list_initiatives` | read | List initiatives with progress + budget. Returns ONE PAGE (50 default, 100 max) — continue with `meta.nextCursor`, or narrow with `programId`, `status`, `priority`, `owner`, `tag`, `search`. Unknown arguments are rejected; the page echoes `appliedFilters` |
90
+ | `anyforge_get_initiative` | read | Initiative + crew and work-item rows + burn-down; long text is excerpted unless `shape: "full"` |
91
+ | `anyforge_get_initiative_spec` | read | Read the active ICE spec, its readiness, what backlog approval will decide (`approvalGate`), and any submission awaiting human review |
92
+ | `anyforge_propose_initiative_spec` | write | Submit an ICE spec for human review; it becomes active only when a person reviews and publishes it in the Console |
93
+ | `anyforge_update_initiative` | write | Update a (non-system) initiative — only the fields you pass change |
94
+ | `anyforge_delete_initiative` | write | Delete a DRAFT initiative (archive via update once it's past DRAFT) |
95
+ | `anyforge_list_opportunities` | read | List opportunities in the Discovery (product-planning) layer |
96
+ | `anyforge_create_opportunity` | write | Create an opportunity (bridges raw signals to themed roadmap work) |
97
+ | `anyforge_update_opportunity` | write | Edit an opportunity's RICE inputs, stage, theme assignment, or program link (`programId`; `null` unlinks) |
98
+ | `anyforge_delete_opportunity` | write | Hard-delete an opportunity (prefer archiving via `anyforge_update_opportunity`) |
99
+ | `anyforge_promote_opportunity` | write | Promote a prioritized opportunity into a Program + Initiative |
100
+ | `anyforge_list_signals` | read | List signals in the Discovery (product-planning) layer |
101
+ | `anyforge_create_signal` | write | Capture a signal — a raw data point that may inform product direction |
102
+ | `anyforge_update_signal` | write | Edit a signal's status, linked opportunity, or other fields |
103
+ | `anyforge_delete_signal` | write | Hard-delete a signal (prefer archiving via `anyforge_update_signal`) |
104
+ | `anyforge_list_themes` | read | List themes in the Discovery (product-planning) layer |
105
+ | `anyforge_create_theme` | write | Create a theme — a strategic grouping above individual initiatives |
106
+ | `anyforge_update_theme` | write | Edit a theme's name, status, objective, or other fields |
107
+ | `anyforge_delete_theme` | write | Hard-delete a theme (prefer archiving via `anyforge_update_theme`) |
108
+ | `anyforge_get_strategy` | read | Read the complete strategy tree, attainment, delivery rollups, horizons, orphan work, and delivery conditions |
109
+ | `anyforge_list_pillars` | read | List strategy pillars |
110
+ | `anyforge_create_pillar` | write | Create a strategy pillar |
111
+ | `anyforge_update_pillar` | write | Update a pillar's name, description, lead, or order |
112
+ | `anyforge_delete_pillar` | write | Delete a pillar when it has no objectives |
113
+ | `anyforge_list_objectives` | read | List strategy objectives |
114
+ | `anyforge_create_objective` | write | Create an objective under a pillar |
115
+ | `anyforge_update_objective` | write | Update or move an objective |
116
+ | `anyforge_delete_objective` | write | Delete an objective when it has no key results |
117
+ | `anyforge_list_key_results` | read | List strategy key results |
118
+ | `anyforge_create_key_result` | write | Create a measurable key result |
119
+ | `anyforge_update_key_result` | write | Update a key result or record a reading |
120
+ | `anyforge_delete_key_result` | write | Delete a key result |
121
+ | `anyforge_get_horizons` | read | Read NOW / NEXT / LATER narratives and completion criteria |
122
+ | `anyforge_set_horizon_narrative` | write | Update a horizon narrative |
123
+ | `anyforge_get_cluster_charter` | read | Read one theme's charter and outstanding lines |
66
124
  | `anyforge_approve_backlog` | approve | Approve a proposed backlog (HIL #1) |
67
125
  | `anyforge_approve_task_proposal` | approve | Approve a mid-flight task proposal |
68
- | `anyforge_list_work_items` | read | List backlog items + crew state |
126
+ | `anyforge_list_work_items` | read | List backlog items + crew state with status, owner, assignee, program, initiative, priority, type, and search filters. Returns ONE PAGE (50 default, 200 max) — continue with `nextCursor`. Unknown arguments are rejected; the page echoes `appliedFilters` |
69
127
  | `anyforge_get_work_item` | read | Get one work item |
70
- | `anyforge_create_work_item` | write | Create a work item |
71
- | `anyforge_update_work_item` | write | Edit / advance / dispatch / archive / close |
128
+ | `anyforge_create_work_item` | write | Create a work item with routing, migration, incident, intake, estimate, and evidence fields |
129
+ | `anyforge_update_work_item` | write | Edit, assign, begin, expedite, dispatch, confirm, drop (with optional `droppedReason`), archive, close, or reopen a work item |
130
+ | `anyforge_retry_work_item` | write | Terminate a work item's crew and dispatch a fresh one on the same branch; recovers missing/phantom crew records from work-item + initiative defaults |
131
+ | `anyforge_list_work_item_comments` | read | List the work item's discussion thread, separate from crew transcripts |
132
+ | `anyforge_post_work_item_comment` | write | Add a discussion comment to a work item |
133
+ | `anyforge_split_work_item` | write | Replace one unstarted work item with multiple children |
134
+ | `anyforge_merge_work_items` | write | Replace multiple unstarted work items with one merged item |
135
+ | `anyforge_list_crews` | read | Discover crews by status, active state, and limit |
72
136
  | `anyforge_get_crew` | read | Crew state + recent outputs + comments |
73
- | `anyforge_post_crew_comment` | write | Comment on / @-mention in a crew |
137
+ | `anyforge_post_crew_comment` | write | Comment on / @-mention people on a crew (the crew does not read comments; use `anyforge_amend_crew` to redirect it) |
74
138
  | `anyforge_resume_crew` | approve | Resume a PAUSED/HALTED crew |
75
139
  | `anyforge_halt_crew` | approve | Halt a crew |
76
140
  | `anyforge_amend_crew` | approve | Continue & finish — send a crew at its HIL gate back to the engineer with guidance |
77
141
  | `anyforge_create_program` | write | Create a program (cross-initiative grouping) |
78
- | `anyforge_write_program_brief` | write | Write/update a program's brief (charter) — seeds each initiative's architect context |
79
142
  | `anyforge_create_initiative` | write | Create a (DRAFT) initiative, optionally under a program |
80
143
  | `anyforge_dispatch_architect` | write | Decompose an initiative into a backlog (→ HIL #1) |
81
144
  | `anyforge_list_repo_index` | read | List the org repo index (activity, coverage, analyzed) — discover codebases to scope |
82
145
  | `anyforge_get_repo_analysis` | read | One repo's coverage / architecture / gap summary |
83
- | `anyforge_analyze_repos` | write | Start Phase-1 analysis for one or more repos |
146
+ | `anyforge_check_dispatch_readiness` | read | Check the repository's Phase 1 + Phase 2 analysis gate before dispatch; does not launch a crew |
147
+ | `anyforge_analyze_repos` | write | Start Phase-1 analysis for one or more repos; Phase 2 follows automatically when Phase 1 completes |
84
148
  | `anyforge_start_coverage_sweep` | write | Paced Phase 1→2 analysis sweep over a program/repo set |
85
149
  | `anyforge_refresh_repo_index` | write | Refresh the repo index + committed-coverage detection now |
150
+ | `anyforge_upload_coverage` | write | Upload test-coverage measurements for one or many repos (e.g. synced from SonarQube) |
151
+ | `anyforge_list_escrow_deposits` | read | List a codebase's (or the company's) escrow deposit ledger |
152
+ | `anyforge_generate_escrow_deposit` | write | Generate a source-escrow deposit bundle for one codebase |
153
+ | `anyforge_list_escrow_scope` | read | List the codebases currently in escrow scope (escrow.enabled) |
154
+ | `anyforge_set_escrow_scope` | write | Bulk-set the "In escrow scope" checkbox across many codebases (repos and/or codebaseIds, up to 1000 per call) |
155
+ | `anyforge_start_escrow_sweep` | write | Seed/inspect a paced fleet-wide escrow deposit sweep |
156
+ | `anyforge_escrow_scoping_report` | read (write if store=true) | Generate the Escode scoping-answers report (markdown); `store=true` persists it to Storage |
157
+ | `anyforge_deliver_escrow_deposit` | write | SFTP a stored deposit bundle to the escrow agent; stamps the ledger with a delivery receipt |
158
+ | `anyforge_ask_oracle` | read | Ask the AnyForge Oracle a workspace question (codebases, releases, decisions, live data from connected integrations); runs the full research loop server-side and returns one cited answer — can take minutes |
159
+ | `anyforge_investigate_repository` | read | Delegate a bounded repository investigation across one to five selected repos; returns an evidence-backed report from indexed code intelligence and analysis docs without exposing raw graph records or live source |
160
+ | `anyforge_list_workflows` | read | List the company's Operator Workflows — reusable multi-step orchestrations (agent / tool / parallel / map / gate steps) with each one's inputs and enabled flag |
161
+ | `anyforge_get_workflow` | read | Get one workflow including its full current spec (steps, inputs, budget) — inspect required inputs before a run |
162
+ | `anyforge_run_workflow` | write | Dispatch a run of a workflow (returns the QUEUED run); runs pause at gate steps for an operator decision |
163
+ | `anyforge_get_workflow_run` | read | Get a workflow run's status and per-step progress; gate decisions are made on the Console run page |
164
+ | `anyforge_resolve_workflow_gate` | approve | Resolve a run paused at a gate (`approve` / `amend` / `reject`; `amend` carries guidance in `comment`) |
165
+ | `anyforge_list_observability_signals` | read | List production-error triage signals (filter by `status`) |
166
+ | `anyforge_accept_observability_signal` | write | Accept a signal into a governed incident under the KTLO program |
167
+ | `anyforge_dismiss_observability_signal` | write | Dismiss a production-error signal as noise |
168
+ | `anyforge_triage_ticket` | read | Run or continue a Support Triage interview — classification, readiness scoring, owning-team routing — and get a paste-ready rendering plus the structured draft; pass the same `sessionId` to continue an interview. Never files anything itself |
169
+ | `anyforge_list_triage_eval_cases` | read | List the company's triage eval cases |
170
+ | `anyforge_upsert_triage_eval_cases` | write | Create or update triage eval cases in bulk; pass an existing case's `id` to update it in place |
171
+ | `anyforge_delete_triage_eval_case` | write | Delete one triage eval case by id |
172
+ | `anyforge_update_triage_eval_case` | write | Edit one triage eval case in place (bulk-edit via `anyforge_upsert_triage_eval_cases`) |
173
+ | `anyforge_run_triage_eval` | write | Run the eval corpus through the real Support Triage Agent; 10 cases or fewer run synchronously, a larger corpus returns a QUEUED run |
174
+ | `anyforge_get_triage_eval_run` | read | Poll a queued triage eval run by id and read its completed result |
175
+
176
+ `anyforge_update_work_item` advertises the complete action enum: `advance`,
177
+ `approve_refinement`, `dispatch`, `complete`, `update`, `reorder`, `archive`,
178
+ `unarchive`, `close-as-fixed`, `reopen`, `mark-incident`, `drop`,
179
+ `confirm-repo`, `assign`, `begin`, `dismiss-automation-suggestion`,
180
+ `expedite`, `link-external`, and `verification`. Use `drop` for an obsolete
181
+ unfinished item and pass `droppedReason` when the reconciliation needs an audit
182
+ explanation. `archive` requires `DONE` or `DROPPED`; if it returns
183
+ `archive_requires_terminal`, drop the item first. `close-as-fixed` instead
184
+ records an external fix and requires `closedReason`; `closedEvidenceUrls`
185
+ optionally adds up to 10 http(s) evidence links. `link-external` records the
186
+ item's key in another tracker (`externalKey`, optional `externalUrl`; `null`
187
+ unlinks). `verification` with `verificationState: "verified"` records the
188
+ client's acceptance of a `DONE` item and needs a key bound to a user; a key
189
+ with no user gets `user_bound_credential_required`.
190
+
191
+ The structured Program Genesis writes are program-scoped. Brief saves are full
192
+ versioned replacements through `anyforge_save_program_brief_version`. Initiative
193
+ closures and batch close-as-fixed operations use `preview` followed by
194
+ `execute` with the short-lived `proposalToken` returned by the preview. A
195
+ successful initiative enrichment returns `changedFields`; a valid request that
196
+ does not change stored data returns `changed: false` and
197
+ `reason: "no_changes_requested"`.
198
+
199
+ With the default analysis gate enabled, Crew dispatches require a connected
200
+ Codebase with both Phase 1 and Phase 2 analysis complete. Use
201
+ `anyforge_analyze_repos` to start Phase 1, then wait for the automatically
202
+ chained Phase 2 before dispatching a work item. The dispatch response identifies
203
+ the missing stage when a repository is not ready.
204
+
205
+ ### Tool metadata: annotations + structured output
206
+
207
+ Every tool advertises 2025-06-18 MCP metadata so clients can present it well:
208
+
209
+ - **Title + behaviour annotations** — a human-readable `title` plus hints
210
+ (`readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) derived
211
+ from the tool's verb, matching the read/write/approve column above. Clients use
212
+ these to, e.g., auto-run read-only tools and confirm before a `delete_*`. They
213
+ are advisory only: the control API still re-checks the key's scopes on every
214
+ call, so annotations never widen access.
215
+ - **Structured output** — every tool declares an `outputSchema` (a JSON object)
216
+ and returns the result as `structuredContent` alongside the human-readable
217
+ text block, so structured-output-aware clients get machine-parseable data.
218
+ Arrays come back as `{ items: [...] }` and prose as `{ text: "…" }`.
219
+
220
+ Both are filled in centrally (`lib/toolMeta`, `lib/toolResult`) so the stdio and
221
+ hosted-HTTP transports advertise and return exactly the same thing.
86
222
 
87
223
  ## Prompts (guided flows)
88
224
 
@@ -92,17 +228,33 @@ MCP clients that support server prompts (e.g. Claude Code surfaces them as
92
228
  | Prompt | Args | What it does |
93
229
  |--------|------|--------------|
94
230
  | `genesis` | `programId?`, `goal?` | Turns the client into the **Program Genesis agent**: it interviews you to scope a program across your codebases (using `anyforge_list_repo_index` / `anyforge_get_repo_analysis`), writes the program brief, then creates one initiative per in-scope codebase and offers to dispatch the architect on each. |
231
+ | `platform_guide` | `topic?` | Loads the static AnyForge platform model, surface map, tool-selection rules, and safety boundaries. Use live tools for current tenant state. |
95
232
 
96
233
  The Genesis flow runs entirely in *your* agent — there's no server-side
97
234
  chat-in-a-tool. The prompt gives your client the persona + interview script;
98
235
  it drives the conversation and calls the tools above as it goes.
99
236
 
237
+ ## Resources
238
+
239
+ Clients that support MCP resources can list and read:
240
+
241
+ | URI | Content |
242
+ |-----|---------|
243
+ | `anyforge://guide/platform` | The portable `anyforge-platform` Agent Skill |
244
+ | `anyforge://guide/platform/references/entity-model.md` | Entity relationships and delivery lifecycle |
245
+ | `anyforge://guide/platform/references/tool-map.md` | Representative tool categories and selection rules |
246
+ | `anyforge://guide/platform/references/operating-boundaries.md` | Identity, evidence, trust, and secret-handling boundaries |
247
+
248
+ The server's bootstrap instructions point clients at the prompt and resource
249
+ when platform context is needed. They are orientation only; permissions and
250
+ current state still come from the authenticated server and live tool results.
251
+
100
252
  ## Example prompts
101
253
 
102
254
  - "What's waiting for my approval in AnyForge?" → `anyforge_list_pending_approvals`
103
255
  - "Show me the plan for approval `abc123` then approve it." → `anyforge_get_approval_detail` → `anyforge_submit_approval`
104
256
  - "Add a P1 bug: rate-limit the export endpoint." → `anyforge_create_work_item`
105
- - "What did crew `xyz` produce? Post a comment asking it to add tests." → `anyforge_get_crew` → `anyforge_post_crew_comment`
257
+ - "What did crew `xyz` produce? Tag Sam on it to review the tests." → `anyforge_get_crew` → `anyforge_post_crew_comment`
106
258
  - "Scope a coverage program across our Go services." → run the `genesis` prompt → it lists repos, scopes, and creates an initiative per service.
107
259
 
108
260
  ## How it works
@@ -114,16 +266,37 @@ Claude CLI ──stdio──▶ MCP server ──HTTPS (Bearer sk_anyforge_…)
114
266
  The `/api/v1/control/*` routes share the exact same service layer as the
115
267
  AnyForge web app, so the CLI and the dashboard behave identically.
116
268
 
269
+ ### Console links in findings
270
+
271
+ The server advertises MCP `instructions` (see `lib/consoleLinks.ts`, mirrored by
272
+ the hosted `/api/mcp` transport) telling every client to present entity ids as
273
+ clickable links to their Console views by default — crew → `/studio?crew={crewId}`,
274
+ work item → `/work?item={workItemId}`, initiative → `/initiatives/{initiativeId}`,
275
+ and so on — never as bare ids. Crew payloads additionally carry an absolute `url`
276
+ field built server-side from the deployment's public origin. The path table is a
277
+ hand copy of the app's single source of truth
278
+ (`app/lib/navigation/entityRoutes.ts`), kept in lock-step by a drift test
279
+ (`__tests__/lib/navigation/entityRoutes.test.ts`) — change them together. The
280
+ Console enforces the viewer's permissions when a link is opened, so linking never
281
+ widens access.
282
+
117
283
  ## Build & publish (maintainers)
118
284
 
119
- The package ships **compiled JS** (`dist/`), so end users can run
120
- `npx -y @anyforge/mcp-server` without a TypeScript toolchain. Source lives
121
- in `index.ts` / `lib/` / `tools/`; `tsc` emits `dist/` (shebang preserved,
122
- `.js` import specifiers already in source for NodeNext).
285
+ The package ships a single **bundled, minified JS** file (`dist/index.js`),
286
+ so end users can run `npx -y @anyforge/mcp-server` without a TypeScript
287
+ toolchain. Source lives in `index.ts` / `lib/` / `tools/`; **esbuild**
288
+ bundles it into one ESM file with the shebang preserved and `node_modules`
289
+ deps left external (`--packages=external`). The bundle is minified — not as
290
+ a security control (a downloaded npm package is always readable), but to keep
291
+ the tarball small; the real trust boundary is the key-authenticated control
292
+ API, and this process holds no secrets. Type-checking is a separate `tsc
293
+ --noEmit` step. `dist/` is git-ignored and rebuilt at publish by
294
+ `prepublishOnly`.
123
295
 
124
296
  ```bash
125
- npm install # includes the typescript devDependency
126
- npm run build # tsc → dist/
297
+ npm install # esbuild + typescript devDependencies
298
+ npm run type-check # tsc --noEmit (types only, no output)
299
+ npm run build # esbuild → dist/index.js (bundled + minified)
127
300
  npm pack --dry-run # verify the tarball: dist/ + README + package.json only
128
301
  ```
129
302