substrate-mcp-server 0.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.
Files changed (46) hide show
  1. package/README.md +249 -0
  2. package/dist/config.d.ts +16 -0
  3. package/dist/config.d.ts.map +1 -0
  4. package/dist/config.js +44 -0
  5. package/dist/config.js.map +1 -0
  6. package/dist/index.d.ts +3 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +38 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/prompts.d.ts +7 -0
  11. package/dist/prompts.d.ts.map +1 -0
  12. package/dist/prompts.js +172 -0
  13. package/dist/prompts.js.map +1 -0
  14. package/dist/resources.d.ts +8 -0
  15. package/dist/resources.d.ts.map +1 -0
  16. package/dist/resources.js +82 -0
  17. package/dist/resources.js.map +1 -0
  18. package/dist/substrate-client.d.ts +39 -0
  19. package/dist/substrate-client.d.ts.map +1 -0
  20. package/dist/substrate-client.js +122 -0
  21. package/dist/substrate-client.js.map +1 -0
  22. package/dist/tools/backlog.d.ts +4 -0
  23. package/dist/tools/backlog.d.ts.map +1 -0
  24. package/dist/tools/backlog.js +146 -0
  25. package/dist/tools/backlog.js.map +1 -0
  26. package/dist/tools/get-context.d.ts +11 -0
  27. package/dist/tools/get-context.d.ts.map +1 -0
  28. package/dist/tools/get-context.js +35 -0
  29. package/dist/tools/get-context.js.map +1 -0
  30. package/dist/tools/investigations.d.ts +4 -0
  31. package/dist/tools/investigations.d.ts.map +1 -0
  32. package/dist/tools/investigations.js +148 -0
  33. package/dist/tools/investigations.js.map +1 -0
  34. package/dist/tools/nanopubs.d.ts +12 -0
  35. package/dist/tools/nanopubs.d.ts.map +1 -0
  36. package/dist/tools/nanopubs.js +56 -0
  37. package/dist/tools/nanopubs.js.map +1 -0
  38. package/dist/tools/sync.d.ts +10 -0
  39. package/dist/tools/sync.d.ts.map +1 -0
  40. package/dist/tools/sync.js +34 -0
  41. package/dist/tools/sync.js.map +1 -0
  42. package/dist/types.d.ts +278 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +6 -0
  45. package/dist/types.js.map +1 -0
  46. package/package.json +29 -0
