coherence-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 (2) hide show
  1. package/index.mjs +379 -0
  2. package/package.json +30 -0
package/index.mjs ADDED
@@ -0,0 +1,379 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Coherence Network MCP Server
5
+ *
6
+ * Exposes the Coherence Network API as typed MCP tools that any
7
+ * MCP-compatible AI agent (Claude, Cursor, Windsurf, etc.) can invoke.
8
+ *
9
+ * Usage:
10
+ * npx coherence-mcp-server
11
+ * COHERENCE_API_URL=http://localhost:8000 npx coherence-mcp-server
12
+ */
13
+
14
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
15
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
16
+ import {
17
+ CallToolRequestSchema,
18
+ ListToolsRequestSchema,
19
+ } from "@modelcontextprotocol/sdk/types.js";
20
+
21
+ const API_BASE = process.env.COHERENCE_API_URL || "https://api.coherencycoin.com";
22
+ const API_KEY = process.env.COHERENCE_API_KEY || "";
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // HTTP helpers
26
+ // ---------------------------------------------------------------------------
27
+
28
+ async function apiGet(path, params) {
29
+ const url = new URL(path, API_BASE);
30
+ if (params) {
31
+ for (const [k, v] of Object.entries(params)) {
32
+ if (v != null) url.searchParams.set(k, String(v));
33
+ }
34
+ }
35
+ const res = await fetch(url.toString(), {
36
+ signal: AbortSignal.timeout(15_000),
37
+ });
38
+ if (!res.ok) return { error: `${res.status} ${res.statusText}` };
39
+ return await res.json();
40
+ }
41
+
42
+ async function apiPost(path, body) {
43
+ const headers = { "Content-Type": "application/json" };
44
+ if (API_KEY) headers["X-API-Key"] = API_KEY;
45
+ const res = await fetch(new URL(path, API_BASE).toString(), {
46
+ method: "POST",
47
+ headers,
48
+ body: JSON.stringify(body),
49
+ signal: AbortSignal.timeout(15_000),
50
+ });
51
+ if (!res.ok) {
52
+ const err = await res.json().catch(() => ({}));
53
+ return { error: err.detail || `${res.status} ${res.statusText}` };
54
+ }
55
+ return await res.json();
56
+ }
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // Tool definitions
60
+ // ---------------------------------------------------------------------------
61
+
62
+ const TOOLS = [
63
+ // Ideas
64
+ {
65
+ name: "coherence_list_ideas",
66
+ description: "Browse the idea portfolio ranked by ROI and free-energy score. Returns ideas with scores, manifestation status, and selection weights.",
67
+ inputSchema: {
68
+ type: "object",
69
+ properties: {
70
+ limit: { type: "number", description: "Max ideas to return (default 20)", default: 20 },
71
+ search: { type: "string", description: "Search keyword to filter ideas" },
72
+ },
73
+ },
74
+ },
75
+ {
76
+ name: "coherence_get_idea",
77
+ description: "Get full details for a single idea including scores, open questions, value gap, and linked tasks.",
78
+ inputSchema: {
79
+ type: "object",
80
+ properties: {
81
+ idea_id: { type: "string", description: "The idea ID" },
82
+ },
83
+ required: ["idea_id"],
84
+ },
85
+ },
86
+ {
87
+ name: "coherence_idea_progress",
88
+ description: "Get progress for an idea: stage, tasks by phase, CC staked/spent, contributors.",
89
+ inputSchema: {
90
+ type: "object",
91
+ properties: { idea_id: { type: "string" } },
92
+ required: ["idea_id"],
93
+ },
94
+ },
95
+ {
96
+ name: "coherence_select_idea",
97
+ description: "Let the portfolio engine select the next highest-ROI idea to work on. Temperature controls exploration vs exploitation.",
98
+ inputSchema: {
99
+ type: "object",
100
+ properties: {
101
+ temperature: { type: "number", description: "0=deterministic (highest ROI), >1=explore (default 0.5)", default: 0.5 },
102
+ },
103
+ },
104
+ },
105
+ {
106
+ name: "coherence_showcase",
107
+ description: "List validated, shipped ideas that have proven their value.",
108
+ inputSchema: { type: "object", properties: {} },
109
+ },
110
+ {
111
+ name: "coherence_resonance",
112
+ description: "Show which ideas are generating the most energy and activity right now.",
113
+ inputSchema: { type: "object", properties: {} },
114
+ },
115
+
116
+ // Specs
117
+ {
118
+ name: "coherence_list_specs",
119
+ description: "List feature specs with ROI metrics, value gaps, and implementation summaries.",
120
+ inputSchema: {
121
+ type: "object",
122
+ properties: {
123
+ limit: { type: "number", default: 20 },
124
+ search: { type: "string", description: "Search keyword" },
125
+ },
126
+ },
127
+ },
128
+ {
129
+ name: "coherence_get_spec",
130
+ description: "Get full spec detail including implementation summary, pseudocode, and ROI.",
131
+ inputSchema: {
132
+ type: "object",
133
+ properties: { spec_id: { type: "string" } },
134
+ required: ["spec_id"],
135
+ },
136
+ },
137
+
138
+ // Lineage
139
+ {
140
+ name: "coherence_list_lineage",
141
+ description: "List value lineage chains connecting ideas to specs, implementations, and payouts.",
142
+ inputSchema: {
143
+ type: "object",
144
+ properties: { limit: { type: "number", default: 20 } },
145
+ },
146
+ },
147
+ {
148
+ name: "coherence_lineage_valuation",
149
+ description: "Get ROI valuation for a lineage chain — measured value, estimated cost, and ROI ratio.",
150
+ inputSchema: {
151
+ type: "object",
152
+ properties: { lineage_id: { type: "string" } },
153
+ required: ["lineage_id"],
154
+ },
155
+ },
156
+
157
+ // Identity
158
+ {
159
+ name: "coherence_list_providers",
160
+ description: "List all 37 supported identity providers grouped by category (Social, Dev, Crypto/Web3, Professional, Identity, Custom).",
161
+ inputSchema: { type: "object", properties: {} },
162
+ },
163
+ {
164
+ name: "coherence_link_identity",
165
+ description: "Link a provider identity (GitHub, Discord, Ethereum, etc.) to a contributor. No registration required.",
166
+ inputSchema: {
167
+ type: "object",
168
+ properties: {
169
+ contributor_id: { type: "string", description: "Contributor name" },
170
+ provider: { type: "string", description: "Provider key (github, discord, ethereum, solana, ...)" },
171
+ provider_id: { type: "string", description: "Handle, address, or username on that provider" },
172
+ },
173
+ required: ["contributor_id", "provider", "provider_id"],
174
+ },
175
+ },
176
+ {
177
+ name: "coherence_lookup_identity",
178
+ description: "Find which contributor owns a specific provider identity. Reverse lookup.",
179
+ inputSchema: {
180
+ type: "object",
181
+ properties: {
182
+ provider: { type: "string" },
183
+ provider_id: { type: "string" },
184
+ },
185
+ required: ["provider", "provider_id"],
186
+ },
187
+ },
188
+ {
189
+ name: "coherence_get_identities",
190
+ description: "Get all linked identities for a contributor.",
191
+ inputSchema: {
192
+ type: "object",
193
+ properties: { contributor_id: { type: "string" } },
194
+ required: ["contributor_id"],
195
+ },
196
+ },
197
+
198
+ // Contributions
199
+ {
200
+ name: "coherence_record_contribution",
201
+ description: "Record a contribution. Identify by contributor_id OR by provider+provider_id (no registration needed).",
202
+ inputSchema: {
203
+ type: "object",
204
+ properties: {
205
+ contributor_id: { type: "string", description: "Contributor name (optional if provider+provider_id given)" },
206
+ provider: { type: "string", description: "Identity provider (optional)" },
207
+ provider_id: { type: "string", description: "Identity handle (optional)" },
208
+ type: { type: "string", description: "Contribution type: code, docs, review, design, community, other" },
209
+ amount_cc: { type: "number", description: "CC value (default 1)", default: 1 },
210
+ idea_id: { type: "string", description: "Related idea ID (optional)" },
211
+ },
212
+ required: ["type"],
213
+ },
214
+ },
215
+ {
216
+ name: "coherence_contributor_ledger",
217
+ description: "Get a contributor's CC balance and contribution history.",
218
+ inputSchema: {
219
+ type: "object",
220
+ properties: { contributor_id: { type: "string" } },
221
+ required: ["contributor_id"],
222
+ },
223
+ },
224
+
225
+ // Status
226
+ {
227
+ name: "coherence_status",
228
+ description: "Get network health: API status, uptime, federation nodes, idea count.",
229
+ inputSchema: { type: "object", properties: {} },
230
+ },
231
+ {
232
+ name: "coherence_friction_report",
233
+ description: "Get friction report — where the pipeline struggles.",
234
+ inputSchema: {
235
+ type: "object",
236
+ properties: {
237
+ window_days: { type: "number", default: 30 },
238
+ },
239
+ },
240
+ },
241
+
242
+ // Governance
243
+ {
244
+ name: "coherence_list_change_requests",
245
+ description: "List governance change requests.",
246
+ inputSchema: { type: "object", properties: {} },
247
+ },
248
+
249
+ // Federation
250
+ {
251
+ name: "coherence_list_federation_nodes",
252
+ description: "List federated nodes and their capabilities.",
253
+ inputSchema: { type: "object", properties: {} },
254
+ },
255
+ ];
256
+
257
+ // ---------------------------------------------------------------------------
258
+ // Tool handlers
259
+ // ---------------------------------------------------------------------------
260
+
261
+ async function handleTool(name, args) {
262
+ switch (name) {
263
+ // Ideas
264
+ case "coherence_list_ideas":
265
+ if (args.search) return apiGet("/api/ideas/cards", { search: args.search, limit: args.limit || 20 });
266
+ return apiGet("/api/ideas", { limit: args.limit || 20 });
267
+ case "coherence_get_idea":
268
+ return apiGet(`/api/ideas/${args.idea_id}`);
269
+ case "coherence_idea_progress":
270
+ return apiGet(`/api/ideas/${args.idea_id}/progress`);
271
+ case "coherence_select_idea":
272
+ return apiPost("/api/ideas/select", { temperature: args.temperature ?? 0.5 });
273
+ case "coherence_showcase":
274
+ return apiGet("/api/ideas/showcase");
275
+ case "coherence_resonance":
276
+ return apiGet("/api/ideas/resonance");
277
+
278
+ // Specs
279
+ case "coherence_list_specs":
280
+ if (args.search) return apiGet("/api/spec-registry/cards", { search: args.search, limit: args.limit || 20 });
281
+ return apiGet("/api/spec-registry", { limit: args.limit || 20 });
282
+ case "coherence_get_spec":
283
+ return apiGet(`/api/spec-registry/${args.spec_id}`);
284
+
285
+ // Lineage
286
+ case "coherence_list_lineage":
287
+ return apiGet("/api/value-lineage/links", { limit: args.limit || 20 });
288
+ case "coherence_lineage_valuation":
289
+ return apiGet(`/api/value-lineage/links/${args.lineage_id}/valuation`);
290
+
291
+ // Identity
292
+ case "coherence_list_providers":
293
+ return apiGet("/api/identity/providers");
294
+ case "coherence_link_identity":
295
+ return apiPost("/api/identity/link", {
296
+ contributor_id: args.contributor_id,
297
+ provider: args.provider,
298
+ provider_id: args.provider_id,
299
+ display_name: args.provider_id,
300
+ });
301
+ case "coherence_lookup_identity":
302
+ return apiGet(`/api/identity/lookup/${encodeURIComponent(args.provider)}/${encodeURIComponent(args.provider_id)}`);
303
+ case "coherence_get_identities":
304
+ return apiGet(`/api/identity/${encodeURIComponent(args.contributor_id)}`);
305
+
306
+ // Contributions
307
+ case "coherence_record_contribution":
308
+ return apiPost("/api/contributions/record", {
309
+ contributor_id: args.contributor_id || undefined,
310
+ provider: args.provider || undefined,
311
+ provider_id: args.provider_id || undefined,
312
+ type: args.type,
313
+ amount_cc: args.amount_cc ?? 1,
314
+ idea_id: args.idea_id || undefined,
315
+ });
316
+ case "coherence_contributor_ledger":
317
+ return apiGet(`/api/contributions/ledger/${encodeURIComponent(args.contributor_id)}`);
318
+
319
+ // Status
320
+ case "coherence_status": {
321
+ const [health, count, nodes] = await Promise.all([
322
+ apiGet("/api/health"),
323
+ apiGet("/api/ideas/count"),
324
+ apiGet("/api/federation/nodes"),
325
+ ]);
326
+ return { health, ideas: count, federation_nodes: Array.isArray(nodes) ? nodes.length : 0 };
327
+ }
328
+ case "coherence_friction_report":
329
+ return apiGet("/api/friction/report", { window_days: args.window_days || 30 });
330
+
331
+ // Governance
332
+ case "coherence_list_change_requests":
333
+ return apiGet("/api/governance/change-requests");
334
+
335
+ // Federation
336
+ case "coherence_list_federation_nodes": {
337
+ const [nodes, caps] = await Promise.all([
338
+ apiGet("/api/federation/nodes"),
339
+ apiGet("/api/federation/nodes/capabilities"),
340
+ ]);
341
+ return { nodes, capabilities: caps };
342
+ }
343
+
344
+ default:
345
+ return { error: `Unknown tool: ${name}` };
346
+ }
347
+ }
348
+
349
+ // ---------------------------------------------------------------------------
350
+ // MCP server setup
351
+ // ---------------------------------------------------------------------------
352
+
353
+ const server = new Server(
354
+ { name: "coherence-network", version: "0.1.0" },
355
+ { capabilities: { tools: {} } },
356
+ );
357
+
358
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
359
+ tools: TOOLS,
360
+ }));
361
+
362
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
363
+ const { name, arguments: args } = request.params;
364
+ try {
365
+ const result = await handleTool(name, args || {});
366
+ return {
367
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
368
+ };
369
+ } catch (err) {
370
+ return {
371
+ content: [{ type: "text", text: `Error: ${err.message}` }],
372
+ isError: true,
373
+ };
374
+ }
375
+ });
376
+
377
+ // Start
378
+ const transport = new StdioServerTransport();
379
+ await server.connect(transport);
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "coherence-mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for the Coherence Network — exposes ideas, specs, lineage, identity, and contributions as typed tools for AI agents",
5
+ "type": "module",
6
+ "bin": {
7
+ "coherence-mcp-server": "index.mjs"
8
+ },
9
+ "engines": {
10
+ "node": ">=18.0.0"
11
+ },
12
+ "dependencies": {
13
+ "@modelcontextprotocol/sdk": "^1.0.0"
14
+ },
15
+ "files": [
16
+ "index.mjs"
17
+ ],
18
+ "keywords": [
19
+ "mcp",
20
+ "coherence",
21
+ "ai-agent",
22
+ "model-context-protocol",
23
+ "tools"
24
+ ],
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/seeker71/Coherence-Network.git"
29
+ }
30
+ }