@noelclaw/mcp 3.0.0 → 3.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.
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runAgent = runAgent;
4
+ const server_js_1 = require("./server.js");
5
+ const llm_js_1 = require("./llm.js");
6
+ const SYSTEM_PROMPT = "You are Noelclaw, a persistent AI with 74 tools covering memory, automations, DeFi execution, research, and code. " +
7
+ "Be concise and direct. Use tools when needed. Summarize tool results in plain English.";
8
+ async function runAgent(userMessage, history, onToolCall) {
9
+ const anthropicKey = process.env.ANTHROPIC_API_KEY;
10
+ const bankrKey = process.env.BANKR_API_KEY;
11
+ if (anthropicKey)
12
+ return runAnthropicLoop(anthropicKey, userMessage, history, onToolCall);
13
+ if (bankrKey)
14
+ return runBankrLoop(bankrKey, userMessage, history, onToolCall);
15
+ // Fallback — no direct tool execution, just LLM chat via Convex
16
+ const text = await (0, llm_js_1.callLLM)(SYSTEM_PROMPT, userMessage, 1024, history);
17
+ return { text, toolCalls: [] };
18
+ }
19
+ // ── Anthropic agent loop ─────────────────────────────────────────────────────
20
+ function toAnthropicTool(tool) {
21
+ return {
22
+ name: tool.name,
23
+ description: tool.description ?? "",
24
+ input_schema: tool.inputSchema ?? { type: "object", properties: {} },
25
+ };
26
+ }
27
+ async function runAnthropicLoop(apiKey, userMessage, history, onToolCall) {
28
+ const model = process.env.ANTHROPIC_MODEL ?? "claude-haiku-4-5-20251001";
29
+ const tools = server_js_1.ALL_TOOLS.map(toAnthropicTool);
30
+ const toolCalls = [];
31
+ const messages = [
32
+ ...history.map(h => ({ role: h.role, content: h.content })),
33
+ { role: "user", content: userMessage },
34
+ ];
35
+ for (let turn = 0; turn < 10; turn++) {
36
+ const res = await fetch("https://api.anthropic.com/v1/messages", {
37
+ method: "POST",
38
+ headers: {
39
+ "Content-Type": "application/json",
40
+ "x-api-key": apiKey,
41
+ "anthropic-version": "2023-06-01",
42
+ },
43
+ body: JSON.stringify({ model, max_tokens: 2048, system: SYSTEM_PROMPT, tools, messages }),
44
+ signal: AbortSignal.timeout(90000),
45
+ });
46
+ if (!res.ok) {
47
+ const body = await res.text().catch(() => "");
48
+ throw new Error(`Anthropic ${res.status}: ${body.slice(0, 300)}`);
49
+ }
50
+ const data = await res.json();
51
+ messages.push({ role: "assistant", content: data.content });
52
+ if (data.stop_reason !== "tool_use") {
53
+ const text = data.content
54
+ .filter(b => b.type === "text")
55
+ .map(b => b.text)
56
+ .join("");
57
+ return { text, toolCalls };
58
+ }
59
+ // Execute all tool_use blocks
60
+ const toolResults = [];
61
+ for (const block of data.content) {
62
+ if (block.type !== "tool_use")
63
+ continue;
64
+ onToolCall(block.name);
65
+ toolCalls.push({ name: block.name });
66
+ let resultText;
67
+ try {
68
+ const handler = server_js_1.HANDLER_MAP.get(block.name);
69
+ if (!handler)
70
+ throw new Error(`Unknown tool: ${block.name}`);
71
+ const result = await handler(block.name, block.input ?? {});
72
+ resultText = result?.content?.[0]?.text ?? "Done.";
73
+ }
74
+ catch (err) {
75
+ resultText = `Error: ${err.message}`;
76
+ }
77
+ toolResults.push({ type: "tool_result", tool_use_id: block.id, content: resultText });
78
+ }
79
+ messages.push({ role: "user", content: toolResults });
80
+ }
81
+ return { text: "Reached max tool iterations.", toolCalls };
82
+ }
83
+ // ── Bankr (OpenAI-compatible) agent loop ─────────────────────────────────────
84
+ function toBankrTool(tool) {
85
+ return {
86
+ type: "function",
87
+ function: {
88
+ name: tool.name,
89
+ description: tool.description ?? "",
90
+ parameters: tool.inputSchema ?? { type: "object", properties: {} },
91
+ },
92
+ };
93
+ }
94
+ async function runBankrLoop(apiKey, userMessage, history, onToolCall) {
95
+ const model = process.env.BANKR_MODEL ?? "grok-3";
96
+ const tools = server_js_1.ALL_TOOLS.map(toBankrTool);
97
+ const toolCalls = [];
98
+ const messages = [
99
+ { role: "system", content: SYSTEM_PROMPT },
100
+ ...history.map(h => ({ role: h.role, content: h.content })),
101
+ { role: "user", content: userMessage },
102
+ ];
103
+ for (let turn = 0; turn < 10; turn++) {
104
+ const res = await fetch("https://llm.bankr.bot/v1/chat/completions", {
105
+ method: "POST",
106
+ headers: { "Content-Type": "application/json", "X-API-Key": apiKey },
107
+ body: JSON.stringify({ model, messages, tools, max_tokens: 2048 }),
108
+ signal: AbortSignal.timeout(90000),
109
+ });
110
+ if (!res.ok) {
111
+ const body = await res.text().catch(() => "");
112
+ throw new Error(`Bankr ${res.status}: ${body.slice(0, 300)}`);
113
+ }
114
+ const data = await res.json();
115
+ const choice = data.choices?.[0]?.message;
116
+ if (!choice)
117
+ throw new Error("Empty response from Bankr");
118
+ messages.push(choice);
119
+ if (!choice.tool_calls?.length) {
120
+ return { text: choice.content ?? "", toolCalls };
121
+ }
122
+ for (const call of choice.tool_calls) {
123
+ onToolCall(call.function.name);
124
+ toolCalls.push({ name: call.function.name });
125
+ let resultText;
126
+ try {
127
+ const args = JSON.parse(call.function.arguments ?? "{}");
128
+ const handler = server_js_1.HANDLER_MAP.get(call.function.name);
129
+ if (!handler)
130
+ throw new Error(`Unknown tool: ${call.function.name}`);
131
+ const result = await handler(call.function.name, args);
132
+ resultText = result?.content?.[0]?.text ?? "Done.";
133
+ }
134
+ catch (err) {
135
+ resultText = `Error: ${err.message}`;
136
+ }
137
+ messages.push({ role: "tool", tool_call_id: call.id, content: resultText });
138
+ }
139
+ }
140
+ return { text: "Reached max tool iterations.", toolCalls };
141
+ }
package/dist/cli.js ADDED
@@ -0,0 +1,170 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const readline = __importStar(require("readline"));
38
+ const agent_loop_js_1 = require("./agent-loop.js");
39
+ const server_js_1 = require("./server.js");
40
+ // ── ANSI ─────────────────────────────────────────────────────────────────────
41
+ const C = {
42
+ reset: "\x1b[0m",
43
+ bold: "\x1b[1m",
44
+ dim: "\x1b[2m",
45
+ green: "\x1b[32m",
46
+ cyan: "\x1b[36m",
47
+ violet: "\x1b[35m",
48
+ red: "\x1b[31m",
49
+ yellow: "\x1b[33m",
50
+ };
51
+ const BANNER = `
52
+ ${C.cyan}${C.bold} NOELCLAW${C.reset} ${C.dim}v3.0.0 · 74 tools · persistent AI${C.reset}
53
+ ${C.dim}─────────────────────────────────────────${C.reset}
54
+ ${C.dim}Type anything. /help for commands. Ctrl+C to exit.${C.reset}
55
+ `;
56
+ // ── Spinner ───────────────────────────────────────────────────────────────────
57
+ function spinner(label) {
58
+ const frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
59
+ let i = 0;
60
+ const iv = setInterval(() => {
61
+ process.stdout.write(`\r ${C.dim}${frames[i % frames.length]} ${label}${C.reset} `);
62
+ i++;
63
+ }, 80);
64
+ return () => {
65
+ clearInterval(iv);
66
+ process.stdout.write("\r" + " ".repeat(label.length + 12) + "\r");
67
+ };
68
+ }
69
+ // ── Help ─────────────────────────────────────────────────────────────────────
70
+ function printHelp() {
71
+ console.log(`
72
+ ${C.cyan}Commands:${C.reset}
73
+ /clear Clear conversation history
74
+ /tools List all 74 available tools
75
+ /quit Exit
76
+
77
+ ${C.dim}Examples:
78
+ remember my coding style for next time
79
+ what's ETH doing right now?
80
+ swap 0.5 ETH to USDC on Base
81
+ send me a weekly digest every Monday
82
+ research "best DeFi yields on Base"${C.reset}
83
+ `);
84
+ }
85
+ // ── Main ─────────────────────────────────────────────────────────────────────
86
+ async function main() {
87
+ process.stdout.write(BANNER);
88
+ // Detect active LLM
89
+ const mode = process.env.ANTHROPIC_API_KEY
90
+ ? `${C.green}Anthropic${C.reset} ${C.dim}(full tool use)${C.reset}`
91
+ : process.env.BANKR_API_KEY
92
+ ? `${C.green}Bankr${C.reset} ${C.dim}(full tool use)${C.reset}`
93
+ : `${C.yellow}Convex chat${C.reset} ${C.dim}(no tool execution — set ANTHROPIC_API_KEY for full mode)${C.reset}`;
94
+ console.log(` ${C.dim}Mode:${C.reset} ${mode}\n`);
95
+ const history = [];
96
+ const rl = readline.createInterface({
97
+ input: process.stdin,
98
+ output: process.stdout,
99
+ prompt: `${C.green}>${C.reset} `,
100
+ });
101
+ rl.prompt();
102
+ rl.on("line", async (raw) => {
103
+ const line = raw.trim();
104
+ if (!line) {
105
+ rl.prompt();
106
+ return;
107
+ }
108
+ // Built-in commands
109
+ if (line === "/quit" || line === "/exit") {
110
+ console.log(`\n ${C.dim}Goodbye.${C.reset}\n`);
111
+ process.exit(0);
112
+ }
113
+ if (line === "/clear") {
114
+ history.length = 0;
115
+ console.log(` ${C.dim}History cleared.${C.reset}\n`);
116
+ rl.prompt();
117
+ return;
118
+ }
119
+ if (line === "/help") {
120
+ printHelp();
121
+ rl.prompt();
122
+ return;
123
+ }
124
+ if (line === "/tools") {
125
+ console.log(`\n ${C.cyan}${server_js_1.ALL_TOOLS.length} tools:${C.reset}`);
126
+ for (const t of server_js_1.ALL_TOOLS) {
127
+ console.log(` ${C.dim}·${C.reset} ${t.name} ${C.dim}${(t.description ?? "").slice(0, 60)}${C.reset}`);
128
+ }
129
+ console.log();
130
+ rl.prompt();
131
+ return;
132
+ }
133
+ // Agent call
134
+ const stop = spinner("thinking");
135
+ let toolsUsed = 0;
136
+ try {
137
+ const result = await (0, agent_loop_js_1.runAgent)(line, history, (toolName) => {
138
+ stop();
139
+ toolsUsed++;
140
+ process.stdout.write(` ${C.dim}✦ ${toolName}${C.reset}\n`);
141
+ });
142
+ stop();
143
+ // Update conversation history (keep last 20 turns)
144
+ history.push({ role: "user", content: line });
145
+ history.push({ role: "assistant", content: result.text });
146
+ while (history.length > 20)
147
+ history.splice(0, 2);
148
+ // Output
149
+ console.log();
150
+ const lines = result.text.split("\n");
151
+ for (const l of lines) {
152
+ console.log(` ${l}`);
153
+ }
154
+ console.log();
155
+ }
156
+ catch (err) {
157
+ stop();
158
+ console.log(`\n ${C.red}✗${C.reset} ${err.message}\n`);
159
+ }
160
+ rl.prompt();
161
+ });
162
+ rl.on("close", () => {
163
+ console.log(`\n ${C.dim}Goodbye.${C.reset}\n`);
164
+ process.exit(0);
165
+ });
166
+ }
167
+ main().catch(err => {
168
+ console.error(`Fatal: ${err.message}`);
169
+ process.exit(1);
170
+ });
package/dist/server.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.server = exports.ALL_TOOLS = void 0;
3
+ exports.server = exports.HANDLER_MAP = exports.ALL_TOOLS = void 0;
4
4
  exports.startServer = startServer;
