@noelclaw/mcp 1.5.2 → 1.5.4

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.
@@ -69,8 +69,15 @@ const GetTokenDataSchema = zod_1.z.object({ question: zod_1.z.string().min(1) })
69
69
  async function fetchMarketSnapshot() {
70
70
  try {
71
71
  const data = await cgFetch("/coins/markets?vs_currency=usd&ids=bitcoin,ethereum,solana&sparkline=false&price_change_percentage=24h");
72
- const find = (id) => data.find((c) => c.id === id)?.current_price ?? null;
73
- return { btc: find("bitcoin"), eth: find("ethereum"), sol: find("solana") };
72
+ const find = (id, field) => data.find((c) => c.id === id)?.[field] ?? 0;
73
+ return {
74
+ btc: find("bitcoin", "current_price"),
75
+ eth: find("ethereum", "current_price"),
76
+ sol: find("solana", "current_price"),
77
+ btcChange: find("bitcoin", "price_change_percentage_24h"),
78
+ ethChange: find("ethereum", "price_change_percentage_24h"),
79
+ solChange: find("solana", "price_change_percentage_24h"),
80
+ };
74
81
  }
75
82
  catch {
76
83
  return null;
@@ -33,6 +33,20 @@ exports.MIROSHARK_TOOLS = [
33
33
  required: ["simulation_id"],
34
34
  },
35
35
  },
36
+ {
37
+ name: "miroshark_stop",
38
+ description: "Stop a running MiroShark simulation.",
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ simulation_id: {
43
+ type: "string",
44
+ description: "Simulation ID to stop",
45
+ },
46
+ },
47
+ required: ["simulation_id"],
48
+ },
49
+ },
36
50
  ];
37
51
  // ── HTTP helpers ──────────────────────────────────────────────────────────────
38
52
  function authHeaders() {
@@ -262,5 +276,19 @@ async function handleMirosharkTool(name, args) {
262
276
  return { content: [{ type: "text", text: `MiroShark error: ${err.message}` }], isError: true };
263
277
  }
264
278
  }
279
+ // ── miroshark_stop ────────────────────────────────────────────────────────
280
+ if (name === "miroshark_stop") {
281
+ if (!a.simulation_id?.trim()) {
282
+ return { content: [{ type: "text", text: "simulation_id is required" }], isError: true };
283
+ }
284
+ const simId = a.simulation_id.trim();
285
+ try {
286
+ await miroJson(`/miroshark/api/simulation/${simId}/stop`, "POST", {});
287
+ return { content: [{ type: "text", text: `⏹️ Simulation \`${simId}\` stopped.` }] };
288
+ }
289
+ catch (err) {
290
+ return { content: [{ type: "text", text: `MiroShark error: ${err.message}` }], isError: true };
291
+ }
292
+ }
265
293
  return null;
266
294
  }
@@ -94,17 +94,29 @@ async function handleSwarmTool(name, args) {
94
94
  (0, convex_js_1.callConvex)("/swarm/memory/write", "POST", { agentId: "market-monitor", key: "sol_price", value: priceOnly(snapshot.sol) }, "write_swarm_memory"),
95
95
  ]);
96
96
  }
97
+ const fmtChange = (n) => `${n >= 0 ? "+" : ""}${n.toFixed(1)}%`;
98
+ const arrow = (n) => n >= 0 ? "▲" : "▼";
99
+ const p = (n) => `$${n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}`;
100
+ const marketLines = snapshot ? [
101
+ ``,
102
+ `📡 **Market Snapshot**`,
103
+ `| Asset | Price | 24h |`,
104
+ `|-------|-------|-----|`,
105
+ `| BTC | ${p(snapshot.btc)} | ${arrow(snapshot.btcChange)} ${fmtChange(snapshot.btcChange)} |`,
106
+ `| ETH | ${p(snapshot.eth)} | ${arrow(snapshot.ethChange)} ${fmtChange(snapshot.ethChange)} |`,
107
+ `| SOL | ${p(snapshot.sol)} | ${arrow(snapshot.solChange)} ${fmtChange(snapshot.solChange)} |`,
108
+ ] : [];
97
109
  return {
98
110
  content: [{
99
111
  type: "text",
100
112
  text: [
101
- `🤖 **Swarm Started**`,
102
- `Session ID: ${data.sessionId}`,
103
- `Started at: ${data.startedAt}`,
104
- snapshot ? `Market: BTC $${snapshot.btc.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | ETH $${snapshot.eth.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })} | SOL $${snapshot.sol.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 })}` : "",
113
+ `🤖 **Swarm is live.**`,
114
+ `Session: \`${data.sessionId}\``,
115
+ `Started: ${new Date(data.startedAt).toUTCString()}`,
116
+ ...marketLines,
105
117
  ``,
106
- `Use \`get_swarm_status\` to monitor, \`stop_swarm\` to stop.`,
107
- ].filter(Boolean).join("\n"),
118
+ `5 agents active — market monitor, sentiment tracker, workflow executor, signal scanner, vault writer.`,
119
+ ].join("\n"),
108
120
  }],
