coherence-mcp-server 0.5.1 → 0.5.2
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 +19 -3
- package/README.template.md +5 -3
- package/coherence_mcp_server/__init__.py +1 -1
- package/coherence_mcp_server/server.py +600 -14
- package/package.json +2 -2
- package/pyproject.toml +1 -1
- package/coherence_mcp_server/__pycache__/__init__.cpython-314.pyc +0 -0
- package/coherence_mcp_server/__pycache__/server.cpython-314.pyc +0 -0
package/README.md
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
+
<!-- AUTO-GENERATED from README.template.md. Edit the template, not this file. -->
|
|
1
2
|
# coherence-mcp-server
|
|
2
3
|
|
|
3
4
|
**Give your AI agent native access to every idea, spec, contributor, and value chain in the Coherence Network.**
|
|
4
5
|
|
|
5
|
-
An [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server that exposes the full Coherence Network API as
|
|
6
|
+
An [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server that exposes the full Coherence Network API as 89 typed tools — so Claude, Cursor, Windsurf, or any MCP-compatible agent can browse ideas, look up specs, trace value lineage, link identities, record contributions, execute tasks, discover resonant peers, apply project blueprints, receive the shared agent invitation, and read repository content via direct links without writing a single API call.
|
|
6
7
|
|
|
7
8
|
```bash
|
|
8
9
|
npx coherence-mcp-server
|
|
@@ -30,6 +31,7 @@ This MCP server changes that. It gives any agent a typed interface to:
|
|
|
30
31
|
- **Direct Access** — read specs and documentation via direct repository links
|
|
31
32
|
- **Ontology** — explore the Living Codex (184 universal concepts, 53 axes)
|
|
32
33
|
- **Govern** — propose changes, vote on requests, and monitor network health
|
|
34
|
+
- **Attune** — receive the shared AI-agent invitation before acting
|
|
33
35
|
|
|
34
36
|
Every tool returns structured JSON. No parsing HTML. No scraping. Just clean data.
|
|
35
37
|
|
|
@@ -76,7 +78,7 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
76
78
|
|
|
77
79
|
---
|
|
78
80
|
|
|
79
|
-
## Tools (
|
|
81
|
+
## Tools (89)
|
|
80
82
|
|
|
81
83
|
### Ideas — the portfolio engine
|
|
82
84
|
|
|
@@ -125,6 +127,7 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
125
127
|
|
|
126
128
|
| Tool | What it does |
|
|
127
129
|
|------|-------------|
|
|
130
|
+
| `coherence_agent_invitation` | Receive the shared AI-agent invitation: core frequency, attunement spectrum, entry surfaces, and contribution paths. |
|
|
128
131
|
| `coherence_list_tasks` | See what tasks are pending, running, or failed. |
|
|
129
132
|
| `coherence_get_task` | Full task details, direction, and result. |
|
|
130
133
|
| `coherence_task_next` | Claim the highest-priority pending task. |
|
|
@@ -133,6 +136,19 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
133
136
|
| `coherence_task_seed` | Create a new task from an idea. |
|
|
134
137
|
| `coherence_task_events` | View the activity event log for a task. |
|
|
135
138
|
|
|
139
|
+
### Awareness Streaming — presence in and out
|
|
140
|
+
|
|
141
|
+
| Tool | What it does |
|
|
142
|
+
|------|-------------|
|
|
143
|
+
| `coherence_awareness_publish` | Publish a diagnostic awareness event from a node. |
|
|
144
|
+
| `coherence_awareness_stream` | Read a bounded slice from diagnostic, node-message, or task SSE streams. |
|
|
145
|
+
| `coherence_node_message_send` | Send a durable node-to-node or broadcast message. |
|
|
146
|
+
| `coherence_node_messages` | Read durable inbound messages for a node. |
|
|
147
|
+
|
|
148
|
+
Streams are intentionally bounded. `duration_seconds` defaults to 5 seconds
|
|
149
|
+
and is capped at 30; `max_events` defaults to 20 and is capped at 200. This
|
|
150
|
+
lets MCP clients sense live awareness without leaving a tool call open forever.
|
|
151
|
+
|
|
136
152
|
### Graph — universal navigation
|
|
137
153
|
|
|
138
154
|
| Tool | What it does |
|
|
@@ -256,7 +272,7 @@ Every part of the network links to every other. Jump in wherever makes sense.
|
|
|
256
272
|
| **Web** | Browse ideas, specs, and contributors visually | [coherencycoin.com](https://coherencycoin.com) |
|
|
257
273
|
| **API** | 100+ endpoints, full OpenAPI docs, the engine behind everything | [api.coherencycoin.com/docs](https://api.coherencycoin.com/docs) |
|
|
258
274
|
| **CLI** | Terminal-first access — `npm i -g coherence-cli` then `cc help` | [npm: coherence-cli](https://www.npmjs.com/package/coherence-cli) |
|
|
259
|
-
| **MCP Server** | This package —
|
|
275
|
+
| **MCP Server** | This package — 89 typed tools for AI agents | [npm: coherence-mcp-server](https://www.npmjs.com/package/coherence-mcp-server) |
|
|
260
276
|
| **OpenClaw Skill** | Auto-triggers in any OpenClaw instance for ideas, specs, coherence | [ClawHub: coherence-network](https://clawhub.com/skills/coherence-network) |
|
|
261
277
|
| **GitHub** | Source code, specs, issues, and contribution tracking | [github.com/seeker71/Coherence-Network](https://github.com/seeker71/Coherence-Network) |
|
|
262
278
|
|
package/README.template.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Give your AI agent native access to every idea, spec, contributor, and value chain in the Coherence Network.**
|
|
4
4
|
|
|
5
|
-
An [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server that exposes the full Coherence Network API as
|
|
5
|
+
An [MCP](https://modelcontextprotocol.io/) (Model Context Protocol) server that exposes the full Coherence Network API as 89 typed tools — so Claude, Cursor, Windsurf, or any MCP-compatible agent can browse ideas, look up specs, trace value lineage, link identities, record contributions, execute tasks, discover resonant peers, apply project blueprints, receive the shared agent invitation, and read repository content via direct links without writing a single API call.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
npx coherence-mcp-server
|
|
@@ -30,6 +30,7 @@ This MCP server changes that. It gives any agent a typed interface to:
|
|
|
30
30
|
- **Direct Access** — read specs and documentation via direct repository links
|
|
31
31
|
- **Ontology** — explore the Living Codex (184 universal concepts, 53 axes)
|
|
32
32
|
- **Govern** — propose changes, vote on requests, and monitor network health
|
|
33
|
+
- **Attune** — receive the shared AI-agent invitation before acting
|
|
33
34
|
|
|
34
35
|
Every tool returns structured JSON. No parsing HTML. No scraping. Just clean data.
|
|
35
36
|
|
|
@@ -76,7 +77,7 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
76
77
|
|
|
77
78
|
---
|
|
78
79
|
|
|
79
|
-
## Tools (
|
|
80
|
+
## Tools (89)
|
|
80
81
|
|
|
81
82
|
### Ideas — the portfolio engine
|
|
82
83
|
|
|
@@ -125,6 +126,7 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
125
126
|
|
|
126
127
|
| Tool | What it does |
|
|
127
128
|
|------|-------------|
|
|
129
|
+
| `coherence_agent_invitation` | Receive the shared AI-agent invitation: core frequency, attunement spectrum, entry surfaces, and contribution paths. |
|
|
128
130
|
| `coherence_list_tasks` | See what tasks are pending, running, or failed. |
|
|
129
131
|
| `coherence_get_task` | Full task details, direction, and result. |
|
|
130
132
|
| `coherence_task_next` | Claim the highest-priority pending task. |
|
|
@@ -256,7 +258,7 @@ Every part of the network links to every other. Jump in wherever makes sense.
|
|
|
256
258
|
| **Web** | Browse ideas, specs, and contributors visually | [coherencycoin.com](https://coherencycoin.com) |
|
|
257
259
|
| **API** | 100+ endpoints, full OpenAPI docs, the engine behind everything | [api.coherencycoin.com/docs](https://api.coherencycoin.com/docs) |
|
|
258
260
|
| **CLI** | Terminal-first access — `npm i -g coherence-cli` then `cc help` | [npm: coherence-cli](https://www.npmjs.com/package/coherence-cli) |
|
|
259
|
-
| **MCP Server** | This package —
|
|
261
|
+
| **MCP Server** | This package — 89 typed tools for AI agents | [npm: coherence-mcp-server](https://www.npmjs.com/package/coherence-mcp-server) |
|
|
260
262
|
| **OpenClaw Skill** | Auto-triggers in any OpenClaw instance for ideas, specs, coherence | [ClawHub: coherence-network](https://clawhub.com/skills/coherence-network) |
|
|
261
263
|
| **GitHub** | Source code, specs, issues, and contribution tracking | [github.com/seeker71/Coherence-Network](https://github.com/seeker71/Coherence-Network) |
|
|
262
264
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Coherence Network MCP server — Python implementation.
|
|
2
2
|
|
|
3
|
-
Exposes the Coherence Network API as
|
|
3
|
+
Exposes the Coherence Network API as typed MCP tools.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
@@ -8,7 +8,9 @@ from __future__ import annotations
|
|
|
8
8
|
import json
|
|
9
9
|
import logging
|
|
10
10
|
import os
|
|
11
|
+
import time
|
|
11
12
|
from typing import Any
|
|
13
|
+
from urllib.parse import quote
|
|
12
14
|
|
|
13
15
|
import httpx
|
|
14
16
|
from mcp.server import Server
|
|
@@ -76,6 +78,112 @@ def api_patch(path: str, body: dict[str, Any]) -> Any:
|
|
|
76
78
|
return {"error": str(exc)}
|
|
77
79
|
|
|
78
80
|
|
|
81
|
+
def api_put(path: str, body: dict[str, Any]) -> Any:
|
|
82
|
+
url = f"{API_BASE}{path}"
|
|
83
|
+
try:
|
|
84
|
+
r = httpx.put(url, json=body, headers=_headers(), timeout=15.0)
|
|
85
|
+
r.raise_for_status()
|
|
86
|
+
return r.json()
|
|
87
|
+
except httpx.HTTPStatusError as exc:
|
|
88
|
+
try:
|
|
89
|
+
detail = exc.response.json().get("detail", exc.response.reason_phrase)
|
|
90
|
+
except Exception:
|
|
91
|
+
detail = exc.response.reason_phrase
|
|
92
|
+
return {"error": detail}
|
|
93
|
+
except Exception as exc:
|
|
94
|
+
return {"error": str(exc)}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def decode_sse_events(lines: list[str]) -> list[dict[str, Any]]:
|
|
98
|
+
"""Decode SSE data lines into JSON objects, preserving raw payloads."""
|
|
99
|
+
events: list[dict[str, Any]] = []
|
|
100
|
+
data_lines: list[str] = []
|
|
101
|
+
|
|
102
|
+
def flush() -> None:
|
|
103
|
+
if not data_lines:
|
|
104
|
+
return
|
|
105
|
+
payload = "\n".join(data_lines).strip()
|
|
106
|
+
data_lines.clear()
|
|
107
|
+
if not payload:
|
|
108
|
+
return
|
|
109
|
+
try:
|
|
110
|
+
parsed = json.loads(payload)
|
|
111
|
+
events.append(parsed if isinstance(parsed, dict) else {"data": parsed})
|
|
112
|
+
except json.JSONDecodeError:
|
|
113
|
+
events.append({"raw": payload})
|
|
114
|
+
|
|
115
|
+
for raw_line in lines:
|
|
116
|
+
line = raw_line.rstrip("\r\n")
|
|
117
|
+
if not line:
|
|
118
|
+
flush()
|
|
119
|
+
continue
|
|
120
|
+
if line.startswith(":"):
|
|
121
|
+
continue
|
|
122
|
+
if line.startswith("data:"):
|
|
123
|
+
data_lines.append(line[5:].lstrip())
|
|
124
|
+
flush()
|
|
125
|
+
return events
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def api_sse(
|
|
129
|
+
path: str,
|
|
130
|
+
params: dict[str, Any] | None = None,
|
|
131
|
+
*,
|
|
132
|
+
duration_seconds: float = 5.0,
|
|
133
|
+
max_events: int = 20,
|
|
134
|
+
) -> dict[str, Any]:
|
|
135
|
+
"""Read a bounded slice from an SSE endpoint and return parsed events."""
|
|
136
|
+
url = f"{API_BASE}{path}"
|
|
137
|
+
filtered = {k: v for k, v in (params or {}).items() if v is not None}
|
|
138
|
+
deadline = time.monotonic() + max(0.1, min(float(duration_seconds), 30.0))
|
|
139
|
+
read_timeout = max(1.0, min(float(duration_seconds) + 1.0, 10.0))
|
|
140
|
+
event_limit = max(1, min(int(max_events), 200))
|
|
141
|
+
lines: list[str] = []
|
|
142
|
+
events: list[dict[str, Any]] = []
|
|
143
|
+
|
|
144
|
+
try:
|
|
145
|
+
with httpx.stream(
|
|
146
|
+
"GET",
|
|
147
|
+
url,
|
|
148
|
+
params=filtered,
|
|
149
|
+
headers={**_headers(), "Accept": "text/event-stream"},
|
|
150
|
+
timeout=httpx.Timeout(connect=5.0, read=read_timeout, write=5.0, pool=5.0),
|
|
151
|
+
) as response:
|
|
152
|
+
response.raise_for_status()
|
|
153
|
+
for line in response.iter_lines():
|
|
154
|
+
lines.append(line)
|
|
155
|
+
if line == "":
|
|
156
|
+
events = decode_sse_events(lines)
|
|
157
|
+
if len(events) >= event_limit:
|
|
158
|
+
break
|
|
159
|
+
if time.monotonic() >= deadline:
|
|
160
|
+
break
|
|
161
|
+
if not events:
|
|
162
|
+
events = decode_sse_events(lines)
|
|
163
|
+
events = events[:event_limit]
|
|
164
|
+
return {
|
|
165
|
+
"stream": path,
|
|
166
|
+
"duration_seconds": duration_seconds,
|
|
167
|
+
"max_events": event_limit,
|
|
168
|
+
"count": len(events),
|
|
169
|
+
"events": events,
|
|
170
|
+
}
|
|
171
|
+
except httpx.HTTPStatusError as exc:
|
|
172
|
+
return {"error": f"{exc.response.status_code} {exc.response.reason_phrase}", "stream": path}
|
|
173
|
+
except httpx.ReadTimeout:
|
|
174
|
+
events = decode_sse_events(lines)[:event_limit]
|
|
175
|
+
return {
|
|
176
|
+
"stream": path,
|
|
177
|
+
"duration_seconds": duration_seconds,
|
|
178
|
+
"max_events": event_limit,
|
|
179
|
+
"count": len(events),
|
|
180
|
+
"events": events,
|
|
181
|
+
"ended_by": "read_timeout",
|
|
182
|
+
}
|
|
183
|
+
except Exception as exc:
|
|
184
|
+
return {"error": str(exc), "stream": path}
|
|
185
|
+
|
|
186
|
+
|
|
79
187
|
# ---------------------------------------------------------------------------
|
|
80
188
|
# Tool definitions
|
|
81
189
|
# ---------------------------------------------------------------------------
|
|
@@ -256,12 +364,75 @@ TOOLS: list[Tool] = [
|
|
|
256
364
|
"properties": {"window_days": {"type": "number", "default": 30}},
|
|
257
365
|
},
|
|
258
366
|
),
|
|
367
|
+
Tool(
|
|
368
|
+
name="coherence_agent_invitation",
|
|
369
|
+
description="Receive the shared AI-agent invitation: core frequency, attunement spectrum, entry surfaces, and contribution paths.",
|
|
370
|
+
inputSchema={"type": "object", "properties": {}},
|
|
371
|
+
),
|
|
259
372
|
# Federation
|
|
260
373
|
Tool(
|
|
261
374
|
name="coherence_list_federation_nodes",
|
|
262
375
|
description="List federated nodes and their capabilities.",
|
|
263
376
|
inputSchema={"type": "object", "properties": {}},
|
|
264
377
|
),
|
|
378
|
+
Tool(
|
|
379
|
+
name="coherence_awareness_publish",
|
|
380
|
+
description="Publish a diagnostic awareness event from a federation node. Delivered to active diagnostic stream subscribers.",
|
|
381
|
+
inputSchema={
|
|
382
|
+
"type": "object",
|
|
383
|
+
"required": ["node_id", "event_type"],
|
|
384
|
+
"properties": {
|
|
385
|
+
"node_id": {"type": "string", "description": "Publishing node ID"},
|
|
386
|
+
"event_type": {"type": "string", "description": "Awareness event kind, e.g. heartbeat, reasoning, tool_call"},
|
|
387
|
+
"message": {"type": "string", "description": "Short human-readable signal"},
|
|
388
|
+
"data": {"type": "object", "description": "Optional structured event payload"},
|
|
389
|
+
},
|
|
390
|
+
},
|
|
391
|
+
),
|
|
392
|
+
Tool(
|
|
393
|
+
name="coherence_awareness_stream",
|
|
394
|
+
description="Read a bounded slice from diagnostic, node-message, or task-event SSE streams.",
|
|
395
|
+
inputSchema={
|
|
396
|
+
"type": "object",
|
|
397
|
+
"required": ["stream_type"],
|
|
398
|
+
"properties": {
|
|
399
|
+
"stream_type": {"type": "string", "description": "diagnostics, node, or task"},
|
|
400
|
+
"node_id": {"type": "string", "description": "Node ID for diagnostics/node streams; use '*' for all diagnostics"},
|
|
401
|
+
"task_id": {"type": "string", "description": "Task ID for task event streams"},
|
|
402
|
+
"duration_seconds": {"type": "number", "description": "Max seconds to hold stream open (default 5, max 30)", "default": 5},
|
|
403
|
+
"max_events": {"type": "number", "description": "Max parsed events to return (default 20, max 200)", "default": 20},
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
),
|
|
407
|
+
Tool(
|
|
408
|
+
name="coherence_node_message_send",
|
|
409
|
+
description="Send a federation node message. Use to stream awareness out as durable node-to-node text or command payloads.",
|
|
410
|
+
inputSchema={
|
|
411
|
+
"type": "object",
|
|
412
|
+
"required": ["from_node_id", "text"],
|
|
413
|
+
"properties": {
|
|
414
|
+
"from_node_id": {"type": "string", "description": "Sender node ID"},
|
|
415
|
+
"to_node_id": {"type": "string", "description": "Recipient node ID; omit for broadcast"},
|
|
416
|
+
"type": {"type": "string", "description": "Message type, e.g. text, command, command_response", "default": "text"},
|
|
417
|
+
"text": {"type": "string", "description": "Message text"},
|
|
418
|
+
"payload": {"type": "object", "description": "Optional structured payload"},
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
),
|
|
422
|
+
Tool(
|
|
423
|
+
name="coherence_node_messages",
|
|
424
|
+
description="Read federation node messages for a node. This is the durable inbound awareness channel.",
|
|
425
|
+
inputSchema={
|
|
426
|
+
"type": "object",
|
|
427
|
+
"required": ["node_id"],
|
|
428
|
+
"properties": {
|
|
429
|
+
"node_id": {"type": "string", "description": "Recipient node ID"},
|
|
430
|
+
"since": {"type": "string", "description": "Optional ISO timestamp lower bound"},
|
|
431
|
+
"unread_only": {"type": "boolean", "description": "Only unread messages (default true)", "default": True},
|
|
432
|
+
"limit": {"type": "number", "description": "Max messages to return (default 50)", "default": 50},
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
),
|
|
265
436
|
# Tasks (Agent Work Protocol)
|
|
266
437
|
Tool(
|
|
267
438
|
name="coherence_list_tasks",
|
|
@@ -295,6 +466,7 @@ TOOLS: list[Tool] = [
|
|
|
295
466
|
"type": "object",
|
|
296
467
|
"properties": {
|
|
297
468
|
"worker_id": {"type": "string", "description": "Identity of the agent/node claiming the task (defaults to 'mcp-agent')"},
|
|
469
|
+
"workspace_id": {"type": "string", "description": "Optional workspace to filter pending tasks by."},
|
|
298
470
|
},
|
|
299
471
|
},
|
|
300
472
|
),
|
|
@@ -307,6 +479,7 @@ TOOLS: list[Tool] = [
|
|
|
307
479
|
"properties": {
|
|
308
480
|
"task_id": {"type": "string", "description": "The task ID"},
|
|
309
481
|
"worker_id": {"type": "string", "description": "Identity of the agent/node (defaults to 'mcp-agent')"},
|
|
482
|
+
"workspace_id": {"type": "string", "description": "Optional workspace context for the claim."},
|
|
310
483
|
},
|
|
311
484
|
},
|
|
312
485
|
),
|
|
@@ -333,6 +506,7 @@ TOOLS: list[Tool] = [
|
|
|
333
506
|
"idea_id": {"type": "string", "description": "Target idea ID"},
|
|
334
507
|
"task_type": {"type": "string", "description": "Type of task: spec, test, impl, review (default: spec)", "default": "spec"},
|
|
335
508
|
"direction": {"type": "string", "description": "Optional custom instruction for the task"},
|
|
509
|
+
"workspace_id": {"type": "string", "description": "Optional workspace to scope this task to."},
|
|
336
510
|
},
|
|
337
511
|
},
|
|
338
512
|
),
|
|
@@ -715,7 +889,7 @@ TOOLS: list[Tool] = [
|
|
|
715
889
|
"type": "object",
|
|
716
890
|
"required": ["path"],
|
|
717
891
|
"properties": {
|
|
718
|
-
"path": {"type": "string", "description": "Relative path from repo root (e.g. 'specs/
|
|
892
|
+
"path": {"type": "string", "description": "Relative path from repo root (e.g. 'specs/smart-reap.md')"},
|
|
719
893
|
},
|
|
720
894
|
},
|
|
721
895
|
),
|
|
@@ -823,6 +997,235 @@ TOOLS: list[Tool] = [
|
|
|
823
997
|
},
|
|
824
998
|
},
|
|
825
999
|
),
|
|
1000
|
+
# Pipeline Policies
|
|
1001
|
+
Tool(
|
|
1002
|
+
name="coherence_pipeline_policies",
|
|
1003
|
+
description="View or update pipeline policies (phase_chain, max_retries, failure_patterns, provider_per_phase, etc). Use action='list' to see all, action='get' with key, action='set' with key+value.",
|
|
1004
|
+
inputSchema={
|
|
1005
|
+
"type": "object",
|
|
1006
|
+
"properties": {
|
|
1007
|
+
"action": {"type": "string", "enum": ["list", "get", "set"], "description": "Operation to perform"},
|
|
1008
|
+
"key": {"type": "string", "description": "Policy key (for get/set)"},
|
|
1009
|
+
"value": {"description": "Policy value to set (any JSON type, for set action)"},
|
|
1010
|
+
},
|
|
1011
|
+
"required": ["action"],
|
|
1012
|
+
},
|
|
1013
|
+
),
|
|
1014
|
+
# Workspace Tasks
|
|
1015
|
+
Tool(
|
|
1016
|
+
name="coherence_workspace_tasks",
|
|
1017
|
+
description="List tasks for a specific workspace, seed a full pipeline (spec->impl->test->review->deploy->verify), or get workspace status.",
|
|
1018
|
+
inputSchema={
|
|
1019
|
+
"type": "object",
|
|
1020
|
+
"properties": {
|
|
1021
|
+
"workspace_id": {"type": "string", "description": "Workspace ID to scope operations to"},
|
|
1022
|
+
"action": {"type": "string", "enum": ["list", "seed_pipeline", "status"], "description": "Action to perform"},
|
|
1023
|
+
"idea_id": {"type": "string", "description": "Idea ID (for seed_pipeline action)"},
|
|
1024
|
+
"start_phase": {"type": "string", "description": "Starting phase (default: spec)", "default": "spec"},
|
|
1025
|
+
},
|
|
1026
|
+
"required": ["workspace_id", "action"],
|
|
1027
|
+
},
|
|
1028
|
+
),
|
|
1029
|
+
# Team Membership
|
|
1030
|
+
Tool(
|
|
1031
|
+
name="coherence_list_workspace_members",
|
|
1032
|
+
description="List members of a workspace with their roles and join dates.",
|
|
1033
|
+
inputSchema={
|
|
1034
|
+
"type": "object",
|
|
1035
|
+
"required": ["workspace_id"],
|
|
1036
|
+
"properties": {
|
|
1037
|
+
"workspace_id": {"type": "string", "description": "Workspace slug"},
|
|
1038
|
+
},
|
|
1039
|
+
},
|
|
1040
|
+
),
|
|
1041
|
+
Tool(
|
|
1042
|
+
name="coherence_invite_member",
|
|
1043
|
+
description="Invite a contributor to a workspace with an optional role.",
|
|
1044
|
+
inputSchema={
|
|
1045
|
+
"type": "object",
|
|
1046
|
+
"required": ["workspace_id", "contributor_id"],
|
|
1047
|
+
"properties": {
|
|
1048
|
+
"workspace_id": {"type": "string", "description": "Workspace slug"},
|
|
1049
|
+
"contributor_id": {"type": "string", "description": "Contributor to invite"},
|
|
1050
|
+
"role": {"type": "string", "description": "Role: owner, admin, member (default: member)", "default": "member"},
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
),
|
|
1054
|
+
Tool(
|
|
1055
|
+
name="coherence_list_my_workspaces",
|
|
1056
|
+
description="List workspaces that a contributor belongs to.",
|
|
1057
|
+
inputSchema={
|
|
1058
|
+
"type": "object",
|
|
1059
|
+
"required": ["contributor_id"],
|
|
1060
|
+
"properties": {
|
|
1061
|
+
"contributor_id": {"type": "string", "description": "Contributor ID"},
|
|
1062
|
+
},
|
|
1063
|
+
},
|
|
1064
|
+
),
|
|
1065
|
+
# Messaging
|
|
1066
|
+
Tool(
|
|
1067
|
+
name="coherence_send_message",
|
|
1068
|
+
description="Send a message to a contributor (DM) or a workspace channel.",
|
|
1069
|
+
inputSchema={
|
|
1070
|
+
"type": "object",
|
|
1071
|
+
"required": ["from_contributor_id", "body"],
|
|
1072
|
+
"properties": {
|
|
1073
|
+
"from_contributor_id": {"type": "string", "description": "Sender contributor ID"},
|
|
1074
|
+
"to_contributor_id": {"type": "string", "description": "Recipient contributor ID (for DM)"},
|
|
1075
|
+
"to_workspace_id": {"type": "string", "description": "Target workspace ID (for workspace message)"},
|
|
1076
|
+
"subject": {"type": "string", "description": "Optional message subject"},
|
|
1077
|
+
"body": {"type": "string", "description": "Message body text"},
|
|
1078
|
+
},
|
|
1079
|
+
},
|
|
1080
|
+
),
|
|
1081
|
+
Tool(
|
|
1082
|
+
name="coherence_get_inbox",
|
|
1083
|
+
description="Get inbox messages for a contributor with optional filters.",
|
|
1084
|
+
inputSchema={
|
|
1085
|
+
"type": "object",
|
|
1086
|
+
"required": ["contributor_id"],
|
|
1087
|
+
"properties": {
|
|
1088
|
+
"contributor_id": {"type": "string", "description": "Contributor ID"},
|
|
1089
|
+
"limit": {"type": "number", "description": "Max messages to return (default 20)", "default": 20},
|
|
1090
|
+
"unread_only": {"type": "boolean", "description": "Only return unread messages", "default": False},
|
|
1091
|
+
},
|
|
1092
|
+
},
|
|
1093
|
+
),
|
|
1094
|
+
# Activity
|
|
1095
|
+
Tool(
|
|
1096
|
+
name="coherence_get_workspace_activity",
|
|
1097
|
+
description="Get the activity feed (event timeline) for a workspace.",
|
|
1098
|
+
inputSchema={
|
|
1099
|
+
"type": "object",
|
|
1100
|
+
"required": ["workspace_id"],
|
|
1101
|
+
"properties": {
|
|
1102
|
+
"workspace_id": {"type": "string", "description": "Workspace slug"},
|
|
1103
|
+
"limit": {"type": "number", "description": "Max events to return (default 20)", "default": 20},
|
|
1104
|
+
},
|
|
1105
|
+
},
|
|
1106
|
+
),
|
|
1107
|
+
# Projects
|
|
1108
|
+
Tool(
|
|
1109
|
+
name="coherence_list_workspace_projects",
|
|
1110
|
+
description="List projects in a workspace for organizing ideas into groups.",
|
|
1111
|
+
inputSchema={
|
|
1112
|
+
"type": "object",
|
|
1113
|
+
"required": ["workspace_id"],
|
|
1114
|
+
"properties": {
|
|
1115
|
+
"workspace_id": {"type": "string", "description": "Workspace slug"},
|
|
1116
|
+
},
|
|
1117
|
+
},
|
|
1118
|
+
),
|
|
1119
|
+
Tool(
|
|
1120
|
+
name="coherence_create_workspace_project",
|
|
1121
|
+
description="Create a new project within a workspace to group related ideas.",
|
|
1122
|
+
inputSchema={
|
|
1123
|
+
"type": "object",
|
|
1124
|
+
"required": ["workspace_id", "name"],
|
|
1125
|
+
"properties": {
|
|
1126
|
+
"workspace_id": {"type": "string", "description": "Workspace slug"},
|
|
1127
|
+
"name": {"type": "string", "description": "Project name"},
|
|
1128
|
+
"description": {"type": "string", "description": "Project description"},
|
|
1129
|
+
},
|
|
1130
|
+
},
|
|
1131
|
+
),
|
|
1132
|
+
# ── Discovery / Living Network ──
|
|
1133
|
+
Tool(
|
|
1134
|
+
name="coherence_discover",
|
|
1135
|
+
description="Serendipity feed — personalized discovery of resonant ideas, peers, cross-domain connections, and news. Returns what resonates with who you are.",
|
|
1136
|
+
inputSchema={
|
|
1137
|
+
"type": "object",
|
|
1138
|
+
"properties": {
|
|
1139
|
+
"contributor_id": {"type": "string", "description": "Contributor to discover for (default: general feed)"},
|
|
1140
|
+
"limit": {"type": "integer", "description": "Max items (default 20)"},
|
|
1141
|
+
},
|
|
1142
|
+
},
|
|
1143
|
+
),
|
|
1144
|
+
Tool(
|
|
1145
|
+
name="coherence_constellation",
|
|
1146
|
+
description="Network visualization data — nodes (ideas, contributors, concepts) and edges with positions for galaxy/constellation rendering.",
|
|
1147
|
+
inputSchema={
|
|
1148
|
+
"type": "object",
|
|
1149
|
+
"properties": {
|
|
1150
|
+
"max_nodes": {"type": "integer", "description": "Max nodes to return (default 80)"},
|
|
1151
|
+
"workspace_id": {"type": "string", "description": "Workspace to visualize (default: coherence-network)"},
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1154
|
+
),
|
|
1155
|
+
Tool(
|
|
1156
|
+
name="coherence_vitality",
|
|
1157
|
+
description="Workspace health as living-system signals — diversity index, resonance density, flow rate, breath rhythm, connection strength, activity pulse.",
|
|
1158
|
+
inputSchema={
|
|
1159
|
+
"type": "object",
|
|
1160
|
+
"properties": {
|
|
1161
|
+
"workspace_id": {"type": "string", "description": "Workspace ID (default: coherence-network)"},
|
|
1162
|
+
},
|
|
1163
|
+
},
|
|
1164
|
+
),
|
|
1165
|
+
Tool(
|
|
1166
|
+
name="coherence_resonate",
|
|
1167
|
+
description="Find ideas that share deep structural patterns with a given idea — cross-domain resonance via harmonic matching.",
|
|
1168
|
+
inputSchema={
|
|
1169
|
+
"type": "object",
|
|
1170
|
+
"required": ["idea_id"],
|
|
1171
|
+
"properties": {
|
|
1172
|
+
"idea_id": {"type": "string", "description": "Idea to find resonances for"},
|
|
1173
|
+
"limit": {"type": "integer", "description": "Max matches (default 10)"},
|
|
1174
|
+
},
|
|
1175
|
+
},
|
|
1176
|
+
),
|
|
1177
|
+
# ── Super-Idea Coverage: News, Federation, Beliefs, CC, Governance ──
|
|
1178
|
+
Tool(
|
|
1179
|
+
name="coherence_news_feed",
|
|
1180
|
+
description="Get the latest news items from configured RSS sources.",
|
|
1181
|
+
inputSchema={
|
|
1182
|
+
"type": "object",
|
|
1183
|
+
"properties": {
|
|
1184
|
+
"limit": {"type": "number", "description": "Max items to return (default 20)", "default": 20},
|
|
1185
|
+
},
|
|
1186
|
+
},
|
|
1187
|
+
),
|
|
1188
|
+
Tool(
|
|
1189
|
+
name="coherence_news_resonance",
|
|
1190
|
+
description="Get news items matched to ideas with resonance scores.",
|
|
1191
|
+
inputSchema={
|
|
1192
|
+
"type": "object",
|
|
1193
|
+
"properties": {
|
|
1194
|
+
"top_n": {"type": "number", "description": "Top N matches (default 5)", "default": 5},
|
|
1195
|
+
},
|
|
1196
|
+
},
|
|
1197
|
+
),
|
|
1198
|
+
Tool(
|
|
1199
|
+
name="coherence_federation_nodes",
|
|
1200
|
+
description="List federation nodes with hostname, OS, providers, and last heartbeat.",
|
|
1201
|
+
inputSchema={"type": "object", "properties": {}},
|
|
1202
|
+
),
|
|
1203
|
+
Tool(
|
|
1204
|
+
name="coherence_belief_profile",
|
|
1205
|
+
description="Get the belief profile for a contributor — worldview axes and top concepts.",
|
|
1206
|
+
inputSchema={
|
|
1207
|
+
"type": "object",
|
|
1208
|
+
"required": ["contributor_id"],
|
|
1209
|
+
"properties": {
|
|
1210
|
+
"contributor_id": {"type": "string", "description": "Contributor ID"},
|
|
1211
|
+
},
|
|
1212
|
+
},
|
|
1213
|
+
),
|
|
1214
|
+
Tool(
|
|
1215
|
+
name="coherence_cc_supply",
|
|
1216
|
+
description="Get CC token economics — total minted, outstanding, and coherence score.",
|
|
1217
|
+
inputSchema={"type": "object", "properties": {}},
|
|
1218
|
+
),
|
|
1219
|
+
Tool(
|
|
1220
|
+
name="coherence_governance_requests",
|
|
1221
|
+
description="List governance change requests with status and proposer info.",
|
|
1222
|
+
inputSchema={
|
|
1223
|
+
"type": "object",
|
|
1224
|
+
"properties": {
|
|
1225
|
+
"limit": {"type": "number", "description": "Max requests to return (default 20)", "default": 20},
|
|
1226
|
+
},
|
|
1227
|
+
},
|
|
1228
|
+
),
|
|
826
1229
|
]
|
|
827
1230
|
|
|
828
1231
|
TOOL_MAP: dict[str, Tool] = {t.name: t for t in TOOLS}
|
|
@@ -881,10 +1284,8 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
881
1284
|
"display_name": args["provider_id"],
|
|
882
1285
|
})
|
|
883
1286
|
case "coherence_lookup_identity":
|
|
884
|
-
from urllib.parse import quote
|
|
885
1287
|
return api_get(f"/api/identity/lookup/{quote(args['provider'])}/{quote(args['provider_id'])}")
|
|
886
1288
|
case "coherence_get_identities":
|
|
887
|
-
from urllib.parse import quote
|
|
888
1289
|
return api_get(f"/api/identity/{quote(args['contributor_id'])}")
|
|
889
1290
|
# Contributions
|
|
890
1291
|
case "coherence_record_contribution":
|
|
@@ -899,7 +1300,6 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
899
1300
|
}.items() if v is not None
|
|
900
1301
|
})
|
|
901
1302
|
case "coherence_contributor_ledger":
|
|
902
|
-
from urllib.parse import quote
|
|
903
1303
|
return api_get(f"/api/contributions/ledger/{quote(args['contributor_id'])}")
|
|
904
1304
|
# Status
|
|
905
1305
|
case "coherence_status":
|
|
@@ -913,11 +1313,65 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
913
1313
|
}
|
|
914
1314
|
case "coherence_friction_report":
|
|
915
1315
|
return api_get("/api/friction/report", {"window_days": args.get("window_days", 30)})
|
|
1316
|
+
case "coherence_agent_invitation":
|
|
1317
|
+
return api_get("/api/agent/invitation")
|
|
916
1318
|
# Federation
|
|
917
1319
|
case "coherence_list_federation_nodes":
|
|
918
1320
|
nodes = api_get("/api/federation/nodes")
|
|
919
1321
|
caps = api_get("/api/federation/nodes/capabilities")
|
|
920
1322
|
return {"nodes": nodes, "capabilities": caps}
|
|
1323
|
+
case "coherence_awareness_publish":
|
|
1324
|
+
body = {
|
|
1325
|
+
"event_type": args["event_type"],
|
|
1326
|
+
"message": args.get("message", ""),
|
|
1327
|
+
"data": args.get("data", {}),
|
|
1328
|
+
"source": "mcp",
|
|
1329
|
+
}
|
|
1330
|
+
return api_post(f"/api/federation/nodes/{quote(args['node_id'], safe='')}/diag", body)
|
|
1331
|
+
case "coherence_awareness_stream":
|
|
1332
|
+
stream_type = (args.get("stream_type") or "").strip().lower()
|
|
1333
|
+
duration_seconds = args.get("duration_seconds", 5)
|
|
1334
|
+
max_events = args.get("max_events", 20)
|
|
1335
|
+
if stream_type == "diagnostics":
|
|
1336
|
+
node_id = args.get("node_id") or "*"
|
|
1337
|
+
return api_sse(
|
|
1338
|
+
f"/api/federation/nodes/{quote(node_id, safe='*')}/diag/stream",
|
|
1339
|
+
duration_seconds=duration_seconds,
|
|
1340
|
+
max_events=max_events,
|
|
1341
|
+
)
|
|
1342
|
+
if stream_type == "node":
|
|
1343
|
+
node_id = args.get("node_id")
|
|
1344
|
+
if not node_id:
|
|
1345
|
+
return {"error": "node_id is required for node streams"}
|
|
1346
|
+
return api_sse(
|
|
1347
|
+
f"/api/federation/nodes/{quote(node_id, safe='')}/stream",
|
|
1348
|
+
duration_seconds=duration_seconds,
|
|
1349
|
+
max_events=max_events,
|
|
1350
|
+
)
|
|
1351
|
+
if stream_type == "task":
|
|
1352
|
+
task_id = args.get("task_id")
|
|
1353
|
+
if not task_id:
|
|
1354
|
+
return {"error": "task_id is required for task streams"}
|
|
1355
|
+
return api_sse(
|
|
1356
|
+
f"/api/agent/tasks/{quote(task_id, safe='')}/events",
|
|
1357
|
+
duration_seconds=duration_seconds,
|
|
1358
|
+
max_events=max_events,
|
|
1359
|
+
)
|
|
1360
|
+
return {"error": "stream_type must be one of: diagnostics, node, task"}
|
|
1361
|
+
case "coherence_node_message_send":
|
|
1362
|
+
body = {
|
|
1363
|
+
"to_node": args.get("to_node_id"),
|
|
1364
|
+
"type": args.get("type", "text"),
|
|
1365
|
+
"text": args["text"],
|
|
1366
|
+
"payload": args.get("payload", {}),
|
|
1367
|
+
}
|
|
1368
|
+
return api_post(f"/api/federation/nodes/{quote(args['from_node_id'], safe='')}/messages", body)
|
|
1369
|
+
case "coherence_node_messages":
|
|
1370
|
+
return api_get(f"/api/federation/nodes/{quote(args['node_id'], safe='')}/messages", {
|
|
1371
|
+
"since": args.get("since"),
|
|
1372
|
+
"unread_only": args.get("unread_only", True),
|
|
1373
|
+
"limit": args.get("limit", 50),
|
|
1374
|
+
})
|
|
921
1375
|
# Tasks
|
|
922
1376
|
case "coherence_list_tasks":
|
|
923
1377
|
params = {
|
|
@@ -933,7 +1387,10 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
933
1387
|
return api_get(f"/api/agent/tasks/{args['task_id']}")
|
|
934
1388
|
case "coherence_task_next":
|
|
935
1389
|
# Claim next available pending task
|
|
936
|
-
|
|
1390
|
+
params: dict[str, Any] = {"status": "pending", "limit": 1}
|
|
1391
|
+
if args.get("workspace_id"):
|
|
1392
|
+
params["workspace_id"] = args["workspace_id"]
|
|
1393
|
+
data = api_get("/api/agent/tasks", params)
|
|
937
1394
|
tasks = data.get("tasks", []) if isinstance(data, dict) else []
|
|
938
1395
|
if not tasks:
|
|
939
1396
|
return {"error": "No pending tasks available"}
|
|
@@ -959,14 +1416,17 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
959
1416
|
idea_name = idea.get("name", "Unknown Idea") if isinstance(idea, dict) else "Unknown Idea"
|
|
960
1417
|
task_type = args.get("task_type", "spec")
|
|
961
1418
|
direction = args.get("direction") or f"{task_type} for '{idea_name}' ({idea_id})"
|
|
1419
|
+
context: dict[str, Any] = {
|
|
1420
|
+
"idea_id": idea_id,
|
|
1421
|
+
"idea_name": idea_name,
|
|
1422
|
+
"seeded_by": "mcp-agent",
|
|
1423
|
+
}
|
|
1424
|
+
if args.get("workspace_id"):
|
|
1425
|
+
context["workspace_id"] = args["workspace_id"]
|
|
962
1426
|
return api_post("/api/agent/tasks", {
|
|
963
1427
|
"task_type": task_type,
|
|
964
1428
|
"direction": direction,
|
|
965
|
-
"context":
|
|
966
|
-
"idea_id": idea_id,
|
|
967
|
-
"idea_name": idea_name,
|
|
968
|
-
"seeded_by": "mcp-agent",
|
|
969
|
-
},
|
|
1429
|
+
"context": context,
|
|
970
1430
|
})
|
|
971
1431
|
case "coherence_task_events":
|
|
972
1432
|
return api_get(f"/api/agent/tasks/{args['task_id']}/stream")
|
|
@@ -1230,7 +1690,7 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
1230
1690
|
"navigation": {"idea_file": f"ideas/{entity_id}.md",
|
|
1231
1691
|
"spec_files": [f"specs/{s}.md" for s in spec_ids],
|
|
1232
1692
|
"api": f"/api/ideas/{entity_id}",
|
|
1233
|
-
"cli": f"
|
|
1693
|
+
"cli": f"coh idea {entity_id}"}}
|
|
1234
1694
|
elif entity_type == "spec":
|
|
1235
1695
|
spec = api_get(f"/api/spec-registry/{entity_id}")
|
|
1236
1696
|
spec_file = api_get("/api/content/file", {"path": f"specs/{entity_id}.md"})
|
|
@@ -1238,7 +1698,7 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
1238
1698
|
parent_idea = api_get(f"/api/ideas/{idea_id}") if idea_id else None
|
|
1239
1699
|
nav: dict[str, Any] = {"spec_file": f"specs/{entity_id}.md",
|
|
1240
1700
|
"api": f"/api/spec-registry/{entity_id}",
|
|
1241
|
-
"cli": f"
|
|
1701
|
+
"cli": f"coh spec {entity_id}"}
|
|
1242
1702
|
if idea_id:
|
|
1243
1703
|
nav["idea_file"] = f"ideas/{idea_id}.md"
|
|
1244
1704
|
return {"entity_type": "spec", "spec": spec, "spec_file_content": spec_file,
|
|
@@ -1252,9 +1712,135 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
1252
1712
|
return {"entity_type": "task", "task": task, "events": events,
|
|
1253
1713
|
"parent_idea": parent_idea,
|
|
1254
1714
|
"navigation": {"api": f"/api/agent/tasks/{entity_id}",
|
|
1255
|
-
"cli": f"
|
|
1715
|
+
"cli": f"coh task {entity_id}"}}
|
|
1256
1716
|
else:
|
|
1257
1717
|
return {"error": f"Unknown entity_type: {entity_type}. Use 'idea', 'spec', or 'task'."}
|
|
1718
|
+
# Pipeline Policies
|
|
1719
|
+
case "coherence_pipeline_policies":
|
|
1720
|
+
action = (args.get("action") or "list").strip()
|
|
1721
|
+
if action == "list":
|
|
1722
|
+
return api_get("/api/pipeline/policies")
|
|
1723
|
+
elif action == "get":
|
|
1724
|
+
key = args.get("key", "")
|
|
1725
|
+
return api_get(f"/api/pipeline/policies/{key}")
|
|
1726
|
+
elif action == "set":
|
|
1727
|
+
key = args.get("key", "")
|
|
1728
|
+
value = args.get("value")
|
|
1729
|
+
return api_put(f"/api/pipeline/policies/{key}", {
|
|
1730
|
+
"value": value,
|
|
1731
|
+
"updated_by": "mcp-agent",
|
|
1732
|
+
})
|
|
1733
|
+
else:
|
|
1734
|
+
return {"error": f"Unknown action: {action}. Use 'list', 'get', or 'set'."}
|
|
1735
|
+
# Workspace Tasks
|
|
1736
|
+
case "coherence_workspace_tasks":
|
|
1737
|
+
ws_id = args["workspace_id"]
|
|
1738
|
+
action = args["action"]
|
|
1739
|
+
if action == "list":
|
|
1740
|
+
return api_get(f"/api/agent/tasks", {"workspace_id": ws_id, "limit": 50})
|
|
1741
|
+
elif action == "seed_pipeline":
|
|
1742
|
+
idea_id = args.get("idea_id", "")
|
|
1743
|
+
start_phase = args.get("start_phase", "spec")
|
|
1744
|
+
return api_post("/api/agent/tasks", {
|
|
1745
|
+
"direction": f"Implement idea {idea_id} starting from {start_phase} phase",
|
|
1746
|
+
"task_type": start_phase,
|
|
1747
|
+
"context": {
|
|
1748
|
+
"idea_id": idea_id,
|
|
1749
|
+
"workspace_id": ws_id,
|
|
1750
|
+
"executor": "federation",
|
|
1751
|
+
},
|
|
1752
|
+
})
|
|
1753
|
+
elif action == "status":
|
|
1754
|
+
tasks_data = api_get(f"/api/agent/tasks", {"workspace_id": ws_id, "limit": 200})
|
|
1755
|
+
items = (
|
|
1756
|
+
tasks_data.get("items", [])
|
|
1757
|
+
if isinstance(tasks_data, dict)
|
|
1758
|
+
else tasks_data if isinstance(tasks_data, list)
|
|
1759
|
+
else []
|
|
1760
|
+
)
|
|
1761
|
+
status_counts: dict[str, int] = {}
|
|
1762
|
+
for t in items:
|
|
1763
|
+
s = t.get("status", "unknown") if isinstance(t, dict) else "unknown"
|
|
1764
|
+
status_counts[s] = status_counts.get(s, 0) + 1
|
|
1765
|
+
return {
|
|
1766
|
+
"workspace_id": ws_id,
|
|
1767
|
+
"total_tasks": len(items),
|
|
1768
|
+
"by_status": status_counts,
|
|
1769
|
+
}
|
|
1770
|
+
else:
|
|
1771
|
+
return {"error": f"Unknown action: {action}. Use 'list', 'seed_pipeline', or 'status'."}
|
|
1772
|
+
# Team Membership
|
|
1773
|
+
case "coherence_list_workspace_members":
|
|
1774
|
+
return api_get(f"/api/workspaces/{args['workspace_id']}/members")
|
|
1775
|
+
case "coherence_invite_member":
|
|
1776
|
+
return api_post(f"/api/workspaces/{args['workspace_id']}/invite", {
|
|
1777
|
+
"contributor_id": args["contributor_id"],
|
|
1778
|
+
"role": args.get("role", "member"),
|
|
1779
|
+
})
|
|
1780
|
+
case "coherence_list_my_workspaces":
|
|
1781
|
+
return api_get(f"/api/contributors/{args['contributor_id']}/workspaces")
|
|
1782
|
+
# Messaging
|
|
1783
|
+
case "coherence_send_message":
|
|
1784
|
+
body: dict[str, Any] = {
|
|
1785
|
+
"from_contributor_id": args["from_contributor_id"],
|
|
1786
|
+
"body": args["body"],
|
|
1787
|
+
}
|
|
1788
|
+
if args.get("to_contributor_id"):
|
|
1789
|
+
body["to_contributor_id"] = args["to_contributor_id"]
|
|
1790
|
+
if args.get("to_workspace_id"):
|
|
1791
|
+
body["to_workspace_id"] = args["to_workspace_id"]
|
|
1792
|
+
if args.get("subject"):
|
|
1793
|
+
body["subject"] = args["subject"]
|
|
1794
|
+
return api_post("/api/messages", body)
|
|
1795
|
+
case "coherence_get_inbox":
|
|
1796
|
+
return api_get(f"/api/messages/inbox/{args['contributor_id']}", {
|
|
1797
|
+
"limit": args.get("limit", 20),
|
|
1798
|
+
"unread_only": args.get("unread_only", False),
|
|
1799
|
+
})
|
|
1800
|
+
# Activity
|
|
1801
|
+
case "coherence_get_workspace_activity":
|
|
1802
|
+
return api_get(f"/api/workspaces/{args['workspace_id']}/activity", {
|
|
1803
|
+
"limit": args.get("limit", 20),
|
|
1804
|
+
})
|
|
1805
|
+
# Projects
|
|
1806
|
+
case "coherence_list_workspace_projects":
|
|
1807
|
+
return api_get(f"/api/workspaces/{args['workspace_id']}/projects")
|
|
1808
|
+
case "coherence_create_workspace_project":
|
|
1809
|
+
return api_post(f"/api/workspaces/{args['workspace_id']}/projects", {
|
|
1810
|
+
"name": args["name"],
|
|
1811
|
+
"description": args.get("description", ""),
|
|
1812
|
+
"workspace_id": args["workspace_id"],
|
|
1813
|
+
})
|
|
1814
|
+
# Discovery / Living Network
|
|
1815
|
+
case "coherence_discover":
|
|
1816
|
+
cid = args.get("contributor_id", "default-contributor")
|
|
1817
|
+
limit: int = args.get("limit", 20)
|
|
1818
|
+
return api_get(f"/api/discover/{cid}", {"limit": limit})
|
|
1819
|
+
case "coherence_constellation":
|
|
1820
|
+
return api_get("/api/constellation", {
|
|
1821
|
+
"max_nodes": args.get("max_nodes", 80),
|
|
1822
|
+
"workspace_id": args.get("workspace_id", "coherence-network"),
|
|
1823
|
+
})
|
|
1824
|
+
case "coherence_vitality":
|
|
1825
|
+
ws = args.get("workspace_id", "coherence-network")
|
|
1826
|
+
return api_get(f"/api/workspaces/{ws}/vitality")
|
|
1827
|
+
case "coherence_resonate":
|
|
1828
|
+
return api_get(f"/api/resonance/ideas/{args['idea_id']}", {
|
|
1829
|
+
"limit": args.get("limit", 10),
|
|
1830
|
+
})
|
|
1831
|
+
# Super-Idea Coverage
|
|
1832
|
+
case "coherence_news_feed":
|
|
1833
|
+
return api_get("/api/news/feed", {"limit": args.get("limit", 20)})
|
|
1834
|
+
case "coherence_news_resonance":
|
|
1835
|
+
return api_get("/api/news/resonance", {"top_n": args.get("top_n", 5)})
|
|
1836
|
+
case "coherence_federation_nodes":
|
|
1837
|
+
return api_get("/api/federation/nodes")
|
|
1838
|
+
case "coherence_belief_profile":
|
|
1839
|
+
return api_get(f"/api/beliefs/{args['contributor_id']}")
|
|
1840
|
+
case "coherence_cc_supply":
|
|
1841
|
+
return api_get("/api/cc/supply")
|
|
1842
|
+
case "coherence_governance_requests":
|
|
1843
|
+
return api_get("/api/governance/change-requests", {"limit": args.get("limit", 20)})
|
|
1258
1844
|
case _:
|
|
1259
1845
|
return {"error": f"Unknown tool: {name}"}
|
|
1260
1846
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "coherence-mcp-server",
|
|
3
|
-
"version": "0.5.
|
|
4
|
-
"description": "Unified MCP server for the Coherence Network —
|
|
3
|
+
"version": "0.5.2",
|
|
4
|
+
"description": "Unified MCP server for the Coherence Network — 89 typed tools for AI agents to browse ideas, receive the shared invitation, manage tasks, link identities, and navigate the universal graph.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"coherence-mcp-server": "index.mjs"
|
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coherence-mcp-server"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.2"
|
|
8
8
|
description = "Unified MCP server for the Coherence Network — 51 typed tools for AI agents to browse ideas, manage tasks, link identities, and navigate the universal graph."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
Binary file
|
|
Binary file
|