5
5
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
6
6
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
@@ -54,7 +54,7 @@ exports.ALL_TOOLS = [
54
54
  ...os_js_1.OS_TOOLS, // 3 — noel_status, noel_boot, noel_shutdown
55
55
  // total: 74
56
56
  ];
57
- const HANDLER_MAP = new Map([
57
+ exports.HANDLER_MAP = new Map([
58
58
  ...market_js_1.MARKET_TOOLS.map(t => [t.name, market_js_1.handleMarketTool]),
59
59
  ...defi_js_1.DEFI_TOOLS.map(t => [t.name, defi_js_1.handleDefiTool]),
60
60
  ...automation_js_1.AUTOMATION_TOOLS.map(t => [t.name, automation_js_1.handleAutomationTool]),
@@ -72,13 +72,13 @@ const HANDLER_MAP = new Map([
72
72
  ...memory_js_1.MEMORY_TOOLS.map(t => [t.name, memory_js_1.handleMemoryTool]),
73
73
  ...os_js_1.OS_TOOLS.map(t => [t.name, os_js_1.handleOsTool]),
74
74
  ]);
75
- exports.server = new index_js_1.Server({ name: "noelclaw", version: "2.4.0" }, { capabilities: { tools: {} } });
75
+ exports.server = new index_js_1.Server({ name: "noelclaw", version: "3.0.0" }, { capabilities: { tools: {} } });
76
76
  exports.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({ tools: exports.ALL_TOOLS }));
77
77
  exports.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
78
78
  const { name, arguments: args } = request.params;
79
79
  if (containsSensitiveRequest(args))
80
80
  return PRIVATE_KEY_RESPONSE;
81
- const handler = HANDLER_MAP.get(name);
81
+ const handler = exports.HANDLER_MAP.get(name);
82
82
  if (!handler) {
83
83
  return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
84
84
  }
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@noelclaw/mcp",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Noelclaw AI Operating System — persistent memory, multi-agent swarm, DeFi execution, market intelligence, and Sentinel-gated playbooks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
7
- "noelclaw-mcp": "dist/index.js"
7
+ "noelclaw-mcp": "dist/index.js",
8
+ "noelclaw": "dist/cli.js"
8
9
  },
9
10
  "scripts": {
10
11
  "build": "tsc",