@abderraouf-yt/got-mcp 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +361 -0
- package/dist/bridge.js +128 -0
- package/dist/graph/ThoughtGraph.js +725 -0
- package/dist/graph/index.js +5 -0
- package/dist/index.js +24 -0
- package/dist/resources/handlers.js +35 -0
- package/dist/resources/index.js +5 -0
- package/dist/server/http.js +108 -0
- package/dist/server/mcp.js +308 -0
- package/dist/tools/definitions.js +78 -0
- package/dist/tools/handlers.js +174 -0
- package/dist/tools/index.js +6 -0
- package/dist/types.js +32 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 toumi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="docs/assets/hero-complex-graph.png" alt="GoT MCP β 13-node reasoning DAG visualized in cyber-industrial UI" width="100%" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">π§ GOT MCP</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<strong>Graph of Thoughts MCP Server β Bounded, Auditable Reasoning for AI Agents</strong>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://www.npmjs.com/package/@abderraouf-yt/got-mcp"><img src="https://img.shields.io/npm/v/@abderraouf-yt/got-mcp?style=flat-square&color=00e5ff&label=npm" alt="npm version" /></a>
|
|
13
|
+
<a href="https://github.com/Abderraouf-yt/got-mcp"><img src="https://img.shields.io/github/stars/Abderraouf-yt/got-mcp?style=flat-square&color=ff00ff&label=stars" alt="GitHub stars" /></a>
|
|
14
|
+
<a href="#"><img src="https://img.shields.io/badge/node-%3E%3D20-00e5ff?style=flat-square" alt="Node.js" /></a>
|
|
15
|
+
<a href="#"><img src="https://img.shields.io/badge/MCP-1.26+-ff00ff?style=flat-square" alt="MCP SDK" /></a>
|
|
16
|
+
<a href="#"><img src="https://img.shields.io/badge/tools-10-00ff88?style=flat-square" alt="Tools" /></a>
|
|
17
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-yellow?style=flat-square" alt="License" /></a>
|
|
18
|
+
<a href="https://got-mcp-visualizer.netlify.app"><img src="https://img.shields.io/badge/demo-live-00e5ff?style=flat-square&logo=netlify" alt="Live Demo" /></a>
|
|
19
|
+
<a href="https://arxiv.org/abs/2308.09687"><img src="https://img.shields.io/badge/GoT-Besta%20et%20al.%202023-ff6b6b?style=flat-square" alt="GoT Paper" /></a>
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
<p align="center">
|
|
23
|
+
<a href="#-quick-start">β‘ Quick Start</a> β’
|
|
24
|
+
<a href="https://got-mcp-visualizer.netlify.app">οΏ½ Live Demo</a> β’
|
|
25
|
+
<a href="#-tools-10">π Tools</a> β’
|
|
26
|
+
<a href="#-how-it-thinks">𧬠How It Thinks</a> β’
|
|
27
|
+
<a href="#-governance">π Governance</a> β’
|
|
28
|
+
<a href="#-visualizer">π Visualizer</a>
|
|
29
|
+
</p>
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## What is this?
|
|
34
|
+
|
|
35
|
+
> **Chain of Thought** reasons in a line. **Tree of Thought** can branch. **Graph of Thoughts** can branch, merge, contradict, prune dead ends, and converge on the winning path.
|
|
36
|
+
|
|
37
|
+
Thought Graph is a [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that gives AI agents **non-linear reasoning** β a directed acyclic graph where thoughts can branch into alternatives, get contradicted by evidence, and converge through weighted aggregation.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
Traditional AI: A β B β C β D (linear, no backtracking)
|
|
41
|
+
Tree of Thought: A β Bβ, Bβ (branching, no merging)
|
|
42
|
+
Graph of Thoughts: A β Bβ βcontradictionβ Cβ, Bβ βaggregateβ D β THIS
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
<table>
|
|
46
|
+
<tr>
|
|
47
|
+
<td width="33%" align="center"><strong>π Chain of Thought</strong><br/>Linear β’ No backtrack</td>
|
|
48
|
+
<td width="33%" align="center"><strong>π² Tree of Thoughts</strong><br/>Branching β’ No merge</td>
|
|
49
|
+
<td width="33%" align="center"><strong>π§ Graph of Thoughts</strong><br/>Branch β’ Merge β’ Prune β’ Converge</td>
|
|
50
|
+
</tr>
|
|
51
|
+
</table>
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## β‘ Quick Start
|
|
56
|
+
|
|
57
|
+
### Option 1: Install from npm
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm install -g @abderraouf-yt/got-mcp
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Option 2: Clone & Build
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/Abderraouf-yt/got-mcp.git
|
|
67
|
+
cd got-mcp
|
|
68
|
+
npm install && npm run build
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Configure your IDE
|
|
72
|
+
|
|
73
|
+
Add to your MCP config (`~/.gemini/settings.json`, VS Code `mcp.json`, etc.):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"got-mcp": {
|
|
78
|
+
"command": "npx",
|
|
79
|
+
"args": ["-y", "@abderraouf-yt/got-mcp"],
|
|
80
|
+
"env": { "THOUGHT_GRAPH_HTTP_PORT": "3001" }
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## π¬ Live Demo
|
|
88
|
+
|
|
89
|
+
**Problem:** *"Should we use CRDTs or Operational Transformation for a collaborative editor?"*
|
|
90
|
+
|
|
91
|
+
The agent explored 3 branches, evaluated 13 nodes, rejected dead ends, and converged on a hybrid solution β all visible in the graph:
|
|
92
|
+
|
|
93
|
+
```mermaid
|
|
94
|
+
graph TD
|
|
95
|
+
classDef validated fill:#00ff88,stroke:#00ff88,color:#000
|
|
96
|
+
classDef rejected fill:#ff4444,stroke:#ff4444,color:#fff
|
|
97
|
+
classDef active fill:#00e5ff,stroke:#00e5ff,color:#000
|
|
98
|
+
classDef winner fill:#ffd700,stroke:#ffd700,color:#000
|
|
99
|
+
|
|
100
|
+
N1["π― CRDTs vs OT?<br/>80%"]:::validated
|
|
101
|
+
|
|
102
|
+
N2["π CRDT Research<br/>85%"]:::validated
|
|
103
|
+
N3["π OT Research<br/>70%"]:::active
|
|
104
|
+
|
|
105
|
+
N4["πΏ Branch A: Yjs<br/>90%"]:::validated
|
|
106
|
+
N5["β Branch B: ShareDB<br/>40%"]:::rejected
|
|
107
|
+
N11["πΏ Branch C: Hybrid<br/>95%"]:::validated
|
|
108
|
+
|
|
109
|
+
N6["β
TypeScript + ProseMirror<br/>sub-100ms sync Β· 95%"]:::validated
|
|
110
|
+
N7["β οΈ Memory overhead<br/>10x state size Β· 65%"]:::active
|
|
111
|
+
|
|
112
|
+
N8["β MongoDB persistence<br/>50%"]:::rejected
|
|
113
|
+
N9["π Cannot work offline<br/>90%"]:::validated
|
|
114
|
+
|
|
115
|
+
N10["π§ Y.Doc compaction<br/>90% size reduction Β· 92%"]:::validated
|
|
116
|
+
N12["β
Liveblocks + Tiptap<br/>+ Hocuspocus Β· 88%"]:::validated
|
|
117
|
+
N13["π WINNER: Yjs +<br/>y-websocket + Hocuspocus<br/>100%"]:::winner
|
|
118
|
+
|
|
119
|
+
N1 -->|refinement| N2
|
|
120
|
+
N1 -->|refinement| N3
|
|
121
|
+
N1 -->|branch| N11
|
|
122
|
+
|
|
123
|
+
N2 -->|branch| N4
|
|
124
|
+
N3 -->|branch| N5
|
|
125
|
+
|
|
126
|
+
N4 -->|support| N6
|
|
127
|
+
N4 -->|contradiction| N7
|
|
128
|
+
|
|
129
|
+
N5 -->|support| N8
|
|
130
|
+
N5 -->|contradiction| N9
|
|
131
|
+
|
|
132
|
+
N7 -->|refinement| N10
|
|
133
|
+
|
|
134
|
+
N11 -->|support| N12
|
|
135
|
+
N11 -->|refinement| N13
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
> **Result:** OT branch rejected (offline failure). CRDT memory concern contradicted then resolved via compaction. Hybrid path wins at 100%.
|
|
139
|
+
|
|
140
|
+
<details>
|
|
141
|
+
<summary>π <strong>Load this demo yourself</strong></summary>
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
cp docs/assets/demo-state.json thought-graph-state.json
|
|
145
|
+
npm run start
|
|
146
|
+
# Open visualizer β http://localhost:5173
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The demo state ships with the repo in `docs/assets/demo-state.json`.
|
|
150
|
+
|
|
151
|
+
</details>
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## π Tools (10)
|
|
156
|
+
|
|
157
|
+
<table>
|
|
158
|
+
<tr><th>Tool</th><th>What it does</th><th>Category</th></tr>
|
|
159
|
+
<tr><td><code>propose_thought</code></td><td>Add a reasoning node with optional parent + relation</td><td>π§ Core</td></tr>
|
|
160
|
+
<tr><td><code>evaluate_thought</code></td><td>Score (0.0β1.0) + critique. Omit score β autonomous LLM audit</td><td>π§ Core</td></tr>
|
|
161
|
+
<tr><td><code>get_thought_graph</code></td><td>Retrieve the full DAG state</td><td>π§ Core</td></tr>
|
|
162
|
+
<tr><td><code>reset_graph</code></td><td>Clear graph for new session</td><td>π§ Core</td></tr>
|
|
163
|
+
<tr><td><code>aggregate_thoughts</code></td><td>Merge 2+ nodes β weighted synthesis <code>Ξ£(scoreΓweight)/Ξ£(weights)</code></td><td>β‘ GoT</td></tr>
|
|
164
|
+
<tr><td><code>prune_branch</code></td><td>Hard (reject+zero) or Soft (score decay) pruning</td><td>β‘ GoT</td></tr>
|
|
165
|
+
<tr><td><code>find_winning_path</code></td><td>Greedy DFS or beam search (k-best paths) with threshold gating</td><td>β‘ GoT</td></tr>
|
|
166
|
+
<tr><td><code>get_graph_metrics</code></td><td>Node count, max depth, prune ratio, avg score, status breakdown</td><td>π Ops</td></tr>
|
|
167
|
+
<tr><td><code>export_snapshot</code></td><td>Full graph serialization for replay/recovery</td><td>π Replay</td></tr>
|
|
168
|
+
<tr><td><code>restore_snapshot</code></td><td>Restore from previously exported snapshot</td><td>π Replay</td></tr>
|
|
169
|
+
</table>
|
|
170
|
+
|
|
171
|
+
### Edge Relations
|
|
172
|
+
|
|
173
|
+
`refinement` Β· `contradiction` Β· `support` Β· `branch` Β· `aggregation`
|
|
174
|
+
|
|
175
|
+
### Node Statuses
|
|
176
|
+
|
|
177
|
+
`active` Β· `validated` Β· `rejected` Β· `branching`
|
|
178
|
+
|
|
179
|
+
---
|
|
180
|
+
|
|
181
|
+
## 𧬠How It Thinks
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
Agent: I need to decide between PostgreSQL and MongoDB.
|
|
185
|
+
|
|
186
|
+
β propose_thought("PostgreSQL vs MongoDB for user data store?")
|
|
187
|
+
β propose_thought("PostgreSQL: ACID, strong schema", parent: "node_1", relation: "branch")
|
|
188
|
+
β propose_thought("MongoDB: flexible schema, horizontal scaling", parent: "node_1", relation: "branch")
|
|
189
|
+
β propose_thought("Our data has relational patterns: userβordersβitems", parent: "node_2", relation: "support")
|
|
190
|
+
β propose_thought("MongoDB can't enforce referential integrity", parent: "node_3", relation: "contradiction")
|
|
191
|
+
β evaluate_thought("node_3", score: 0.3, status: "rejected")
|
|
192
|
+
β prune_branch("node_3", reason: "Relational data needs relational DB")
|
|
193
|
+
β find_winning_path(beamWidth: 2, scoreThreshold: 0.5)
|
|
194
|
+
β³ Winner: node_1 β node_2 β node_4 (PostgreSQL path, score: 2.75)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## π Governance
|
|
200
|
+
|
|
201
|
+
Engine-level guards β enforced in the graph engine, not the tool layer:
|
|
202
|
+
|
|
203
|
+
| Guard | Default | Enforcement |
|
|
204
|
+
|-------|---------|-------------|
|
|
205
|
+
| **Node cap** | 200 | `addNode()` throws at limit |
|
|
206
|
+
| **Depth cap** | 15 | `addEdge()` validates depth |
|
|
207
|
+
| **Branch cap** | 5 children/node | `addEdge()` limits branching |
|
|
208
|
+
| **Cycle detection** | Always on | BFS reachability in `addEdge()` |
|
|
209
|
+
| **Thought length** | 5,000 chars | `addNode()` + Zod schema |
|
|
210
|
+
| **Aggregation limit** | 10 inputs | `aggregateNodes()` |
|
|
211
|
+
| **Prune cascade** | 50 nodes | `pruneFromNode()` |
|
|
212
|
+
| **Confidence clamp** | [0, 1] | `aggregateNodes()` |
|
|
213
|
+
|
|
214
|
+
<details>
|
|
215
|
+
<summary>βοΈ <strong>Custom Limits</strong></summary>
|
|
216
|
+
|
|
217
|
+
Override defaults via constructor:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
const graph = new ThoughtGraph(persistPath, {
|
|
221
|
+
maxNodes: 500,
|
|
222
|
+
maxDepth: 25,
|
|
223
|
+
maxBranchFactor: 8,
|
|
224
|
+
maxThoughtLength: 10000,
|
|
225
|
+
maxAggregationInputs: 20,
|
|
226
|
+
maxPruneCascade: 100,
|
|
227
|
+
});
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
</details>
|
|
231
|
+
|
|
232
|
+
### Session Isolation
|
|
233
|
+
|
|
234
|
+
Each session gets its own isolated graph with separate persistence:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
const alice = getGraphInstance("user-alice"); // β thought-graph-state-user-alice.json
|
|
238
|
+
const bob = getGraphInstance("user-bob"); // β thought-graph-state-user-bob.json
|
|
239
|
+
// Alice and Bob never share state
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Concurrency Safety
|
|
243
|
+
|
|
244
|
+
All mutations run under an async mutex:
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
await graph.withLock(async () => {
|
|
248
|
+
graph.addNode("Safe concurrent mutation");
|
|
249
|
+
});
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Snapshot Replay
|
|
253
|
+
|
|
254
|
+
```typescript
|
|
255
|
+
const snapshot = graph.exportSnapshot();
|
|
256
|
+
// { nodes, edges, nodeCounter, timestamp, version: "3.0.0", stateVersion: 42 }
|
|
257
|
+
|
|
258
|
+
graph.restoreSnapshot(snapshot); // Deterministic replay
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## π Visualizer
|
|
264
|
+
|
|
265
|
+
**[π Live Demo β](https://got-mcp-visualizer.netlify.app)**
|
|
266
|
+
|
|
267
|
+
A React 19 + Vite dashboard with a **cyber-industrial UI** β real-time graph rendering via React Flow + Dagre layout.
|
|
268
|
+
|
|
269
|
+
| Feature | Detail |
|
|
270
|
+
|---------|--------|
|
|
271
|
+
| **Layout** | Dagre hierarchical DAG |
|
|
272
|
+
| **Live sync** | SWR polling (2s interval) |
|
|
273
|
+
| **Node colors** | π’ Validated Β· π΅ Active Β· π΄ Rejected Β· π£ Branching |
|
|
274
|
+
| **Edge types** | Animated (branch) Β· Dashed (contradiction) Β· Solid (support) Β· Dotted (aggregation) |
|
|
275
|
+
| **Score bars** | Per-node confidence (0β100%) |
|
|
276
|
+
| **Minimap** | Bottom-right overview |
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
cd visualizer && npm install && npm run dev
|
|
280
|
+
# β http://localhost:5173
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Architecture
|
|
284
|
+
|
|
285
|
+
```
|
|
286
|
+
βββββββββββββββββββ Stdio ββββββββββββββββββββ
|
|
287
|
+
β AI Agent β ββββββββββββββΊ β MCP Server β
|
|
288
|
+
β (Gemini/Cursor) β β (index.ts) β
|
|
289
|
+
βββββββββββββββββββ β β
|
|
290
|
+
β Session Registry β
|
|
291
|
+
βββββββββββββββββββ HTTP:3001 β ThoughtGraph[] β
|
|
292
|
+
β Visualizer β ββββββββββββββΊ β β
|
|
293
|
+
β React + Vite β /api/graph β Express Bridge β
|
|
294
|
+
β :5173 β ββββββββββββββββββββ
|
|
295
|
+
βββββββββββββββββββ β
|
|
296
|
+
thought-graph-state-{session}.json
|
|
297
|
+
(per-session file persistence)
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
---
|
|
301
|
+
|
|
302
|
+
## π¬ GoT Compliance
|
|
303
|
+
|
|
304
|
+
Based on [Besta et al., 2023 β "Graph of Thoughts"](https://arxiv.org/abs/2308.09687):
|
|
305
|
+
|
|
306
|
+
| Primitive | Implementation | Version |
|
|
307
|
+
|-----------|---------------|---------|
|
|
308
|
+
| **Generate** | `propose_thought` | v1.0 |
|
|
309
|
+
| **Evaluate** | `evaluate_thought` | v1.0 |
|
|
310
|
+
| **Backtrack** | `evaluate_thought(status: rejected)` | v1.0 |
|
|
311
|
+
| **Aggregate** | `aggregate_thoughts` β weighted synthesis | v3.0 |
|
|
312
|
+
| **Prune** | `prune_branch` β hard + soft modes | v3.0 |
|
|
313
|
+
| **Converge** | `find_winning_path` β beam search | v3.0 |
|
|
314
|
+
| **Governance** | Engine-level guards + session isolation | v3.0 |
|
|
315
|
+
| **Replay** | `export_snapshot` / `restore_snapshot` | v3.0 |
|
|
316
|
+
| Volume Control | Roadmap | β |
|
|
317
|
+
| Controller Loop | Roadmap | β |
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
## π Tech Stack
|
|
322
|
+
|
|
323
|
+
| Layer | Technology |
|
|
324
|
+
|-------|-----------|
|
|
325
|
+
| Runtime | TypeScript Β· Node.js v20+ |
|
|
326
|
+
| Protocol | `@modelcontextprotocol/sdk` ^1.26 |
|
|
327
|
+
| Validation | Zod schemas with `.max()` length guards |
|
|
328
|
+
| Governance | Engine-level: node/depth/branch caps, cycle detection |
|
|
329
|
+
| HTTP Bridge | Express |
|
|
330
|
+
| Visualizer | React 19 Β· Vite Β· `@xyflow/react` Β· Dagre Β· SWR |
|
|
331
|
+
| Persistence | Session-scoped JSON with `fs.watchFile` sync |
|
|
332
|
+
| Concurrency | Async mutex (`withLock`) per session |
|
|
333
|
+
|
|
334
|
+
## π Structure
|
|
335
|
+
|
|
336
|
+
```
|
|
337
|
+
thought-graph/
|
|
338
|
+
βββ src/
|
|
339
|
+
β βββ index.ts # Bootstrap (Stdio + HTTP)
|
|
340
|
+
β βββ server/
|
|
341
|
+
β β βββ mcp.ts # 10 MCP tool registrations
|
|
342
|
+
β β βββ http.ts # Express bridge + SSE
|
|
343
|
+
β βββ graph/
|
|
344
|
+
β β βββ ThoughtGraph.ts # Core DAG engine + governance
|
|
345
|
+
β β βββ index.ts # Session registry exports
|
|
346
|
+
β βββ types.ts # GraphLimits, SessionContext, GraphMetrics
|
|
347
|
+
βββ visualizer/ # React + Vite dashboard
|
|
348
|
+
βββ tests/ # Unit tests
|
|
349
|
+
βββ docs/assets/ # Demo screenshots & state
|
|
350
|
+
βββ dist/ # Compiled output
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
## π License
|
|
354
|
+
|
|
355
|
+
MIT
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
<p align="center">
|
|
360
|
+
<sub>Evolution of sequential thinking β because the best ideas don't come in a straight line.</sub>
|
|
361
|
+
</p>
|
package/dist/bridge.js
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thought Graph SSE Bridge
|
|
3
|
+
* HTTP bridge for browser-based dashboard connectivity.
|
|
4
|
+
* Exposes the thought-graph MCP server over Server-Sent Events.
|
|
5
|
+
*
|
|
6
|
+
* @module bridge
|
|
7
|
+
* @description SSE/HTTP transport layer for web-based visualization
|
|
8
|
+
* @version 1.3.0
|
|
9
|
+
*/
|
|
10
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
12
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
13
|
+
import express from "express";
|
|
14
|
+
import cors from "cors";
|
|
15
|
+
import { SERVER_CONFIG } from "./types.js";
|
|
16
|
+
import { ThoughtGraph } from "./graph/index.js";
|
|
17
|
+
import { TOOLS, handleToolCall } from "./tools/index.js";
|
|
18
|
+
import { RESOURCES, readResource } from "./resources/index.js";
|
|
19
|
+
/**
|
|
20
|
+
* Bridge Configuration
|
|
21
|
+
*/
|
|
22
|
+
const BRIDGE_CONFIG = {
|
|
23
|
+
port: 3001,
|
|
24
|
+
name: "thought-graph-bridge",
|
|
25
|
+
version: SERVER_CONFIG.version,
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Shared graph instance for all SSE connections.
|
|
29
|
+
* Unlike the main server (which uses singleton), the bridge maintains
|
|
30
|
+
* its own graph that persists across all web clients.
|
|
31
|
+
*/
|
|
32
|
+
const sharedGraph = new ThoughtGraph();
|
|
33
|
+
/**
|
|
34
|
+
* Active SSE transport sessions.
|
|
35
|
+
*/
|
|
36
|
+
const activeSessions = new Map();
|
|
37
|
+
/**
|
|
38
|
+
* Create and configure an MCP server instance for SSE transport.
|
|
39
|
+
* Each SSE connection gets its own server but shares the graph.
|
|
40
|
+
*/
|
|
41
|
+
function createMCPServer() {
|
|
42
|
+
const server = new Server({
|
|
43
|
+
name: BRIDGE_CONFIG.name,
|
|
44
|
+
version: BRIDGE_CONFIG.version,
|
|
45
|
+
}, {
|
|
46
|
+
capabilities: {
|
|
47
|
+
tools: {},
|
|
48
|
+
resources: {},
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
// Register Resource Handlers
|
|
52
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
53
|
+
resources: RESOURCES,
|
|
54
|
+
}));
|
|
55
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
56
|
+
return readResource(request.params.uri, sharedGraph);
|
|
57
|
+
});
|
|
58
|
+
// Register Tool Handlers
|
|
59
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
60
|
+
tools: TOOLS,
|
|
61
|
+
}));
|
|
62
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
63
|
+
const { name, arguments: args } = request.params;
|
|
64
|
+
return handleToolCall(name, args, sharedGraph, server);
|
|
65
|
+
});
|
|
66
|
+
return server;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Express HTTP Server Setup
|
|
70
|
+
*/
|
|
71
|
+
const app = express();
|
|
72
|
+
app.use(cors());
|
|
73
|
+
app.use(express.json());
|
|
74
|
+
/**
|
|
75
|
+
* SSE endpoint for MCP communication.
|
|
76
|
+
* Each connection creates a new MCP server instance.
|
|
77
|
+
*/
|
|
78
|
+
app.get("/sse", async (req, res) => {
|
|
79
|
+
const sessionId = `session_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
80
|
+
console.log(`π‘ New SSE connection: ${sessionId}`);
|
|
81
|
+
const transport = new SSEServerTransport("/messages", res);
|
|
82
|
+
const server = createMCPServer();
|
|
83
|
+
activeSessions.set(sessionId, transport);
|
|
84
|
+
res.on("close", () => {
|
|
85
|
+
console.log(`π΄ SSE connection closed: ${sessionId}`);
|
|
86
|
+
activeSessions.delete(sessionId);
|
|
87
|
+
});
|
|
88
|
+
await server.connect(transport);
|
|
89
|
+
});
|
|
90
|
+
/**
|
|
91
|
+
* Message endpoint for client -> server communication.
|
|
92
|
+
* SSEServerTransport handles message routing internally.
|
|
93
|
+
*/
|
|
94
|
+
app.post("/messages", async (req, res) => {
|
|
95
|
+
res.status(200).json({ status: "received" });
|
|
96
|
+
});
|
|
97
|
+
/**
|
|
98
|
+
* REST API endpoint for direct graph access.
|
|
99
|
+
* Alternative to MCP for simple read operations.
|
|
100
|
+
*/
|
|
101
|
+
app.get("/api/graph", (req, res) => {
|
|
102
|
+
res.json(sharedGraph.getGraph());
|
|
103
|
+
});
|
|
104
|
+
/**
|
|
105
|
+
* Health check endpoint.
|
|
106
|
+
*/
|
|
107
|
+
app.get("/health", (req, res) => {
|
|
108
|
+
res.json({
|
|
109
|
+
status: "ok",
|
|
110
|
+
name: BRIDGE_CONFIG.name,
|
|
111
|
+
version: BRIDGE_CONFIG.version,
|
|
112
|
+
connections: activeSessions.size,
|
|
113
|
+
graph: {
|
|
114
|
+
nodes: sharedGraph.size,
|
|
115
|
+
edges: sharedGraph.edgeCount,
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
/**
|
|
120
|
+
* Start the HTTP server.
|
|
121
|
+
*/
|
|
122
|
+
app.listen(BRIDGE_CONFIG.port, () => {
|
|
123
|
+
console.log(`π ${BRIDGE_CONFIG.name} v${BRIDGE_CONFIG.version}`);
|
|
124
|
+
console.log(` Port: http://localhost:${BRIDGE_CONFIG.port}`);
|
|
125
|
+
console.log(` SSE: http://localhost:${BRIDGE_CONFIG.port}/sse`);
|
|
126
|
+
console.log(` REST API: http://localhost:${BRIDGE_CONFIG.port}/api/graph`);
|
|
127
|
+
console.log(` Health: http://localhost:${BRIDGE_CONFIG.port}/health`);
|
|
128
|
+
});
|