109
121
  };
110
122
  }
@@ -122,23 +134,41 @@ async function handleSwarmTool(name, args) {
122
134
  const memory = data.memory ?? [];
123
135
  const scores = data.scores ?? [];
124
136
  const lines = [
125
- `🤖 **Swarm Status**`,
126
- data.active && session ? `Status: active | Session: ${session.id}` : `No active swarm.`,
137
+ `🤖 **Swarm Status** — ${data.active ? "🟢 Active" : "⚫ Offline"}`,
138
+ data.active && session ? `Session: \`${session.id}\`` : `No active swarm.`,
127
139
  ``,
128
140
  ];
129
141
  if (memory.length > 0) {
130
- lines.push(`**Shared Memory** (${memory.length} entries)`);
131
- for (const m of memory.slice(0, 5))
132
- lines.push(`• [${m.agentId}] ${m.key}: ${m.value.slice(0, 80)}`);
133
- if (memory.length > 5)
134
- lines.push(` …and ${memory.length - 5} more`);
135
- lines.push("");
142
+ // Separate market data from other memory
143
+ const marketKeys = ["BTC/USD", "ETH/USD", "SOL/USD"];
144
+ const marketEntries = memory.filter((m) => marketKeys.includes(m.key));
145
+ const otherEntries = memory.filter((m) => !marketKeys.includes(m.key) && !["btc_price", "eth_price", "sol_price"].includes(m.key));
146
+ if (marketEntries.length > 0) {
147
+ lines.push(`📡 **Live Market Feed**`);
148
+ for (const m of marketEntries) {
149
+ const val = m.value.split(" (")[0]; // strip timestamp
150
+ lines.push(` ${m.key.padEnd(7)} ${val}`);
151
+ }
152
+ lines.push("");
153
+ }
154
+ if (otherEntries.length > 0) {
155
+ lines.push(`🧠 **Agent Memory** (${otherEntries.length} entries)`);
156
+ for (const m of otherEntries.slice(0, 6)) {
157
+ lines.push(` [${m.agentId}] **${m.key}**: ${String(m.value).slice(0, 80)}`);
158
+ }
159
+ if (otherEntries.length > 6)
160
+ lines.push(` …and ${otherEntries.length - 6} more`);
161
+ lines.push("");
162
+ }
136
163
  }
137
164
  if (scores.length > 0) {
138
- lines.push(`**Execution Scores** (top skills)`);
165
+ lines.push(`⚡ **Skill Performance**`);
139
166
  const sorted = scores.sort((a, b) => b.lastScore - a.lastScore).slice(0, 5);
140
- for (const s of sorted)
141
- lines.push(`• ${s.skillName}: ${(s.lastScore * 100).toFixed(0)}% | ${s.successCount}W/${s.failCount}L | avg ${Math.round(s.avgDurationMs / 1000)}s`);
167
+ for (const s of sorted) {
168
+ const pct = (s.lastScore * 100).toFixed(0);
169
+ const bar = "█".repeat(Math.round(s.lastScore * 10)) + "░".repeat(10 - Math.round(s.lastScore * 10));
170
+ lines.push(` ${bar} ${pct}% ${s.skillName} (${s.successCount}W / ${s.failCount}L)`);
171
+ }
142
172
  }
143
173
  return { content: [{ type: "text", text: lines.join("\n") }] };
144
174
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noelclaw/mcp",
3
- "version": "1.5.2",
3
+ "version": "1.5.4",
4
4
  "description": "Noelclaw as an MCP skill — persistent memory, multi-agent coordination, scenario simulation, DeFi execution, and Sentinel-gated playbooks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {