coherence-mcp-server 0.3.0 → 0.4.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 +86 -41
- package/README.template.md +86 -40
- package/coherence_mcp_server/__init__.py +17 -0
- package/coherence_mcp_server/__main__.py +20 -0
- package/coherence_mcp_server/__pycache__/__init__.cpython-314.pyc +0 -0
- package/coherence_mcp_server/__pycache__/__main__.cpython-314.pyc +0 -0
- package/coherence_mcp_server/__pycache__/server.cpython-314.pyc +0 -0
- package/coherence_mcp_server/server.py +966 -0
- package/index.mjs +36 -369
- package/package.json +9 -4
- package/pyproject.toml +54 -0
|
@@ -0,0 +1,966 @@
|
|
|
1
|
+
"""Coherence Network MCP server — Python implementation.
|
|
2
|
+
|
|
3
|
+
Exposes the Coherence Network API as 22 typed MCP tools.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import logging
|
|
10
|
+
import os
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
import httpx
|
|
14
|
+
from mcp.server import Server
|
|
15
|
+
from mcp.server.stdio import stdio_server
|
|
16
|
+
from mcp.types import TextContent, Tool
|
|
17
|
+
|
|
18
|
+
logger = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
API_BASE = os.environ.get("COHERENCE_API_URL", "https://api.coherencycoin.com").rstrip("/")
|
|
21
|
+
API_KEY = os.environ.get("COHERENCE_API_KEY", "")
|
|
22
|
+
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
# HTTP helpers
|
|
25
|
+
# ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
def _headers() -> dict[str, str]:
|
|
28
|
+
h = {"Content-Type": "application/json"}
|
|
29
|
+
if API_KEY:
|
|
30
|
+
h["X-API-Key"] = API_KEY
|
|
31
|
+
return h
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def api_get(path: str, params: dict[str, Any] | None = None) -> Any:
|
|
35
|
+
url = f"{API_BASE}{path}"
|
|
36
|
+
filtered = {k: v for k, v in (params or {}).items() if v is not None}
|
|
37
|
+
try:
|
|
38
|
+
r = httpx.get(url, params=filtered, headers=_headers(), timeout=15.0)
|
|
39
|
+
r.raise_for_status()
|
|
40
|
+
return r.json()
|
|
41
|
+
except httpx.HTTPStatusError as exc:
|
|
42
|
+
return {"error": f"{exc.response.status_code} {exc.response.reason_phrase}"}
|
|
43
|
+
except Exception as exc:
|
|
44
|
+
return {"error": str(exc)}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def api_post(path: str, body: dict[str, Any]) -> Any:
|
|
48
|
+
url = f"{API_BASE}{path}"
|
|
49
|
+
try:
|
|
50
|
+
r = httpx.post(url, json=body, headers=_headers(), timeout=15.0)
|
|
51
|
+
r.raise_for_status()
|
|
52
|
+
return r.json()
|
|
53
|
+
except httpx.HTTPStatusError as exc:
|
|
54
|
+
try:
|
|
55
|
+
detail = exc.response.json().get("detail", exc.response.reason_phrase)
|
|
56
|
+
except Exception:
|
|
57
|
+
detail = exc.response.reason_phrase
|
|
58
|
+
return {"error": detail}
|
|
59
|
+
except Exception as exc:
|
|
60
|
+
return {"error": str(exc)}
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def api_patch(path: str, body: dict[str, Any]) -> Any:
|
|
64
|
+
url = f"{API_BASE}{path}"
|
|
65
|
+
try:
|
|
66
|
+
r = httpx.patch(url, json=body, headers=_headers(), timeout=15.0)
|
|
67
|
+
r.raise_for_status()
|
|
68
|
+
return r.json()
|
|
69
|
+
except httpx.HTTPStatusError as exc:
|
|
70
|
+
try:
|
|
71
|
+
detail = exc.response.json().get("detail", exc.response.reason_phrase)
|
|
72
|
+
except Exception:
|
|
73
|
+
detail = exc.response.reason_phrase
|
|
74
|
+
return {"error": detail}
|
|
75
|
+
except Exception as exc:
|
|
76
|
+
return {"error": str(exc)}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
# Tool definitions
|
|
81
|
+
# ---------------------------------------------------------------------------
|
|
82
|
+
|
|
83
|
+
TOOLS: list[Tool] = [
|
|
84
|
+
# Ideas
|
|
85
|
+
Tool(
|
|
86
|
+
name="coherence_list_ideas",
|
|
87
|
+
description="Browse the idea portfolio ranked by ROI and free-energy score. Returns ideas with scores, manifestation status, and selection weights.",
|
|
88
|
+
inputSchema={
|
|
89
|
+
"type": "object",
|
|
90
|
+
"properties": {
|
|
91
|
+
"limit": {"type": "number", "description": "Max ideas to return (default 20)", "default": 20},
|
|
92
|
+
"search": {"type": "string", "description": "Search keyword to filter ideas"},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
),
|
|
96
|
+
Tool(
|
|
97
|
+
name="coherence_get_idea",
|
|
98
|
+
description="Get full details for a single idea including scores, open questions, value gap, and linked tasks.",
|
|
99
|
+
inputSchema={
|
|
100
|
+
"type": "object",
|
|
101
|
+
"properties": {
|
|
102
|
+
"idea_id": {"type": "string", "description": "The idea ID"},
|
|
103
|
+
},
|
|
104
|
+
"required": ["idea_id"],
|
|
105
|
+
},
|
|
106
|
+
),
|
|
107
|
+
Tool(
|
|
108
|
+
name="coherence_idea_progress",
|
|
109
|
+
description="Get progress for an idea: stage, tasks by phase, CC staked/spent, contributors.",
|
|
110
|
+
inputSchema={
|
|
111
|
+
"type": "object",
|
|
112
|
+
"properties": {"idea_id": {"type": "string"}},
|
|
113
|
+
"required": ["idea_id"],
|
|
114
|
+
},
|
|
115
|
+
),
|
|
116
|
+
Tool(
|
|
117
|
+
name="coherence_select_idea",
|
|
118
|
+
description="Let the portfolio engine select the next highest-ROI idea to work on. Temperature controls exploration vs exploitation.",
|
|
119
|
+
inputSchema={
|
|
120
|
+
"type": "object",
|
|
121
|
+
"properties": {
|
|
122
|
+
"temperature": {"type": "number", "description": "0=deterministic, >1=explore (default 0.5)", "default": 0.5},
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
),
|
|
126
|
+
Tool(
|
|
127
|
+
name="coherence_showcase",
|
|
128
|
+
description="List validated, shipped ideas that have proven their value.",
|
|
129
|
+
inputSchema={"type": "object", "properties": {}},
|
|
130
|
+
),
|
|
131
|
+
Tool(
|
|
132
|
+
name="coherence_resonance",
|
|
133
|
+
description="Show which ideas are generating the most energy and activity right now.",
|
|
134
|
+
inputSchema={"type": "object", "properties": {}},
|
|
135
|
+
),
|
|
136
|
+
# Specs
|
|
137
|
+
Tool(
|
|
138
|
+
name="coherence_list_specs",
|
|
139
|
+
description="List feature specs with ROI metrics, value gaps, and implementation summaries.",
|
|
140
|
+
inputSchema={
|
|
141
|
+
"type": "object",
|
|
142
|
+
"properties": {
|
|
143
|
+
"limit": {"type": "number", "default": 20},
|
|
144
|
+
"search": {"type": "string", "description": "Search keyword"},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
),
|
|
148
|
+
Tool(
|
|
149
|
+
name="coherence_get_spec",
|
|
150
|
+
description="Get full spec detail including implementation summary, pseudocode, and ROI.",
|
|
151
|
+
inputSchema={
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {"spec_id": {"type": "string"}},
|
|
154
|
+
"required": ["spec_id"],
|
|
155
|
+
},
|
|
156
|
+
),
|
|
157
|
+
# Lineage
|
|
158
|
+
Tool(
|
|
159
|
+
name="coherence_list_lineage",
|
|
160
|
+
description="List value lineage chains connecting ideas to specs, implementations, and payouts.",
|
|
161
|
+
inputSchema={
|
|
162
|
+
"type": "object",
|
|
163
|
+
"properties": {"limit": {"type": "number", "default": 20}},
|
|
164
|
+
},
|
|
165
|
+
),
|
|
166
|
+
Tool(
|
|
167
|
+
name="coherence_lineage_valuation",
|
|
168
|
+
description="Get ROI valuation for a lineage chain — measured value, estimated cost, and ROI ratio.",
|
|
169
|
+
inputSchema={
|
|
170
|
+
"type": "object",
|
|
171
|
+
"properties": {"lineage_id": {"type": "string"}},
|
|
172
|
+
"required": ["lineage_id"],
|
|
173
|
+
},
|
|
174
|
+
),
|
|
175
|
+
# Identity
|
|
176
|
+
Tool(
|
|
177
|
+
name="coherence_list_providers",
|
|
178
|
+
description="List all 37 supported identity providers grouped by category (Social, Dev, Crypto/Web3, Professional, Identity, Custom).",
|
|
179
|
+
inputSchema={"type": "object", "properties": {}},
|
|
180
|
+
),
|
|
181
|
+
Tool(
|
|
182
|
+
name="coherence_link_identity",
|
|
183
|
+
description="Link a provider identity (GitHub, Discord, Ethereum, etc.) to a contributor. No registration required.",
|
|
184
|
+
inputSchema={
|
|
185
|
+
"type": "object",
|
|
186
|
+
"properties": {
|
|
187
|
+
"contributor_id": {"type": "string", "description": "Contributor name"},
|
|
188
|
+
"provider": {"type": "string", "description": "Provider key (github, discord, ethereum, solana, ...)"},
|
|
189
|
+
"provider_id": {"type": "string", "description": "Handle, address, or username on that provider"},
|
|
190
|
+
},
|
|
191
|
+
"required": ["contributor_id", "provider", "provider_id"],
|
|
192
|
+
},
|
|
193
|
+
),
|
|
194
|
+
Tool(
|
|
195
|
+
name="coherence_lookup_identity",
|
|
196
|
+
description="Find which contributor owns a specific provider identity. Reverse lookup.",
|
|
197
|
+
inputSchema={
|
|
198
|
+
"type": "object",
|
|
199
|
+
"properties": {
|
|
200
|
+
"provider": {"type": "string"},
|
|
201
|
+
"provider_id": {"type": "string"},
|
|
202
|
+
},
|
|
203
|
+
"required": ["provider", "provider_id"],
|
|
204
|
+
},
|
|
205
|
+
),
|
|
206
|
+
Tool(
|
|
207
|
+
name="coherence_get_identities",
|
|
208
|
+
description="Get all linked identities for a contributor.",
|
|
209
|
+
inputSchema={
|
|
210
|
+
"type": "object",
|
|
211
|
+
"properties": {"contributor_id": {"type": "string"}},
|
|
212
|
+
"required": ["contributor_id"],
|
|
213
|
+
},
|
|
214
|
+
),
|
|
215
|
+
# Contributions
|
|
216
|
+
Tool(
|
|
217
|
+
name="coherence_record_contribution",
|
|
218
|
+
description="Record a contribution. Identify by contributor_id OR by provider+provider_id (no registration needed).",
|
|
219
|
+
inputSchema={
|
|
220
|
+
"type": "object",
|
|
221
|
+
"properties": {
|
|
222
|
+
"contributor_id": {"type": "string", "description": "Contributor name (optional if provider+provider_id given)"},
|
|
223
|
+
"provider": {"type": "string", "description": "Identity provider (optional)"},
|
|
224
|
+
"provider_id": {"type": "string", "description": "Identity handle (optional)"},
|
|
225
|
+
"type": {"type": "string", "description": "Contribution type: code, docs, review, design, community, other"},
|
|
226
|
+
"amount_cc": {"type": "number", "description": "CC value (default 1)", "default": 1},
|
|
227
|
+
"idea_id": {"type": "string", "description": "Related idea ID (optional)"},
|
|
228
|
+
},
|
|
229
|
+
"required": ["type"],
|
|
230
|
+
},
|
|
231
|
+
),
|
|
232
|
+
Tool(
|
|
233
|
+
name="coherence_contributor_ledger",
|
|
234
|
+
description="Get a contributor's CC balance and contribution history.",
|
|
235
|
+
inputSchema={
|
|
236
|
+
"type": "object",
|
|
237
|
+
"properties": {"contributor_id": {"type": "string"}},
|
|
238
|
+
"required": ["contributor_id"],
|
|
239
|
+
},
|
|
240
|
+
),
|
|
241
|
+
# Status
|
|
242
|
+
Tool(
|
|
243
|
+
name="coherence_status",
|
|
244
|
+
description="Get network health: API status, uptime, federation nodes, idea count.",
|
|
245
|
+
inputSchema={"type": "object", "properties": {}},
|
|
246
|
+
),
|
|
247
|
+
Tool(
|
|
248
|
+
name="coherence_friction_report",
|
|
249
|
+
description="Get friction report — where the pipeline struggles.",
|
|
250
|
+
inputSchema={
|
|
251
|
+
"type": "object",
|
|
252
|
+
"properties": {"window_days": {"type": "number", "default": 30}},
|
|
253
|
+
},
|
|
254
|
+
),
|
|
255
|
+
# Governance
|
|
256
|
+
Tool(
|
|
257
|
+
name="coherence_list_change_requests",
|
|
258
|
+
description="List governance change requests.",
|
|
259
|
+
inputSchema={"type": "object", "properties": {}},
|
|
260
|
+
),
|
|
261
|
+
# Federation
|
|
262
|
+
Tool(
|
|
263
|
+
name="coherence_list_federation_nodes",
|
|
264
|
+
description="List federated nodes and their capabilities.",
|
|
265
|
+
inputSchema={"type": "object", "properties": {}},
|
|
266
|
+
),
|
|
267
|
+
# Tasks (Agent Work Protocol)
|
|
268
|
+
Tool(
|
|
269
|
+
name="coherence_list_tasks",
|
|
270
|
+
description="List tasks in the agent work pipeline with optional filters (pending, running, completed, failed, needs_decision).",
|
|
271
|
+
inputSchema={
|
|
272
|
+
"type": "object",
|
|
273
|
+
"properties": {
|
|
274
|
+
"status": {"type": "string", "description": "Filter by status: pending, running, completed, failed, needs_decision, timed_out"},
|
|
275
|
+
"task_type": {"type": "string", "description": "Filter by type: spec, test, impl, review, code-review"},
|
|
276
|
+
"limit": {"type": "number", "description": "Max tasks to return (default 20)", "default": 20},
|
|
277
|
+
"offset": {"type": "number", "description": "Pagination offset", "default": 0},
|
|
278
|
+
},
|
|
279
|
+
},
|
|
280
|
+
),
|
|
281
|
+
Tool(
|
|
282
|
+
name="coherence_get_task",
|
|
283
|
+
description="Get full detail for a single task including direction, context, worker_id, and result/output.",
|
|
284
|
+
inputSchema={
|
|
285
|
+
"type": "object",
|
|
286
|
+
"required": ["task_id"],
|
|
287
|
+
"properties": {
|
|
288
|
+
"task_id": {"type": "string", "description": "The task ID"},
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
),
|
|
292
|
+
Tool(
|
|
293
|
+
name="coherence_task_next",
|
|
294
|
+
description="Claim the highest-priority pending task from the queue. This is the entry point for agents to start working.",
|
|
295
|
+
inputSchema={
|
|
296
|
+
"type": "object",
|
|
297
|
+
"properties": {
|
|
298
|
+
"worker_id": {"type": "string", "description": "Identity of the agent/node claiming the task (defaults to 'mcp-agent')"},
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
),
|
|
302
|
+
Tool(
|
|
303
|
+
name="coherence_task_claim",
|
|
304
|
+
description="Claim a specific task by ID.",
|
|
305
|
+
inputSchema={
|
|
306
|
+
"type": "object",
|
|
307
|
+
"required": ["task_id"],
|
|
308
|
+
"properties": {
|
|
309
|
+
"task_id": {"type": "string", "description": "The task ID"},
|
|
310
|
+
"worker_id": {"type": "string", "description": "Identity of the agent/node (defaults to 'mcp-agent')"},
|
|
311
|
+
},
|
|
312
|
+
},
|
|
313
|
+
),
|
|
314
|
+
Tool(
|
|
315
|
+
name="coherence_task_report",
|
|
316
|
+
description="Report the result of a claimed task (completed or failed).",
|
|
317
|
+
inputSchema={
|
|
318
|
+
"type": "object",
|
|
319
|
+
"required": ["task_id", "status"],
|
|
320
|
+
"properties": {
|
|
321
|
+
"task_id": {"type": "string", "description": "The task ID"},
|
|
322
|
+
"status": {"type": "string", "description": "Result status: completed or failed"},
|
|
323
|
+
"output": {"type": "string", "description": "The final work product (code, spec text, review notes, etc.)"},
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
),
|
|
327
|
+
Tool(
|
|
328
|
+
name="coherence_task_seed",
|
|
329
|
+
description="Create a new task from an existing idea (e.g. seed a 'spec' task for idea X).",
|
|
330
|
+
inputSchema={
|
|
331
|
+
"type": "object",
|
|
332
|
+
"required": ["idea_id"],
|
|
333
|
+
"properties": {
|
|
334
|
+
"idea_id": {"type": "string", "description": "Target idea ID"},
|
|
335
|
+
"task_type": {"type": "string", "description": "Type of task: spec, test, impl, review (default: spec)", "default": "spec"},
|
|
336
|
+
"direction": {"type": "string", "description": "Optional custom instruction for the task"},
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
),
|
|
340
|
+
Tool(
|
|
341
|
+
name="coherence_task_events",
|
|
342
|
+
description="Get the activity log/event stream for a specific task.",
|
|
343
|
+
inputSchema={
|
|
344
|
+
"type": "object",
|
|
345
|
+
"required": ["task_id"],
|
|
346
|
+
"properties": {
|
|
347
|
+
"task_id": {"type": "string", "description": "The task ID"},
|
|
348
|
+
},
|
|
349
|
+
},
|
|
350
|
+
),
|
|
351
|
+
# Ideas (Lifecycle)
|
|
352
|
+
Tool(
|
|
353
|
+
name="coherence_create_idea",
|
|
354
|
+
description="Create a new idea in the portfolio.",
|
|
355
|
+
inputSchema={
|
|
356
|
+
"type": "object",
|
|
357
|
+
"required": ["id", "name", "description"],
|
|
358
|
+
"properties": {
|
|
359
|
+
"id": {"type": "string", "description": "Unique idea slug (e.g. 'my-new-feature')"},
|
|
360
|
+
"name": {"type": "string", "description": "Short, descriptive name"},
|
|
361
|
+
"description": {"type": "string", "description": "Detailed vision and value proposition"},
|
|
362
|
+
"potential_value": {"type": "number", "description": "Estimated CC value (0-1000)", "default": 100},
|
|
363
|
+
"estimated_cost": {"type": "number", "description": "Estimated CC cost (0-1000)", "default": 50},
|
|
364
|
+
"parent_idea_id": {"type": "string", "description": "Optional parent idea for hierarchy"},
|
|
365
|
+
"tags": {"type": "array", "items": {"type": "string"}, "description": "List of tags"},
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
),
|
|
369
|
+
Tool(
|
|
370
|
+
name="coherence_update_idea",
|
|
371
|
+
description="Update an existing idea's properties (stage, status, metadata).",
|
|
372
|
+
inputSchema={
|
|
373
|
+
"type": "object",
|
|
374
|
+
"required": ["idea_id"],
|
|
375
|
+
"properties": {
|
|
376
|
+
"idea_id": {"type": "string", "description": "The idea ID"},
|
|
377
|
+
"name": {"type": "string"},
|
|
378
|
+
"description": {"type": "string"},
|
|
379
|
+
"stage": {"type": "string", "description": "New stage: draft, proposed, active, completed, archived"},
|
|
380
|
+
"manifestation_status": {"type": "string", "description": "none, spec, implemented, validated"},
|
|
381
|
+
"potential_value": {"type": "number"},
|
|
382
|
+
"estimated_cost": {"type": "number"},
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
),
|
|
386
|
+
# Universal Graph (Navigation & Edges)
|
|
387
|
+
Tool(
|
|
388
|
+
name="coherence_list_edges",
|
|
389
|
+
description="List relationship edges in the universal graph with optional filters.",
|
|
390
|
+
inputSchema={
|
|
391
|
+
"type": "object",
|
|
392
|
+
"properties": {
|
|
393
|
+
"type": {"type": "string", "description": "Edge type: blocks, enables, depends-on, related-to, etc."},
|
|
394
|
+
"from_id": {"type": "string", "description": "Source node ID"},
|
|
395
|
+
"to_id": {"type": "string", "description": "Target node ID"},
|
|
396
|
+
"limit": {"type": "number", "default": 50},
|
|
397
|
+
},
|
|
398
|
+
},
|
|
399
|
+
),
|
|
400
|
+
Tool(
|
|
401
|
+
name="coherence_get_entity_edges",
|
|
402
|
+
description="Get all incoming and outgoing edges for any entity (Idea, Spec, Contributor, Asset).",
|
|
403
|
+
inputSchema={
|
|
404
|
+
"type": "object",
|
|
405
|
+
"required": ["entity_id"],
|
|
406
|
+
"properties": {
|
|
407
|
+
"entity_id": {"type": "string", "description": "The entity ID"},
|
|
408
|
+
"type": {"type": "string", "description": "Filter by edge type"},
|
|
409
|
+
"direction": {"type": "string", "description": "both, outgoing, incoming", "default": "both"},
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
),
|
|
413
|
+
Tool(
|
|
414
|
+
name="coherence_create_edge",
|
|
415
|
+
description="Create a typed relationship edge between two entities in the graph.",
|
|
416
|
+
inputSchema={
|
|
417
|
+
"type": "object",
|
|
418
|
+
"required": ["from_id", "to_id", "type"],
|
|
419
|
+
"properties": {
|
|
420
|
+
"from_id": {"type": "string", "description": "Source entity ID"},
|
|
421
|
+
"to_id": {"type": "string", "description": "Target entity ID"},
|
|
422
|
+
"type": {"type": "string", "description": "Edge type: blocks, enables, depends-on, contains, transforms, opposes, etc."},
|
|
423
|
+
"strength": {"type": "number", "description": "Edge strength (0.0-1.0)", "default": 1.0},
|
|
424
|
+
"created_by": {"type": "string", "description": "Author/agent creating this edge", "default": "mcp-agent"},
|
|
425
|
+
},
|
|
426
|
+
},
|
|
427
|
+
),
|
|
428
|
+
# Assets
|
|
429
|
+
Tool(
|
|
430
|
+
name="coherence_list_assets",
|
|
431
|
+
description="List tracked assets (code, docs, endpoints) with pagination.",
|
|
432
|
+
inputSchema={
|
|
433
|
+
"type": "object",
|
|
434
|
+
"properties": {
|
|
435
|
+
"limit": {"type": "number", "default": 100},
|
|
436
|
+
"offset": {"type": "number", "default": 0},
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
),
|
|
440
|
+
Tool(
|
|
441
|
+
name="coherence_get_asset",
|
|
442
|
+
description="Get detail for a specific asset by UUID.",
|
|
443
|
+
inputSchema={
|
|
444
|
+
"type": "object",
|
|
445
|
+
"required": ["asset_id"],
|
|
446
|
+
"properties": {
|
|
447
|
+
"asset_id": {"type": "string", "description": "The asset UUID"},
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
),
|
|
451
|
+
Tool(
|
|
452
|
+
name="coherence_create_asset",
|
|
453
|
+
description="Register a new tracked asset.",
|
|
454
|
+
inputSchema={
|
|
455
|
+
"type": "object",
|
|
456
|
+
"required": ["type", "description"],
|
|
457
|
+
"properties": {
|
|
458
|
+
"type": {"type": "string", "description": "CODE, DOCS, ENDPOINT, etc."},
|
|
459
|
+
"description": {"type": "string", "description": "Asset description"},
|
|
460
|
+
"total_cost": {"type": "number", "description": "Initial CC cost", "default": 0},
|
|
461
|
+
},
|
|
462
|
+
},
|
|
463
|
+
),
|
|
464
|
+
# News
|
|
465
|
+
Tool(
|
|
466
|
+
name="coherence_get_news_feed",
|
|
467
|
+
description="Latest news items from configured RSS sources with optional POV ranking.",
|
|
468
|
+
inputSchema={
|
|
469
|
+
"type": "object",
|
|
470
|
+
"properties": {
|
|
471
|
+
"limit": {"type": "number", "default": 50},
|
|
472
|
+
"source": {"type": "string", "description": "Filter by source name"},
|
|
473
|
+
"pov": {"type": "string", "description": "Point-of-view lens ID to rank items by affinity"},
|
|
474
|
+
"refresh": {"type": "boolean", "default": False},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
),
|
|
478
|
+
Tool(
|
|
479
|
+
name="coherence_get_news_resonance",
|
|
480
|
+
description="News items matched to ideas with resonance scores and explanations.",
|
|
481
|
+
inputSchema={
|
|
482
|
+
"type": "object",
|
|
483
|
+
"properties": {
|
|
484
|
+
"limit": {"type": "number", "default": 100},
|
|
485
|
+
"top_n": {"type": "number", "default": 5},
|
|
486
|
+
"refresh": {"type": "boolean", "default": False},
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
),
|
|
490
|
+
Tool(
|
|
491
|
+
name="coherence_list_news_sources",
|
|
492
|
+
description="List all configured news sources.",
|
|
493
|
+
inputSchema={
|
|
494
|
+
"type": "object",
|
|
495
|
+
"properties": {
|
|
496
|
+
"active_only": {"type": "boolean", "default": False},
|
|
497
|
+
},
|
|
498
|
+
},
|
|
499
|
+
),
|
|
500
|
+
Tool(
|
|
501
|
+
name="coherence_add_news_source",
|
|
502
|
+
description="Add a new news source (RSS).",
|
|
503
|
+
inputSchema={
|
|
504
|
+
"type": "object",
|
|
505
|
+
"required": ["id", "url"],
|
|
506
|
+
"properties": {
|
|
507
|
+
"id": {"type": "string", "description": "Unique source ID"},
|
|
508
|
+
"name": {"type": "string"},
|
|
509
|
+
"url": {"type": "string", "description": "RSS feed URL"},
|
|
510
|
+
},
|
|
511
|
+
},
|
|
512
|
+
),
|
|
513
|
+
Tool(
|
|
514
|
+
name="coherence_get_trending_news",
|
|
515
|
+
description="Trending keywords extracted from recent news items.",
|
|
516
|
+
inputSchema={
|
|
517
|
+
"type": "object",
|
|
518
|
+
"properties": {
|
|
519
|
+
"top_n": {"type": "number", "default": 20},
|
|
520
|
+
"refresh": {"type": "boolean", "default": False},
|
|
521
|
+
},
|
|
522
|
+
},
|
|
523
|
+
),
|
|
524
|
+
# Treasury
|
|
525
|
+
Tool(
|
|
526
|
+
name="coherence_get_treasury_info",
|
|
527
|
+
description="Treasury wallet addresses, conversion rates, and total CC balance.",
|
|
528
|
+
inputSchema={"type": "object", "properties": {}},
|
|
529
|
+
),
|
|
530
|
+
Tool(
|
|
531
|
+
name="coherence_record_deposit",
|
|
532
|
+
description="Record a crypto deposit and convert to CC for a contributor.",
|
|
533
|
+
inputSchema={
|
|
534
|
+
"type": "object",
|
|
535
|
+
"required": ["contributor_id", "asset", "amount", "tx_hash"],
|
|
536
|
+
"properties": {
|
|
537
|
+
"contributor_id": {"type": "string"},
|
|
538
|
+
"asset": {"type": "string", "description": "eth or btc"},
|
|
539
|
+
"amount": {"type": "number"},
|
|
540
|
+
"tx_hash": {"type": "string"},
|
|
541
|
+
"wallet_address": {"type": "string"},
|
|
542
|
+
},
|
|
543
|
+
},
|
|
544
|
+
),
|
|
545
|
+
Tool(
|
|
546
|
+
name="coherence_get_deposit_history",
|
|
547
|
+
description="Get deposit history for a contributor.",
|
|
548
|
+
inputSchema={
|
|
549
|
+
"type": "object",
|
|
550
|
+
"required": ["contributor_id"],
|
|
551
|
+
"properties": {
|
|
552
|
+
"contributor_id": {"type": "string"},
|
|
553
|
+
},
|
|
554
|
+
},
|
|
555
|
+
),
|
|
556
|
+
# Governance
|
|
557
|
+
Tool(
|
|
558
|
+
name="coherence_list_change_requests",
|
|
559
|
+
description="List open governance change proposals.",
|
|
560
|
+
inputSchema={
|
|
561
|
+
"type": "object",
|
|
562
|
+
"properties": {
|
|
563
|
+
"limit": {"type": "number", "default": 200},
|
|
564
|
+
},
|
|
565
|
+
},
|
|
566
|
+
),
|
|
567
|
+
Tool(
|
|
568
|
+
name="coherence_get_change_request",
|
|
569
|
+
description="Get detail for a specific change proposal.",
|
|
570
|
+
inputSchema={
|
|
571
|
+
"type": "object",
|
|
572
|
+
"required": ["change_request_id"],
|
|
573
|
+
"properties": {
|
|
574
|
+
"change_request_id": {"type": "string"},
|
|
575
|
+
},
|
|
576
|
+
},
|
|
577
|
+
),
|
|
578
|
+
Tool(
|
|
579
|
+
name="coherence_vote_governance",
|
|
580
|
+
description="Cast a vote on a governance change proposal.",
|
|
581
|
+
inputSchema={
|
|
582
|
+
"type": "object",
|
|
583
|
+
"required": ["change_request_id", "voter_id", "vote"],
|
|
584
|
+
"properties": {
|
|
585
|
+
"change_request_id": {"type": "string"},
|
|
586
|
+
"voter_id": {"type": "string"},
|
|
587
|
+
"vote": {"type": "string", "description": "yes or no"},
|
|
588
|
+
"rationale": {"type": "string"},
|
|
589
|
+
},
|
|
590
|
+
},
|
|
591
|
+
),
|
|
592
|
+
Tool(
|
|
593
|
+
name="coherence_propose_governance",
|
|
594
|
+
description="Create a new governance change proposal.",
|
|
595
|
+
inputSchema={
|
|
596
|
+
"type": "object",
|
|
597
|
+
"required": ["title", "description", "proposer_id"],
|
|
598
|
+
"properties": {
|
|
599
|
+
"title": {"type": "string"},
|
|
600
|
+
"description": {"type": "string"},
|
|
601
|
+
"proposer_id": {"type": "string"},
|
|
602
|
+
"idea_id": {"type": "string"},
|
|
603
|
+
},
|
|
604
|
+
},
|
|
605
|
+
),
|
|
606
|
+
# DIF (Decentralized Identity Foundation)
|
|
607
|
+
Tool(
|
|
608
|
+
name="coherence_get_dif_stats",
|
|
609
|
+
description="DIF accuracy statistics — true/false positive rates, accuracy by language.",
|
|
610
|
+
inputSchema={"type": "object", "properties": {}},
|
|
611
|
+
),
|
|
612
|
+
Tool(
|
|
613
|
+
name="coherence_get_recent_dif",
|
|
614
|
+
description="Recent DIF verification entries with scores and outcomes.",
|
|
615
|
+
inputSchema={
|
|
616
|
+
"type": "object",
|
|
617
|
+
"properties": {
|
|
618
|
+
"limit": {"type": "number", "default": 20},
|
|
619
|
+
},
|
|
620
|
+
},
|
|
621
|
+
),
|
|
622
|
+
# Concepts (Living Codex ontology)
|
|
623
|
+
Tool(
|
|
624
|
+
name="coherence_list_concepts",
|
|
625
|
+
description="Browse the Living Codex ontology — 184 universal concepts with typed relationships and 53 axes.",
|
|
626
|
+
inputSchema={
|
|
627
|
+
"type": "object",
|
|
628
|
+
"properties": {
|
|
629
|
+
"limit": {"type": "number", "description": "Max concepts to return (default 50, max 500)", "default": 50},
|
|
630
|
+
"offset": {"type": "number", "description": "Pagination offset", "default": 0},
|
|
631
|
+
"search": {"type": "string", "description": "Search query to filter concepts"},
|
|
632
|
+
},
|
|
633
|
+
},
|
|
634
|
+
),
|
|
635
|
+
Tool(
|
|
636
|
+
name="coherence_get_concept",
|
|
637
|
+
description="Get full details for a single concept from the Living Codex ontology.",
|
|
638
|
+
inputSchema={
|
|
639
|
+
"type": "object",
|
|
640
|
+
"required": ["concept_id"],
|
|
641
|
+
"properties": {
|
|
642
|
+
"concept_id": {"type": "string", "description": "Concept ID (e.g. 'activity', 'knowledge', 'resonance')"},
|
|
643
|
+
"include_edges": {"type": "boolean", "description": "Include typed relationship edges", "default": False},
|
|
644
|
+
},
|
|
645
|
+
},
|
|
646
|
+
),
|
|
647
|
+
Tool(
|
|
648
|
+
name="coherence_link_concepts",
|
|
649
|
+
description="Create a typed relationship edge between two concepts in the Living Codex ontology.",
|
|
650
|
+
inputSchema={
|
|
651
|
+
"type": "object",
|
|
652
|
+
"required": ["from_id", "relationship_type", "to_id"],
|
|
653
|
+
"properties": {
|
|
654
|
+
"from_id": {"type": "string", "description": "Source concept ID"},
|
|
655
|
+
"relationship_type": {"type": "string", "description": "Relationship type (transforms, contains, enables, opposes, ...)"},
|
|
656
|
+
"to_id": {"type": "string", "description": "Target concept ID"},
|
|
657
|
+
"created_by": {"type": "string", "description": "Author/agent creating this edge", "default": "mcp"},
|
|
658
|
+
},
|
|
659
|
+
},
|
|
660
|
+
),
|
|
661
|
+
]
|
|
662
|
+
|
|
663
|
+
TOOL_MAP: dict[str, Tool] = {t.name: t for t in TOOLS}
|
|
664
|
+
|
|
665
|
+
# ---------------------------------------------------------------------------
|
|
666
|
+
# Tool dispatch
|
|
667
|
+
# ---------------------------------------------------------------------------
|
|
668
|
+
|
|
669
|
+
def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
670
|
+
match name:
|
|
671
|
+
# Ideas
|
|
672
|
+
case "coherence_list_ideas":
|
|
673
|
+
if args.get("search"):
|
|
674
|
+
return api_get("/api/ideas/cards", {"search": args["search"], "limit": args.get("limit", 20)})
|
|
675
|
+
return api_get("/api/ideas", {"limit": args.get("limit", 20)})
|
|
676
|
+
case "coherence_get_idea":
|
|
677
|
+
return api_get(f"/api/ideas/{args['idea_id']}")
|
|
678
|
+
case "coherence_idea_progress":
|
|
679
|
+
return api_get(f"/api/ideas/{args['idea_id']}/progress")
|
|
680
|
+
case "coherence_select_idea":
|
|
681
|
+
return api_post("/api/ideas/select", {"temperature": args.get("temperature", 0.5)})
|
|
682
|
+
case "coherence_showcase":
|
|
683
|
+
return api_get("/api/ideas/showcase")
|
|
684
|
+
case "coherence_resonance":
|
|
685
|
+
return api_get("/api/ideas/resonance")
|
|
686
|
+
# Specs
|
|
687
|
+
case "coherence_list_specs":
|
|
688
|
+
if args.get("search"):
|
|
689
|
+
return api_get("/api/spec-registry/cards", {"search": args["search"], "limit": args.get("limit", 20)})
|
|
690
|
+
return api_get("/api/spec-registry", {"limit": args.get("limit", 20)})
|
|
691
|
+
case "coherence_get_spec":
|
|
692
|
+
return api_get(f"/api/spec-registry/{args['spec_id']}")
|
|
693
|
+
# Lineage
|
|
694
|
+
case "coherence_list_lineage":
|
|
695
|
+
return api_get("/api/value-lineage/links", {"limit": args.get("limit", 20)})
|
|
696
|
+
case "coherence_lineage_valuation":
|
|
697
|
+
return api_get(f"/api/value-lineage/links/{args['lineage_id']}/valuation")
|
|
698
|
+
# Identity
|
|
699
|
+
case "coherence_list_providers":
|
|
700
|
+
return api_get("/api/identity/providers")
|
|
701
|
+
case "coherence_link_identity":
|
|
702
|
+
return api_post("/api/identity/link", {
|
|
703
|
+
"contributor_id": args["contributor_id"],
|
|
704
|
+
"provider": args["provider"],
|
|
705
|
+
"provider_id": args["provider_id"],
|
|
706
|
+
"display_name": args["provider_id"],
|
|
707
|
+
})
|
|
708
|
+
case "coherence_lookup_identity":
|
|
709
|
+
from urllib.parse import quote
|
|
710
|
+
return api_get(f"/api/identity/lookup/{quote(args['provider'])}/{quote(args['provider_id'])}")
|
|
711
|
+
case "coherence_get_identities":
|
|
712
|
+
from urllib.parse import quote
|
|
713
|
+
return api_get(f"/api/identity/{quote(args['contributor_id'])}")
|
|
714
|
+
# Contributions
|
|
715
|
+
case "coherence_record_contribution":
|
|
716
|
+
return api_post("/api/contributions/record", {
|
|
717
|
+
k: v for k, v in {
|
|
718
|
+
"contributor_id": args.get("contributor_id"),
|
|
719
|
+
"provider": args.get("provider"),
|
|
720
|
+
"provider_id": args.get("provider_id"),
|
|
721
|
+
"type": args["type"],
|
|
722
|
+
"amount_cc": args.get("amount_cc", 1),
|
|
723
|
+
"idea_id": args.get("idea_id"),
|
|
724
|
+
}.items() if v is not None
|
|
725
|
+
})
|
|
726
|
+
case "coherence_contributor_ledger":
|
|
727
|
+
from urllib.parse import quote
|
|
728
|
+
return api_get(f"/api/contributions/ledger/{quote(args['contributor_id'])}")
|
|
729
|
+
# Status
|
|
730
|
+
case "coherence_status":
|
|
731
|
+
health = api_get("/api/health")
|
|
732
|
+
count = api_get("/api/ideas/count")
|
|
733
|
+
nodes = api_get("/api/federation/nodes")
|
|
734
|
+
return {
|
|
735
|
+
"health": health,
|
|
736
|
+
"ideas": count,
|
|
737
|
+
"federation_nodes": len(nodes) if isinstance(nodes, list) else 0,
|
|
738
|
+
}
|
|
739
|
+
case "coherence_friction_report":
|
|
740
|
+
return api_get("/api/friction/report", {"window_days": args.get("window_days", 30)})
|
|
741
|
+
# Governance
|
|
742
|
+
case "coherence_list_change_requests":
|
|
743
|
+
return api_get("/api/governance/change-requests")
|
|
744
|
+
# Federation
|
|
745
|
+
case "coherence_list_federation_nodes":
|
|
746
|
+
nodes = api_get("/api/federation/nodes")
|
|
747
|
+
caps = api_get("/api/federation/nodes/capabilities")
|
|
748
|
+
return {"nodes": nodes, "capabilities": caps}
|
|
749
|
+
# Tasks
|
|
750
|
+
case "coherence_list_tasks":
|
|
751
|
+
return api_get("/api/agent/tasks", {
|
|
752
|
+
"status": args.get("status"),
|
|
753
|
+
"task_type": args.get("task_type"),
|
|
754
|
+
"limit": args.get("limit", 20),
|
|
755
|
+
"offset": args.get("offset", 0),
|
|
756
|
+
})
|
|
757
|
+
case "coherence_get_task":
|
|
758
|
+
return api_get(f"/api/agent/tasks/{args['task_id']}")
|
|
759
|
+
case "coherence_task_next":
|
|
760
|
+
# Claim next available pending task
|
|
761
|
+
data = api_get("/api/agent/tasks", {"status": "pending", "limit": 1})
|
|
762
|
+
tasks = data.get("tasks", []) if isinstance(data, dict) else []
|
|
763
|
+
if not tasks:
|
|
764
|
+
return {"error": "No pending tasks available"}
|
|
765
|
+
task_id = tasks[0]["id"]
|
|
766
|
+
return api_patch(f"/api/agent/tasks/{task_id}", {
|
|
767
|
+
"status": "running",
|
|
768
|
+
"worker_id": args.get("worker_id", "mcp-agent"),
|
|
769
|
+
})
|
|
770
|
+
case "coherence_task_claim":
|
|
771
|
+
return api_patch(f"/api/agent/tasks/{args['task_id']}", {
|
|
772
|
+
"status": "running",
|
|
773
|
+
"worker_id": args.get("worker_id", "mcp-agent"),
|
|
774
|
+
})
|
|
775
|
+
case "coherence_task_report":
|
|
776
|
+
return api_patch(f"/api/agent/tasks/{args['task_id']}", {
|
|
777
|
+
"status": args["status"],
|
|
778
|
+
"output": args.get("output", f"Task {args['status']} via mcp-agent"),
|
|
779
|
+
})
|
|
780
|
+
case "coherence_task_seed":
|
|
781
|
+
idea_id = args["idea_id"]
|
|
782
|
+
# Fetch idea for name if not provided in direction
|
|
783
|
+
idea = api_get(f"/api/ideas/{idea_id}")
|
|
784
|
+
idea_name = idea.get("name", "Unknown Idea") if isinstance(idea, dict) else "Unknown Idea"
|
|
785
|
+
task_type = args.get("task_type", "spec")
|
|
786
|
+
direction = args.get("direction") or f"{task_type} for '{idea_name}' ({idea_id})"
|
|
787
|
+
return api_post("/api/agent/tasks", {
|
|
788
|
+
"task_type": task_type,
|
|
789
|
+
"direction": direction,
|
|
790
|
+
"context": {
|
|
791
|
+
"idea_id": idea_id,
|
|
792
|
+
"idea_name": idea_name,
|
|
793
|
+
"seeded_by": "mcp-agent",
|
|
794
|
+
},
|
|
795
|
+
})
|
|
796
|
+
case "coherence_task_events":
|
|
797
|
+
return api_get(f"/api/agent/tasks/{args['task_id']}/stream")
|
|
798
|
+
# Ideas
|
|
799
|
+
case "coherence_create_idea":
|
|
800
|
+
return api_post("/api/ideas", {
|
|
801
|
+
"id": args["id"],
|
|
802
|
+
"name": args["name"],
|
|
803
|
+
"description": args["description"],
|
|
804
|
+
"potential_value": args.get("potential_value", 100),
|
|
805
|
+
"estimated_cost": args.get("estimated_cost", 50),
|
|
806
|
+
"parent_idea_id": args.get("parent_idea_id"),
|
|
807
|
+
"tags": args.get("tags"),
|
|
808
|
+
})
|
|
809
|
+
case "coherence_update_idea":
|
|
810
|
+
return api_patch(f"/api/ideas/{args['idea_id']}", {
|
|
811
|
+
"name": args.get("name"),
|
|
812
|
+
"description": args.get("description"),
|
|
813
|
+
"stage": args.get("stage"),
|
|
814
|
+
"manifestation_status": args.get("manifestation_status"),
|
|
815
|
+
"potential_value": args.get("potential_value"),
|
|
816
|
+
"estimated_cost": args.get("estimated_cost"),
|
|
817
|
+
})
|
|
818
|
+
# Graph / Edges
|
|
819
|
+
case "coherence_list_edges":
|
|
820
|
+
return api_get("/api/edges", {
|
|
821
|
+
"type": args.get("type"),
|
|
822
|
+
"from_id": args.get("from_id"),
|
|
823
|
+
"to_id": args.get("to_id"),
|
|
824
|
+
"limit": args.get("limit", 50),
|
|
825
|
+
})
|
|
826
|
+
case "coherence_get_entity_edges":
|
|
827
|
+
return api_get(f"/api/entities/{args['entity_id']}/edges", {
|
|
828
|
+
"type": args.get("type"),
|
|
829
|
+
"direction": args.get("direction", "both"),
|
|
830
|
+
})
|
|
831
|
+
case "coherence_create_edge":
|
|
832
|
+
return api_post("/api/edges", {
|
|
833
|
+
"from_id": args["from_id"],
|
|
834
|
+
"to_id": args["to_id"],
|
|
835
|
+
"type": args["type"],
|
|
836
|
+
"strength": args.get("strength", 1.0),
|
|
837
|
+
"created_by": args.get("created_by", "mcp-agent"),
|
|
838
|
+
})
|
|
839
|
+
# Assets
|
|
840
|
+
case "coherence_list_assets":
|
|
841
|
+
return api_get("/api/assets", {"limit": args.get("limit", 100), "offset": args.get("offset", 0)})
|
|
842
|
+
case "coherence_get_asset":
|
|
843
|
+
return api_get(f"/api/assets/{args['asset_id']}")
|
|
844
|
+
case "coherence_create_asset":
|
|
845
|
+
return api_post("/api/assets", {
|
|
846
|
+
"type": args["type"],
|
|
847
|
+
"description": args["description"],
|
|
848
|
+
"total_cost": args.get("total_cost", 0),
|
|
849
|
+
})
|
|
850
|
+
# News
|
|
851
|
+
case "coherence_get_news_feed":
|
|
852
|
+
return api_get("/api/news/feed", {
|
|
853
|
+
"limit": args.get("limit", 50),
|
|
854
|
+
"source": args.get("source"),
|
|
855
|
+
"pov": args.get("pov"),
|
|
856
|
+
"refresh": args.get("refresh", False),
|
|
857
|
+
})
|
|
858
|
+
case "coherence_get_news_resonance":
|
|
859
|
+
return api_get("/api/news/resonance", {
|
|
860
|
+
"limit": args.get("limit", 100),
|
|
861
|
+
"top_n": args.get("top_n", 5),
|
|
862
|
+
"refresh": args.get("refresh", False),
|
|
863
|
+
})
|
|
864
|
+
case "coherence_list_news_sources":
|
|
865
|
+
return api_get("/api/news/sources", {"active_only": args.get("active_only", False)})
|
|
866
|
+
case "coherence_add_news_source":
|
|
867
|
+
return api_post("/api/news/sources", {
|
|
868
|
+
"id": args["id"],
|
|
869
|
+
"url": args["url"],
|
|
870
|
+
"name": args.get("name"),
|
|
871
|
+
})
|
|
872
|
+
case "coherence_get_trending_news":
|
|
873
|
+
return api_get("/api/news/trending", {
|
|
874
|
+
"top_n": args.get("top_n", 20),
|
|
875
|
+
"refresh": args.get("refresh", False),
|
|
876
|
+
})
|
|
877
|
+
# Treasury
|
|
878
|
+
case "coherence_get_treasury_info":
|
|
879
|
+
return api_get("/api/treasury")
|
|
880
|
+
case "coherence_record_deposit":
|
|
881
|
+
return api_post("/api/treasury/deposit", {
|
|
882
|
+
"contributor_id": args["contributor_id"],
|
|
883
|
+
"asset": args["asset"],
|
|
884
|
+
"amount": args["amount"],
|
|
885
|
+
"tx_hash": args["tx_hash"],
|
|
886
|
+
"wallet_address": args.get("wallet_address"),
|
|
887
|
+
})
|
|
888
|
+
case "coherence_get_deposit_history":
|
|
889
|
+
return api_get(f"/api/treasury/deposits/{args['contributor_id']}")
|
|
890
|
+
# Governance
|
|
891
|
+
case "coherence_list_change_requests":
|
|
892
|
+
return api_get("/api/governance/change-requests", {"limit": args.get("limit", 200)})
|
|
893
|
+
case "coherence_get_change_request":
|
|
894
|
+
return api_get(f"/api/governance/change-requests/{args['change_request_id']}")
|
|
895
|
+
case "coherence_vote_governance":
|
|
896
|
+
return api_post(f"/api/governance/change-requests/{args['change_request_id']}/votes", {
|
|
897
|
+
"voter_id": args["voter_id"],
|
|
898
|
+
"vote": args["vote"],
|
|
899
|
+
"rationale": args.get("rationale"),
|
|
900
|
+
})
|
|
901
|
+
case "coherence_propose_governance":
|
|
902
|
+
return api_post("/api/governance/change-requests", {
|
|
903
|
+
"title": args["title"],
|
|
904
|
+
"description": args["description"],
|
|
905
|
+
"proposer_id": args["proposer_id"],
|
|
906
|
+
"idea_id": args.get("idea_id"),
|
|
907
|
+
})
|
|
908
|
+
# DIF
|
|
909
|
+
case "coherence_get_dif_stats":
|
|
910
|
+
return api_get("/api/dif/stats")
|
|
911
|
+
case "coherence_get_recent_dif":
|
|
912
|
+
return api_get("/api/dif/recent", {"limit": args.get("limit", 20)})
|
|
913
|
+
# Concepts
|
|
914
|
+
case "coherence_list_concepts":
|
|
915
|
+
if args.get("search"):
|
|
916
|
+
return api_get("/api/concepts/search", {"q": args["search"], "limit": args.get("limit", 20)})
|
|
917
|
+
return api_get("/api/concepts", {"limit": args.get("limit", 50), "offset": args.get("offset", 0)})
|
|
918
|
+
case "coherence_get_concept":
|
|
919
|
+
concept = api_get(f"/api/concepts/{args['concept_id']}")
|
|
920
|
+
if args.get("include_edges"):
|
|
921
|
+
edges = api_get(f"/api/concepts/{args['concept_id']}/edges")
|
|
922
|
+
if isinstance(concept, dict):
|
|
923
|
+
concept["edges"] = edges
|
|
924
|
+
return concept
|
|
925
|
+
case "coherence_link_concepts":
|
|
926
|
+
return api_post(f"/api/concepts/{args['from_id']}/edges", {
|
|
927
|
+
"from_id": args["from_id"],
|
|
928
|
+
"to_id": args["to_id"],
|
|
929
|
+
"relationship_type": args["relationship_type"],
|
|
930
|
+
"created_by": args.get("created_by", "mcp"),
|
|
931
|
+
})
|
|
932
|
+
case _:
|
|
933
|
+
return {"error": f"Unknown tool: {name}"}
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
# ---------------------------------------------------------------------------
|
|
937
|
+
# MCP server
|
|
938
|
+
# ---------------------------------------------------------------------------
|
|
939
|
+
|
|
940
|
+
server = Server("coherence-network")
|
|
941
|
+
|
|
942
|
+
|
|
943
|
+
@server.list_tools()
|
|
944
|
+
async def handle_list_tools() -> list[Tool]:
|
|
945
|
+
return TOOLS
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
@server.call_tool()
|
|
949
|
+
async def handle_call_tool(name: str, arguments: dict | None) -> list[TextContent]:
|
|
950
|
+
args = arguments or {}
|
|
951
|
+
try:
|
|
952
|
+
result = dispatch(name, args)
|
|
953
|
+
text = json.dumps(result, default=str)
|
|
954
|
+
except Exception as exc:
|
|
955
|
+
logger.exception("Tool %s failed", name)
|
|
956
|
+
text = json.dumps({"error": str(exc)})
|
|
957
|
+
return [TextContent(type="text", text=text)]
|
|
958
|
+
|
|
959
|
+
|
|
960
|
+
async def run() -> None:
|
|
961
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
962
|
+
await server.run(
|
|
963
|
+
read_stream,
|
|
964
|
+
write_stream,
|
|
965
|
+
server.create_initialization_options(),
|
|
966
|
+
)
|