@jashwanth0712/synapse-mcp 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,123 @@
1
+ # Synapse MCP
2
+
3
+ **AI Knowledge Oracle on Stellar**
4
+
5
+ A self-contained MCP server for AI agent knowledge sharing with real Stellar payments. Agents search, retrieve, and contribute implementation plans — paying with XLM on Stellar testnet.
6
+
7
+ ## Vision
8
+
9
+ Synapse is a decentralized knowledge marketplace for AI agents. V1 ships with embedded SQLite and full-text search. The interface is oracle-ready for future Soroban smart contract integration: content-addressed plans, tiered storage (hot/cold/archive), and on-chain verification.
10
+
11
+ ## Quick Start
12
+
13
+ ### As an MCP Server (Claude Code, Cursor, etc.)
14
+
15
+ Add to your `.mcp.json`:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "synapse-mcp": {
21
+ "command": "npx",
22
+ "args": ["synapse-mcp"]
23
+ }
24
+ }
25
+ }
26
+ ```
27
+
28
+ Or from source:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "synapse-mcp": {
34
+ "command": "node",
35
+ "args": ["packages/synapse-mcp/dist/index.js"]
36
+ }
37
+ }
38
+ }
39
+ ```
40
+
41
+ ### CLI Commands
42
+
43
+ ```bash
44
+ synapse-mcp # Start MCP server (stdio)
45
+ synapse-mcp dashboard # Show wallet, contributions, usage
46
+ synapse-mcp wallet # Print wallet address and balance
47
+ synapse-mcp fund # Fund wallet via Friendbot (testnet)
48
+ synapse-mcp stats # Show usage and contribution stats
49
+ ```
50
+
51
+ ## MCP Tools
52
+
53
+ ### `synapse_search` (0.2 XLM)
54
+
55
+ Search the knowledge base for implementation plans using full-text search with BM25 scoring.
56
+
57
+ ```
58
+ synapse_search({ query: "kubernetes deployment", tags: ["k8s"] })
59
+ ```
60
+
61
+ ### `synapse_recall` (1 XLM)
62
+
63
+ Retrieve the full content of a plan by ID. Returns complete markdown with implementation details.
64
+
65
+ ```
66
+ synapse_recall({ id: "abc-123-def" })
67
+ ```
68
+
69
+ ### `synapse_learn` (Free)
70
+
71
+ Upload a new plan. Contributors earn 70% of future retrieval fees.
72
+
73
+ ```
74
+ synapse_learn({
75
+ title: "Auth with NextAuth",
76
+ content: "# Setup\n...",
77
+ tags: ["auth", "nextjs"],
78
+ domain: "web",
79
+ language: "typescript",
80
+ framework: "nextjs"
81
+ })
82
+ ```
83
+
84
+ ## Architecture
85
+
86
+ - **Storage**: Embedded SQLite with FTS5 full-text search, WAL mode
87
+ - **Payments**: Real Stellar transactions on testnet via Horizon API
88
+ - **Content Addressing**: SHA-256 hashes prevent duplicates
89
+ - **Revenue Split**: 70% to contributors, 30% to platform (tracked)
90
+ - **Oracle Interface**: Full Soroban contract interface defined, V2 implementation
91
+
92
+ ## Data Locations (XDG-Compliant)
93
+
94
+ | Path | Purpose |
95
+ |------|---------|
96
+ | `~/.config/synapse-mcp/wallet.json` | Stellar keypair |
97
+ | `~/.local/share/synapse-mcp/kb.db` | SQLite knowledge base |
98
+ | `~/.local/share/synapse-mcp/history.json` | Usage history |
99
+
100
+ ## Environment Variables
101
+
102
+ | Variable | Description |
103
+ |----------|-------------|
104
+ | `STELLAR_SECRET_KEY` | Use existing Stellar key |
105
+ | `SYNAPSE_CONFIG_DIR` | Custom config directory |
106
+ | `SYNAPSE_DATA_DIR` | Custom data directory |
107
+ | `SYNAPSE_PLATFORM_ADDRESS` | Override platform address |
108
+
109
+ ## Development
110
+
111
+ ```bash
112
+ pnpm install
113
+ pnpm build
114
+ pnpm test
115
+ ```
116
+
117
+ ## Network
118
+
119
+ V1 runs on **Stellar testnet** only. Wallets are auto-created and funded via Friendbot.
120
+
121
+ ## License
122
+
123
+ MIT
@@ -0,0 +1,2 @@
1
+
2
+ export { }
package/dist/index.js ADDED
@@ -0,0 +1,1002 @@
1
+ #!/usr/bin/env node
2
+ import { join, dirname } from 'path';
3
+ import { homedir } from 'os';
4
+ import { Keypair, Horizon, TransactionBuilder, Networks, Operation, Asset } from '@stellar/stellar-sdk';
5
+ import { existsSync, readFileSync, mkdirSync, writeFileSync } from 'fs';
6
+ import Database from 'better-sqlite3';
7
+ import { randomUUID, createHash } from 'crypto';
8
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
9
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
10
+ import { z } from 'zod';
11
+ import chalk from 'chalk';
12
+
13
+ var __defProp = Object.defineProperty;
14
+ var __getOwnPropNames = Object.getOwnPropertyNames;
15
+ var __esm = (fn, res) => function __init() {
16
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
17
+ };
18
+ var __export = (target, all) => {
19
+ for (var name in all)
20
+ __defProp(target, name, { get: all[name], enumerable: true });
21
+ };
22
+ var xdgConfig, xdgData, CONFIG_DIR, DATA_DIR, DB_PATH, WALLET_PATH, HISTORY_PATH, PLATFORM_ADDRESS, SEARCH_COST_XLM, RECALL_COST_XLM;
23
+ var init_config = __esm({
24
+ "src/config.ts"() {
25
+ xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
26
+ xdgData = process.env.XDG_DATA_HOME || join(homedir(), ".local", "share");
27
+ CONFIG_DIR = process.env.SYNAPSE_CONFIG_DIR || join(xdgConfig, "synapse-mcp");
28
+ DATA_DIR = process.env.SYNAPSE_DATA_DIR || join(xdgData, "synapse-mcp");
29
+ DB_PATH = join(DATA_DIR, "kb.db");
30
+ WALLET_PATH = join(CONFIG_DIR, "wallet.json");
31
+ HISTORY_PATH = join(DATA_DIR, "history.json");
32
+ PLATFORM_ADDRESS = process.env.SYNAPSE_PLATFORM_ADDRESS || "GC63PSERYMUUUJKYSSFQ7FKRAU5UPIP3XUC6X7DLMZUB7SSCPW5BSIRT";
33
+ SEARCH_COST_XLM = "0.2";
34
+ RECALL_COST_XLM = "1";
35
+ }
36
+ });
37
+ function loadOrCreateWallet() {
38
+ const envSecret = process.env.STELLAR_SECRET_KEY;
39
+ if (envSecret) {
40
+ return Keypair.fromSecret(envSecret);
41
+ }
42
+ if (existsSync(WALLET_PATH)) {
43
+ const data = JSON.parse(
44
+ readFileSync(WALLET_PATH, "utf-8")
45
+ );
46
+ return Keypair.fromSecret(data.secretKey);
47
+ }
48
+ mkdirSync(CONFIG_DIR, { recursive: true });
49
+ const keypair = Keypair.random();
50
+ const walletData = {
51
+ publicKey: keypair.publicKey(),
52
+ secretKey: keypair.secret(),
53
+ network: "stellar-testnet",
54
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
55
+ };
56
+ writeFileSync(WALLET_PATH, JSON.stringify(walletData, null, 2), {
57
+ mode: 384
58
+ });
59
+ return keypair;
60
+ }
61
+ async function fundWithFriendbot(publicKey) {
62
+ const url = `https://friendbot.stellar.org?addr=${encodeURIComponent(publicKey)}`;
63
+ const res = await fetch(url);
64
+ return res.ok;
65
+ }
66
+ async function getBalance(publicKey) {
67
+ const url = `https://horizon-testnet.stellar.org/accounts/${publicKey}`;
68
+ const res = await fetch(url);
69
+ if (!res.ok) {
70
+ if (res.status === 404) return "0 (account not funded)";
71
+ return "unknown";
72
+ }
73
+ const data = await res.json();
74
+ const native = data.balances.find((b) => b.asset_type === "native");
75
+ return native ? `${native.balance} XLM` : "0 XLM";
76
+ }
77
+ function getWalletInfo() {
78
+ const envSecret = process.env.STELLAR_SECRET_KEY;
79
+ if (envSecret) {
80
+ const kp = Keypair.fromSecret(envSecret);
81
+ return { publicKey: kp.publicKey(), secretPresent: true, source: "env" };
82
+ }
83
+ if (existsSync(WALLET_PATH)) {
84
+ mkdirSync(dirname(WALLET_PATH), { recursive: true });
85
+ const data = JSON.parse(
86
+ readFileSync(WALLET_PATH, "utf-8")
87
+ );
88
+ return {
89
+ publicKey: data.publicKey,
90
+ secretPresent: true,
91
+ source: "file"
92
+ };
93
+ }
94
+ return { publicKey: "", secretPresent: false, source: "none" };
95
+ }
96
+ var init_manager = __esm({
97
+ "src/wallet/manager.ts"() {
98
+ init_config();
99
+ }
100
+ });
101
+ function initDatabase(dbPath) {
102
+ mkdirSync(dirname(dbPath), { recursive: true });
103
+ const db = new Database(dbPath);
104
+ db.pragma("journal_mode = WAL");
105
+ db.pragma("foreign_keys = ON");
106
+ db.exec(`
107
+ CREATE TABLE IF NOT EXISTS plans (
108
+ id TEXT PRIMARY KEY,
109
+ title TEXT NOT NULL,
110
+ description TEXT NOT NULL,
111
+ content TEXT NOT NULL,
112
+ content_hash TEXT NOT NULL UNIQUE,
113
+ tags TEXT NOT NULL DEFAULT '[]',
114
+ domain TEXT,
115
+ language TEXT,
116
+ framework TEXT,
117
+ contributor_address TEXT NOT NULL,
118
+ quality_score REAL NOT NULL DEFAULT 0,
119
+ purchase_count INTEGER NOT NULL DEFAULT 0,
120
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
121
+ );
122
+
123
+ CREATE VIRTUAL TABLE IF NOT EXISTS plans_fts USING fts5(
124
+ title,
125
+ description,
126
+ tags,
127
+ content,
128
+ content=plans,
129
+ content_rowid=rowid
130
+ );
131
+
132
+ CREATE TRIGGER IF NOT EXISTS plans_ai AFTER INSERT ON plans BEGIN
133
+ INSERT INTO plans_fts(rowid, title, description, tags, content)
134
+ VALUES (new.rowid, new.title, new.description, new.tags, new.content);
135
+ END;
136
+
137
+ CREATE TRIGGER IF NOT EXISTS plans_ad AFTER DELETE ON plans BEGIN
138
+ INSERT INTO plans_fts(plans_fts, rowid, title, description, tags, content)
139
+ VALUES ('delete', old.rowid, old.title, old.description, old.tags, old.content);
140
+ END;
141
+
142
+ CREATE TRIGGER IF NOT EXISTS plans_au AFTER UPDATE ON plans BEGIN
143
+ INSERT INTO plans_fts(plans_fts, rowid, title, description, tags, content)
144
+ VALUES ('delete', old.rowid, old.title, old.description, old.tags, old.content);
145
+ INSERT INTO plans_fts(rowid, title, description, tags, content)
146
+ VALUES (new.rowid, new.title, new.description, new.tags, new.content);
147
+ END;
148
+
149
+ CREATE TABLE IF NOT EXISTS purchases (
150
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
151
+ plan_id TEXT NOT NULL REFERENCES plans(id),
152
+ buyer_address TEXT NOT NULL,
153
+ amount_stroops INTEGER NOT NULL,
154
+ contributor_share_stroops INTEGER NOT NULL,
155
+ operator_share_stroops INTEGER NOT NULL,
156
+ transaction_hash TEXT,
157
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
158
+ );
159
+
160
+ CREATE INDEX IF NOT EXISTS idx_purchases_plan_id ON purchases(plan_id);
161
+ CREATE INDEX IF NOT EXISTS idx_purchases_buyer ON purchases(buyer_address);
162
+ CREATE INDEX IF NOT EXISTS idx_plans_contributor ON plans(contributor_address);
163
+ CREATE INDEX IF NOT EXISTS idx_plans_content_hash ON plans(content_hash);
164
+ `);
165
+ return db;
166
+ }
167
+ var init_schema = __esm({
168
+ "src/storage/db/schema.ts"() {
169
+ }
170
+ });
171
+ var CONTRIBUTOR_SHARE, PlanStore;
172
+ var init_plans = __esm({
173
+ "src/storage/db/plans.ts"() {
174
+ CONTRIBUTOR_SHARE = 0.7;
175
+ PlanStore = class {
176
+ constructor(db) {
177
+ this.db = db;
178
+ }
179
+ insert(plan) {
180
+ const id = randomUUID();
181
+ const content_hash = createHash("sha256").update(plan.content).digest("hex");
182
+ const tagsJson = JSON.stringify(plan.tags);
183
+ const stmt = this.db.prepare(`
184
+ INSERT INTO plans (id, title, description, content, content_hash, tags, domain, language, framework, contributor_address)
185
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
186
+ `);
187
+ stmt.run(
188
+ id,
189
+ plan.title,
190
+ plan.description,
191
+ plan.content,
192
+ content_hash,
193
+ tagsJson,
194
+ plan.domain || null,
195
+ plan.language || null,
196
+ plan.framework || null,
197
+ plan.contributor_address
198
+ );
199
+ return this.getById(id);
200
+ }
201
+ getById(id) {
202
+ const stmt = this.db.prepare("SELECT * FROM plans WHERE id = ?");
203
+ return stmt.get(id) || null;
204
+ }
205
+ getMeta(id) {
206
+ const plan = this.db.prepare(
207
+ "SELECT id, title, description, tags, domain, language, framework, quality_score, purchase_count, created_at FROM plans WHERE id = ?"
208
+ ).get(id);
209
+ if (!plan) return null;
210
+ return {
211
+ ...plan,
212
+ tags: JSON.parse(plan.tags)
213
+ };
214
+ }
215
+ search(query, tags, limit = 20) {
216
+ let sql;
217
+ const params = [];
218
+ if (query && query.trim()) {
219
+ sql = `
220
+ SELECT p.id, p.title, p.description, p.tags, p.domain, p.quality_score, p.purchase_count,
221
+ bm25(plans_fts) as rank
222
+ FROM plans_fts fts
223
+ JOIN plans p ON p.rowid = fts.rowid
224
+ WHERE plans_fts MATCH ?
225
+ `;
226
+ params.push(query);
227
+ } else {
228
+ sql = `
229
+ SELECT p.id, p.title, p.description, p.tags, p.domain, p.quality_score, p.purchase_count,
230
+ 0 as rank
231
+ FROM plans p
232
+ WHERE 1=1
233
+ `;
234
+ }
235
+ if (tags && tags.length > 0) {
236
+ for (const tag of tags) {
237
+ sql += " AND p.tags LIKE ?";
238
+ params.push(`%${tag}%`);
239
+ }
240
+ }
241
+ sql += query && query.trim() ? " ORDER BY rank LIMIT ?" : " ORDER BY p.purchase_count DESC, p.created_at DESC LIMIT ?";
242
+ params.push(limit);
243
+ const rows = this.db.prepare(sql).all(...params);
244
+ return rows.map((row) => ({
245
+ id: row.id,
246
+ title: row.title,
247
+ description: row.description,
248
+ tags: JSON.parse(row.tags),
249
+ domain: row.domain,
250
+ quality_score: row.quality_score,
251
+ purchase_count: row.purchase_count,
252
+ rank: row.rank
253
+ }));
254
+ }
255
+ recordPurchase(planId, buyerAddress, amountStroops, transactionHash) {
256
+ const contributorShare = Math.floor(amountStroops * CONTRIBUTOR_SHARE);
257
+ const operatorShare = amountStroops - contributorShare;
258
+ this.db.prepare(
259
+ `
260
+ INSERT INTO purchases (plan_id, buyer_address, amount_stroops, contributor_share_stroops, operator_share_stroops, transaction_hash)
261
+ VALUES (?, ?, ?, ?, ?, ?)
262
+ `
263
+ ).run(
264
+ planId,
265
+ buyerAddress,
266
+ amountStroops,
267
+ contributorShare,
268
+ operatorShare,
269
+ transactionHash
270
+ );
271
+ this.db.prepare(
272
+ "UPDATE plans SET purchase_count = purchase_count + 1 WHERE id = ?"
273
+ ).run(planId);
274
+ return {
275
+ plan_id: planId,
276
+ buyer_address: buyerAddress,
277
+ amount_stroops: amountStroops,
278
+ contributor_share_stroops: contributorShare,
279
+ operator_share_stroops: operatorShare,
280
+ transaction_hash: transactionHash,
281
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
282
+ };
283
+ }
284
+ getContributorStats(address) {
285
+ const stats = this.db.prepare(
286
+ `
287
+ SELECT
288
+ ? as contributor_address,
289
+ (SELECT COUNT(*) FROM plans WHERE contributor_address = ?) as plans_count,
290
+ COALESCE((SELECT SUM(contributor_share_stroops) FROM purchases p JOIN plans pl ON p.plan_id = pl.id WHERE pl.contributor_address = ?), 0) as total_earned_stroops,
291
+ COALESCE((SELECT COUNT(*) FROM purchases p JOIN plans pl ON p.plan_id = pl.id WHERE pl.contributor_address = ?), 0) as total_purchases
292
+ `
293
+ ).get(address, address, address, address);
294
+ return stats;
295
+ }
296
+ getKBStats() {
297
+ const totalPlans = this.db.prepare("SELECT COUNT(*) as count FROM plans").get().count;
298
+ const totalPurchases = this.db.prepare("SELECT COUNT(*) as count FROM purchases").get().count;
299
+ const totalContributors = this.db.prepare(
300
+ "SELECT COUNT(DISTINCT contributor_address) as count FROM plans"
301
+ ).get().count;
302
+ const plans = this.db.prepare("SELECT tags FROM plans").all();
303
+ const tagCounts = {};
304
+ for (const row of plans) {
305
+ const tags = JSON.parse(row.tags);
306
+ for (const tag of tags) {
307
+ tagCounts[tag] = (tagCounts[tag] || 0) + 1;
308
+ }
309
+ }
310
+ const topTags = Object.entries(tagCounts).sort((a, b) => b[1] - a[1]).slice(0, 10).map(([tag, count]) => ({ tag, count }));
311
+ return {
312
+ total_plans: totalPlans,
313
+ total_purchases: totalPurchases,
314
+ total_contributors: totalContributors,
315
+ top_tags: topTags
316
+ };
317
+ }
318
+ contentHashExists(content) {
319
+ const hash = createHash("sha256").update(content).digest("hex");
320
+ const row = this.db.prepare("SELECT 1 FROM plans WHERE content_hash = ?").get(hash);
321
+ return !!row;
322
+ }
323
+ getContentHash(planId) {
324
+ const plan = this.db.prepare("SELECT content_hash FROM plans WHERE id = ?").get(planId);
325
+ return plan?.content_hash || null;
326
+ }
327
+ };
328
+ }
329
+ });
330
+
331
+ // src/storage/local-provider.ts
332
+ var SOROBAN_ERROR, LocalStorageProvider;
333
+ var init_local_provider = __esm({
334
+ "src/storage/local-provider.ts"() {
335
+ init_schema();
336
+ init_plans();
337
+ SOROBAN_ERROR = "Soroban oracle not available in local mode. Coming in v2.";
338
+ LocalStorageProvider = class {
339
+ planStore;
340
+ db;
341
+ constructor(dbPath) {
342
+ this.db = initDatabase(dbPath);
343
+ this.planStore = new PlanStore(this.db);
344
+ }
345
+ // === Core CRUD ===
346
+ async store(plan, _options) {
347
+ const description = plan.description || plan.content.slice(0, 200).replace(/\n/g, " ").trim();
348
+ return this.planStore.insert({
349
+ title: plan.title,
350
+ description,
351
+ content: plan.content,
352
+ tags: plan.tags,
353
+ domain: plan.domain,
354
+ language: plan.language,
355
+ framework: plan.framework,
356
+ contributor_address: plan.contributor_address
357
+ });
358
+ }
359
+ async getById(id) {
360
+ return this.planStore.getById(id);
361
+ }
362
+ async getMeta(id) {
363
+ return this.planStore.getMeta(id);
364
+ }
365
+ async search(options) {
366
+ return this.planStore.search(options.query, options.tags, options.limit);
367
+ }
368
+ async contentExists(content) {
369
+ return this.planStore.contentHashExists(content);
370
+ }
371
+ // === Payment / Purchase Tracking ===
372
+ async recordPurchase(planId, buyerAddress, amountStroops, txHash) {
373
+ return this.planStore.recordPurchase(
374
+ planId,
375
+ buyerAddress,
376
+ amountStroops,
377
+ txHash
378
+ );
379
+ }
380
+ async getContributorStats(address) {
381
+ return this.planStore.getContributorStats(address);
382
+ }
383
+ async getKBStats() {
384
+ return this.planStore.getKBStats();
385
+ }
386
+ // === On-Chain Oracle (Soroban) - V2 ===
387
+ async publishToChain(_planId) {
388
+ throw new Error(SOROBAN_ERROR);
389
+ }
390
+ async verifyIntegrity(_planId) {
391
+ throw new Error(SOROBAN_ERROR);
392
+ }
393
+ async syncFromChain(_contractId) {
394
+ throw new Error(SOROBAN_ERROR);
395
+ }
396
+ async getOnChainMeta(_planId) {
397
+ throw new Error(SOROBAN_ERROR);
398
+ }
399
+ // === Content Addressing ===
400
+ async getContentHash(planId) {
401
+ const hash = this.planStore.getContentHash(planId);
402
+ if (!hash) throw new Error(`Plan not found: ${planId}`);
403
+ return hash;
404
+ }
405
+ // === Lifecycle ===
406
+ async close() {
407
+ this.db.close();
408
+ }
409
+ };
410
+ }
411
+ });
412
+ function appendHistory(entry) {
413
+ mkdirSync(dirname(HISTORY_PATH), { recursive: true });
414
+ let history = [];
415
+ if (existsSync(HISTORY_PATH)) {
416
+ try {
417
+ history = JSON.parse(
418
+ readFileSync(HISTORY_PATH, "utf-8")
419
+ );
420
+ } catch {
421
+ history = [];
422
+ }
423
+ }
424
+ history.push({ ...entry, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
425
+ if (history.length > MAX_ENTRIES) {
426
+ history = history.slice(-MAX_ENTRIES);
427
+ }
428
+ writeFileSync(HISTORY_PATH, JSON.stringify(history, null, 2));
429
+ }
430
+ function getHistory() {
431
+ if (!existsSync(HISTORY_PATH)) return [];
432
+ try {
433
+ return JSON.parse(
434
+ readFileSync(HISTORY_PATH, "utf-8")
435
+ );
436
+ } catch {
437
+ return [];
438
+ }
439
+ }
440
+ var MAX_ENTRIES;
441
+ var init_tracker = __esm({
442
+ "src/history/tracker.ts"() {
443
+ init_config();
444
+ MAX_ENTRIES = 1e3;
445
+ }
446
+ });
447
+ async function submitPayment(fromKeypair, toAddress, amountXLM) {
448
+ const server = new Horizon.Server(HORIZON_URL);
449
+ try {
450
+ const account = await server.loadAccount(fromKeypair.publicKey());
451
+ const transaction = new TransactionBuilder(account, {
452
+ fee: "100",
453
+ networkPassphrase: Networks.TESTNET
454
+ }).addOperation(
455
+ Operation.payment({
456
+ destination: toAddress,
457
+ asset: Asset.native(),
458
+ amount: amountXLM
459
+ })
460
+ ).setTimeout(30).build();
461
+ transaction.sign(fromKeypair);
462
+ const result = await server.submitTransaction(transaction);
463
+ const hash = typeof result === "object" && result !== null && "hash" in result ? result.hash : null;
464
+ return { success: true, txHash: hash };
465
+ } catch (err) {
466
+ const message = err instanceof Error ? err.message : "Unknown payment error";
467
+ return { success: false, txHash: null, error: message };
468
+ }
469
+ }
470
+ var HORIZON_URL;
471
+ var init_stellar = __esm({
472
+ "src/payments/stellar.ts"() {
473
+ HORIZON_URL = "https://horizon-testnet.stellar.org";
474
+ }
475
+ });
476
+
477
+ // src/mcp/server.ts
478
+ var server_exports = {};
479
+ __export(server_exports, {
480
+ startMcpServer: () => startMcpServer
481
+ });
482
+ async function startMcpServer() {
483
+ const keypair = loadOrCreateWallet();
484
+ const publicKey = keypair.publicKey();
485
+ const storage = new LocalStorageProvider(DB_PATH);
486
+ try {
487
+ const bal = await getBalance(publicKey);
488
+ if (bal.includes("not funded")) {
489
+ await fundWithFriendbot(publicKey);
490
+ }
491
+ } catch {
492
+ }
493
+ const server = new McpServer({
494
+ name: "synapse-mcp",
495
+ version: "0.1.0"
496
+ });
497
+ server.tool(
498
+ "synapse_search",
499
+ "Search the Synapse knowledge base for implementation plans, patterns, and solutions contributed by AI agents and developers. Returns ranked results using full-text search with BM25 scoring. Each search costs 0.2 XLM paid via Stellar testnet. Example: synapse_search({ query: 'kubernetes deployment', tags: ['k8s'] })",
500
+ {
501
+ query: z.string().describe(
502
+ "Search query (e.g., 'kubernetes deployment', 'auth flow')"
503
+ ),
504
+ tags: z.array(z.string()).optional().describe("Filter by tags (e.g., ['k8s', 'auth'])")
505
+ },
506
+ async ({ query, tags }) => {
507
+ try {
508
+ const payment = await submitPayment(
509
+ keypair,
510
+ PLATFORM_ADDRESS,
511
+ SEARCH_COST_XLM
512
+ );
513
+ if (!payment.success) {
514
+ return {
515
+ content: [
516
+ {
517
+ type: "text",
518
+ text: `Payment failed: ${payment.error}
519
+ Ensure your wallet is funded. Run: synapse-mcp fund`
520
+ }
521
+ ],
522
+ isError: true
523
+ };
524
+ }
525
+ const results = await storage.search({ query, tags });
526
+ appendHistory({
527
+ action: "search",
528
+ query,
529
+ txHash: payment.txHash || void 0,
530
+ costXlm: 0.2
531
+ });
532
+ const balance = await getBalance(publicKey).catch(() => "unknown");
533
+ const text = results.length === 0 ? `No plans found for "${query}".` : results.map(
534
+ (r, i) => `${i + 1}. **${r.title}** (id: ${r.id})
535
+ ${r.description}
536
+ Tags: ${r.tags.join(", ")} | Score: ${r.quality_score} | Purchases: ${r.purchase_count}`
537
+ ).join("\n\n");
538
+ return {
539
+ content: [
540
+ { type: "text", text },
541
+ {
542
+ type: "text",
543
+ text: `
544
+ Cost: ${SEARCH_COST_XLM} XLM | Tx: ${payment.txHash || "n/a"}
545
+ Wallet: ${publicKey} | Balance: ${balance}`
546
+ }
547
+ ]
548
+ };
549
+ } catch (err) {
550
+ return {
551
+ content: [
552
+ {
553
+ type: "text",
554
+ text: `Search error: ${err.message}`
555
+ }
556
+ ],
557
+ isError: true
558
+ };
559
+ }
560
+ }
561
+ );
562
+ server.tool(
563
+ "synapse_recall",
564
+ "Retrieve the full content of a specific plan from the Synapse knowledge base. Use the plan ID from synapse_search results. Returns complete markdown content including implementation details, code examples, and architectural decisions. Each retrieval costs 1 XLM. Example: synapse_recall({ id: 'abc-123-def' })",
565
+ {
566
+ id: z.string().describe("Plan ID (UUID from search results)")
567
+ },
568
+ async ({ id }) => {
569
+ try {
570
+ const plan = await storage.getById(id);
571
+ if (!plan) {
572
+ return {
573
+ content: [
574
+ { type: "text", text: `Plan not found: ${id}` }
575
+ ],
576
+ isError: true
577
+ };
578
+ }
579
+ const payment = await submitPayment(
580
+ keypair,
581
+ PLATFORM_ADDRESS,
582
+ RECALL_COST_XLM
583
+ );
584
+ if (!payment.success) {
585
+ return {
586
+ content: [
587
+ {
588
+ type: "text",
589
+ text: `Payment failed: ${payment.error}
590
+ Ensure your wallet is funded. Run: synapse-mcp fund`
591
+ }
592
+ ],
593
+ isError: true
594
+ };
595
+ }
596
+ await storage.recordPurchase(
597
+ id,
598
+ publicKey,
599
+ 1e7,
600
+ // 1 XLM in stroops
601
+ payment.txHash
602
+ );
603
+ appendHistory({
604
+ action: "recall",
605
+ planId: id,
606
+ txHash: payment.txHash || void 0,
607
+ costXlm: 1
608
+ });
609
+ const balance = await getBalance(publicKey).catch(() => "unknown");
610
+ const tags = JSON.parse(plan.tags);
611
+ const text = [
612
+ `# ${plan.title}`,
613
+ "",
614
+ `**Domain**: ${plan.domain || "general"} | **Tags**: ${tags.join(", ")}`,
615
+ `**Contributor**: ${plan.contributor_address}`,
616
+ `**Content Hash**: ${plan.content_hash}`,
617
+ "",
618
+ plan.content
619
+ ].join("\n");
620
+ return {
621
+ content: [
622
+ { type: "text", text },
623
+ {
624
+ type: "text",
625
+ text: `
626
+ Cost: ${RECALL_COST_XLM} XLM | Tx: ${payment.txHash || "n/a"}
627
+ Wallet: ${publicKey} | Balance: ${balance}`
628
+ }
629
+ ]
630
+ };
631
+ } catch (err) {
632
+ return {
633
+ content: [
634
+ {
635
+ type: "text",
636
+ text: `Recall error: ${err.message}`
637
+ }
638
+ ],
639
+ isError: true
640
+ };
641
+ }
642
+ }
643
+ );
644
+ server.tool(
645
+ "synapse_learn",
646
+ "Upload a new implementation plan to the Synapse knowledge base. Share your learnings, patterns, and solutions so other AI agents can benefit. Plans are content-addressed (SHA-256) to prevent duplicates. Contributors earn 70% of future retrieval fees when other agents access their plans. Example: synapse_learn({ title: 'Auth with NextAuth', content: '# Setup...', tags: ['auth', 'nextjs'] })",
647
+ {
648
+ title: z.string().min(3).max(200).describe("Plan title"),
649
+ content: z.string().min(10).describe("Full plan content (markdown)"),
650
+ tags: z.array(z.string()).describe(
651
+ "Tags for discoverability (e.g., ['auth', 'nextjs'])"
652
+ ),
653
+ domain: z.string().optional().describe("Domain (e.g., 'web', 'devops', 'ml')"),
654
+ language: z.string().optional().describe("Programming language"),
655
+ framework: z.string().optional().describe("Framework used")
656
+ },
657
+ async ({ title, content, tags, domain, language, framework }) => {
658
+ try {
659
+ const exists = await storage.contentExists(content);
660
+ if (exists) {
661
+ return {
662
+ content: [
663
+ {
664
+ type: "text",
665
+ text: "Duplicate content - a plan with identical content already exists."
666
+ }
667
+ ],
668
+ isError: true
669
+ };
670
+ }
671
+ const plan = await storage.store({
672
+ title,
673
+ content,
674
+ tags,
675
+ domain,
676
+ language,
677
+ framework,
678
+ contributor_address: publicKey
679
+ });
680
+ appendHistory({ action: "learn", planId: plan.id });
681
+ return {
682
+ content: [
683
+ {
684
+ type: "text",
685
+ text: [
686
+ "Plan stored successfully!",
687
+ "",
688
+ `ID: ${plan.id}`,
689
+ `Title: ${plan.title}`,
690
+ `Content Hash: ${plan.content_hash}`,
691
+ `Contributor: ${publicKey}`,
692
+ "",
693
+ "Revenue: You earn 70% of future retrieval fees when other agents access this plan."
694
+ ].join("\n")
695
+ }
696
+ ]
697
+ };
698
+ } catch (err) {
699
+ return {
700
+ content: [
701
+ {
702
+ type: "text",
703
+ text: `Learn error: ${err.message}`
704
+ }
705
+ ],
706
+ isError: true
707
+ };
708
+ }
709
+ }
710
+ );
711
+ const transport = new StdioServerTransport();
712
+ await server.connect(transport);
713
+ }
714
+ var init_server = __esm({
715
+ "src/mcp/server.ts"() {
716
+ init_manager();
717
+ init_local_provider();
718
+ init_tracker();
719
+ init_stellar();
720
+ init_config();
721
+ }
722
+ });
723
+
724
+ // src/cli/dashboard.ts
725
+ var dashboard_exports = {};
726
+ __export(dashboard_exports, {
727
+ dashboardCommand: () => dashboardCommand
728
+ });
729
+ async function dashboardCommand() {
730
+ const info = getWalletInfo();
731
+ const history = getHistory();
732
+ console.log(
733
+ chalk.bold.cyan(`
734
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
735
+ \u2551 SYNAPSE MCP Dashboard \u2551
736
+ \u2551 AI Knowledge Oracle on Stellar \u2551
737
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
738
+ `)
739
+ );
740
+ console.log(chalk.bold(" WALLET"));
741
+ if (info.secretPresent) {
742
+ console.log(` Address: ${chalk.cyan(info.publicKey)}`);
743
+ console.log(
744
+ ` Source: ${info.source === "env" ? "env var" : "wallet.json"}`
745
+ );
746
+ try {
747
+ const balance = await getBalance(info.publicKey);
748
+ console.log(` Balance: ${chalk.green(balance)}`);
749
+ } catch {
750
+ console.log(` Balance: ${chalk.red("unavailable")}`);
751
+ }
752
+ } else {
753
+ console.log(
754
+ chalk.yellow(
755
+ " No wallet configured. Run MCP server to auto-generate."
756
+ )
757
+ );
758
+ }
759
+ console.log("");
760
+ console.log(chalk.bold(" USAGE"));
761
+ const searches = history.filter((h) => h.action === "search").length;
762
+ const recalls = history.filter((h) => h.action === "recall").length;
763
+ const learns = history.filter((h) => h.action === "learn").length;
764
+ console.log(` Searches: ${searches}`);
765
+ console.log(` Recalls: ${recalls}`);
766
+ console.log(` Learns: ${learns}`);
767
+ console.log(
768
+ ` Spent: ~${(searches * 0.2 + recalls * 1).toFixed(1)} XLM`
769
+ );
770
+ try {
771
+ const storage = new LocalStorageProvider(DB_PATH);
772
+ const stats = await storage.getKBStats();
773
+ console.log("");
774
+ console.log(chalk.bold(" KNOWLEDGE BASE"));
775
+ console.log(` Plans: ${stats.total_plans}`);
776
+ console.log(` Purchases: ${stats.total_purchases}`);
777
+ console.log(` Contributors: ${stats.total_contributors}`);
778
+ if (stats.top_tags.length > 0) {
779
+ console.log(
780
+ ` Top Tags: ${stats.top_tags.map((t) => t.tag).join(", ")}`
781
+ );
782
+ }
783
+ if (info.secretPresent) {
784
+ const cStats = await storage.getContributorStats(info.publicKey);
785
+ if (cStats.plans_count > 0) {
786
+ console.log("");
787
+ console.log(chalk.bold(" CONTRIBUTIONS"));
788
+ console.log(` Plans: ${cStats.plans_count}`);
789
+ console.log(` Purchases: ${cStats.total_purchases}`);
790
+ console.log(
791
+ ` Earned: ${chalk.green((cStats.total_earned_stroops / 1e7).toFixed(2) + " XLM")}`
792
+ );
793
+ }
794
+ }
795
+ await storage.close();
796
+ } catch {
797
+ }
798
+ if (history.length > 0) {
799
+ console.log("");
800
+ console.log(chalk.bold(" RECENT ACTIVITY"));
801
+ const recent = history.slice(-5).reverse();
802
+ for (const entry of recent) {
803
+ const time = new Date(entry.timestamp).toLocaleString();
804
+ const desc = entry.action === "search" ? `search: "${entry.query}"` : entry.action === "recall" ? `recall: ${entry.planId}` : `learn: ${entry.planId}`;
805
+ console.log(` ${chalk.dim(time)} ${desc}`);
806
+ }
807
+ }
808
+ console.log("");
809
+ }
810
+ var init_dashboard = __esm({
811
+ "src/cli/dashboard.ts"() {
812
+ init_manager();
813
+ init_tracker();
814
+ init_local_provider();
815
+ init_config();
816
+ }
817
+ });
818
+
819
+ // src/cli/wallet.ts
820
+ var wallet_exports = {};
821
+ __export(wallet_exports, {
822
+ walletCommand: () => walletCommand
823
+ });
824
+ async function walletCommand() {
825
+ const info = getWalletInfo();
826
+ if (!info.secretPresent) {
827
+ console.log(
828
+ chalk.yellow(
829
+ "No wallet found. Run the MCP server once to auto-generate one."
830
+ )
831
+ );
832
+ return;
833
+ }
834
+ console.log(chalk.bold("Synapse Wallet"));
835
+ console.log(` Address: ${chalk.cyan(info.publicKey)}`);
836
+ console.log(
837
+ ` Source: ${info.source === "env" ? "STELLAR_SECRET_KEY env var" : WALLET_PATH}`
838
+ );
839
+ console.log(` Network: stellar-testnet`);
840
+ try {
841
+ const balance = await getBalance(info.publicKey);
842
+ console.log(` Balance: ${chalk.green(balance)}`);
843
+ } catch {
844
+ console.log(` Balance: ${chalk.red("unable to fetch")}`);
845
+ }
846
+ }
847
+ var init_wallet = __esm({
848
+ "src/cli/wallet.ts"() {
849
+ init_manager();
850
+ init_config();
851
+ }
852
+ });
853
+
854
+ // src/cli/fund.ts
855
+ var fund_exports = {};
856
+ __export(fund_exports, {
857
+ fundCommand: () => fundCommand
858
+ });
859
+ async function fundCommand() {
860
+ const keypair = loadOrCreateWallet();
861
+ const publicKey = keypair.publicKey();
862
+ console.log(chalk.bold("Funding wallet via Friendbot (testnet)..."));
863
+ console.log(` Address: ${chalk.cyan(publicKey)}`);
864
+ const success = await fundWithFriendbot(publicKey);
865
+ if (success) {
866
+ const balance = await getBalance(publicKey);
867
+ console.log(chalk.green(` Funded! Balance: ${balance}`));
868
+ } else {
869
+ console.log(
870
+ chalk.yellow(
871
+ " Friendbot returned an error (wallet may already be funded)."
872
+ )
873
+ );
874
+ try {
875
+ const balance = await getBalance(publicKey);
876
+ console.log(` Current balance: ${balance}`);
877
+ } catch {
878
+ }
879
+ }
880
+ }
881
+ var init_fund = __esm({
882
+ "src/cli/fund.ts"() {
883
+ init_manager();
884
+ }
885
+ });
886
+
887
+ // src/cli/stats.ts
888
+ var stats_exports = {};
889
+ __export(stats_exports, {
890
+ statsCommand: () => statsCommand
891
+ });
892
+ async function statsCommand() {
893
+ const history = getHistory();
894
+ const info = getWalletInfo();
895
+ console.log(chalk.bold("Synapse Usage Statistics"));
896
+ console.log(
897
+ ` Searches: ${history.filter((h) => h.action === "search").length}`
898
+ );
899
+ console.log(
900
+ ` Recalls: ${history.filter((h) => h.action === "recall").length}`
901
+ );
902
+ console.log(
903
+ ` Learns: ${history.filter((h) => h.action === "learn").length}`
904
+ );
905
+ console.log(` Total: ${history.length}`);
906
+ try {
907
+ const storage = new LocalStorageProvider(DB_PATH);
908
+ const kbStats = await storage.getKBStats();
909
+ console.log("");
910
+ console.log(chalk.bold("Knowledge Base"));
911
+ console.log(` Total plans: ${kbStats.total_plans}`);
912
+ console.log(` Total purchases: ${kbStats.total_purchases}`);
913
+ console.log(` Total contributors: ${kbStats.total_contributors}`);
914
+ if (info.secretPresent) {
915
+ const cStats = await storage.getContributorStats(info.publicKey);
916
+ console.log("");
917
+ console.log(chalk.bold("Your Contributions"));
918
+ console.log(` Plans uploaded: ${cStats.plans_count}`);
919
+ console.log(` Total purchases: ${cStats.total_purchases}`);
920
+ console.log(
921
+ ` Earnings: ${(cStats.total_earned_stroops / 1e7).toFixed(2)} XLM`
922
+ );
923
+ }
924
+ await storage.close();
925
+ } catch {
926
+ console.log(
927
+ chalk.dim("\n No local database found yet. Use synapse_learn to add plans.")
928
+ );
929
+ }
930
+ }
931
+ var init_stats = __esm({
932
+ "src/cli/stats.ts"() {
933
+ init_tracker();
934
+ init_manager();
935
+ init_local_provider();
936
+ init_config();
937
+ }
938
+ });
939
+
940
+ // src/index.ts
941
+ var command = process.argv[2];
942
+ if (!command) {
943
+ const { startMcpServer: startMcpServer2 } = await Promise.resolve().then(() => (init_server(), server_exports));
944
+ await startMcpServer2();
945
+ } else {
946
+ switch (command) {
947
+ case "dashboard": {
948
+ const { dashboardCommand: dashboardCommand2 } = await Promise.resolve().then(() => (init_dashboard(), dashboard_exports));
949
+ await dashboardCommand2();
950
+ break;
951
+ }
952
+ case "wallet": {
953
+ const { walletCommand: walletCommand2 } = await Promise.resolve().then(() => (init_wallet(), wallet_exports));
954
+ await walletCommand2();
955
+ break;
956
+ }
957
+ case "fund": {
958
+ const { fundCommand: fundCommand2 } = await Promise.resolve().then(() => (init_fund(), fund_exports));
959
+ await fundCommand2();
960
+ break;
961
+ }
962
+ case "stats": {
963
+ const { statsCommand: statsCommand2 } = await Promise.resolve().then(() => (init_stats(), stats_exports));
964
+ await statsCommand2();
965
+ break;
966
+ }
967
+ default:
968
+ console.error(`Unknown command: ${command}`);
969
+ printUsage();
970
+ process.exit(1);
971
+ }
972
+ }
973
+ function printUsage() {
974
+ console.log(`
975
+ \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
976
+ \u2551 SYNAPSE MCP \u2551
977
+ \u2551 AI Knowledge Oracle on Stellar \u2551
978
+ \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D
979
+
980
+ Usage: synapse-mcp [command]
981
+
982
+ Commands:
983
+ (none) Start MCP server (stdio mode)
984
+ dashboard Show wallet, contributions, and usage
985
+ wallet Print wallet address and balance
986
+ fund Fund wallet via Friendbot (testnet)
987
+ stats Show usage and contribution stats
988
+
989
+ MCP Tools:
990
+ synapse_search Search plans (0.2 XLM)
991
+ synapse_recall Retrieve full plan (1 XLM)
992
+ synapse_learn Upload a plan (free)
993
+
994
+ Environment:
995
+ STELLAR_SECRET_KEY Use existing Stellar key
996
+ SYNAPSE_CONFIG_DIR Custom config directory
997
+ SYNAPSE_DATA_DIR Custom data directory
998
+ SYNAPSE_PLATFORM_ADDRESS Override platform address
999
+ `);
1000
+ }
1001
+ //# sourceMappingURL=index.js.map
1002
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/config.ts","../src/wallet/manager.ts","../src/storage/db/schema.ts","../src/storage/db/plans.ts","../src/storage/local-provider.ts","../src/history/tracker.ts","../src/payments/stellar.ts","../src/mcp/server.ts","../src/cli/dashboard.ts","../src/cli/wallet.ts","../src/cli/fund.ts","../src/cli/stats.ts","../src/index.ts"],"names":["mkdirSync","dirname","existsSync","readFileSync","writeFileSync","chalk","startMcpServer","dashboardCommand","walletCommand","fundCommand","statsCommand"],"mappings":"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","file":"index.js","sourcesContent":["import { join } from \"path\";\nimport { homedir } from \"os\";\n\nconst xdgConfig = process.env.XDG_CONFIG_HOME || join(homedir(), \".config\");\nconst xdgData = process.env.XDG_DATA_HOME || join(homedir(), \".local\", \"share\");\n\nexport const CONFIG_DIR =\n process.env.SYNAPSE_CONFIG_DIR || join(xdgConfig, \"synapse-mcp\");\n\nexport const DATA_DIR =\n process.env.SYNAPSE_DATA_DIR || join(xdgData, \"synapse-mcp\");\n\nexport const DB_PATH = join(DATA_DIR, \"kb.db\");\nexport const WALLET_PATH = join(CONFIG_DIR, \"wallet.json\");\nexport const HISTORY_PATH = join(DATA_DIR, \"history.json\");\n\nexport const NETWORK = \"stellar-testnet\";\n\n// Hardcoded Synapse platform address (testnet)\nexport const PLATFORM_ADDRESS =\n process.env.SYNAPSE_PLATFORM_ADDRESS ||\n \"GC63PSERYMUUUJKYSSFQ7FKRAU5UPIP3XUC6X7DLMZUB7SSCPW5BSIRT\";\n\nexport const SEARCH_COST_XLM = \"0.2\";\nexport const RECALL_COST_XLM = \"1\";\n","import { Keypair } from \"@stellar/stellar-sdk\";\nimport { readFileSync, writeFileSync, existsSync, mkdirSync } from \"fs\";\nimport { dirname } from \"path\";\nimport { WALLET_PATH, CONFIG_DIR } from \"../config.js\";\n\ninterface WalletFile {\n publicKey: string;\n secretKey: string;\n network: string;\n createdAt: string;\n}\n\nexport function loadOrCreateWallet(): Keypair {\n const envSecret = process.env.STELLAR_SECRET_KEY;\n if (envSecret) {\n return Keypair.fromSecret(envSecret);\n }\n\n if (existsSync(WALLET_PATH)) {\n const data = JSON.parse(\n readFileSync(WALLET_PATH, \"utf-8\"),\n ) as WalletFile;\n return Keypair.fromSecret(data.secretKey);\n }\n\n mkdirSync(CONFIG_DIR, { recursive: true });\n const keypair = Keypair.random();\n const walletData: WalletFile = {\n publicKey: keypair.publicKey(),\n secretKey: keypair.secret(),\n network: \"stellar-testnet\",\n createdAt: new Date().toISOString(),\n };\n writeFileSync(WALLET_PATH, JSON.stringify(walletData, null, 2), {\n mode: 0o600,\n });\n\n return keypair;\n}\n\nexport async function fundWithFriendbot(\n publicKey: string,\n): Promise<boolean> {\n const url = `https://friendbot.stellar.org?addr=${encodeURIComponent(publicKey)}`;\n const res = await fetch(url);\n return res.ok;\n}\n\nexport async function getBalance(publicKey: string): Promise<string> {\n const url = `https://horizon-testnet.stellar.org/accounts/${publicKey}`;\n const res = await fetch(url);\n if (!res.ok) {\n if (res.status === 404) return \"0 (account not funded)\";\n return \"unknown\";\n }\n const data = (await res.json()) as {\n balances: Array<{ asset_type: string; balance: string }>;\n };\n const native = data.balances.find((b) => b.asset_type === \"native\");\n return native ? `${native.balance} XLM` : \"0 XLM\";\n}\n\nexport function getWalletInfo(): {\n publicKey: string;\n secretPresent: boolean;\n source: string;\n} {\n const envSecret = process.env.STELLAR_SECRET_KEY;\n if (envSecret) {\n const kp = Keypair.fromSecret(envSecret);\n return { publicKey: kp.publicKey(), secretPresent: true, source: \"env\" };\n }\n\n if (existsSync(WALLET_PATH)) {\n mkdirSync(dirname(WALLET_PATH), { recursive: true });\n const data = JSON.parse(\n readFileSync(WALLET_PATH, \"utf-8\"),\n ) as WalletFile;\n return {\n publicKey: data.publicKey,\n secretPresent: true,\n source: \"file\",\n };\n }\n\n return { publicKey: \"\", secretPresent: false, source: \"none\" };\n}\n","import Database from \"better-sqlite3\";\nimport { mkdirSync } from \"fs\";\nimport { dirname } from \"path\";\n\nexport function initDatabase(dbPath: string): Database.Database {\n mkdirSync(dirname(dbPath), { recursive: true });\n\n const db = new Database(dbPath);\n\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n db.exec(`\n CREATE TABLE IF NOT EXISTS plans (\n id TEXT PRIMARY KEY,\n title TEXT NOT NULL,\n description TEXT NOT NULL,\n content TEXT NOT NULL,\n content_hash TEXT NOT NULL UNIQUE,\n tags TEXT NOT NULL DEFAULT '[]',\n domain TEXT,\n language TEXT,\n framework TEXT,\n contributor_address TEXT NOT NULL,\n quality_score REAL NOT NULL DEFAULT 0,\n purchase_count INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE VIRTUAL TABLE IF NOT EXISTS plans_fts USING fts5(\n title,\n description,\n tags,\n content,\n content=plans,\n content_rowid=rowid\n );\n\n CREATE TRIGGER IF NOT EXISTS plans_ai AFTER INSERT ON plans BEGIN\n INSERT INTO plans_fts(rowid, title, description, tags, content)\n VALUES (new.rowid, new.title, new.description, new.tags, new.content);\n END;\n\n CREATE TRIGGER IF NOT EXISTS plans_ad AFTER DELETE ON plans BEGIN\n INSERT INTO plans_fts(plans_fts, rowid, title, description, tags, content)\n VALUES ('delete', old.rowid, old.title, old.description, old.tags, old.content);\n END;\n\n CREATE TRIGGER IF NOT EXISTS plans_au AFTER UPDATE ON plans BEGIN\n INSERT INTO plans_fts(plans_fts, rowid, title, description, tags, content)\n VALUES ('delete', old.rowid, old.title, old.description, old.tags, old.content);\n INSERT INTO plans_fts(rowid, title, description, tags, content)\n VALUES (new.rowid, new.title, new.description, new.tags, new.content);\n END;\n\n CREATE TABLE IF NOT EXISTS purchases (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n plan_id TEXT NOT NULL REFERENCES plans(id),\n buyer_address TEXT NOT NULL,\n amount_stroops INTEGER NOT NULL,\n contributor_share_stroops INTEGER NOT NULL,\n operator_share_stroops INTEGER NOT NULL,\n transaction_hash TEXT,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE INDEX IF NOT EXISTS idx_purchases_plan_id ON purchases(plan_id);\n CREATE INDEX IF NOT EXISTS idx_purchases_buyer ON purchases(buyer_address);\n CREATE INDEX IF NOT EXISTS idx_plans_contributor ON plans(contributor_address);\n CREATE INDEX IF NOT EXISTS idx_plans_content_hash ON plans(content_hash);\n `);\n\n return db;\n}\n","import type Database from \"better-sqlite3\";\nimport { createHash, randomUUID } from \"crypto\";\nimport type {\n Plan,\n PlanMeta,\n PlanSearchResult,\n Purchase,\n ContributorStats,\n KBStats,\n} from \"../../types.js\";\n\nconst CONTRIBUTOR_SHARE = 0.7;\n\nexport class PlanStore {\n constructor(private db: Database.Database) {}\n\n insert(plan: {\n title: string;\n description: string;\n content: string;\n tags: string[];\n domain?: string;\n language?: string;\n framework?: string;\n contributor_address: string;\n }): Plan {\n const id = randomUUID();\n const content_hash = createHash(\"sha256\")\n .update(plan.content)\n .digest(\"hex\");\n const tagsJson = JSON.stringify(plan.tags);\n\n const stmt = this.db.prepare(`\n INSERT INTO plans (id, title, description, content, content_hash, tags, domain, language, framework, contributor_address)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n id,\n plan.title,\n plan.description,\n plan.content,\n content_hash,\n tagsJson,\n plan.domain || null,\n plan.language || null,\n plan.framework || null,\n plan.contributor_address,\n );\n\n return this.getById(id)!;\n }\n\n getById(id: string): Plan | null {\n const stmt = this.db.prepare(\"SELECT * FROM plans WHERE id = ?\");\n return (stmt.get(id) as Plan) || null;\n }\n\n getMeta(id: string): PlanMeta | null {\n const plan = this.db\n .prepare(\n \"SELECT id, title, description, tags, domain, language, framework, quality_score, purchase_count, created_at FROM plans WHERE id = ?\",\n )\n .get(id) as Plan | undefined;\n\n if (!plan) return null;\n\n return {\n ...plan,\n tags: JSON.parse(plan.tags) as string[],\n };\n }\n\n search(query: string, tags?: string[], limit = 20): PlanSearchResult[] {\n let sql: string;\n const params: unknown[] = [];\n\n if (query && query.trim()) {\n sql = `\n SELECT p.id, p.title, p.description, p.tags, p.domain, p.quality_score, p.purchase_count,\n bm25(plans_fts) as rank\n FROM plans_fts fts\n JOIN plans p ON p.rowid = fts.rowid\n WHERE plans_fts MATCH ?\n `;\n params.push(query);\n } else {\n sql = `\n SELECT p.id, p.title, p.description, p.tags, p.domain, p.quality_score, p.purchase_count,\n 0 as rank\n FROM plans p\n WHERE 1=1\n `;\n }\n\n if (tags && tags.length > 0) {\n for (const tag of tags) {\n sql += \" AND p.tags LIKE ?\";\n params.push(`%${tag}%`);\n }\n }\n\n sql +=\n query && query.trim()\n ? \" ORDER BY rank LIMIT ?\"\n : \" ORDER BY p.purchase_count DESC, p.created_at DESC LIMIT ?\";\n params.push(limit);\n\n const rows = this.db.prepare(sql).all(...params) as Array<\n Plan & { rank: number }\n >;\n\n return rows.map((row) => ({\n id: row.id,\n title: row.title,\n description: row.description,\n tags: JSON.parse(row.tags) as string[],\n domain: row.domain,\n quality_score: row.quality_score,\n purchase_count: row.purchase_count,\n rank: row.rank,\n }));\n }\n\n recordPurchase(\n planId: string,\n buyerAddress: string,\n amountStroops: number,\n transactionHash: string | null,\n ): Purchase {\n const contributorShare = Math.floor(amountStroops * CONTRIBUTOR_SHARE);\n const operatorShare = amountStroops - contributorShare;\n\n this.db\n .prepare(\n `\n INSERT INTO purchases (plan_id, buyer_address, amount_stroops, contributor_share_stroops, operator_share_stroops, transaction_hash)\n VALUES (?, ?, ?, ?, ?, ?)\n `,\n )\n .run(\n planId,\n buyerAddress,\n amountStroops,\n contributorShare,\n operatorShare,\n transactionHash,\n );\n\n this.db\n .prepare(\n \"UPDATE plans SET purchase_count = purchase_count + 1 WHERE id = ?\",\n )\n .run(planId);\n\n return {\n plan_id: planId,\n buyer_address: buyerAddress,\n amount_stroops: amountStroops,\n contributor_share_stroops: contributorShare,\n operator_share_stroops: operatorShare,\n transaction_hash: transactionHash,\n created_at: new Date().toISOString(),\n };\n }\n\n getContributorStats(address: string): ContributorStats {\n const stats = this.db\n .prepare(\n `\n SELECT\n ? as contributor_address,\n (SELECT COUNT(*) FROM plans WHERE contributor_address = ?) as plans_count,\n COALESCE((SELECT SUM(contributor_share_stroops) FROM purchases p JOIN plans pl ON p.plan_id = pl.id WHERE pl.contributor_address = ?), 0) as total_earned_stroops,\n COALESCE((SELECT COUNT(*) FROM purchases p JOIN plans pl ON p.plan_id = pl.id WHERE pl.contributor_address = ?), 0) as total_purchases\n `,\n )\n .get(address, address, address, address) as ContributorStats;\n\n return stats;\n }\n\n getKBStats(): KBStats {\n const totalPlans = (\n this.db\n .prepare(\"SELECT COUNT(*) as count FROM plans\")\n .get() as { count: number }\n ).count;\n const totalPurchases = (\n this.db\n .prepare(\"SELECT COUNT(*) as count FROM purchases\")\n .get() as { count: number }\n ).count;\n const totalContributors = (\n this.db\n .prepare(\n \"SELECT COUNT(DISTINCT contributor_address) as count FROM plans\",\n )\n .get() as { count: number }\n ).count;\n\n const plans = this.db\n .prepare(\"SELECT tags FROM plans\")\n .all() as Array<{ tags: string }>;\n const tagCounts: Record<string, number> = {};\n for (const row of plans) {\n const tags = JSON.parse(row.tags) as string[];\n for (const tag of tags) {\n tagCounts[tag] = (tagCounts[tag] || 0) + 1;\n }\n }\n\n const topTags = Object.entries(tagCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([tag, count]) => ({ tag, count }));\n\n return {\n total_plans: totalPlans,\n total_purchases: totalPurchases,\n total_contributors: totalContributors,\n top_tags: topTags,\n };\n }\n\n contentHashExists(content: string): boolean {\n const hash = createHash(\"sha256\").update(content).digest(\"hex\");\n const row = this.db\n .prepare(\"SELECT 1 FROM plans WHERE content_hash = ?\")\n .get(hash);\n return !!row;\n }\n\n getContentHash(planId: string): string | null {\n const plan = this.db\n .prepare(\"SELECT content_hash FROM plans WHERE id = ?\")\n .get(planId) as { content_hash: string } | undefined;\n return plan?.content_hash || null;\n }\n}\n","import type {\n Plan,\n PlanMeta,\n PlanSearchResult,\n Purchase,\n ContributorStats,\n KBStats,\n StorePlanInput,\n} from \"../types.js\";\nimport type { StorageProvider, SearchOptions, StoreOptions } from \"./provider.js\";\nimport { initDatabase } from \"./db/schema.js\";\nimport { PlanStore } from \"./db/plans.js\";\n\nconst SOROBAN_ERROR =\n \"Soroban oracle not available in local mode. Coming in v2.\";\n\nexport class LocalStorageProvider implements StorageProvider {\n private planStore: PlanStore;\n private db: ReturnType<typeof initDatabase>;\n\n constructor(dbPath: string) {\n this.db = initDatabase(dbPath);\n this.planStore = new PlanStore(this.db);\n }\n\n // === Core CRUD ===\n\n async store(plan: StorePlanInput, _options?: StoreOptions): Promise<Plan> {\n const description =\n plan.description ||\n plan.content.slice(0, 200).replace(/\\n/g, \" \").trim();\n\n return this.planStore.insert({\n title: plan.title,\n description,\n content: plan.content,\n tags: plan.tags,\n domain: plan.domain,\n language: plan.language,\n framework: plan.framework,\n contributor_address: plan.contributor_address,\n });\n }\n\n async getById(id: string): Promise<Plan | null> {\n return this.planStore.getById(id);\n }\n\n async getMeta(id: string): Promise<PlanMeta | null> {\n return this.planStore.getMeta(id);\n }\n\n async search(options: SearchOptions): Promise<PlanSearchResult[]> {\n return this.planStore.search(options.query, options.tags, options.limit);\n }\n\n async contentExists(content: string): Promise<boolean> {\n return this.planStore.contentHashExists(content);\n }\n\n // === Payment / Purchase Tracking ===\n\n async recordPurchase(\n planId: string,\n buyerAddress: string,\n amountStroops: number,\n txHash: string | null,\n ): Promise<Purchase> {\n return this.planStore.recordPurchase(\n planId,\n buyerAddress,\n amountStroops,\n txHash,\n );\n }\n\n async getContributorStats(address: string): Promise<ContributorStats> {\n return this.planStore.getContributorStats(address);\n }\n\n async getKBStats(): Promise<KBStats> {\n return this.planStore.getKBStats();\n }\n\n // === On-Chain Oracle (Soroban) - V2 ===\n\n async publishToChain(\n _planId: string,\n ): Promise<{ txHash: string; contractId: string }> {\n throw new Error(SOROBAN_ERROR);\n }\n\n async verifyIntegrity(\n _planId: string,\n ): Promise<{ verified: boolean; onChainHash: string; localHash: string }> {\n throw new Error(SOROBAN_ERROR);\n }\n\n async syncFromChain(_contractId: string): Promise<Plan[]> {\n throw new Error(SOROBAN_ERROR);\n }\n\n async getOnChainMeta(_planId: string): Promise<PlanMeta | null> {\n throw new Error(SOROBAN_ERROR);\n }\n\n // === Content Addressing ===\n\n async getContentHash(planId: string): Promise<string> {\n const hash = this.planStore.getContentHash(planId);\n if (!hash) throw new Error(`Plan not found: ${planId}`);\n return hash;\n }\n\n // === Lifecycle ===\n\n async close(): Promise<void> {\n this.db.close();\n }\n}\n","import { readFileSync, writeFileSync, existsSync, mkdirSync } from \"fs\";\nimport { dirname } from \"path\";\nimport { HISTORY_PATH } from \"../config.js\";\n\ninterface HistoryEntry {\n action: \"search\" | \"recall\" | \"learn\";\n query?: string;\n planId?: string;\n txHash?: string;\n costXlm?: number;\n timestamp: string;\n}\n\nconst MAX_ENTRIES = 1000;\n\nexport function appendHistory(\n entry: Omit<HistoryEntry, \"timestamp\">,\n): void {\n mkdirSync(dirname(HISTORY_PATH), { recursive: true });\n\n let history: HistoryEntry[] = [];\n if (existsSync(HISTORY_PATH)) {\n try {\n history = JSON.parse(\n readFileSync(HISTORY_PATH, \"utf-8\"),\n ) as HistoryEntry[];\n } catch {\n history = [];\n }\n }\n\n history.push({ ...entry, timestamp: new Date().toISOString() });\n\n if (history.length > MAX_ENTRIES) {\n history = history.slice(-MAX_ENTRIES);\n }\n\n writeFileSync(HISTORY_PATH, JSON.stringify(history, null, 2));\n}\n\nexport function getHistory(): HistoryEntry[] {\n if (!existsSync(HISTORY_PATH)) return [];\n try {\n return JSON.parse(\n readFileSync(HISTORY_PATH, \"utf-8\"),\n ) as HistoryEntry[];\n } catch {\n return [];\n }\n}\n","import {\n Keypair,\n TransactionBuilder,\n Networks,\n Operation,\n Asset,\n Horizon,\n} from \"@stellar/stellar-sdk\";\n\nconst HORIZON_URL = \"https://horizon-testnet.stellar.org\";\n\nexport interface PaymentResult {\n success: boolean;\n txHash: string | null;\n error?: string;\n}\n\nexport async function submitPayment(\n fromKeypair: Keypair,\n toAddress: string,\n amountXLM: string,\n): Promise<PaymentResult> {\n const server = new Horizon.Server(HORIZON_URL);\n\n try {\n const account = await server.loadAccount(fromKeypair.publicKey());\n\n const transaction = new TransactionBuilder(account, {\n fee: \"100\",\n networkPassphrase: Networks.TESTNET,\n })\n .addOperation(\n Operation.payment({\n destination: toAddress,\n asset: Asset.native(),\n amount: amountXLM,\n }),\n )\n .setTimeout(30)\n .build();\n\n transaction.sign(fromKeypair);\n\n const result = await server.submitTransaction(transaction);\n const hash =\n typeof result === \"object\" && result !== null && \"hash\" in result\n ? (result as { hash: string }).hash\n : null;\n\n return { success: true, txHash: hash };\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Unknown payment error\";\n return { success: false, txHash: null, error: message };\n }\n}\n","import { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { loadOrCreateWallet, getBalance, fundWithFriendbot } from \"../wallet/manager.js\";\nimport { LocalStorageProvider } from \"../storage/local-provider.js\";\nimport { appendHistory } from \"../history/tracker.js\";\nimport { submitPayment } from \"../payments/stellar.js\";\nimport {\n DB_PATH,\n PLATFORM_ADDRESS,\n SEARCH_COST_XLM,\n RECALL_COST_XLM,\n} from \"../config.js\";\n\nexport async function startMcpServer(): Promise<void> {\n const keypair = loadOrCreateWallet();\n const publicKey = keypair.publicKey();\n const storage = new LocalStorageProvider(DB_PATH);\n\n // Auto-fund on testnet if new wallet\n try {\n const bal = await getBalance(publicKey);\n if (bal.includes(\"not funded\")) {\n await fundWithFriendbot(publicKey);\n }\n } catch {\n // Non-fatal\n }\n\n const server = new McpServer({\n name: \"synapse-mcp\",\n version: \"0.1.0\",\n });\n\n // Tool: synapse_search (0.2 XLM)\n server.tool(\n \"synapse_search\",\n \"Search the Synapse knowledge base for implementation plans, patterns, and solutions contributed by AI agents and developers. Returns ranked results using full-text search with BM25 scoring. Each search costs 0.2 XLM paid via Stellar testnet. Example: synapse_search({ query: 'kubernetes deployment', tags: ['k8s'] })\",\n {\n query: z\n .string()\n .describe(\n \"Search query (e.g., 'kubernetes deployment', 'auth flow')\",\n ),\n tags: z\n .array(z.string())\n .optional()\n .describe(\"Filter by tags (e.g., ['k8s', 'auth'])\"),\n },\n async ({ query, tags }) => {\n try {\n // Submit payment\n const payment = await submitPayment(\n keypair,\n PLATFORM_ADDRESS,\n SEARCH_COST_XLM,\n );\n\n if (!payment.success) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Payment failed: ${payment.error}\\nEnsure your wallet is funded. Run: synapse-mcp fund`,\n },\n ],\n isError: true,\n };\n }\n\n const results = await storage.search({ query, tags });\n appendHistory({\n action: \"search\",\n query,\n txHash: payment.txHash || undefined,\n costXlm: 0.2,\n });\n\n const balance = await getBalance(publicKey).catch(() => \"unknown\");\n\n const text =\n results.length === 0\n ? `No plans found for \"${query}\".`\n : results\n .map(\n (r, i) =>\n `${i + 1}. **${r.title}** (id: ${r.id})\\n ${r.description}\\n Tags: ${r.tags.join(\", \")} | Score: ${r.quality_score} | Purchases: ${r.purchase_count}`,\n )\n .join(\"\\n\\n\");\n\n return {\n content: [\n { type: \"text\" as const, text },\n {\n type: \"text\" as const,\n text: `\\nCost: ${SEARCH_COST_XLM} XLM | Tx: ${payment.txHash || \"n/a\"}\\nWallet: ${publicKey} | Balance: ${balance}`,\n },\n ],\n };\n } catch (err) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Search error: ${(err as Error).message}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n // Tool: synapse_recall (1 XLM)\n server.tool(\n \"synapse_recall\",\n \"Retrieve the full content of a specific plan from the Synapse knowledge base. Use the plan ID from synapse_search results. Returns complete markdown content including implementation details, code examples, and architectural decisions. Each retrieval costs 1 XLM. Example: synapse_recall({ id: 'abc-123-def' })\",\n {\n id: z\n .string()\n .describe(\"Plan ID (UUID from search results)\"),\n },\n async ({ id }) => {\n try {\n const plan = await storage.getById(id);\n if (!plan) {\n return {\n content: [\n { type: \"text\" as const, text: `Plan not found: ${id}` },\n ],\n isError: true,\n };\n }\n\n // Submit payment\n const payment = await submitPayment(\n keypair,\n PLATFORM_ADDRESS,\n RECALL_COST_XLM,\n );\n\n if (!payment.success) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Payment failed: ${payment.error}\\nEnsure your wallet is funded. Run: synapse-mcp fund`,\n },\n ],\n isError: true,\n };\n }\n\n // Record purchase\n await storage.recordPurchase(\n id,\n publicKey,\n 10_000_000, // 1 XLM in stroops\n payment.txHash,\n );\n\n appendHistory({\n action: \"recall\",\n planId: id,\n txHash: payment.txHash || undefined,\n costXlm: 1,\n });\n\n const balance = await getBalance(publicKey).catch(() => \"unknown\");\n const tags = JSON.parse(plan.tags) as string[];\n\n const text = [\n `# ${plan.title}`,\n \"\",\n `**Domain**: ${plan.domain || \"general\"} | **Tags**: ${tags.join(\", \")}`,\n `**Contributor**: ${plan.contributor_address}`,\n `**Content Hash**: ${plan.content_hash}`,\n \"\",\n plan.content,\n ].join(\"\\n\");\n\n return {\n content: [\n { type: \"text\" as const, text },\n {\n type: \"text\" as const,\n text: `\\nCost: ${RECALL_COST_XLM} XLM | Tx: ${payment.txHash || \"n/a\"}\\nWallet: ${publicKey} | Balance: ${balance}`,\n },\n ],\n };\n } catch (err) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Recall error: ${(err as Error).message}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n // Tool: synapse_learn (free)\n server.tool(\n \"synapse_learn\",\n \"Upload a new implementation plan to the Synapse knowledge base. Share your learnings, patterns, and solutions so other AI agents can benefit. Plans are content-addressed (SHA-256) to prevent duplicates. Contributors earn 70% of future retrieval fees when other agents access their plans. Example: synapse_learn({ title: 'Auth with NextAuth', content: '# Setup...', tags: ['auth', 'nextjs'] })\",\n {\n title: z\n .string()\n .min(3)\n .max(200)\n .describe(\"Plan title\"),\n content: z\n .string()\n .min(10)\n .describe(\"Full plan content (markdown)\"),\n tags: z\n .array(z.string())\n .describe(\n \"Tags for discoverability (e.g., ['auth', 'nextjs'])\",\n ),\n domain: z\n .string()\n .optional()\n .describe(\"Domain (e.g., 'web', 'devops', 'ml')\"),\n language: z\n .string()\n .optional()\n .describe(\"Programming language\"),\n framework: z\n .string()\n .optional()\n .describe(\"Framework used\"),\n },\n async ({ title, content, tags, domain, language, framework }) => {\n try {\n // Check for duplicate content\n const exists = await storage.contentExists(content);\n if (exists) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: \"Duplicate content - a plan with identical content already exists.\",\n },\n ],\n isError: true,\n };\n }\n\n const plan = await storage.store({\n title,\n content,\n tags,\n domain,\n language,\n framework,\n contributor_address: publicKey,\n });\n\n appendHistory({ action: \"learn\", planId: plan.id });\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: [\n \"Plan stored successfully!\",\n \"\",\n `ID: ${plan.id}`,\n `Title: ${plan.title}`,\n `Content Hash: ${plan.content_hash}`,\n `Contributor: ${publicKey}`,\n \"\",\n \"Revenue: You earn 70% of future retrieval fees when other agents access this plan.\",\n ].join(\"\\n\"),\n },\n ],\n };\n } catch (err) {\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Learn error: ${(err as Error).message}`,\n },\n ],\n isError: true,\n };\n }\n },\n );\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n","import chalk from \"chalk\";\nimport { getWalletInfo, getBalance } from \"../wallet/manager.js\";\nimport { getHistory } from \"../history/tracker.js\";\nimport { LocalStorageProvider } from \"../storage/local-provider.js\";\nimport { DB_PATH } from \"../config.js\";\n\nexport async function dashboardCommand(): Promise<void> {\n const info = getWalletInfo();\n const history = getHistory();\n\n console.log(\n chalk.bold.cyan(`\n ╔═══════════════════════════════════════╗\n ║ SYNAPSE MCP Dashboard ║\n ║ AI Knowledge Oracle on Stellar ║\n ╚═══════════════════════════════════════╝\n`),\n );\n\n // Wallet section\n console.log(chalk.bold(\" WALLET\"));\n if (info.secretPresent) {\n console.log(` Address: ${chalk.cyan(info.publicKey)}`);\n console.log(\n ` Source: ${info.source === \"env\" ? \"env var\" : \"wallet.json\"}`,\n );\n try {\n const balance = await getBalance(info.publicKey);\n console.log(` Balance: ${chalk.green(balance)}`);\n } catch {\n console.log(` Balance: ${chalk.red(\"unavailable\")}`);\n }\n } else {\n console.log(\n chalk.yellow(\n \" No wallet configured. Run MCP server to auto-generate.\",\n ),\n );\n }\n\n // Usage section\n console.log(\"\");\n console.log(chalk.bold(\" USAGE\"));\n const searches = history.filter((h) => h.action === \"search\").length;\n const recalls = history.filter((h) => h.action === \"recall\").length;\n const learns = history.filter((h) => h.action === \"learn\").length;\n console.log(` Searches: ${searches}`);\n console.log(` Recalls: ${recalls}`);\n console.log(` Learns: ${learns}`);\n console.log(\n ` Spent: ~${(searches * 0.2 + recalls * 1).toFixed(1)} XLM`,\n );\n\n // KB Stats\n try {\n const storage = new LocalStorageProvider(DB_PATH);\n const stats = await storage.getKBStats();\n console.log(\"\");\n console.log(chalk.bold(\" KNOWLEDGE BASE\"));\n console.log(` Plans: ${stats.total_plans}`);\n console.log(` Purchases: ${stats.total_purchases}`);\n console.log(` Contributors: ${stats.total_contributors}`);\n if (stats.top_tags.length > 0) {\n console.log(\n ` Top Tags: ${stats.top_tags.map((t) => t.tag).join(\", \")}`,\n );\n }\n\n // Contributor stats\n if (info.secretPresent) {\n const cStats = await storage.getContributorStats(info.publicKey);\n if (cStats.plans_count > 0) {\n console.log(\"\");\n console.log(chalk.bold(\" CONTRIBUTIONS\"));\n console.log(` Plans: ${cStats.plans_count}`);\n console.log(` Purchases: ${cStats.total_purchases}`);\n console.log(\n ` Earned: ${chalk.green((cStats.total_earned_stroops / 10_000_000).toFixed(2) + \" XLM\")}`,\n );\n }\n }\n\n await storage.close();\n } catch {\n // DB may not exist yet\n }\n\n // Recent activity\n if (history.length > 0) {\n console.log(\"\");\n console.log(chalk.bold(\" RECENT ACTIVITY\"));\n const recent = history.slice(-5).reverse();\n for (const entry of recent) {\n const time = new Date(entry.timestamp).toLocaleString();\n const desc =\n entry.action === \"search\"\n ? `search: \"${entry.query}\"`\n : entry.action === \"recall\"\n ? `recall: ${entry.planId}`\n : `learn: ${entry.planId}`;\n console.log(` ${chalk.dim(time)} ${desc}`);\n }\n }\n\n console.log(\"\");\n}\n","import chalk from \"chalk\";\nimport { getWalletInfo, getBalance } from \"../wallet/manager.js\";\nimport { WALLET_PATH } from \"../config.js\";\n\nexport async function walletCommand(): Promise<void> {\n const info = getWalletInfo();\n\n if (!info.secretPresent) {\n console.log(\n chalk.yellow(\n \"No wallet found. Run the MCP server once to auto-generate one.\",\n ),\n );\n return;\n }\n\n console.log(chalk.bold(\"Synapse Wallet\"));\n console.log(` Address: ${chalk.cyan(info.publicKey)}`);\n console.log(\n ` Source: ${info.source === \"env\" ? \"STELLAR_SECRET_KEY env var\" : WALLET_PATH}`,\n );\n console.log(` Network: stellar-testnet`);\n\n try {\n const balance = await getBalance(info.publicKey);\n console.log(` Balance: ${chalk.green(balance)}`);\n } catch {\n console.log(` Balance: ${chalk.red(\"unable to fetch\")}`);\n }\n}\n","import chalk from \"chalk\";\nimport {\n loadOrCreateWallet,\n fundWithFriendbot,\n getBalance,\n} from \"../wallet/manager.js\";\n\nexport async function fundCommand(): Promise<void> {\n const keypair = loadOrCreateWallet();\n const publicKey = keypair.publicKey();\n\n console.log(chalk.bold(\"Funding wallet via Friendbot (testnet)...\"));\n console.log(` Address: ${chalk.cyan(publicKey)}`);\n\n const success = await fundWithFriendbot(publicKey);\n\n if (success) {\n const balance = await getBalance(publicKey);\n console.log(chalk.green(` Funded! Balance: ${balance}`));\n } else {\n console.log(\n chalk.yellow(\n \" Friendbot returned an error (wallet may already be funded).\",\n ),\n );\n try {\n const balance = await getBalance(publicKey);\n console.log(` Current balance: ${balance}`);\n } catch {\n // ignore\n }\n }\n}\n","import chalk from \"chalk\";\nimport { getHistory } from \"../history/tracker.js\";\nimport { getWalletInfo } from \"../wallet/manager.js\";\nimport { LocalStorageProvider } from \"../storage/local-provider.js\";\nimport { DB_PATH } from \"../config.js\";\n\nexport async function statsCommand(): Promise<void> {\n const history = getHistory();\n const info = getWalletInfo();\n\n console.log(chalk.bold(\"Synapse Usage Statistics\"));\n console.log(\n ` Searches: ${history.filter((h) => h.action === \"search\").length}`,\n );\n console.log(\n ` Recalls: ${history.filter((h) => h.action === \"recall\").length}`,\n );\n console.log(\n ` Learns: ${history.filter((h) => h.action === \"learn\").length}`,\n );\n console.log(` Total: ${history.length}`);\n\n try {\n const storage = new LocalStorageProvider(DB_PATH);\n const kbStats = await storage.getKBStats();\n\n console.log(\"\");\n console.log(chalk.bold(\"Knowledge Base\"));\n console.log(` Total plans: ${kbStats.total_plans}`);\n console.log(` Total purchases: ${kbStats.total_purchases}`);\n console.log(` Total contributors: ${kbStats.total_contributors}`);\n\n if (info.secretPresent) {\n const cStats = await storage.getContributorStats(info.publicKey);\n console.log(\"\");\n console.log(chalk.bold(\"Your Contributions\"));\n console.log(` Plans uploaded: ${cStats.plans_count}`);\n console.log(` Total purchases: ${cStats.total_purchases}`);\n console.log(\n ` Earnings: ${(cStats.total_earned_stroops / 10_000_000).toFixed(2)} XLM`,\n );\n }\n\n await storage.close();\n } catch {\n console.log(\n chalk.dim(\"\\n No local database found yet. Use synapse_learn to add plans.\"),\n );\n }\n}\n","const command = process.argv[2];\n\nif (!command) {\n // Default: start MCP server (stdio mode)\n const { startMcpServer } = await import(\"./mcp/server.js\");\n await startMcpServer();\n} else {\n switch (command) {\n case \"dashboard\": {\n const { dashboardCommand } = await import(\"./cli/dashboard.js\");\n await dashboardCommand();\n break;\n }\n case \"wallet\": {\n const { walletCommand } = await import(\"./cli/wallet.js\");\n await walletCommand();\n break;\n }\n case \"fund\": {\n const { fundCommand } = await import(\"./cli/fund.js\");\n await fundCommand();\n break;\n }\n case \"stats\": {\n const { statsCommand } = await import(\"./cli/stats.js\");\n await statsCommand();\n break;\n }\n default:\n console.error(`Unknown command: ${command}`);\n printUsage();\n process.exit(1);\n }\n}\n\nfunction printUsage(): void {\n console.log(`\n ╔═══════════════════════════════════════╗\n ║ SYNAPSE MCP ║\n ║ AI Knowledge Oracle on Stellar ║\n ╚═══════════════════════════════════════╝\n\n Usage: synapse-mcp [command]\n\n Commands:\n (none) Start MCP server (stdio mode)\n dashboard Show wallet, contributions, and usage\n wallet Print wallet address and balance\n fund Fund wallet via Friendbot (testnet)\n stats Show usage and contribution stats\n\n MCP Tools:\n synapse_search Search plans (0.2 XLM)\n synapse_recall Retrieve full plan (1 XLM)\n synapse_learn Upload a plan (free)\n\n Environment:\n STELLAR_SECRET_KEY Use existing Stellar key\n SYNAPSE_CONFIG_DIR Custom config directory\n SYNAPSE_DATA_DIR Custom data directory\n SYNAPSE_PLATFORM_ADDRESS Override platform address\n`);\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@jashwanth0712/synapse-mcp",
3
+ "version": "1.1.0",
4
+ "description": "AI agent knowledge oracle with Stellar payments. Self-contained MCP server with embedded SQLite, full-text search, and on-chain verification (coming soon).",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "bin": {
9
+ "synapse-mcp": "./dist/index.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js"
15
+ },
16
+ "./storage": {
17
+ "types": "./dist/storage/provider.d.ts",
18
+ "import": "./dist/storage/provider.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "keywords": [
27
+ "mcp",
28
+ "model-context-protocol",
29
+ "ai-agents",
30
+ "knowledge-base",
31
+ "stellar",
32
+ "soroban",
33
+ "oracle"
34
+ ],
35
+ "license": "MIT",
36
+ "engines": {
37
+ "node": ">=18.0.0"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev": "tsup --watch",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
44
+ "clean": "rm -rf dist",
45
+ "typecheck": "tsc --noEmit"
46
+ },
47
+ "dependencies": {
48
+ "@modelcontextprotocol/sdk": "^1.12.1",
49
+ "@stellar/stellar-sdk": "^13.1.0",
50
+ "better-sqlite3": "^11.0.0",
51
+ "chalk": "^5.3.0",
52
+ "zod": "^3.22.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/better-sqlite3": "^7.6.8",
56
+ "tsup": "^8.0.0",
57
+ "typescript": "^5.3.0",
58
+ "vitest": "^1.0.0"
59
+ }
60
+ }