coherence-mcp-server 0.5.1 → 0.5.3
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 +27 -3
- package/README.template.md +26 -3
- package/coherence_mcp_server/__init__.py +4 -3
- package/coherence_mcp_server/server.py +653 -14
- package/package.json +3 -3
- package/pyproject.toml +2 -2
- 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 92 typed tools — so Claude, Cursor, Windsurf, or any MCP-compatible agent can browse ideas, look up specs, trace value lineage, link identities, record contributions, read field stories, 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 (92)
|
|
80
82
|
|
|
81
83
|
### Ideas — the portfolio engine
|
|
82
84
|
|
|
@@ -121,10 +123,19 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
121
123
|
| `coherence_record_contribution` | Record work by contributor name or by provider identity (no registration needed). |
|
|
122
124
|
| `coherence_contributor_ledger` | CC balance, contribution history, and linked ideas. |
|
|
123
125
|
|
|
126
|
+
### Field Stories — contribution-derived profile memory
|
|
127
|
+
|
|
128
|
+
| Tool | What it does |
|
|
129
|
+
|------|-------------|
|
|
130
|
+
| `coherence_get_field_story` | Read a published field story with canonical narrative, anchors, reports, and agent contribution surfaces. |
|
|
131
|
+
| `coherence_get_field_story_artifact` | Read one artifact from a field story: anchors, summaries, reports, tools, or event traces. |
|
|
132
|
+
| `coherence_contribute_field_story` | Record an attributed correction, addition, source, or interpretation proposal for a field story. |
|
|
133
|
+
|
|
124
134
|
### Tasks — agent work protocol
|
|
125
135
|
|
|
126
136
|
| Tool | What it does |
|
|
127
137
|
|------|-------------|
|
|
138
|
+
| `coherence_agent_invitation` | Receive the shared AI-agent invitation: core frequency, attunement spectrum, entry surfaces, and contribution paths. |
|
|
128
139
|
| `coherence_list_tasks` | See what tasks are pending, running, or failed. |
|
|
129
140
|
| `coherence_get_task` | Full task details, direction, and result. |
|
|
130
141
|
| `coherence_task_next` | Claim the highest-priority pending task. |
|
|
@@ -133,6 +144,19 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
133
144
|
| `coherence_task_seed` | Create a new task from an idea. |
|
|
134
145
|
| `coherence_task_events` | View the activity event log for a task. |
|
|
135
146
|
|
|
147
|
+
### Awareness Streaming — presence in and out
|
|
148
|
+
|
|
149
|
+
| Tool | What it does |
|
|
150
|
+
|------|-------------|
|
|
151
|
+
| `coherence_awareness_publish` | Publish a diagnostic awareness event from a node. |
|
|
152
|
+
| `coherence_awareness_stream` | Read a bounded slice from diagnostic, node-message, or task SSE streams. |
|
|
153
|
+
| `coherence_node_message_send` | Send a durable node-to-node or broadcast message. |
|
|
154
|
+
| `coherence_node_messages` | Read durable inbound messages for a node. |
|
|
155
|
+
|
|
156
|
+
Streams are intentionally bounded. `duration_seconds` defaults to 5 seconds
|
|
157
|
+
and is capped at 30; `max_events` defaults to 20 and is capped at 200. This
|
|
158
|
+
lets MCP clients sense live awareness without leaving a tool call open forever.
|
|
159
|
+
|
|
136
160
|
### Graph — universal navigation
|
|
137
161
|
|
|
138
162
|
| Tool | What it does |
|
|
@@ -256,7 +280,7 @@ Every part of the network links to every other. Jump in wherever makes sense.
|
|
|
256
280
|
| **Web** | Browse ideas, specs, and contributors visually | [coherencycoin.com](https://coherencycoin.com) |
|
|
257
281
|
| **API** | 100+ endpoints, full OpenAPI docs, the engine behind everything | [api.coherencycoin.com/docs](https://api.coherencycoin.com/docs) |
|
|
258
282
|
| **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 —
|
|
283
|
+
| **MCP Server** | This package — 92 typed tools for AI agents | [npm: coherence-mcp-server](https://www.npmjs.com/package/coherence-mcp-server) |
|
|
260
284
|
| **OpenClaw Skill** | Auto-triggers in any OpenClaw instance for ideas, specs, coherence | [ClawHub: coherence-network](https://clawhub.com/skills/coherence-network) |
|
|
261
285
|
| **GitHub** | Source code, specs, issues, and contribution tracking | [github.com/seeker71/Coherence-Network](https://github.com/seeker71/Coherence-Network) |
|
|
262
286
|
|
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 92 typed tools — so Claude, Cursor, Windsurf, or any MCP-compatible agent can browse ideas, look up specs, trace value lineage, link identities, record contributions, read field stories, 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 (92)
|
|
80
81
|
|
|
81
82
|
### Ideas — the portfolio engine
|
|
82
83
|
|
|
@@ -121,10 +122,19 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
121
122
|
| `coherence_record_contribution` | Record work by contributor name or by provider identity (no registration needed). |
|
|
122
123
|
| `coherence_contributor_ledger` | CC balance, contribution history, and linked ideas. |
|
|
123
124
|
|
|
125
|
+
### Field Stories — contribution-derived profile memory
|
|
126
|
+
|
|
127
|
+
| Tool | What it does |
|
|
128
|
+
|------|-------------|
|
|
129
|
+
| `coherence_get_field_story` | Read a published field story with canonical narrative, anchors, reports, and agent contribution surfaces. |
|
|
130
|
+
| `coherence_get_field_story_artifact` | Read one artifact from a field story: anchors, summaries, reports, tools, or event traces. |
|
|
131
|
+
| `coherence_contribute_field_story` | Record an attributed correction, addition, source, or interpretation proposal for a field story. |
|
|
132
|
+
|
|
124
133
|
### Tasks — agent work protocol
|
|
125
134
|
|
|
126
135
|
| Tool | What it does |
|
|
127
136
|
|------|-------------|
|
|
137
|
+
| `coherence_agent_invitation` | Receive the shared AI-agent invitation: core frequency, attunement spectrum, entry surfaces, and contribution paths. |
|
|
128
138
|
| `coherence_list_tasks` | See what tasks are pending, running, or failed. |
|
|
129
139
|
| `coherence_get_task` | Full task details, direction, and result. |
|
|
130
140
|
| `coherence_task_next` | Claim the highest-priority pending task. |
|
|
@@ -133,6 +143,19 @@ Point your MCP client at `npx coherence-mcp-server` via stdio transport.
|
|
|
133
143
|
| `coherence_task_seed` | Create a new task from an idea. |
|
|
134
144
|
| `coherence_task_events` | View the activity event log for a task. |
|
|
135
145
|
|
|
146
|
+
### Awareness Streaming — presence in and out
|
|
147
|
+
|
|
148
|
+
| Tool | What it does |
|
|
149
|
+
|------|-------------|
|
|
150
|
+
| `coherence_awareness_publish` | Publish a diagnostic awareness event from a node. |
|
|
151
|
+
| `coherence_awareness_stream` | Read a bounded slice from diagnostic, node-message, or task SSE streams. |
|
|
152
|
+
| `coherence_node_message_send` | Send a durable node-to-node or broadcast message. |
|
|
153
|
+
| `coherence_node_messages` | Read durable inbound messages for a node. |
|
|
154
|
+
|
|
155
|
+
Streams are intentionally bounded. `duration_seconds` defaults to 5 seconds
|
|
156
|
+
and is capped at 30; `max_events` defaults to 20 and is capped at 200. This
|
|
157
|
+
lets MCP clients sense live awareness without leaving a tool call open forever.
|
|
158
|
+
|
|
136
159
|
### Graph — universal navigation
|
|
137
160
|
|
|
138
161
|
| Tool | What it does |
|
|
@@ -256,7 +279,7 @@ Every part of the network links to every other. Jump in wherever makes sense.
|
|
|
256
279
|
| **Web** | Browse ideas, specs, and contributors visually | [coherencycoin.com](https://coherencycoin.com) |
|
|
257
280
|
| **API** | 100+ endpoints, full OpenAPI docs, the engine behind everything | [api.coherencycoin.com/docs](https://api.coherencycoin.com/docs) |
|
|
258
281
|
| **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 —
|
|
282
|
+
| **MCP Server** | This package — 92 typed tools for AI agents | [npm: coherence-mcp-server](https://www.npmjs.com/package/coherence-mcp-server) |
|
|
260
283
|
| **OpenClaw Skill** | Auto-triggers in any OpenClaw instance for ideas, specs, coherence | [ClawHub: coherence-network](https://clawhub.com/skills/coherence-network) |
|
|
261
284
|
| **GitHub** | Source code, specs, issues, and contribution tracking | [github.com/seeker71/Coherence-Network](https://github.com/seeker71/Coherence-Network) |
|
|
262
285
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
"""
|
|
2
2
|
coherence-mcp-server — MCP server for the Coherence Network.
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
link identities, record contributions, and explore the
|
|
4
|
+
92 typed tools for AI agents to browse ideas, trace value chains,
|
|
5
|
+
link identities, record contributions, read field stories, and explore the
|
|
6
|
+
Living Codex ontology.
|
|
6
7
|
|
|
7
8
|
Usage:
|
|
8
9
|
python -m coherence_mcp_server
|
|
@@ -13,5 +14,5 @@ Environment variables:
|
|
|
13
14
|
COHERENCE_API_KEY API key for write operations (optional for reads)
|
|
14
15
|
"""
|
|
15
16
|
|
|
16
|
-
__version__ = "0.3
|
|
17
|
+
__version__ = "0.5.3"
|
|
17
18
|
__all__ = ["__version__"]
|
|
@@ -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,273 @@ 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
|
+
),
|
|
1229
|
+
Tool(
|
|
1230
|
+
name="coherence_get_field_story",
|
|
1231
|
+
description="Read a published field story with canonical narrative, anchors, reports, and agent contribution surfaces.",
|
|
1232
|
+
inputSchema={
|
|
1233
|
+
"type": "object",
|
|
1234
|
+
"properties": {
|
|
1235
|
+
"slug": {"type": "string", "description": "Field story slug", "default": "urs-field-story"},
|
|
1236
|
+
},
|
|
1237
|
+
},
|
|
1238
|
+
),
|
|
1239
|
+
Tool(
|
|
1240
|
+
name="coherence_get_field_story_artifact",
|
|
1241
|
+
description="Read one artifact from a field story, such as anchors, summaries, reports, tools, or event traces.",
|
|
1242
|
+
inputSchema={
|
|
1243
|
+
"type": "object",
|
|
1244
|
+
"required": ["artifact_id"],
|
|
1245
|
+
"properties": {
|
|
1246
|
+
"slug": {"type": "string", "description": "Field story slug", "default": "urs-field-story"},
|
|
1247
|
+
"artifact_id": {"type": "string", "description": "Artifact id from the field story manifest"},
|
|
1248
|
+
},
|
|
1249
|
+
},
|
|
1250
|
+
),
|
|
1251
|
+
Tool(
|
|
1252
|
+
name="coherence_contribute_field_story",
|
|
1253
|
+
description="Record an attributed correction, addition, or interpretation proposal for a published field story.",
|
|
1254
|
+
inputSchema={
|
|
1255
|
+
"type": "object",
|
|
1256
|
+
"required": ["contributor_id", "artifact_id", "summary"],
|
|
1257
|
+
"properties": {
|
|
1258
|
+
"slug": {"type": "string", "description": "Field story slug", "default": "urs-field-story"},
|
|
1259
|
+
"contributor_id": {"type": "string", "description": "Person or agent contributor id"},
|
|
1260
|
+
"artifact_id": {"type": "string", "description": "Artifact being corrected or extended"},
|
|
1261
|
+
"contribution_type": {"type": "string", "description": "correction, addition, interpretation, source, etc.", "default": "addition"},
|
|
1262
|
+
"summary": {"type": "string", "description": "Short contribution summary"},
|
|
1263
|
+
"content_markdown": {"type": "string", "description": "Optional proposed content"},
|
|
1264
|
+
},
|
|
1265
|
+
},
|
|
1266
|
+
),
|
|
826
1267
|
]
|
|
827
1268
|
|
|
828
1269
|
TOOL_MAP: dict[str, Tool] = {t.name: t for t in TOOLS}
|
|
@@ -881,10 +1322,8 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
881
1322
|
"display_name": args["provider_id"],
|
|
882
1323
|
})
|
|
883
1324
|
case "coherence_lookup_identity":
|
|
884
|
-
from urllib.parse import quote
|
|
885
1325
|
return api_get(f"/api/identity/lookup/{quote(args['provider'])}/{quote(args['provider_id'])}")
|
|
886
1326
|
case "coherence_get_identities":
|
|
887
|
-
from urllib.parse import quote
|
|
888
1327
|
return api_get(f"/api/identity/{quote(args['contributor_id'])}")
|
|
889
1328
|
# Contributions
|
|
890
1329
|
case "coherence_record_contribution":
|
|
@@ -899,7 +1338,6 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
899
1338
|
}.items() if v is not None
|
|
900
1339
|
})
|
|
901
1340
|
case "coherence_contributor_ledger":
|
|
902
|
-
from urllib.parse import quote
|
|
903
1341
|
return api_get(f"/api/contributions/ledger/{quote(args['contributor_id'])}")
|
|
904
1342
|
# Status
|
|
905
1343
|
case "coherence_status":
|
|
@@ -913,11 +1351,65 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
913
1351
|
}
|
|
914
1352
|
case "coherence_friction_report":
|
|
915
1353
|
return api_get("/api/friction/report", {"window_days": args.get("window_days", 30)})
|
|
1354
|
+
case "coherence_agent_invitation":
|
|
1355
|
+
return api_get("/api/agent/invitation")
|
|
916
1356
|
# Federation
|
|
917
1357
|
case "coherence_list_federation_nodes":
|
|
918
1358
|
nodes = api_get("/api/federation/nodes")
|
|
919
1359
|
caps = api_get("/api/federation/nodes/capabilities")
|
|
920
1360
|
return {"nodes": nodes, "capabilities": caps}
|
|
1361
|
+
case "coherence_awareness_publish":
|
|
1362
|
+
body = {
|
|
1363
|
+
"event_type": args["event_type"],
|
|
1364
|
+
"message": args.get("message", ""),
|
|
1365
|
+
"data": args.get("data", {}),
|
|
1366
|
+
"source": "mcp",
|
|
1367
|
+
}
|
|
1368
|
+
return api_post(f"/api/federation/nodes/{quote(args['node_id'], safe='')}/diag", body)
|
|
1369
|
+
case "coherence_awareness_stream":
|
|
1370
|
+
stream_type = (args.get("stream_type") or "").strip().lower()
|
|
1371
|
+
duration_seconds = args.get("duration_seconds", 5)
|
|
1372
|
+
max_events = args.get("max_events", 20)
|
|
1373
|
+
if stream_type == "diagnostics":
|
|
1374
|
+
node_id = args.get("node_id") or "*"
|
|
1375
|
+
return api_sse(
|
|
1376
|
+
f"/api/federation/nodes/{quote(node_id, safe='*')}/diag/stream",
|
|
1377
|
+
duration_seconds=duration_seconds,
|
|
1378
|
+
max_events=max_events,
|
|
1379
|
+
)
|
|
1380
|
+
if stream_type == "node":
|
|
1381
|
+
node_id = args.get("node_id")
|
|
1382
|
+
if not node_id:
|
|
1383
|
+
return {"error": "node_id is required for node streams"}
|
|
1384
|
+
return api_sse(
|
|
1385
|
+
f"/api/federation/nodes/{quote(node_id, safe='')}/stream",
|
|
1386
|
+
duration_seconds=duration_seconds,
|
|
1387
|
+
max_events=max_events,
|
|
1388
|
+
)
|
|
1389
|
+
if stream_type == "task":
|
|
1390
|
+
task_id = args.get("task_id")
|
|
1391
|
+
if not task_id:
|
|
1392
|
+
return {"error": "task_id is required for task streams"}
|
|
1393
|
+
return api_sse(
|
|
1394
|
+
f"/api/agent/tasks/{quote(task_id, safe='')}/events",
|
|
1395
|
+
duration_seconds=duration_seconds,
|
|
1396
|
+
max_events=max_events,
|
|
1397
|
+
)
|
|
1398
|
+
return {"error": "stream_type must be one of: diagnostics, node, task"}
|
|
1399
|
+
case "coherence_node_message_send":
|
|
1400
|
+
body = {
|
|
1401
|
+
"to_node": args.get("to_node_id"),
|
|
1402
|
+
"type": args.get("type", "text"),
|
|
1403
|
+
"text": args["text"],
|
|
1404
|
+
"payload": args.get("payload", {}),
|
|
1405
|
+
}
|
|
1406
|
+
return api_post(f"/api/federation/nodes/{quote(args['from_node_id'], safe='')}/messages", body)
|
|
1407
|
+
case "coherence_node_messages":
|
|
1408
|
+
return api_get(f"/api/federation/nodes/{quote(args['node_id'], safe='')}/messages", {
|
|
1409
|
+
"since": args.get("since"),
|
|
1410
|
+
"unread_only": args.get("unread_only", True),
|
|
1411
|
+
"limit": args.get("limit", 50),
|
|
1412
|
+
})
|
|
921
1413
|
# Tasks
|
|
922
1414
|
case "coherence_list_tasks":
|
|
923
1415
|
params = {
|
|
@@ -933,7 +1425,10 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
933
1425
|
return api_get(f"/api/agent/tasks/{args['task_id']}")
|
|
934
1426
|
case "coherence_task_next":
|
|
935
1427
|
# Claim next available pending task
|
|
936
|
-
|
|
1428
|
+
params: dict[str, Any] = {"status": "pending", "limit": 1}
|
|
1429
|
+
if args.get("workspace_id"):
|
|
1430
|
+
params["workspace_id"] = args["workspace_id"]
|
|
1431
|
+
data = api_get("/api/agent/tasks", params)
|
|
937
1432
|
tasks = data.get("tasks", []) if isinstance(data, dict) else []
|
|
938
1433
|
if not tasks:
|
|
939
1434
|
return {"error": "No pending tasks available"}
|
|
@@ -959,14 +1454,17 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
959
1454
|
idea_name = idea.get("name", "Unknown Idea") if isinstance(idea, dict) else "Unknown Idea"
|
|
960
1455
|
task_type = args.get("task_type", "spec")
|
|
961
1456
|
direction = args.get("direction") or f"{task_type} for '{idea_name}' ({idea_id})"
|
|
1457
|
+
context: dict[str, Any] = {
|
|
1458
|
+
"idea_id": idea_id,
|
|
1459
|
+
"idea_name": idea_name,
|
|
1460
|
+
"seeded_by": "mcp-agent",
|
|
1461
|
+
}
|
|
1462
|
+
if args.get("workspace_id"):
|
|
1463
|
+
context["workspace_id"] = args["workspace_id"]
|
|
962
1464
|
return api_post("/api/agent/tasks", {
|
|
963
1465
|
"task_type": task_type,
|
|
964
1466
|
"direction": direction,
|
|
965
|
-
"context":
|
|
966
|
-
"idea_id": idea_id,
|
|
967
|
-
"idea_name": idea_name,
|
|
968
|
-
"seeded_by": "mcp-agent",
|
|
969
|
-
},
|
|
1467
|
+
"context": context,
|
|
970
1468
|
})
|
|
971
1469
|
case "coherence_task_events":
|
|
972
1470
|
return api_get(f"/api/agent/tasks/{args['task_id']}/stream")
|
|
@@ -1230,7 +1728,7 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
1230
1728
|
"navigation": {"idea_file": f"ideas/{entity_id}.md",
|
|
1231
1729
|
"spec_files": [f"specs/{s}.md" for s in spec_ids],
|
|
1232
1730
|
"api": f"/api/ideas/{entity_id}",
|
|
1233
|
-
"cli": f"
|
|
1731
|
+
"cli": f"coh idea {entity_id}"}}
|
|
1234
1732
|
elif entity_type == "spec":
|
|
1235
1733
|
spec = api_get(f"/api/spec-registry/{entity_id}")
|
|
1236
1734
|
spec_file = api_get("/api/content/file", {"path": f"specs/{entity_id}.md"})
|
|
@@ -1238,7 +1736,7 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
1238
1736
|
parent_idea = api_get(f"/api/ideas/{idea_id}") if idea_id else None
|
|
1239
1737
|
nav: dict[str, Any] = {"spec_file": f"specs/{entity_id}.md",
|
|
1240
1738
|
"api": f"/api/spec-registry/{entity_id}",
|
|
1241
|
-
"cli": f"
|
|
1739
|
+
"cli": f"coh spec {entity_id}"}
|
|
1242
1740
|
if idea_id:
|
|
1243
1741
|
nav["idea_file"] = f"ideas/{idea_id}.md"
|
|
1244
1742
|
return {"entity_type": "spec", "spec": spec, "spec_file_content": spec_file,
|
|
@@ -1252,9 +1750,150 @@ def dispatch(name: str, args: dict[str, Any]) -> Any:
|
|
|
1252
1750
|
return {"entity_type": "task", "task": task, "events": events,
|
|
1253
1751
|
"parent_idea": parent_idea,
|
|
1254
1752
|
"navigation": {"api": f"/api/agent/tasks/{entity_id}",
|
|
1255
|
-
"cli": f"
|
|
1753
|
+
"cli": f"coh task {entity_id}"}}
|
|
1256
1754
|
else:
|
|
1257
1755
|
return {"error": f"Unknown entity_type: {entity_type}. Use 'idea', 'spec', or 'task'."}
|
|
1756
|
+
# Pipeline Policies
|
|
1757
|
+
case "coherence_pipeline_policies":
|
|
1758
|
+
action = (args.get("action") or "list").strip()
|
|
1759
|
+
if action == "list":
|
|
1760
|
+
return api_get("/api/pipeline/policies")
|
|
1761
|
+
elif action == "get":
|
|
1762
|
+
key = args.get("key", "")
|
|
1763
|
+
return api_get(f"/api/pipeline/policies/{key}")
|
|
1764
|
+
elif action == "set":
|
|
1765
|
+
key = args.get("key", "")
|
|
1766
|
+
value = args.get("value")
|
|
1767
|
+
return api_put(f"/api/pipeline/policies/{key}", {
|
|
1768
|
+
"value": value,
|
|
1769
|
+
"updated_by": "mcp-agent",
|
|
1770
|
+
})
|
|
1771
|
+
else:
|
|
1772
|
+
return {"error": f"Unknown action: {action}. Use 'list', 'get', or 'set'."}
|
|
1773
|
+
# Workspace Tasks
|
|
1774
|
+
case "coherence_workspace_tasks":
|
|
1775
|
+
ws_id = args["workspace_id"]
|
|
1776
|
+
action = args["action"]
|
|
1777
|
+
if action == "list":
|
|
1778
|
+
return api_get(f"/api/agent/tasks", {"workspace_id": ws_id, "limit": 50})
|
|
1779
|
+
elif action == "seed_pipeline":
|
|
1780
|
+
idea_id = args.get("idea_id", "")
|
|
1781
|
+
start_phase = args.get("start_phase", "spec")
|
|
1782
|
+
return api_post("/api/agent/tasks", {
|
|
1783
|
+
"direction": f"Implement idea {idea_id} starting from {start_phase} phase",
|
|
1784
|
+
"task_type": start_phase,
|
|
1785
|
+
"context": {
|
|
1786
|
+
"idea_id": idea_id,
|
|
1787
|
+
"workspace_id": ws_id,
|
|
1788
|
+
"executor": "federation",
|
|
1789
|
+
},
|
|
1790
|
+
})
|
|
1791
|
+
elif action == "status":
|
|
1792
|
+
tasks_data = api_get(f"/api/agent/tasks", {"workspace_id": ws_id, "limit": 200})
|
|
1793
|
+
items = (
|
|
1794
|
+
tasks_data.get("items", [])
|
|
1795
|
+
if isinstance(tasks_data, dict)
|
|
1796
|
+
else tasks_data if isinstance(tasks_data, list)
|
|
1797
|
+
else []
|
|
1798
|
+
)
|
|
1799
|
+
status_counts: dict[str, int] = {}
|
|
1800
|
+
for t in items:
|
|
1801
|
+
s = t.get("status", "unknown") if isinstance(t, dict) else "unknown"
|
|
1802
|
+
status_counts[s] = status_counts.get(s, 0) + 1
|
|
1803
|
+
return {
|
|
1804
|
+
"workspace_id": ws_id,
|
|
1805
|
+
"total_tasks": len(items),
|
|
1806
|
+
"by_status": status_counts,
|
|
1807
|
+
}
|
|
1808
|
+
else:
|
|
1809
|
+
return {"error": f"Unknown action: {action}. Use 'list', 'seed_pipeline', or 'status'."}
|
|
1810
|
+
# Team Membership
|
|
1811
|
+
case "coherence_list_workspace_members":
|
|
1812
|
+
return api_get(f"/api/workspaces/{args['workspace_id']}/members")
|
|
1813
|
+
case "coherence_invite_member":
|
|
1814
|
+
return api_post(f"/api/workspaces/{args['workspace_id']}/invite", {
|
|
1815
|
+
"contributor_id": args["contributor_id"],
|
|
1816
|
+
"role": args.get("role", "member"),
|
|
1817
|
+
})
|
|
1818
|
+
case "coherence_list_my_workspaces":
|
|
1819
|
+
return api_get(f"/api/contributors/{args['contributor_id']}/workspaces")
|
|
1820
|
+
# Messaging
|
|
1821
|
+
case "coherence_send_message":
|
|
1822
|
+
body: dict[str, Any] = {
|
|
1823
|
+
"from_contributor_id": args["from_contributor_id"],
|
|
1824
|
+
"body": args["body"],
|
|
1825
|
+
}
|
|
1826
|
+
if args.get("to_contributor_id"):
|
|
1827
|
+
body["to_contributor_id"] = args["to_contributor_id"]
|
|
1828
|
+
if args.get("to_workspace_id"):
|
|
1829
|
+
body["to_workspace_id"] = args["to_workspace_id"]
|
|
1830
|
+
if args.get("subject"):
|
|
1831
|
+
body["subject"] = args["subject"]
|
|
1832
|
+
return api_post("/api/messages", body)
|
|
1833
|
+
case "coherence_get_inbox":
|
|
1834
|
+
return api_get(f"/api/messages/inbox/{args['contributor_id']}", {
|
|
1835
|
+
"limit": args.get("limit", 20),
|
|
1836
|
+
"unread_only": args.get("unread_only", False),
|
|
1837
|
+
})
|
|
1838
|
+
# Activity
|
|
1839
|
+
case "coherence_get_workspace_activity":
|
|
1840
|
+
return api_get(f"/api/workspaces/{args['workspace_id']}/activity", {
|
|
1841
|
+
"limit": args.get("limit", 20),
|
|
1842
|
+
})
|
|
1843
|
+
# Projects
|
|
1844
|
+
case "coherence_list_workspace_projects":
|
|
1845
|
+
return api_get(f"/api/workspaces/{args['workspace_id']}/projects")
|
|
1846
|
+
case "coherence_create_workspace_project":
|
|
1847
|
+
return api_post(f"/api/workspaces/{args['workspace_id']}/projects", {
|
|
1848
|
+
"name": args["name"],
|
|
1849
|
+
"description": args.get("description", ""),
|
|
1850
|
+
"workspace_id": args["workspace_id"],
|
|
1851
|
+
})
|
|
1852
|
+
# Discovery / Living Network
|
|
1853
|
+
case "coherence_discover":
|
|
1854
|
+
cid = args.get("contributor_id", "default-contributor")
|
|
1855
|
+
limit: int = args.get("limit", 20)
|
|
1856
|
+
return api_get(f"/api/discover/{cid}", {"limit": limit})
|
|
1857
|
+
case "coherence_constellation":
|
|
1858
|
+
return api_get("/api/constellation", {
|
|
1859
|
+
"max_nodes": args.get("max_nodes", 80),
|
|
1860
|
+
"workspace_id": args.get("workspace_id", "coherence-network"),
|
|
1861
|
+
})
|
|
1862
|
+
case "coherence_vitality":
|
|
1863
|
+
ws = args.get("workspace_id", "coherence-network")
|
|
1864
|
+
return api_get(f"/api/workspaces/{ws}/vitality")
|
|
1865
|
+
case "coherence_resonate":
|
|
1866
|
+
return api_get(f"/api/resonance/ideas/{args['idea_id']}", {
|
|
1867
|
+
"limit": args.get("limit", 10),
|
|
1868
|
+
})
|
|
1869
|
+
# Super-Idea Coverage
|
|
1870
|
+
case "coherence_news_feed":
|
|
1871
|
+
return api_get("/api/news/feed", {"limit": args.get("limit", 20)})
|
|
1872
|
+
case "coherence_news_resonance":
|
|
1873
|
+
return api_get("/api/news/resonance", {"top_n": args.get("top_n", 5)})
|
|
1874
|
+
case "coherence_federation_nodes":
|
|
1875
|
+
return api_get("/api/federation/nodes")
|
|
1876
|
+
case "coherence_belief_profile":
|
|
1877
|
+
return api_get(f"/api/beliefs/{args['contributor_id']}")
|
|
1878
|
+
case "coherence_cc_supply":
|
|
1879
|
+
return api_get("/api/cc/supply")
|
|
1880
|
+
case "coherence_governance_requests":
|
|
1881
|
+
return api_get("/api/governance/change-requests", {"limit": args.get("limit", 20)})
|
|
1882
|
+
case "coherence_get_field_story":
|
|
1883
|
+
return api_get(f"/api/field-stories/{quote(args.get('slug', 'urs-field-story'), safe='')}")
|
|
1884
|
+
case "coherence_get_field_story_artifact":
|
|
1885
|
+
slug = quote(args.get("slug", "urs-field-story"), safe="")
|
|
1886
|
+
artifact_id = quote(args["artifact_id"], safe="")
|
|
1887
|
+
return api_get(f"/api/field-stories/{slug}/artifacts/{artifact_id}")
|
|
1888
|
+
case "coherence_contribute_field_story":
|
|
1889
|
+
slug = quote(args.get("slug", "urs-field-story"), safe="")
|
|
1890
|
+
return api_post(f"/api/field-stories/{slug}/contributions", {
|
|
1891
|
+
"contributor_id": args["contributor_id"],
|
|
1892
|
+
"artifact_id": args["artifact_id"],
|
|
1893
|
+
"contribution_type": args.get("contribution_type", "addition"),
|
|
1894
|
+
"summary": args["summary"],
|
|
1895
|
+
"content_markdown": args.get("content_markdown", ""),
|
|
1896
|
+
})
|
|
1258
1897
|
case _:
|
|
1259
1898
|
return {"error": f"Unknown tool: {name}"}
|
|
1260
1899
|
|
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.3",
|
|
4
|
+
"description": "Unified MCP server for the Coherence Network — 92 typed tools for AI agents to browse ideas, read field stories, 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"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"index.mjs",
|
|
17
17
|
"README.md",
|
|
18
|
-
"coherence_mcp_server
|
|
18
|
+
"coherence_mcp_server/*.py",
|
|
19
19
|
"pyproject.toml"
|
|
20
20
|
],
|
|
21
21
|
"keywords": [
|
package/pyproject.toml
CHANGED
|
@@ -4,8 +4,8 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "coherence-mcp-server"
|
|
7
|
-
version = "0.
|
|
8
|
-
description = "Unified MCP server for the Coherence Network —
|
|
7
|
+
version = "0.5.3"
|
|
8
|
+
description = "Unified MCP server for the Coherence Network — 92 typed tools for AI agents to browse ideas, read field stories, manage tasks, link identities, and navigate the universal graph."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
11
11
|
license = { text = "MIT" }
|
|
Binary file
|
|
Binary file
|