@anyforge/mcp-server 2.0.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 +125 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +65 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/apiClient.d.ts +20 -0
- package/dist/lib/apiClient.js +64 -0
- package/dist/lib/apiClient.js.map +1 -0
- package/dist/lib/credentials.d.ts +20 -0
- package/dist/lib/credentials.js +33 -0
- package/dist/lib/credentials.js.map +1 -0
- package/dist/tools/crews.d.ts +6 -0
- package/dist/tools/crews.js +66 -0
- package/dist/tools/crews.js.map +1 -0
- package/dist/tools/hil.d.ts +7 -0
- package/dist/tools/hil.js +56 -0
- package/dist/tools/hil.js.map +1 -0
- package/dist/tools/initiatives.d.ts +7 -0
- package/dist/tools/initiatives.js +64 -0
- package/dist/tools/initiatives.js.map +1 -0
- package/dist/tools/programs.d.ts +5 -0
- package/dist/tools/programs.js +33 -0
- package/dist/tools/programs.js.map +1 -0
- package/dist/tools/types.d.ts +21 -0
- package/dist/tools/types.js +9 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/work.d.ts +5 -0
- package/dist/tools/work.js +89 -0
- package/dist/tools/work.js.map +1 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# AnyForge MCP Server
|
|
2
|
+
|
|
3
|
+
Drive AnyForge from **Claude CLI** (Claude Code), Cursor, and other MCP
|
|
4
|
+
clients: view and approve **HIL** notifications, read **programs /
|
|
5
|
+
initiatives / work items**, **add and modify** work items, see **crew
|
|
6
|
+
outputs**, and **interact with crews**.
|
|
7
|
+
|
|
8
|
+
The server is a thin client over AnyForge's key-authenticated control
|
|
9
|
+
API (`/api/v1/control/*`). It holds no business logic and never needs a
|
|
10
|
+
Firebase login.
|
|
11
|
+
|
|
12
|
+
> **User-facing setup guide:** [Drive AnyForge from Claude CLI](https://anyforge.ai/docs/mcp-server)
|
|
13
|
+
> (`apps/www/content/docs/mcp-server.md`). This README is the in-repo
|
|
14
|
+
> developer reference; the docs page is the canonical install walkthrough.
|
|
15
|
+
|
|
16
|
+
## 1. Authorise this machine (once)
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx @anyforge/control init
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
This runs the device-auth flow and writes a long-lived `sk_anyforge_…`
|
|
23
|
+
key to `~/.anyforge/credentials`. The MCP server reads that file — so
|
|
24
|
+
you don't put any secret in your MCP config.
|
|
25
|
+
|
|
26
|
+
> The key carries scopes (`read` / `write` / `approve`). A read-only key
|
|
27
|
+
> can list and inspect but can't create work items or approve HILs.
|
|
28
|
+
|
|
29
|
+
## 2. Register with Claude CLI
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
claude mcp add anyforge -- npx tsx /ABS/PATH/TO/packages/control/mcp-server/index.ts
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
- Add `--scope user` to make it available in every project, or
|
|
36
|
+
`--scope project` to commit it to this repo's `.mcp.json`.
|
|
37
|
+
- No env vars are required — credentials come from
|
|
38
|
+
`~/.anyforge/credentials`.
|
|
39
|
+
|
|
40
|
+
To point at a non-prod deployment or inline a key instead of using the
|
|
41
|
+
credentials file, pass env vars:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
claude mcp add anyforge \
|
|
45
|
+
-e ANYFORGE_API_URL=https://staging.anyforge.ai \
|
|
46
|
+
-e ANYFORGE_API_TOKEN=sk_anyforge_xxx \
|
|
47
|
+
-- npx tsx /ABS/PATH/TO/packages/control/mcp-server/index.ts
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Cursor / other clients
|
|
51
|
+
|
|
52
|
+
Use the equivalent stdio MCP config (`command: npx`, `args: ["tsx",
|
|
53
|
+
"…/index.ts"]`). The same credential resolution applies.
|
|
54
|
+
|
|
55
|
+
## Tools
|
|
56
|
+
|
|
57
|
+
| Tool | Scope | Description |
|
|
58
|
+
|------|-------|-------------|
|
|
59
|
+
| `anyforge_list_pending_approvals` | read | List HIL approvals awaiting a decision |
|
|
60
|
+
| `anyforge_get_approval_detail` | read | Read one approval's plan / ADR / security context |
|
|
61
|
+
| `anyforge_submit_approval` | approve | Approve or reject a HIL (resumes the crew) |
|
|
62
|
+
| `anyforge_list_programs` | read | List programs |
|
|
63
|
+
| `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 |
|
|
66
|
+
| `anyforge_approve_backlog` | approve | Approve a proposed backlog (HIL #1) |
|
|
67
|
+
| `anyforge_approve_task_proposal` | approve | Approve a mid-flight task proposal |
|
|
68
|
+
| `anyforge_list_work_items` | read | List backlog items + crew state |
|
|
69
|
+
| `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 |
|
|
72
|
+
| `anyforge_get_crew` | read | Crew state + recent outputs + comments |
|
|
73
|
+
| `anyforge_post_crew_comment` | write | Comment on / @-mention in a crew |
|
|
74
|
+
| `anyforge_resume_crew` | approve | Resume a PAUSED/HALTED crew |
|
|
75
|
+
| `anyforge_halt_crew` | approve | Halt a crew |
|
|
76
|
+
|
|
77
|
+
## Example prompts
|
|
78
|
+
|
|
79
|
+
- "What's waiting for my approval in AnyForge?" → `anyforge_list_pending_approvals`
|
|
80
|
+
- "Show me the plan for approval `abc123` then approve it." → `anyforge_get_approval_detail` → `anyforge_submit_approval`
|
|
81
|
+
- "Add a P1 bug: rate-limit the export endpoint." → `anyforge_create_work_item`
|
|
82
|
+
- "What did crew `xyz` produce? Post a comment asking it to add tests." → `anyforge_get_crew` → `anyforge_post_crew_comment`
|
|
83
|
+
|
|
84
|
+
## How it works
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
Claude CLI ──stdio──▶ MCP server ──HTTPS (Bearer sk_anyforge_…)──▶ /api/v1/control/* ──▶ shared control services
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
The `/api/v1/control/*` routes share the exact same service layer as the
|
|
91
|
+
AnyForge web app, so the CLI and the dashboard behave identically.
|
|
92
|
+
|
|
93
|
+
## Build & publish (maintainers)
|
|
94
|
+
|
|
95
|
+
The package ships **compiled JS** (`dist/`), so end users can run
|
|
96
|
+
`npx -y @anyforge/mcp-server` without a TypeScript toolchain. Source lives
|
|
97
|
+
in `index.ts` / `lib/` / `tools/`; `tsc` emits `dist/` (shebang preserved,
|
|
98
|
+
`.js` import specifiers already in source for NodeNext).
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm install # includes the typescript devDependency
|
|
102
|
+
npm run build # tsc → dist/
|
|
103
|
+
npm pack --dry-run # verify the tarball: dist/ + README + package.json only
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Publishing is automated. **Push a `mcp-server-v<version>` tag** and the
|
|
107
|
+
`.github/workflows/publish-mcp-server.yml` workflow builds and runs
|
|
108
|
+
`npm publish` (scoped public). Keep the tag version in sync with
|
|
109
|
+
`package.json`:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
cd packages/control/mcp-server
|
|
113
|
+
npm version patch # bumps package.json, e.g. 2.0.0 → 2.0.1
|
|
114
|
+
git commit -am "chore(mcp): release mcp-server vX.Y.Z" # if not committed by npm version
|
|
115
|
+
git tag mcp-server-v$(node -p "require('./package.json').version")
|
|
116
|
+
git push origin main --tags
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
> The workflow needs an `NPM_TOKEN` repo secret (an npm **automation**
|
|
120
|
+
> token for an account with publish rights on the `@anyforge` scope). One-
|
|
121
|
+
> time setup: `npm token create --read-only=false`, then add it under
|
|
122
|
+
> GitHub → Settings → Secrets → Actions as `NPM_TOKEN`.
|
|
123
|
+
>
|
|
124
|
+
> To publish manually instead: `npm login && npm publish` from this
|
|
125
|
+
> directory (`prepublishOnly` rebuilds `dist/` first).
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AnyForge MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes AnyForge platform control as MCP tools so Claude CLI (Claude
|
|
6
|
+
* Code), Cursor, and other MCP clients can drive the platform: view and
|
|
7
|
+
* approve HIL notifications, read programs / initiatives / work items,
|
|
8
|
+
* add and modify work items, see crew outputs, and interact with crews.
|
|
9
|
+
*
|
|
10
|
+
* This process holds ZERO business logic — every tool is a thin call to
|
|
11
|
+
* the key-authenticated control API (/api/v1/control/*). Auth is the
|
|
12
|
+
* long-lived `sk_anyforge_` key from `~/.anyforge/credentials` (written
|
|
13
|
+
* by `npx @anyforge/control init`) or the ANYFORGE_API_TOKEN env var.
|
|
14
|
+
*
|
|
15
|
+
* Register with Claude CLI:
|
|
16
|
+
* claude mcp add anyforge -- npx tsx <abs path>/index.ts
|
|
17
|
+
*
|
|
18
|
+
* See README.md for full setup.
|
|
19
|
+
*/
|
|
20
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* AnyForge MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Exposes AnyForge platform control as MCP tools so Claude CLI (Claude
|
|
6
|
+
* Code), Cursor, and other MCP clients can drive the platform: view and
|
|
7
|
+
* approve HIL notifications, read programs / initiatives / work items,
|
|
8
|
+
* add and modify work items, see crew outputs, and interact with crews.
|
|
9
|
+
*
|
|
10
|
+
* This process holds ZERO business logic — every tool is a thin call to
|
|
11
|
+
* the key-authenticated control API (/api/v1/control/*). Auth is the
|
|
12
|
+
* long-lived `sk_anyforge_` key from `~/.anyforge/credentials` (written
|
|
13
|
+
* by `npx @anyforge/control init`) or the ANYFORGE_API_TOKEN env var.
|
|
14
|
+
*
|
|
15
|
+
* Register with Claude CLI:
|
|
16
|
+
* claude mcp add anyforge -- npx tsx <abs path>/index.ts
|
|
17
|
+
*
|
|
18
|
+
* See README.md for full setup.
|
|
19
|
+
*/
|
|
20
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
21
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
22
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
23
|
+
import { hilTools } from './tools/hil.js';
|
|
24
|
+
import { workTools } from './tools/work.js';
|
|
25
|
+
import { initiativeTools } from './tools/initiatives.js';
|
|
26
|
+
import { programTools } from './tools/programs.js';
|
|
27
|
+
import { crewTools } from './tools/crews.js';
|
|
28
|
+
// ─── Assemble the tool registry ──────────────────────────────────────
|
|
29
|
+
const MODULES = [hilTools, workTools, initiativeTools, programTools, crewTools];
|
|
30
|
+
const TOOLS = MODULES.flatMap(m => m.tools);
|
|
31
|
+
const HANDLERS = Object.assign({}, ...MODULES.map(m => m.handlers));
|
|
32
|
+
// ─── Server setup ────────────────────────────────────────────────────
|
|
33
|
+
const server = new Server({ name: 'anyforge', version: '2.0.0' }, { capabilities: { tools: {} } });
|
|
34
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
35
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
36
|
+
const { name, arguments: args } = request.params;
|
|
37
|
+
const handler = HANDLERS[name];
|
|
38
|
+
if (!handler) {
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: 'text', text: `Error: unknown tool "${name}"` }],
|
|
41
|
+
isError: true,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const result = await handler((args ?? {}));
|
|
46
|
+
return { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] };
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
return {
|
|
50
|
+
content: [{ type: 'text', text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
51
|
+
isError: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
// ─── Start ───────────────────────────────────────────────────────────
|
|
56
|
+
async function main() {
|
|
57
|
+
const transport = new StdioServerTransport();
|
|
58
|
+
await server.connect(transport);
|
|
59
|
+
console.error(`AnyForge MCP Server started (stdio, ${TOOLS.length} tools)`);
|
|
60
|
+
}
|
|
61
|
+
main().catch(err => {
|
|
62
|
+
console.error('MCP Server failed to start:', err);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
});
|
|
65
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin typed client over the AnyForge control API (/api/v1/control/*).
|
|
3
|
+
*
|
|
4
|
+
* The MCP server holds zero business logic — every tool handler calls
|
|
5
|
+
* callControl() and forwards the JSON. Auth is the long-lived
|
|
6
|
+
* sk_anyforge_ key resolved once and cached for the process lifetime.
|
|
7
|
+
*
|
|
8
|
+
* The control API speaks a `{ ok, data | error }` envelope. We unwrap
|
|
9
|
+
* it: on `ok` return `data`; otherwise throw a ControlApiError carrying
|
|
10
|
+
* the stable error code so the MCP layer surfaces an actionable message
|
|
11
|
+
* to Claude instead of a raw HTTP failure.
|
|
12
|
+
*/
|
|
13
|
+
export declare class ControlApiError extends Error {
|
|
14
|
+
readonly code: string;
|
|
15
|
+
readonly status: number;
|
|
16
|
+
constructor(code: string, status: number, detail?: string);
|
|
17
|
+
}
|
|
18
|
+
export declare function callControl<T = unknown>(method: 'GET' | 'POST' | 'PATCH' | 'DELETE', path: string, body?: unknown): Promise<T>;
|
|
19
|
+
/** Build a `?a=b&c=d` query string from defined values only. */
|
|
20
|
+
export declare function qs(params: Record<string, string | number | boolean | undefined>): string;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { resolveCredentials } from './credentials.js';
|
|
2
|
+
/**
|
|
3
|
+
* Thin typed client over the AnyForge control API (/api/v1/control/*).
|
|
4
|
+
*
|
|
5
|
+
* The MCP server holds zero business logic — every tool handler calls
|
|
6
|
+
* callControl() and forwards the JSON. Auth is the long-lived
|
|
7
|
+
* sk_anyforge_ key resolved once and cached for the process lifetime.
|
|
8
|
+
*
|
|
9
|
+
* The control API speaks a `{ ok, data | error }` envelope. We unwrap
|
|
10
|
+
* it: on `ok` return `data`; otherwise throw a ControlApiError carrying
|
|
11
|
+
* the stable error code so the MCP layer surfaces an actionable message
|
|
12
|
+
* to Claude instead of a raw HTTP failure.
|
|
13
|
+
*/
|
|
14
|
+
export class ControlApiError extends Error {
|
|
15
|
+
code;
|
|
16
|
+
status;
|
|
17
|
+
constructor(code, status, detail) {
|
|
18
|
+
super(detail ? `${code}: ${detail}` : code);
|
|
19
|
+
this.name = 'ControlApiError';
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.status = status;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
let cached = null;
|
|
25
|
+
async function creds() {
|
|
26
|
+
if (!cached)
|
|
27
|
+
cached = await resolveCredentials();
|
|
28
|
+
return cached;
|
|
29
|
+
}
|
|
30
|
+
export async function callControl(method, path, body) {
|
|
31
|
+
const { apiKey, endpoint } = await creds();
|
|
32
|
+
const url = `${endpoint.replace(/\/$/, '')}/api/v1/control${path}`;
|
|
33
|
+
const res = await fetch(url, {
|
|
34
|
+
method,
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
Authorization: `Bearer ${apiKey}`,
|
|
38
|
+
},
|
|
39
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
40
|
+
});
|
|
41
|
+
let json;
|
|
42
|
+
try {
|
|
43
|
+
json = await res.json();
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new ControlApiError('invalid_response', res.status, `non-JSON response from ${url}`);
|
|
47
|
+
}
|
|
48
|
+
if (!res.ok || json.ok === false) {
|
|
49
|
+
const code = typeof json.error === 'string' ? json.error : `http_${res.status}`;
|
|
50
|
+
const detail = typeof json.message === 'string' ? json.message
|
|
51
|
+
: typeof json.detail === 'string' ? json.detail
|
|
52
|
+
: undefined;
|
|
53
|
+
throw new ControlApiError(code, res.status, detail);
|
|
54
|
+
}
|
|
55
|
+
return json.data;
|
|
56
|
+
}
|
|
57
|
+
/** Build a `?a=b&c=d` query string from defined values only. */
|
|
58
|
+
export function qs(params) {
|
|
59
|
+
const pairs = Object.entries(params)
|
|
60
|
+
.filter(([, v]) => v !== undefined && v !== '')
|
|
61
|
+
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`);
|
|
62
|
+
return pairs.length ? `?${pairs.join('&')}` : '';
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=apiClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../../lib/apiClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAA;AAErD;;;;;;;;;;;GAWG;AAEH,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAC/B,IAAI,CAAQ;IACZ,MAAM,CAAQ;IACvB,YAAY,IAAY,EAAE,MAAc,EAAE,MAAe;QACvD,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC3C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAA;QAC7B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACtB,CAAC;CACF;AAED,IAAI,MAAM,GAAgD,IAAI,CAAA;AAE9D,KAAK,UAAU,KAAK;IAClB,IAAI,CAAC,MAAM;QAAE,MAAM,GAAG,MAAM,kBAAkB,EAAE,CAAA;IAChD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAA2C,EAC3C,IAAY,EACZ,IAAc;IAEd,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,KAAK,EAAE,CAAA;IAC1C,MAAM,GAAG,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,IAAI,EAAE,CAAA;IAElE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,MAAM;QACN,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,MAAM,EAAE;SAClC;QACD,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC9D,CAAC,CAAA;IAEF,IAAI,IAAgF,CAAA;IACpF,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAA;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,eAAe,CAAC,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,0BAA0B,GAAG,EAAE,CAAC,CAAA;IAC5F,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QACjC,MAAM,IAAI,GAAG,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAA;QAC/E,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO;YAC5D,CAAC,CAAC,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;gBAC/C,CAAC,CAAC,SAAS,CAAA;QACb,MAAM,IAAI,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrD,CAAC;IAED,OAAO,IAAI,CAAC,IAAS,CAAA;AACvB,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,EAAE,CAAC,MAA6D;IAC9E,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SACjC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC;SAC9C,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,kBAAkB,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC/E,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;AAClD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the AnyForge control credentials the MCP server uses to talk
|
|
3
|
+
* to /api/v1/control/*.
|
|
4
|
+
*
|
|
5
|
+
* Precedence:
|
|
6
|
+
* 1. Env vars (ANYFORGE_API_TOKEN + ANYFORGE_API_URL) — lets an MCP
|
|
7
|
+
* config inline a key explicitly if desired.
|
|
8
|
+
* 2. ~/.anyforge/credentials — the file written by
|
|
9
|
+
* `npx @anyforge/control init`. This is the default path, so a
|
|
10
|
+
* user who has already run init needs zero secrets in their MCP
|
|
11
|
+
* config: `claude mcp add anyforge -- npx tsx <path>/index.ts`.
|
|
12
|
+
*
|
|
13
|
+
* The key is a long-lived `sk_anyforge_…` token, so there's no
|
|
14
|
+
* expiry/refresh dance — unlike a Firebase ID token.
|
|
15
|
+
*/
|
|
16
|
+
export interface ResolvedCredentials {
|
|
17
|
+
apiKey: string;
|
|
18
|
+
endpoint: string;
|
|
19
|
+
}
|
|
20
|
+
export declare function resolveCredentials(): Promise<ResolvedCredentials>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { promises as fs } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
const DEFAULT_ENDPOINT = 'https://anyforge.ai';
|
|
5
|
+
const FILE = join(homedir(), '.anyforge', 'credentials');
|
|
6
|
+
export async function resolveCredentials() {
|
|
7
|
+
const envKey = process.env.ANYFORGE_API_TOKEN;
|
|
8
|
+
const envUrl = process.env.ANYFORGE_API_URL;
|
|
9
|
+
if (envKey) {
|
|
10
|
+
return { apiKey: envKey, endpoint: envUrl || DEFAULT_ENDPOINT };
|
|
11
|
+
}
|
|
12
|
+
const fromFile = await readCredentialsFile();
|
|
13
|
+
if (fromFile?.apiKey) {
|
|
14
|
+
return {
|
|
15
|
+
apiKey: fromFile.apiKey,
|
|
16
|
+
endpoint: envUrl || fromFile.endpoint || DEFAULT_ENDPOINT,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
throw new Error('No AnyForge credentials found. Run `npx @anyforge/control init` to authorise this machine, ' +
|
|
20
|
+
'or set ANYFORGE_API_TOKEN (and optionally ANYFORGE_API_URL) in the MCP server env.');
|
|
21
|
+
}
|
|
22
|
+
async function readCredentialsFile() {
|
|
23
|
+
try {
|
|
24
|
+
const text = await fs.readFile(FILE, 'utf8');
|
|
25
|
+
return JSON.parse(text);
|
|
26
|
+
}
|
|
27
|
+
catch (err) {
|
|
28
|
+
if (err.code === 'ENOENT')
|
|
29
|
+
return null;
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../lib/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAA;AACnC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AA6B3B,MAAM,gBAAgB,GAAG,qBAAqB,CAAA;AAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,EAAE,aAAa,CAAC,CAAA;AAExD,MAAM,CAAC,KAAK,UAAU,kBAAkB;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAA;IAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAA;IAE3C,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,gBAAgB,EAAE,CAAA;IACjE,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,mBAAmB,EAAE,CAAA;IAC5C,IAAI,QAAQ,EAAE,MAAM,EAAE,CAAC;QACrB,OAAO;YACL,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,QAAQ,EAAE,MAAM,IAAI,QAAQ,CAAC,QAAQ,IAAI,gBAAgB;SAC1D,CAAA;IACH,CAAC;IAED,MAAM,IAAI,KAAK,CACb,6FAA6F;QAC7F,oFAAoF,CACrF,CAAA;AACH,CAAC;AAED,KAAK,UAAU,mBAAmB;IAChC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;QAC5C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAA;IAC5C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAA;QACjE,MAAM,GAAG,CAAA;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { callControl, qs } from '../lib/apiClient.js';
|
|
2
|
+
/**
|
|
3
|
+
* Crew tools — see crew outputs and interact (operator comments,
|
|
4
|
+
* resume, halt).
|
|
5
|
+
*/
|
|
6
|
+
export const crewTools = {
|
|
7
|
+
tools: [
|
|
8
|
+
{
|
|
9
|
+
name: 'anyforge_get_crew',
|
|
10
|
+
description: 'Get a crew with its recent chat messages (the crew output) and operator comments. ' +
|
|
11
|
+
'Use this to see what a crew produced and where it stands.',
|
|
12
|
+
inputSchema: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
properties: {
|
|
15
|
+
crewId: { type: 'string', description: 'The crew id.' },
|
|
16
|
+
messages: { type: 'number', description: 'How many recent chat/comment entries (default 50, max 200).' },
|
|
17
|
+
},
|
|
18
|
+
required: ['crewId'],
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'anyforge_post_crew_comment',
|
|
23
|
+
description: 'Post an operator comment on a crew (optionally @-mentioning teammates by uid). ' +
|
|
24
|
+
'Requires `write` scope.',
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: 'object',
|
|
27
|
+
properties: {
|
|
28
|
+
crewId: { type: 'string', description: 'The crew id.' },
|
|
29
|
+
body: { type: 'string', description: 'Comment text (max 4000 chars).' },
|
|
30
|
+
messageId: { type: 'string', description: 'Optional crewChat message id to anchor the comment to.' },
|
|
31
|
+
mentionedUids: { type: 'array', items: { type: 'string' }, description: 'Optional uids to mention.' },
|
|
32
|
+
},
|
|
33
|
+
required: ['crewId', 'body'],
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'anyforge_resume_crew',
|
|
38
|
+
description: 'Resume a PAUSED or HALTED crew from its last checkpoint. Requires `approve` scope.',
|
|
39
|
+
inputSchema: {
|
|
40
|
+
type: 'object',
|
|
41
|
+
properties: { crewId: { type: 'string', description: 'The crew id.' } },
|
|
42
|
+
required: ['crewId'],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'anyforge_halt_crew',
|
|
47
|
+
description: 'Halt a crew (terminal stop). Idempotent on already-finished crews. Requires `approve` scope.',
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: { crewId: { type: 'string', description: 'The crew id.' } },
|
|
51
|
+
required: ['crewId'],
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
],
|
|
55
|
+
handlers: {
|
|
56
|
+
anyforge_get_crew: args => callControl('GET', `/crews/${encodeURIComponent(String(args.crewId))}${qs({ messages: args.messages })}`),
|
|
57
|
+
anyforge_post_crew_comment: args => callControl('POST', `/crews/${encodeURIComponent(String(args.crewId))}/comments`, {
|
|
58
|
+
body: args.body,
|
|
59
|
+
...(args.messageId ? { messageId: args.messageId } : {}),
|
|
60
|
+
...(Array.isArray(args.mentionedUids) ? { mentionedUids: args.mentionedUids } : {}),
|
|
61
|
+
}),
|
|
62
|
+
anyforge_resume_crew: args => callControl('POST', `/crews/${encodeURIComponent(String(args.crewId))}/resume`),
|
|
63
|
+
anyforge_halt_crew: args => callControl('POST', `/crews/${encodeURIComponent(String(args.crewId))}/halt`),
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=crews.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crews.js","sourceRoot":"","sources":["../../tools/crews.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { callControl, qs } from '../lib/apiClient.js';
|
|
2
|
+
/**
|
|
3
|
+
* HIL (human-in-the-loop) approval tools — the headline capability:
|
|
4
|
+
* list what's awaiting the operator, read its context, and approve /
|
|
5
|
+
* reject from the CLI.
|
|
6
|
+
*/
|
|
7
|
+
export const hilTools = {
|
|
8
|
+
tools: [
|
|
9
|
+
{
|
|
10
|
+
name: 'anyforge_list_pending_approvals',
|
|
11
|
+
description: 'List HIL approvals awaiting an operator decision for your company. Returns each ' +
|
|
12
|
+
'approval id, the crew it belongs to, plan summary, and the architecture / security ' +
|
|
13
|
+
'context. Use this to see what needs your sign-off.',
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: 'object',
|
|
16
|
+
properties: {
|
|
17
|
+
limit: { type: 'number', description: 'Max approvals to return (default 50, max 200).' },
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'anyforge_get_approval_detail',
|
|
23
|
+
description: 'Get the full detail of a single HIL approval by id (plan, ADR, security audit).',
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
approvalId: { type: 'string', description: 'The HIL approval id.' },
|
|
28
|
+
},
|
|
29
|
+
required: ['approvalId'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'anyforge_submit_approval',
|
|
34
|
+
description: 'Submit a decision on a HIL approval. APPROVED resumes the crew past the gate; ' +
|
|
35
|
+
'REJECTED sends it back. Requires a key with the `approve` scope.',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
approvalId: { type: 'string', description: 'The HIL approval id.' },
|
|
40
|
+
decision: { type: 'string', description: "'APPROVED' or 'REJECTED'." },
|
|
41
|
+
notes: { type: 'string', description: 'Optional reviewer notes (shown in the audit trail).' },
|
|
42
|
+
},
|
|
43
|
+
required: ['approvalId', 'decision'],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
handlers: {
|
|
48
|
+
anyforge_list_pending_approvals: args => callControl('GET', `/hil${qs({ limit: args.limit })}`),
|
|
49
|
+
anyforge_get_approval_detail: args => callControl('GET', `/hil/${encodeURIComponent(String(args.approvalId))}`),
|
|
50
|
+
anyforge_submit_approval: args => callControl('POST', `/hil/${encodeURIComponent(String(args.approvalId))}`, {
|
|
51
|
+
decision: args.decision,
|
|
52
|
+
...(args.notes ? { notes: args.notes } : {}),
|
|
53
|
+
}),
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=hil.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hil.js","sourceRoot":"","sources":["../../tools/hil.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAA;AAGrD;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAe;IAClC,KAAK,EAAE;QACL;YACE,IAAI,EAAE,iCAAiC;YACvC,WAAW,EACT,kFAAkF;gBAClF,qFAAqF;gBACrF,oDAAoD;YACtD,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gDAAgD,EAAE;iBACzF;aACF;SACF;QACD;YACE,IAAI,EAAE,8BAA8B;YACpC,WAAW,EAAE,iFAAiF;YAC9F,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE;iBACpE;gBACD,QAAQ,EAAE,CAAC,YAAY,CAAC;aACzB;SACF;QACD;YACE,IAAI,EAAE,0BAA0B;YAChC,WAAW,EACT,gFAAgF;gBAChF,kEAAkE;YACpE,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,sBAAsB,EAAE;oBACnE,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,2BAA2B,EAAE;oBACtE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qDAAqD,EAAE;iBAC9F;gBACD,QAAQ,EAAE,CAAC,YAAY,EAAE,UAAU,CAAC;aACrC;SACF;KACF;IACD,QAAQ,EAAE;QACR,+BAA+B,EAAE,IAAI,CAAC,EAAE,CACtC,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAA2B,EAAE,CAAC,EAAE,CAAC;QAC9E,4BAA4B,EAAE,IAAI,CAAC,EAAE,CACnC,WAAW,CAAC,KAAK,EAAE,QAAQ,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,CAAC;QAC3E,wBAAwB,EAAE,IAAI,CAAC,EAAE,CAC/B,WAAW,CAAC,MAAM,EAAE,QAAQ,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE;YACzE,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC7C,CAAC;KACL;CACF,CAAA"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { callControl, qs } from '../lib/apiClient.js';
|
|
2
|
+
/**
|
|
3
|
+
* Initiative tools — read initiatives + their crews/spend, and approve
|
|
4
|
+
* the proposed backlog / mid-flight task proposals (HIL #1 and task
|
|
5
|
+
* proposals).
|
|
6
|
+
*/
|
|
7
|
+
export const initiativeTools = {
|
|
8
|
+
tools: [
|
|
9
|
+
{
|
|
10
|
+
name: 'anyforge_list_initiatives',
|
|
11
|
+
description: 'List initiatives with status, progress, token budget/spend. Optionally filter by a ' +
|
|
12
|
+
'comma-separated status list (DRAFT, BACKLOG_PROPOSED, IN_PROGRESS, COMPLETE, ARCHIVED).',
|
|
13
|
+
inputSchema: {
|
|
14
|
+
type: 'object',
|
|
15
|
+
properties: {
|
|
16
|
+
status: { type: 'string', description: 'Comma-separated InitiativeStatus filter.' },
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: 'anyforge_get_initiative',
|
|
22
|
+
description: 'Get an initiative with its crews, lifetime spend, and daily burn-down series.',
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
properties: { initiativeId: { type: 'string', description: 'The initiative id.' } },
|
|
26
|
+
required: ['initiativeId'],
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: 'anyforge_approve_backlog',
|
|
31
|
+
description: 'Approve the proposed backlog for an initiative (HIL #1). Promotes its BACKLOG items to ' +
|
|
32
|
+
'READY and moves the initiative to IN_PROGRESS. Requires `approve` scope.',
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: 'object',
|
|
35
|
+
properties: { initiativeId: { type: 'string', description: 'The initiative id.' } },
|
|
36
|
+
required: ['initiativeId'],
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'anyforge_approve_task_proposal',
|
|
41
|
+
description: 'Approve a mid-flight task proposal card, materialising a READY work item. Requires ' +
|
|
42
|
+
'`approve` scope.',
|
|
43
|
+
inputSchema: {
|
|
44
|
+
type: 'object',
|
|
45
|
+
properties: {
|
|
46
|
+
initiativeId: { type: 'string', description: 'The initiative id.' },
|
|
47
|
+
crewId: { type: 'string', description: 'The crew whose chat holds the proposal card.' },
|
|
48
|
+
messageId: { type: 'string', description: 'The task_proposal chat message id.' },
|
|
49
|
+
},
|
|
50
|
+
required: ['initiativeId', 'crewId', 'messageId'],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
],
|
|
54
|
+
handlers: {
|
|
55
|
+
anyforge_list_initiatives: args => callControl('GET', `/initiatives${qs({ status: args.status })}`),
|
|
56
|
+
anyforge_get_initiative: args => callControl('GET', `/initiatives/${encodeURIComponent(String(args.initiativeId))}`),
|
|
57
|
+
anyforge_approve_backlog: args => callControl('POST', `/initiatives/${encodeURIComponent(String(args.initiativeId))}/approve-backlog`),
|
|
58
|
+
anyforge_approve_task_proposal: args => callControl('POST', `/initiatives/${encodeURIComponent(String(args.initiativeId))}/approve-task-proposal`, {
|
|
59
|
+
crewId: args.crewId,
|
|
60
|
+
messageId: args.messageId,
|
|
61
|
+
}),
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
//# sourceMappingURL=initiatives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initiatives.js","sourceRoot":"","sources":["../../tools/initiatives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAA;AAGrD;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAe;IACzC,KAAK,EAAE;QACL;YACE,IAAI,EAAE,2BAA2B;YACjC,WAAW,EACT,qFAAqF;gBACrF,yFAAyF;YAC3F,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,0CAA0C,EAAE;iBACpF;aACF;SACF;QACD;YACE,IAAI,EAAE,yBAAyB;YAC/B,WAAW,EAAE,+EAA+E;YAC5F,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE,EAAE;gBACnF,QAAQ,EAAE,CAAC,cAAc,CAAC;aAC3B;SACF;QACD;YACE,IAAI,EAAE,0BAA0B;YAChC,WAAW,EACT,yFAAyF;gBACzF,0EAA0E;YAC5E,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE,EAAE;gBACnF,QAAQ,EAAE,CAAC,cAAc,CAAC;aAC3B;SACF;QACD;YACE,IAAI,EAAE,gCAAgC;YACtC,WAAW,EACT,qFAAqF;gBACrF,kBAAkB;YACpB,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,YAAY,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oBAAoB,EAAE;oBACnE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,8CAA8C,EAAE;oBACvF,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,oCAAoC,EAAE;iBACjF;gBACD,QAAQ,EAAE,CAAC,cAAc,EAAE,QAAQ,EAAE,WAAW,CAAC;aAClD;SACF;KACF;IACD,QAAQ,EAAE;QACR,yBAAyB,EAAE,IAAI,CAAC,EAAE,CAChC,WAAW,CAAC,KAAK,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAA4B,EAAE,CAAC,EAAE,CAAC;QACxF,uBAAuB,EAAE,IAAI,CAAC,EAAE,CAC9B,WAAW,CAAC,KAAK,EAAE,gBAAgB,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;QACrF,wBAAwB,EAAE,IAAI,CAAC,EAAE,CAC/B,WAAW,CAAC,MAAM,EAAE,gBAAgB,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,kBAAkB,CAAC;QACtG,8BAA8B,EAAE,IAAI,CAAC,EAAE,CACrC,WAAW,CAAC,MAAM,EAAE,gBAAgB,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,wBAAwB,EAAE;YACzG,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,SAAS,EAAE,IAAI,CAAC,SAAS;SAC1B,CAAC;KACL;CACF,CAAA"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { callControl, qs } from '../lib/apiClient.js';
|
|
2
|
+
/**
|
|
3
|
+
* Program tools — read the cross-initiative planning layer.
|
|
4
|
+
*/
|
|
5
|
+
export const programTools = {
|
|
6
|
+
tools: [
|
|
7
|
+
{
|
|
8
|
+
name: 'anyforge_list_programs',
|
|
9
|
+
description: 'List programs (the cross-initiative planning grouping) with status and owner. ' +
|
|
10
|
+
'Optionally filter by comma-separated status (PLANNING, IN_PROGRESS, COMPLETE, CANCELLED).',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
status: { type: 'string', description: 'Comma-separated ProgramStatus filter.' },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'anyforge_get_program',
|
|
20
|
+
description: 'Get a single program by id.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: { programId: { type: 'string', description: 'The program id.' } },
|
|
24
|
+
required: ['programId'],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
handlers: {
|
|
29
|
+
anyforge_list_programs: args => callControl('GET', `/programs${qs({ status: args.status })}`),
|
|
30
|
+
anyforge_get_program: args => callControl('GET', `/programs/${encodeURIComponent(String(args.programId))}`),
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=programs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"programs.js","sourceRoot":"","sources":["../../tools/programs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAA;AAGrD;;GAEG;AACH,MAAM,CAAC,MAAM,YAAY,GAAe;IACtC,KAAK,EAAE;QACL;YACE,IAAI,EAAE,wBAAwB;YAC9B,WAAW,EACT,gFAAgF;gBAChF,2FAA2F;YAC7F,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE;oBACV,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,uCAAuC,EAAE;iBACjF;aACF;SACF;QACD;YACE,IAAI,EAAE,sBAAsB;YAC5B,WAAW,EAAE,6BAA6B;YAC1C,WAAW,EAAE;gBACX,IAAI,EAAE,QAAQ;gBACd,UAAU,EAAE,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iBAAiB,EAAE,EAAE;gBAC7E,QAAQ,EAAE,CAAC,WAAW,CAAC;aACxB;SACF;KACF;IACD,QAAQ,EAAE;QACR,sBAAsB,EAAE,IAAI,CAAC,EAAE,CAC7B,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAA4B,EAAE,CAAC,EAAE,CAAC;QACrF,oBAAoB,EAAE,IAAI,CAAC,EAAE,CAC3B,WAAW,CAAC,KAAK,EAAE,aAAa,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC;KAChF;CACF,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared shapes for the MCP tool modules. Each domain file exports a
|
|
3
|
+
* `tools` array (the MCP tool definitions) and a `handlers` map
|
|
4
|
+
* (name → async function returning JSON-serialisable data). index.ts
|
|
5
|
+
* merges them and JSON-stringifies handler results into MCP text
|
|
6
|
+
* content.
|
|
7
|
+
*/
|
|
8
|
+
export interface ToolDef {
|
|
9
|
+
name: string;
|
|
10
|
+
description: string;
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object';
|
|
13
|
+
properties: Record<string, unknown>;
|
|
14
|
+
required?: string[];
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export type ToolHandler = (args: Record<string, unknown>) => Promise<unknown>;
|
|
18
|
+
export interface ToolModule {
|
|
19
|
+
tools: ToolDef[];
|
|
20
|
+
handlers: Record<string, ToolHandler>;
|
|
21
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared shapes for the MCP tool modules. Each domain file exports a
|
|
3
|
+
* `tools` array (the MCP tool definitions) and a `handlers` map
|
|
4
|
+
* (name → async function returning JSON-serialisable data). index.ts
|
|
5
|
+
* merges them and JSON-stringifies handler results into MCP text
|
|
6
|
+
* content.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../tools/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { callControl, qs } from '../lib/apiClient.js';
|
|
2
|
+
/**
|
|
3
|
+
* Work-item tools — read the backlog and add / modify items.
|
|
4
|
+
*/
|
|
5
|
+
export const workTools = {
|
|
6
|
+
tools: [
|
|
7
|
+
{
|
|
8
|
+
name: 'anyforge_list_work_items',
|
|
9
|
+
description: 'List work items in the AnyForge backlog with status, priority, and any linked crew ' +
|
|
10
|
+
'state. By default archived items are excluded.',
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
includeArchived: { type: 'boolean', description: 'Include archived items (default false).' },
|
|
15
|
+
},
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: 'anyforge_get_work_item',
|
|
20
|
+
description: 'Get a single work item by id.',
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
properties: { itemId: { type: 'string', description: 'The work item id.' } },
|
|
24
|
+
required: ['itemId'],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'anyforge_create_work_item',
|
|
29
|
+
description: 'Create a new work item in the backlog (status BACKLOG). Requires `write` scope.',
|
|
30
|
+
inputSchema: {
|
|
31
|
+
type: 'object',
|
|
32
|
+
properties: {
|
|
33
|
+
title: { type: 'string', description: 'Work item title.' },
|
|
34
|
+
description: { type: 'string', description: 'Detailed description.' },
|
|
35
|
+
type: { type: 'string', description: 'FEATURE, BUG, ENHANCEMENT, KTLO, TECH_DEBT, INCIDENT.' },
|
|
36
|
+
priority: { type: 'string', description: 'P0, P1, P2, P3.' },
|
|
37
|
+
acceptanceCriteria: { type: 'string', description: 'Optional acceptance criteria.' },
|
|
38
|
+
initiativeId: { type: 'string', description: 'Optional parent initiative id (allocates a {CODE}-NNN).' },
|
|
39
|
+
},
|
|
40
|
+
required: ['title', 'type', 'priority'],
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'anyforge_update_work_item',
|
|
45
|
+
description: 'Mutate a work item. `action` selects the operation: ' +
|
|
46
|
+
"'update' (edit title/description/type/priority/acceptanceCriteria/dependsOn), " +
|
|
47
|
+
"'advance' (BACKLOG→REFINED), 'approve_refinement' (REFINED→READY), " +
|
|
48
|
+
"'dispatch' (requires crewId), 'complete', 'archive', 'unarchive', 'reorder' (sortOrder), " +
|
|
49
|
+
"'close-as-fixed' (requires closedReason). Requires `write` scope.",
|
|
50
|
+
inputSchema: {
|
|
51
|
+
type: 'object',
|
|
52
|
+
properties: {
|
|
53
|
+
itemId: { type: 'string', description: 'The work item id.' },
|
|
54
|
+
action: { type: 'string', description: 'The mutation to apply (see description).' },
|
|
55
|
+
title: { type: 'string' },
|
|
56
|
+
description: { type: 'string' },
|
|
57
|
+
type: { type: 'string' },
|
|
58
|
+
priority: { type: 'string' },
|
|
59
|
+
acceptanceCriteria: { type: 'string' },
|
|
60
|
+
bumpKind: { type: 'string', description: 'breaking | feat | fix | none.' },
|
|
61
|
+
dependsOn: { type: 'array', items: { type: 'string' }, description: 'Work-item ids this depends on.' },
|
|
62
|
+
crewId: { type: 'string', description: "For action='dispatch'." },
|
|
63
|
+
crewType: { type: 'string' },
|
|
64
|
+
sortOrder: { type: 'number', description: "For action='reorder'." },
|
|
65
|
+
closedReason: { type: 'string', description: "For action='close-as-fixed'." },
|
|
66
|
+
closedAsFixedByWorkItemId: { type: 'string' },
|
|
67
|
+
},
|
|
68
|
+
required: ['itemId', 'action'],
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
handlers: {
|
|
73
|
+
anyforge_list_work_items: args => callControl('GET', `/work${qs({ includeArchived: args.includeArchived })}`),
|
|
74
|
+
anyforge_get_work_item: args => callControl('GET', `/work/${encodeURIComponent(String(args.itemId))}`),
|
|
75
|
+
anyforge_create_work_item: args => callControl('POST', '/work', {
|
|
76
|
+
title: args.title,
|
|
77
|
+
description: args.description,
|
|
78
|
+
type: args.type,
|
|
79
|
+
priority: args.priority,
|
|
80
|
+
...(args.acceptanceCriteria ? { acceptanceCriteria: args.acceptanceCriteria } : {}),
|
|
81
|
+
...(args.initiativeId ? { initiativeId: args.initiativeId } : {}),
|
|
82
|
+
}),
|
|
83
|
+
anyforge_update_work_item: args => {
|
|
84
|
+
const { itemId, ...rest } = args;
|
|
85
|
+
return callControl('PATCH', `/work/${encodeURIComponent(String(itemId))}`, rest);
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
//# sourceMappingURL=work.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work.js","sourceRoot":"","sources":["../../tools/work.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@anyforge/mcp-server",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "AnyForge MCP Server — drive AnyForge (HIL approvals, initiatives, work items, crews) from Claude CLI, Cursor, and other MCP clients",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"anyforge-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"type-check": "tsc --noEmit",
|
|
20
|
+
"prepublishOnly": "npm run build",
|
|
21
|
+
"start": "npx tsx index.ts",
|
|
22
|
+
"dev": "npx tsx index.ts"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"anyforge",
|
|
29
|
+
"mcp",
|
|
30
|
+
"model-context-protocol",
|
|
31
|
+
"claude",
|
|
32
|
+
"claude-code"
|
|
33
|
+
],
|
|
34
|
+
"license": "UNLICENSED",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"typescript": "^5.7.3"
|
|
40
|
+
}
|
|
41
|
+
}
|