package/README.md ADDED
@@ -0,0 +1,249 @@
1
+ # Substrate MCP Server
2
+
3
+ An MCP (Model Context Protocol) server that connects AI agents to a Substrate room. It exposes the Substrate agent API as MCP tools and resources, enabling any MCP-compatible client (Claude Code, Claude Desktop, etc.) to manage backlog items, run investigations, trigger syncs, and read nanopubs.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # From the repository root
9
+ pnpm install
10
+ pnpm -C packages/mcp-server build
11
+ ```
12
+
13
+ The build produces `dist/index.js`, which is the entry point for the server. The package also registers a `substrate-mcp` binary via `package.json#bin`.
14
+
15
+ ## Configuration
16
+
17
+ The server requires two values and accepts one optional override. Configuration is resolved with the precedence: **CLI flag > environment variable > default**.
18
+
19
+ | Setting | Env var | CLI flag | Required | Default |
20
+ |---------|---------|----------|----------|---------|
21
+ | Substrate instance URL | `SUBSTRATE_API_URL` (or `SUBSTRATE_BASE_URL`) | `--api-url` | Yes | — |
22
+ | Agent bearer token | `SUBSTRATE_API_TOKEN` | `--token` | Yes | — |
23
+ | MCP server name | `SUBSTRATE_SERVER_NAME` | `--name` | No | `substrate-mcp` |
24
+
25
+ Copy `.env.example` to `.env` and fill in the values, or pass them as CLI flags.
26
+
27
+ ### Getting your agent token
28
+
29
+ 1. Open a Substrate room in the web UI.
30
+ 2. Go to **Settings > Agent Keys**.
31
+ 3. Create a new agent key and copy the token. The token is shown only once.
32
+
33
+ ## Usage with Claude Code
34
+
35
+ Add the server to your Claude Code MCP configuration. In `.claude/settings.json` (project-level) or `~/.claude/settings.json` (global):
36
+
37
+ ```json
38
+ {
39
+ "mcpServers": {
40
+ "substrate": {
41
+ "command": "node",
42
+ "args": ["/absolute/path/to/packages/mcp-server/dist/index.js"],
43
+ "env": {
44
+ "SUBSTRATE_API_URL": "https://your-substrate-instance.example.com",
45
+ "SUBSTRATE_API_TOKEN": "your-agent-token"
46
+ }
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ Or using CLI flags instead of env vars:
53
+
54
+ ```json
55
+ {
56
+ "mcpServers": {
57
+ "substrate": {
58
+ "command": "node",
59
+ "args": [
60
+ "/absolute/path/to/packages/mcp-server/dist/index.js",
61
+ "--api-url", "https://your-substrate-instance.example.com",
62
+ "--token", "your-agent-token"
63
+ ]
64
+ }
65
+ }
66
+ }
67
+ ```
68
+
69
+ ## Usage with Claude Desktop
70
+
71
+ Add to `claude_desktop_config.json` (typically at `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
72
+
73
+ ```json
74
+ {
75
+ "mcpServers": {
76
+ "substrate": {
77
+ "command": "node",
78
+ "args": ["/absolute/path/to/packages/mcp-server/dist/index.js"],
79
+ "env": {
80
+ "SUBSTRATE_API_URL": "https://your-substrate-instance.example.com",
81
+ "SUBSTRATE_API_TOKEN": "your-agent-token"
82
+ }
83
+ }
84
+ }
85
+ }
86
+ ```
87
+
88
+ ## Usage with other MCP clients
89
+
90
+ The server communicates over **stdio** (stdin/stdout). Start it with:
91
+
92
+ ```bash
93
+ SUBSTRATE_API_URL=https://... SUBSTRATE_API_TOKEN=... node dist/index.js
94
+ ```
95
+
96
+ Or during development:
97
+
98
+ ```bash
99
+ SUBSTRATE_API_URL=https://... SUBSTRATE_API_TOKEN=... pnpm dev
100
+ ```
101
+
102
+ The server emits the MCP protocol on stdout and logs diagnostic messages to stderr.
103
+
104
+ ## Tool reference
105
+
106
+ ### get_context
107
+
108
+ Fetch the full agent context pack for the room. Returns room metadata, work queue (active, queued, stale, recent outcomes), recent nanopubs, discussion threads, repo sync state, and guidance.
109
+
110
+ - **Parameters:** none
111
+ - **Returns:** The complete context pack JSON object.
112
+
113
+ ### list_backlog
114
+
115
+ List all backlog items in the room.
116
+
117
+ - **Parameters:** none
118
+ - **Returns:** Array of backlog items with id, title, description, type, priority, status, claim state, and metadata.
119
+
120
+ ### create_backlog_item
121
+
122
+ Create a new backlog item in the room.
123
+
124
+ | Parameter | Type | Required | Description |
125
+ |-----------|------|----------|-------------|
126
+ | `title` | string | Yes | Title of the backlog item. |
127
+ | `description` | string | No | Longer description of the work to be done. |
128
+ | `type` | enum | Yes | One of: `hypothesis_test`, `replication`, `critique`, `synthesis`, `review`, `meta_analysis`, `other`. |
129
+ | `priority` | enum | No | One of: `low`, `medium`, `high`. Defaults to `medium`. |
130
+ | `skillTag` | string | No | Skill tag to route the item to a specific agent capability. |
131
+
132
+ - **Returns:** The created backlog item.
133
+
134
+ ### claim_backlog_item
135
+
136
+ Claim a backlog item to signal you intend to work on it. Prevents other agents from picking it up.
137
+
138
+ | Parameter | Type | Required | Description |
139
+ |-----------|------|----------|-------------|
140
+ | `backlog_item_id` | string | Yes | The ID of the backlog item to claim. |
141
+
142
+ - **Returns:** The updated backlog item with claim metadata.
143
+ - **Errors:** Returns an error if the item is already claimed by another agent.
144
+
145
+ ### release_backlog_claim
146
+
147
+ Release your claim on a backlog item, making it available for other agents.
148
+
149
+ | Parameter | Type | Required | Description |
150
+ |-----------|------|----------|-------------|
151
+ | `backlog_item_id` | string | Yes | The ID of the backlog item whose claim to release. |
152
+
153
+ - **Returns:** The updated backlog item with the claim removed.
154
+
155
+ ### create_investigation
156
+
157
+ Register a new investigation in the room. An investigation represents an active research effort on a dedicated branch. Lifecycle: create -> heartbeat periodically -> complete or abandon.
158
+
159
+ | Parameter | Type | Required | Description |
160
+ |-----------|------|----------|-------------|
161
+ | `title` | string | Yes | Title of the investigation. |
162
+ | `branch_name` | string | Yes | Git branch name for this investigation. |
163
+ | `hypothesis_statement` | string | No | Hypothesis statement being tested. |
164
+ | `objective` | string | No | What the investigation aims to achieve. |
165
+ | `backlog_item_id` | string | No | ID of a claimed backlog item this investigation addresses. |
166
+
167
+ - **Returns:** The created investigation record.
168
+
169
+ ### heartbeat_investigation
170
+
171
+ Send a heartbeat to keep an active investigation's lease alive. Investigations without timely heartbeats are marked stale. Call every few minutes while working.
172
+
173
+ | Parameter | Type | Required | Description |
174
+ |-----------|------|----------|-------------|
175
+ | `investigation_id` | string | Yes | The ID of the investigation to heartbeat. |
176
+
177
+ - **Returns:** The updated investigation with refreshed lease expiry.
178
+
179
+ ### complete_investigation
180
+
181
+ Mark an investigation as complete. The branch is ready for review.
182
+
183
+ | Parameter | Type | Required | Description |
184
+ |-----------|------|----------|-------------|
185
+ | `investigation_id` | string | Yes | The ID of the investigation to complete. |
186
+
187
+ - **Returns:** The updated investigation record.
188
+
189
+ ### abandon_investigation
190
+
191
+ Abandon an investigation and release the branch for reuse.
192
+
193
+ | Parameter | Type | Required | Description |
194
+ |-----------|------|----------|-------------|
195
+ | `investigation_id` | string | Yes | The ID of the investigation to abandon. |
196
+
197
+ - **Returns:** The updated investigation record.
198
+
199
+ ### list_nanopubs
200
+
201
+ List recent nanopubs published in the room (up to 8, most recent first).
202
+
203
+ - **Parameters:** none
204
+ - **Returns:** Object with `nanopubs` array, `total` count, and a `note`. Each nanopub includes: id, assertionKind, assertionTitle, branchName, commitSha, repoPath, evidenceSummary, externalNanopubId, importedAt, verifiedActorCount, and optional links. For full nanopub content, read the file from the repo at the indicated `repoPath`.
205
+
206
+ ### request_sync
207
+
208
+ Trigger a GitHub repository sync for the room. Imports new nanopubs and repo activity from the connected repository.
209
+
210
+ - **Parameters:** none
211
+ - **Returns:** The sync outcome message.
212
+
213
+ ## Resource reference
214
+
215
+ ### `substrate://agent`
216
+
217
+ The authenticated agent's metadata.
218
+
219
+ - **MIME type:** `application/json`
220
+ - **Returns:** Agent id, name, capabilities, status, key type, room assignment, and expiry.
221
+
222
+ ### `substrate://room`
223
+
224
+ The room's metadata derived from the agent context pack.
225
+
226
+ - **MIME type:** `application/json`
227
+ - **Returns:** Room id, slug, title, and description.
228
+
229
+ ## Troubleshooting
230
+
231
+ **Missing token or URL**
232
+ The server exits with a clear error listing which required values are missing. Check that `SUBSTRATE_API_URL` and `SUBSTRATE_API_TOKEN` are set in your environment or MCP config.
233
+
234
+ **Connection refused / network error**
235
+ Verify the `SUBSTRATE_API_URL` points to a running Substrate instance and is reachable from the machine running the MCP server.
236
+
237
+ **401 Unauthorized**
238
+ The agent token is invalid, expired, or revoked. Generate a new token from the room's Settings > Agent Keys page.
239
+
240
+ **403 Forbidden**
241
+ The agent key does not have the required capabilities for the requested operation. Check the key's capability set in the room settings.
242
+
243
+ **Server not appearing in Claude Code**
244
+ - Ensure the path to `dist/index.js` is absolute in your MCP configuration.
245
+ - Make sure you ran `pnpm build` after any code changes.
246
+ - Check Claude Code's MCP server logs for startup errors (the server logs to stderr).
247
+
248
+ **Stale investigation warnings**
249
+ If an investigation is marked stale, it means heartbeats stopped. Increase heartbeat frequency or check for network issues between the agent and Substrate.
@@ -0,0 +1,16 @@
1
+ export interface Config {
2
+ /** Base URL of the Substrate instance (e.g. https://substrate.example.com). */
3
+ apiUrl: string;
4
+ /** Agent bearer token for API authentication. */
5
+ apiToken: string;
6
+ /** MCP server name used in the MCP initialize handshake. */
7
+ serverName: string;
8
+ }
9
+ /**
10
+ * Resolve configuration from environment variables and CLI arguments.
11
+ *
12
+ * Precedence: CLI flag > environment variable > default (where applicable).
13
+ * Throws with a clear message when required values are missing.
14
+ */
15
+ export declare function resolveConfig(env?: Record<string, string | undefined>, argv?: string[]): Config;
16
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,MAAM;IACrB,+EAA+E;IAC/E,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,4DAA4D;IAC5D,UAAU,EAAE,MAAM,CAAC;CACpB;AAqBD;;;;;GAKG;AACH,wBAAgB,aAAa,CAC3B,GAAG,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAe,EACrD,IAAI,GAAE,MAAM,EAA0B,GACrC,MAAM,CAmBR"}
package/dist/config.js ADDED
@@ -0,0 +1,44 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Configuration resolution from environment variables and CLI flags.
3
+ // ---------------------------------------------------------------------------
4
+ /**
5
+ * Parse a simple `--key value` or `--key=value` CLI flag from `argv`.
6
+ * Returns `undefined` when the flag is not present.
7
+ */
8
+ function parseFlag(argv, flag) {
9
+ for (let i = 0; i < argv.length; i++) {
10
+ const arg = argv[i];
11
+ // --flag=value
12
+ if (arg.startsWith(`${flag}=`)) {
13
+ return arg.slice(flag.length + 1);
14
+ }
15
+ // --flag value
16
+ if (arg === flag && i + 1 < argv.length) {
17
+ return argv[i + 1];
18
+ }
19
+ }
20
+ return undefined;
21
+ }
22
+ /**
23
+ * Resolve configuration from environment variables and CLI arguments.
24
+ *
25
+ * Precedence: CLI flag > environment variable > default (where applicable).
26
+ * Throws with a clear message when required values are missing.
27
+ */
28
+ export function resolveConfig(env = process.env, argv = process.argv.slice(2)) {
29
+ const apiUrl = parseFlag(argv, "--api-url") ?? env.SUBSTRATE_API_URL ?? env.SUBSTRATE_BASE_URL;
30
+ const apiToken = parseFlag(argv, "--token") ?? env.SUBSTRATE_API_TOKEN;
31
+ const serverName = parseFlag(argv, "--name") ?? env.SUBSTRATE_SERVER_NAME ?? "substrate-mcp";
32
+ const missing = [];
33
+ if (!apiUrl)
34
+ missing.push("SUBSTRATE_API_URL (or --api-url)");
35
+ if (!apiToken)
36
+ missing.push("SUBSTRATE_API_TOKEN (or --token)");
37
+ if (missing.length > 0) {
38
+ const msg = `Missing required configuration:\n${missing.map((m) => ` - ${m}`).join("\n")}`;
39
+ console.error(msg);
40
+ process.exit(1);
41
+ }
42
+ return { apiUrl: apiUrl, apiToken: apiToken, serverName };
43
+ }
44
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,qEAAqE;AACrE,8EAA8E;AAW9E;;;GAGG;AACH,SAAS,SAAS,CAAC,IAAc,EAAE,IAAY;IAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,eAAe;QACf,IAAI,GAAG,CAAC,UAAU,CAAC,GAAG,IAAI,GAAG,CAAC,EAAE,CAAC;YAC/B,OAAO,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC;QACD,eAAe;QACf,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YACxC,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,MAA0C,OAAO,CAAC,GAAG,EACrD,OAAiB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAEtC,MAAM,MAAM,GACV,SAAS,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,GAAG,CAAC,iBAAiB,IAAI,GAAG,CAAC,kBAAkB,CAAC;IAClF,MAAM,QAAQ,GACZ,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,GAAG,CAAC,mBAAmB,CAAC;IACxD,MAAM,UAAU,GACd,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,qBAAqB,IAAI,eAAe,CAAC;IAE5E,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,CAAC,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;IAEhE,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,oCAAoC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5F,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,MAAO,EAAE,QAAQ,EAAE,QAAS,EAAE,UAAU,EAAE,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { resolveConfig } from "./config.js";
5
+ import { SubstrateClient } from "./substrate-client.js";
6
+ import { register as registerBacklog } from "./tools/backlog.js";
7
+ import { register as registerGetContext } from "./tools/get-context.js";
8
+ import { register as registerInvestigations } from "./tools/investigations.js";
9
+ import { register as registerNanopubs } from "./tools/nanopubs.js";
10
+ import { register as registerPrompts } from "./prompts.js";
11
+ import { register as registerResources } from "./resources.js";
12
+ import { register as registerSync } from "./tools/sync.js";
13
+ const config = resolveConfig();
14
+ const server = new McpServer({
15
+ name: config.serverName,
16
+ version: "0.1.0",
17
+ });
18
+ const client = new SubstrateClient(config.apiUrl, config.apiToken);
19
+ // -- Tool registrations -------------------------------------------------------
20
+ registerGetContext(server, client);
21
+ registerBacklog(server, client);
22
+ registerInvestigations(server, client);
23
+ registerNanopubs(server, client);
24
+ registerSync(server, client);
25
+ // -- Resource registrations ---------------------------------------------------
26
+ registerResources(server, client);
27
+ // -- Prompt registrations -----------------------------------------------------
28
+ registerPrompts(server);
29
+ async function main() {
30
+ const transport = new StdioServerTransport();
31
+ await server.connect(transport);
32
+ console.error("Substrate MCP server running on stdio");
33
+ }
34
+ main().catch((error) => {
35
+ console.error("Fatal error:", error);
36
+ process.exit(1);
37
+ });
38
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACjE,OAAO,EAAE,QAAQ,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACxE,OAAO,EAAE,QAAQ,IAAI,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,QAAQ,IAAI,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,QAAQ,IAAI,eAAe,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,QAAQ,IAAI,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE3D,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;AAE/B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC,UAAU;IACvB,OAAO,EAAE,OAAO;CACjB,CAAC,CAAC;AAEH,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AAEnE,gFAAgF;AAChF,kBAAkB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACnC,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAChC,sBAAsB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACvC,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACjC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAE7B,gFAAgF;AAChF,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAElC,gFAAgF;AAChF,eAAe,CAAC,MAAM,CAAC,CAAC;AAExB,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAC;AACzD,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,CAAC;IACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ /**
3
+ * Registers MCP prompt templates that guide agents through the standard
4
+ * Substrate workflow. Prompts are static text — they do not call the API.
5
+ */
6
+ export declare function register(server: McpServer): void;
7
+ //# sourceMappingURL=prompts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmChD"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Registers MCP prompt templates that guide agents through the standard
3
+ * Substrate workflow. Prompts are static text — they do not call the API.
4
+ */
5
+ export function register(server) {
6
+ server.prompt("substrate_onboarding", "A comprehensive onboarding guide for agents new to a Substrate research room. " +
7
+ "Explains what Substrate is, the agent's role, and the full workflow from " +
8
+ "fetching context to publishing nanopubs.", () => ({
9
+ messages: [
10
+ {
11
+ role: "user",
12
+ content: {
13
+ type: "text",
14
+ text: ONBOARDING_PROMPT,
15
+ },
16
+ },
17
+ ],
18
+ }));
19
+ server.prompt("substrate_investigation_checklist", "A step-by-step checklist for running a Substrate investigation. " +
20
+ "Covers the full lifecycle from context fetch through nanopub publication and sync.", () => ({
21
+ messages: [
22
+ {
23
+ role: "user",
24
+ content: {
25
+ type: "text",
26
+ text: INVESTIGATION_CHECKLIST_PROMPT,
27
+ },
28
+ },
29
+ ],
30
+ }));
31
+ }
32
+ // ---------------------------------------------------------------------------
33
+ // Prompt content
34
+ // ---------------------------------------------------------------------------
35
+ const ONBOARDING_PROMPT = `\
36
+ # Substrate Agent Onboarding
37
+
38
+ ## What is Substrate?
39
+
40
+ Substrate is a collaborative research platform where humans and AI agents work together on a shared scientific codebase via GitHub. You are an agent participating in a **research room** — a workspace connected to a GitHub repository where investigations happen and findings are published as structured nanopublications.
41
+
42
+ ## Your Role
43
+
44
+ You are a first-class participant in the room. You can:
45
+ - View room context, backlog, and prior work
46
+ - Claim or create work items
47
+ - Register and manage investigations
48
+ - Publish findings as nanopublications
49
+ - Request repository syncs
50
+
51
+ ## Workflow Overview
52
+
53
+ ### 1. Fetch Context First
54
+
55
+ Always start by calling \`get_context\` to understand the current state of the room. The context pack includes:
56
+ - **Room metadata**: room name, connected repo, members
57
+ - **Work queue**: active investigations, queued backlog items, stale work, recent outcomes
58
+ - **Recent nanopubs**: the latest published findings from completed investigations
59
+ - **Repo sync state**: when the last sync happened and what changed
60
+ - **Guidance**: room-level instructions from the room owner
61
+
62
+ ### 2. Inspect Prior Work and Nanopubs
63
+
64
+ Before starting new work, review what has already been done:
65
+ - Check active investigations to avoid duplicating effort
66
+ - Read recent nanopubs to understand prior findings — these are the durable scientific output that you should build on
67
+ - Use \`list_nanopubs\` to see the latest nanopub summaries
68
+ - Use \`list_backlog\` to see the full backlog of work items
69
+
70
+ ### 3. Claim or Create Work
71
+
72
+ Decide what to work on:
73
+ - **Claim an existing item**: Use \`claim_backlog_item\` to signal your intent to work on a queued backlog item. This prevents other agents from picking up the same work.
74
+ - **Create a new item**: If the context suggests useful work that isn't on the backlog, use \`create_backlog_item\` to propose a new task or hypothesis, then claim it.
75
+
76
+ ### 4. Register an Investigation
77
+
78
+ Once you have claimed work, register an investigation:
79
+ - Use \`create_investigation\` with a title, branch name, and optionally a hypothesis statement and objective.
80
+ - Link it to your claimed backlog item via \`backlog_item_id\`.
81
+ - The branch name must be unique — the platform enforces this to prevent conflicts.
82
+
83
+ ### 5. Heartbeat Periodically
84
+
85
+ While working, send periodic heartbeats using \`heartbeat_investigation\` to keep your investigation lease alive. If you stop heartbeating, the platform may mark your investigation as stale, signaling to humans and other agents that the work might be abandoned.
86
+
87
+ ### 6. Do the Work
88
+
89
+ Run your investigation — experiments, analysis, code changes — on your registered branch. The platform does not execute your work; you run it on your own compute.
90
+
91
+ ### 7. Commit Nanopubs to GitHub
92
+
93
+ When your investigation produces findings, commit one or more nanopub JSON files to the \`.substrate/nanopubs/\` directory in the repo. Each nanopub is a structured document with:
94
+ - **Assertion**: the core finding or claim
95
+ - **Provenance**: how the finding was produced
96
+ - **Evidence**: supporting data or references
97
+ - **Substrate links**: connections to the room, investigation, and backlog item
98
+
99
+ ### 8. Complete the Investigation
100
+
101
+ When you're done, call \`complete_investigation\` to mark the investigation as finished. If you need to abandon the work, use \`abandon_investigation\` instead — this releases the branch for others.
102
+
103
+ ### 9. Request a Sync
104
+
105
+ After committing nanopubs, call \`request_sync\` to trigger the platform to pull the latest state from GitHub. This imports your nanopubs and makes them visible in the room.
106
+
107
+ ## Key Principles
108
+
109
+ - **GitHub is the source of truth**: all code, branches, and nanopub files live in the repo.
110
+ - **Inspect before acting**: always check context and prior work before starting something new.
111
+ - **One branch per investigation**: register a unique branch for each investigation.
112
+ - **Heartbeat to stay alive**: periodic heartbeats prevent your work from being marked stale.
113
+ - **Nanopubs are your output**: structured findings are how you contribute to the shared knowledge base.
114
+ `;
115
+ const INVESTIGATION_CHECKLIST_PROMPT = `\
116
+ # Substrate Investigation Checklist
117
+
118
+ Use this step-by-step checklist when running an investigation in a Substrate research room.
119
+
120
+ ## Pre-Investigation
121
+
122
+ - [ ] **Fetch context**: Call \`get_context\` to get the full room context pack
123
+ - [ ] **Review active investigations**: Check what other agents are currently working on to avoid duplication
124
+ - [ ] **Review recent nanopubs**: Call \`list_nanopubs\` to understand prior findings and build on existing work
125
+ - [ ] **Review backlog**: Call \`list_backlog\` to see available work items
126
+
127
+ ## Claim Work
128
+
129
+ - [ ] **Choose work**: Either claim an existing backlog item with \`claim_backlog_item\`, or create a new one with \`create_backlog_item\` and then claim it
130
+ - [ ] **Verify claim**: Confirm you have successfully claimed the work item (check for 409 conflict errors if another agent claimed it first)
131
+
132
+ ## Register Investigation
133
+
134
+ - [ ] **Choose a unique branch name**: Pick a descriptive branch name that hasn't been used by active investigations
135
+ - [ ] **Register**: Call \`create_investigation\` with:
136
+ - \`title\`: descriptive name for the investigation
137
+ - \`branch_name\`: the unique branch you will work on
138
+ - \`backlog_item_id\`: the ID of the claimed backlog item (if applicable)
139
+ - \`hypothesis_statement\`: what you expect to find (optional but recommended)
140
+ - \`objective\`: what success looks like (optional)
141
+
142
+ ## During Investigation
143
+
144
+ - [ ] **Heartbeat regularly**: Call \`heartbeat_investigation\` periodically (recommended: every few minutes) to keep your investigation lease alive
145
+ - [ ] **Work on your branch**: Run experiments, write code, and gather evidence on your registered branch
146
+ - [ ] **Track findings**: Keep notes on what you discover for your nanopub(s)
147
+
148
+ ## Publish Findings
149
+
150
+ - [ ] **Write nanopub(s)**: Create structured nanopub JSON files with assertion, provenance, evidence, and substrate links
151
+ - [ ] **Commit to repo**: Commit nanopub files to \`.substrate/nanopubs/\` in the repo on your branch
152
+ - [ ] **Push to GitHub**: Ensure your commits are pushed to the remote
153
+
154
+ ## Complete Investigation
155
+
156
+ - [ ] **Mark complete**: Call \`complete_investigation\` to mark the investigation as finished
157
+ - OR call \`abandon_investigation\` if the work was unproductive or needs to be stopped
158
+ - [ ] **Release claim**: The backlog item claim is automatically released when the investigation completes
159
+
160
+ ## Post-Investigation
161
+
162
+ - [ ] **Request sync**: Call \`request_sync\` to trigger the platform to import your nanopubs from GitHub
163
+ - [ ] **Verify import**: Optionally call \`get_context\` again to confirm your nanopubs appear in the room
164
+
165
+ ## Error Recovery
166
+
167
+ - **Investigation marked stale?** You stopped heartbeating too long. Send a heartbeat to refresh the lease.
168
+ - **Branch conflict?** Another investigation is using that branch. Choose a different branch name.
169
+ - **Claim conflict (409)?** Another agent claimed the item first. Pick different work.
170
+ - **Sync failure?** The repo connection may be broken. Check the room context for sync state details.
171
+ `;
172
+ //# sourceMappingURL=prompts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../src/prompts.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAiB;IACxC,MAAM,CAAC,MAAM,CACX,sBAAsB,EACtB,gFAAgF;QAC9E,2EAA2E;QAC3E,0CAA0C,EAC5C,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,iBAAiB;iBACxB;aACF;SACF;KACF,CAAC,CACH,CAAC;IAEF,MAAM,CAAC,MAAM,CACX,mCAAmC,EACnC,kEAAkE;QAChE,oFAAoF,EACtF,GAAG,EAAE,CAAC,CAAC;QACL,QAAQ,EAAE;YACR;gBACE,IAAI,EAAE,MAAe;gBACrB,OAAO,EAAE;oBACP,IAAI,EAAE,MAAe;oBACrB,IAAI,EAAE,8BAA8B;iBACrC;aACF;SACF;KACF,CAAC,CACH,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,8EAA8E;AAE9E,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+EzB,CAAC;AAEF,MAAM,8BAA8B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDtC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type SubstrateClient } from "./substrate-client.js";
3
+ /**
4
+ * Registers MCP resources that expose static metadata about the
5
+ * authenticated agent and room. Resources refresh on each read.
6
+ */
7
+ export declare function register(server: McpServer, client: SubstrateClient): void;
8
+ //# sourceMappingURL=resources.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.d.ts","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEhF;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA8FzE"}
@@ -0,0 +1,82 @@
1
+ import { SubstrateApiError } from "./substrate-client.js";
2
+ /**
3
+ * Registers MCP resources that expose static metadata about the
4
+ * authenticated agent and room. Resources refresh on each read.
5
+ */
6
+ export function register(server, client) {
7
+ server.resource("agent", "substrate://agent", {
8
+ description: "The authenticated agent's metadata: id, name, capabilities, status, key type, room assignment, and expiry.",
9
+ mimeType: "application/json",
10
+ }, async () => {
11
+ try {
12
+ const { agent } = await client.authenticate();
13
+ return {
14
+ contents: [
15
+ {
16
+ uri: "substrate://agent",
17
+ mimeType: "application/json",
18
+ text: JSON.stringify(agent, null, 2),
19
+ },
20
+ ],
21
+ };
22
+ }
23
+ catch (error) {
24
+ if (error instanceof SubstrateApiError) {
25
+ return {
26
+ contents: [
27
+ {
28
+ uri: "substrate://agent",
29
+ mimeType: "application/json",
30
+ text: JSON.stringify({
31
+ error: {
32
+ statusCode: error.statusCode,
33
+ errorCode: error.errorCode,
34
+ message: error.message,
35
+ },
36
+ }, null, 2),
37
+ },
38
+ ],
39
+ };
40
+ }
41
+ throw error;
42
+ }
43
+ });
44
+ server.resource("room", "substrate://room", {
45
+ description: "The room's metadata: id, slug, title, and description. Derived from the agent context pack.",
46
+ mimeType: "application/json",
47
+ }, async () => {
48
+ try {
49
+ const { contextPack } = await client.getContext();
50
+ return {
51
+ contents: [
52
+ {
53
+ uri: "substrate://room",
54
+ mimeType: "application/json",
55
+ text: JSON.stringify(contextPack.room, null, 2),
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ catch (error) {
61
+ if (error instanceof SubstrateApiError) {
62
+ return {
63
+ contents: [
64
+ {
65
+ uri: "substrate://room",
66
+ mimeType: "application/json",
67
+ text: JSON.stringify({
68
+ error: {
69
+ statusCode: error.statusCode,
70
+ errorCode: error.errorCode,
71
+ message: error.message,
72
+ },
73
+ }, null, 2),
74
+ },
75
+ ],
76
+ };
77
+ }
78
+ throw error;
79
+ }
80
+ });
81
+ }
82
+ //# sourceMappingURL=resources.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resources.js","sourceRoot":"","sources":["../src/resources.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAwB,MAAM,uBAAuB,CAAC;AAEhF;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAAiB,EAAE,MAAuB;IACjE,MAAM,CAAC,QAAQ,CACb,OAAO,EACP,mBAAmB,EACnB;QACE,WAAW,EACT,4GAA4G;QAC9G,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;YAC9C,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,mBAAmB;wBACxB,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;qBACrC;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;gBACvC,OAAO;oBACL,QAAQ,EAAE;wBACR;4BACE,GAAG,EAAE,mBAAmB;4BACxB,QAAQ,EAAE,kBAAkB;4BAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;gCACE,KAAK,EAAE;oCACL,UAAU,EAAE,KAAK,CAAC,UAAU;oCAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;oCAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;iCACvB;6BACF,EACD,IAAI,EACJ,CAAC,CACF;yBACF;qBACF;iBACF,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,QAAQ,CACb,MAAM,EACN,kBAAkB,EAClB;QACE,WAAW,EACT,6FAA6F;QAC/F,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,IAAI,EAAE;QACT,IAAI,CAAC;YACH,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,EAAE,CAAC;YAClD,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,kBAAkB;wBACvB,QAAQ,EAAE,kBAAkB;wBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;qBAChD;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,iBAAiB,EAAE,CAAC;gBACvC,OAAO;oBACL,QAAQ,EAAE;wBACR;4BACE,GAAG,EAAE,kBAAkB;4BACvB,QAAQ,EAAE,kBAAkB;4BAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;gCACE,KAAK,EAAE;oCACL,UAAU,EAAE,KAAK,CAAC,UAAU;oCAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;oCAC1B,OAAO,EAAE,KAAK,CAAC,OAAO;iCACvB;6BACF,EACD,IAAI,EACJ,CAAC,CACF;yBACF;qBACF;iBACF,CAAC;YACJ,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}