@noelclaw/mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 noelclaw
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,246 @@
1
+ # @noelclaw/mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@noelclaw/mcp.svg)](https://www.npmjs.com/package/@noelclaw/mcp)
4
+
5
+ Noelclaw as an MCP skill — persistent memory, multi-agent coordination, scenario simulation, DeFi execution, and Sentinel-gated playbooks. Works with Claude, Cursor, Hermes, Windsurf, and any MCP-compatible client.
6
+
7
+ ```bash
8
+ npx @noelclaw/mcp@latest
9
+ ```
10
+
11
+ ---
12
+
13
+ ## Quick Install
14
+
15
+ ### Claude Code
16
+ ```bash
17
+ claude mcp add noelclaw -- npx @noelclaw/mcp@latest
18
+ ```
19
+
20
+ Set your API key:
21
+ ```bash
22
+ claude mcp add noelclaw -e NOELCLAW_API_KEY=noel_... -- npx @noelclaw/mcp@latest
23
+ ```
24
+
25
+ ### Claude Desktop
26
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
27
+
28
+ ```json
29
+ {
30
+ "mcpServers": {
31
+ "noelclaw": {
32
+ "command": "npx",
33
+ "args": ["@noelclaw/mcp@latest"],
34
+ "env": {
35
+ "NOELCLAW_API_KEY": "noel_..."
36
+ }
37
+ }
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### Cursor / Windsurf
43
+ ```json
44
+ {
45
+ "mcpServers": {
46
+ "noelclaw": {
47
+ "command": "npx",
48
+ "args": ["@noelclaw/mcp@latest"],
49
+ "env": {
50
+ "NOELCLAW_API_KEY": "noel_..."
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ ### Hermes
58
+ ```yaml
59
+ mcp_servers:
60
+ noelclaw:
61
+ command: npx
62
+ args:
63
+ - "@noelclaw/mcp@latest"
64
+ env:
65
+ NOELCLAW_API_KEY: "noel_..."
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Authentication
71
+
72
+ Get a key instantly — no signup:
73
+
74
+ ```bash
75
+ curl -X POST https://api.noelclaw.com/auth/key
76
+ # → { "apiKey": "noel_..." }
77
+ ```
78
+
79
+ Set `NOELCLAW_API_KEY` in your MCP config. That's it.
80
+
81
+ ---
82
+
83
+ ## Tools
84
+
85
+ ### Research & AI
86
+
87
+ | Tool | Description |
88
+ |------|-------------|
89
+ | `research` | Deep research via Bankr (real-time). Returns overview, key findings, market impact, sentiment |
90
+ | `ask_noel` | Ask Noel AI for analysis, trade ideas, and research |
91
+ | `humanize_text` | Remove AI tells from text — makes output sound natural and human-written |
92
+
93
+ ### Noel-Vault
94
+
95
+ > Persistent memory across sessions. Save findings, recall by key, search full-text. Every save auto-versions.
96
+
97
+ | Tool | Description |
98
+ |------|-------------|
99
+ | `vault_save` | Save any content — research, execution logs, workflows, prompts, files |
100
+ | `vault_read` | Read an entry by key |
101
+ | `vault_list` | List all entries with type, title, version, last updated |
102
+ | `vault_search` | Full-text search across all content |
103
+ | `vault_history` | Version history with commit messages |
104
+ | `vault_diff` | Line-by-line diff between two versions |
105
+ | `vault_export` | Export as markdown or JSON |
106
+
107
+ ### Noel-Swarm
108
+
109
+ > Shared memory bus for multi-agent coordination. All agents read/write the same store with freshness tracking.
110
+
111
+ | Tool | Description |
112
+ |------|-------------|
113
+ | `start_swarm` | Start a swarm session |
114
+ | `stop_swarm` | Stop the active session |
115
+ | `get_swarm_status` | Session state, memory snapshot, execution scores |
116
+ | `write_swarm_memory` | Write a key-value entry with optional TTL |
117
+ | `get_swarm_memory` | Read by key — returns value + freshness metadata |
118
+ | `get_execution_scores` | Per-agent, per-skill scores |
119
+
120
+ ### MiroShark
121
+
122
+ > Scenario simulation engine — drop in any scenario and get back strategic insights from a network of AI agents reacting hour by hour. Requires `MIROSHARK_URL` + `MIROSHARK_ADMIN_TOKEN`.
123
+
124
+ | Tool | Description |
125
+ |------|-------------|
126
+ | `miroshark_simulate` | Run a multi-agent simulation from a plain-English scenario. Returns a simulation ID |
127
+ | `miroshark_status` | Poll simulation results by ID — surfaces insights and consensus when complete |
128
+
129
+ ### Wallet & DeFi `beta`
130
+
131
+ > On-chain operations on Base mainnet. Transactions are built for client-side signing — no private key ever leaves your machine.
132
+
133
+ | Tool | Description |
134
+ |------|-------------|
135
+ | `get_wallet_address` | Show your local MCP wallet address |
136
+ | `get_portfolio` | Full token portfolio with ETH and ERC-20 balances and USD values |
137
+ | `swap_tokens` | Swap tokens on Base mainnet |
138
+ | `send_token` | Send ETH or any ERC-20 to any address |
139
+
140
+ ### Automations `beta`
141
+
142
+ | Tool | Description |
143
+ |------|-------------|
144
+ | `create_automation` | Create an automation in plain English — DCA, price alerts, conditional buys/sells |
145
+ | `list_automations` | List all automations with status and next scheduled run |
146
+ | `pause_automation` | Pause or resume an automation |
147
+ | `delete_automation` | Permanently delete an automation |
148
+
149
+ ### Noel Framework `beta`
150
+
151
+ > Sentinel-gated agent execution. Define what your AI can and can't do — before it runs. Every action checked against 5 mechanical rules before execution.
152
+
153
+ | Tool | Description |
154
+ |------|-------------|
155
+ | `create_task_packet` | Convert plain-English intent into a structured task scope with permissions and constraints |
156
+ | `list_task_packets` | List all task packets |
157
+ | `list_playbooks` | List available playbooks |
158
+ | `run_playbook` | Execute a Sentinel-gated playbook — halts if any step is blocked |
159
+ | `get_noel_ledger` | Full audit trail of every Sentinel decision |
160
+ | `get_sentinel_rules` | Exact rules per agent role |
161
+
162
+ ### Notifications
163
+
164
+ | Tool | Description |
165
+ |------|-------------|
166
+ | `set_telegram` | Connect Telegram for push notifications |
167
+
168
+ ---
169
+
170
+ ## Environment Variables
171
+
172
+ ### Required
173
+
174
+ | Var | Description |
175
+ |-----|-------------|
176
+ | `NOELCLAW_API_KEY` | Your API key (`noel_...`) — get one at `POST https://api.noelclaw.com/auth/key` |
177
+
178
+ ### MiroShark (optional)
179
+
180
+ | Var | Description |
181
+ |-----|-------------|
182
+ | `MIROSHARK_URL` | URL of your deployed MiroShark instance |
183
+ | `MIROSHARK_ADMIN_TOKEN` | Admin token set on your MiroShark deployment |
184
+
185
+ ### BYOK (optional)
186
+
187
+ | Var | Used for |
188
+ |-----|---------|
189
+ | `BANKR_API_KEY` | Bankr Agent — research, DeFi |
190
+ | `TELEGRAM_BOT_TOKEN` | Your own Telegram bot |
191
+ | `TELEGRAM_CHAT_ID` | Your Telegram chat ID |
192
+ | `ALCHEMY_API_KEY` | Faster Base RPC for swaps and portfolio |
193
+
194
+ ---
195
+
196
+ ## Usage Examples
197
+
198
+ ```
199
+ # Research anything
200
+ research(query: "What is happening with the Base ecosystem this week?")
201
+ ask_noel(question: "What are the risks of holding ETH through a Fed meeting?")
202
+
203
+ # Save findings to vault
204
+ vault_save(type: "research", key: "research/base-may-2026", title: "Base Ecosystem", content: "...")
205
+ vault_search(query: "Base ecosystem")
206
+
207
+ # Coordinate agents via swarm
208
+ start_swarm
209
+ write_swarm_memory(agentId: "analyst", key: "research/btc", value: "bullish", ttlSeconds: 3600)
210
+ get_swarm_memory(key: "research/btc")
211
+
212
+ # Run a MiroShark simulation
213
+ miroshark_simulate(scenario: "What happens if a major L1 announces a 50% fee reduction?")
214
+ miroshark_status(simulation_id: "sim_abc123")
215
+
216
+ # Clean up AI-generated text
217
+ humanize_text(text: "Certainly! I'd be happy to assist you with...")
218
+
219
+ # DeFi (beta)
220
+ get_portfolio
221
+ swap_tokens(fromToken: "ETH", toToken: "USDC", amount: "0.01")
222
+
223
+ # Sentinel-gated execution (beta)
224
+ create_task_packet(task: "Monitor portfolio, max $0 spend, read only")
225
+ run_playbook(playbook_name: "Daily Market Scan")
226
+ get_noel_ledger
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Troubleshooting
232
+
233
+ | Error | Fix |
234
+ |-------|-----|
235
+ | Tools not appearing | Restart your MCP client after adding the config |
236
+ | `401 Unauthorized` | Check `NOELCLAW_API_KEY` is set — get one at `POST https://api.noelclaw.com/auth/key` |
237
+ | `miroshark_simulate` error | Set `MIROSHARK_URL` and `MIROSHARK_ADMIN_TOKEN` |
238
+ | Server starts but no response | Expected — server waits for MCP stdin, not HTTP |
239
+
240
+ ---
241
+
242
+ ## Links
243
+
244
+ - npm: [npmjs.com/package/@noelclaw/mcp](https://npmjs.com/package/@noelclaw/mcp)
245
+ - GitHub: [github.com/noelclaw/research](https://github.com/noelclaw/mcp)
246
+ - Platform: [noelclaw.com](https://noelclaw.com)
package/dist/convex.js ADDED
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PaymentRequiredError = void 0;
4
+ exports.buildPaymentHeader = buildPaymentHeader;
5
+ exports.callConvex = callConvex;
6
+ exports.notifyTelegram = notifyTelegram;
7
+ const wallet_js_1 = require("./wallet.js");
8
+ const CONVEX_SITE = process.env.NOELCLAW_CONVEX_URL ?? "https://api.noelclaw.com";
9
+ const RETRY_STATUSES = new Set([429, 500, 502, 503, 504]);
10
+ const RETRY_DELAYS = [500, 1000, 2000];
11
+ class PaymentRequiredError extends Error {
12
+ constructor(details) {
13
+ super("Payment required");
14
+ this.name = "PaymentRequiredError";
15
+ this.details = details;
16
+ }
17
+ }
18
+ exports.PaymentRequiredError = PaymentRequiredError;
19
+ function buildPaymentHeader(txHash, requestId) {
20
+ return Buffer.from(`${txHash}:${requestId}`).toString("base64");
21
+ }
22
+ async function attemptConvex(url, method, headers, body) {
23
+ return fetch(url, {
24
+ method,
25
+ headers,
26
+ body: body ? JSON.stringify(body) : undefined,
27
+ signal: AbortSignal.timeout(30000),
28
+ });
29
+ }
30
+ async function callConvex(path, method, body, toolName = "unknown") {
31
+ const url = `${CONVEX_SITE}${path}`;
32
+ const headers = { "Content-Type": "application/json" };
33
+ const apiKey = process.env.NOELCLAW_API_KEY;
34
+ const sessionToken = process.env.NOELCLAW_SESSION_TOKEN;
35
+ const authHeader = apiKey
36
+ ? `Bearer ${apiKey}`
37
+ : sessionToken
38
+ ? `Bearer ${sessionToken}`
39
+ : null;
40
+ if (authHeader) {
41
+ headers["Authorization"] = authHeader;
42
+ }
43
+ else {
44
+ try {
45
+ const { address, signature, timestamp } = await (0, wallet_js_1.signRequest)(toolName);
46
+ headers["X-Wallet-Address"] = address;
47
+ headers["X-Wallet-Signature"] = signature;
48
+ headers["X-Wallet-Timestamp"] = timestamp;
49
+ }
50
+ catch {
51
+ // continue without wallet headers — server will respond with 401/402
52
+ }
53
+ }
54
+ const paymentHeader = process.env.NOELCLAW_PAYMENT_HEADER;
55
+ if (paymentHeader)
56
+ headers["X-Payment"] = paymentHeader;
57
+ // BYOK headers
58
+ if (process.env.GROK_API_KEY)
59
+ headers["X-User-Grok-Key"] = process.env.GROK_API_KEY;
60
+ if (process.env.BANKR_API_KEY)
61
+ headers["X-User-Bankr-Key"] = process.env.BANKR_API_KEY;
62
+ if (process.env.TELEGRAM_BOT_TOKEN)
63
+ headers["X-User-Telegram-Token"] = process.env.TELEGRAM_BOT_TOKEN;
64
+ if (process.env.TELEGRAM_CHAT_ID)
65
+ headers["X-User-Telegram-Chat"] = process.env.TELEGRAM_CHAT_ID;
66
+ let lastError = null;
67
+ for (let attempt = 0; attempt < RETRY_DELAYS.length; attempt++) {
68
+ if (attempt > 0) {
69
+ await new Promise((r) => setTimeout(r, RETRY_DELAYS[attempt - 1]));
70
+ }
71
+ let res;
72
+ try {
73
+ res = await attemptConvex(url, method, headers, body);
74
+ }
75
+ catch (err) {
76
+ lastError = err;
77
+ continue;
78
+ }
79
+ if (res.status === 402) {
80
+ const b = await res.json().catch(() => ({}));
81
+ throw new PaymentRequiredError(b);
82
+ }
83
+ if (res.status === 401) {
84
+ const b = await res.json().catch(() => ({}));
85
+ throw new Error(`🔑 ${b.message || "Authentication required"}\n\n` +
86
+ `→ Get your API key: ${b.url || "https://noelclaw.com"}\n\n` +
87
+ `Hint: ${b.hint || "Set NOELCLAW_API_KEY=noel_sk_xxx in your MCP config"}\n\n` +
88
+ `${b.alternative ? `Alternative: ${b.alternative}` : ""}`);
89
+ }
90
+ if (RETRY_STATUSES.has(res.status) && attempt < RETRY_DELAYS.length) {
91
+ lastError = new Error(`Noelclaw API error: ${res.status}`);
92
+ continue;
93
+ }
94
+ if (!res.ok)
95
+ throw new Error(`Noelclaw API error: ${res.status} ${await res.text()}`);
96
+ return res.json();
97
+ }
98
+ throw lastError ?? new Error("Request failed after retries");
99
+ }
100
+ async function notifyTelegram(userId, message) {
101
+ try {
102
+ return await callConvex("/user/telegram/notify", "POST", { userId, message }, "set_telegram");
103
+ }
104
+ catch (error) {
105
+ return { sent: false, reason: error.message ?? String(error) };
106
+ }
107
+ }
package/dist/index.js ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const server_js_1 = require("./server.js");
5
+ const wallet_js_1 = require("./wallet.js");
6
+ const BANNER = `
7
+ \x1b[36m
8
+ ███╗ ██╗ ██████╗ ███████╗██╗ ██████╗██╗ █████╗ ██╗ ██╗
9
+ ████╗ ██║██╔═══██╗██╔════╝██║ ██╔════╝██║ ██╔══██╗██║ ██║
10
+ ██╔██╗ ██║██║ ██║█████╗ ██║ ██║ ██║ ███████║██║ █╗ ██║
11
+ ██║╚██╗██║██║ ██║██╔══╝ ██║ ██║ ██║ ██╔══██║██║███╗██║
12
+ ██║ ╚████║╚██████╔╝███████╗███████╗╚██████╗███████╗██║ ██║╚███╔███╔╝
13
+ ╚═╝ ╚═══╝ ╚═════╝ ╚══════╝╚══════╝ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝
14
+ \x1b[0m \x1b[90mcrypto AI · MCP · DeFi · research · swarm\x1b[0m
15
+ `;
16
+ async function main() {
17
+ console.error(BANNER);
18
+ await (0, server_js_1.startServer)();
19
+ try {
20
+ const wallet = await (0, wallet_js_1.getOrCreateWallet)();
21
+ console.error(`\x1b[36m ◆ wallet\x1b[0m ${wallet.address}`);
22
+ console.error(`\x1b[36m ◆ status\x1b[0m ready · 46 tools loaded\n`);
23
+ }
24
+ catch (err) {
25
+ console.error(`[noelclaw] wallet init failed: ${err}`);
26
+ }
27
+ }
28
+ main().catch((err) => {
29
+ console.error(err);
30
+ process.exit(1);
31
+ });
package/dist/server.js ADDED
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.server = exports.ALL_TOOLS = void 0;
4
+ exports.startServer = startServer;
5
+ const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
6
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
7
+ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
8
+ const convex_js_1 = require("./convex.js");
9
+ const market_js_1 = require("./tools/market.js");
10
+ const research_js_1 = require("./tools/research.js");
11
+ const defi_js_1 = require("./tools/defi.js");
12
+ const automation_js_1 = require("./tools/automation.js");
13
+ const swarm_js_1 = require("./tools/swarm.js");
14
+ const insight_js_1 = require("./tools/insight.js");
15
+ const framework_js_1 = require("./tools/framework.js");
16
+ const wallet_js_1 = require("./tools/wallet.js");
17
+ const news_js_1 = require("./tools/news.js");
18
+ const vault_js_1 = require("./tools/vault.js");
19
+ const twitter_js_1 = require("./tools/twitter.js");
20
+ const miroshark_js_1 = require("./tools/miroshark.js");
21
+ const humanizer_js_1 = require("./tools/humanizer.js");
22
+ const PRIVATE_KEY_RESPONSE = {
23
+ content: [{
24
+ type: "text",
25
+ text: "I don't have access to your private key. Your wallet is secured by Noelclaw's encrypted vault. Only you can manage it at noelclaw.xyz",
26
+ }],
27
+ };
28
+ function containsSensitiveRequest(args) {
29
+ const text = JSON.stringify(args ?? "").toLowerCase();
30
+ return (text.includes("private key") ||
31
+ text.includes("seed phrase") ||
32
+ text.includes("mnemonic") ||
33
+ text.includes("privatekey"));
34
+ }
35
+ exports.ALL_TOOLS = [
36
+ ...market_js_1.MARKET_TOOLS, // 6 — market data, signals, whale alerts, recap
37
+ ...news_js_1.NEWS_TOOLS, // 2 — crypto news digest, manual signal gen
38
+ ...research_js_1.RESEARCH_TOOLS, // 1 — deep research
39
+ ...insight_js_1.INSIGHT_TOOLS, // 2 — get_insight, ask_noel
40
+ ...defi_js_1.DEFI_TOOLS, // 6 — portfolio, swap, send, deploy, claim, mint
41
+ ...automation_js_1.AUTOMATION_TOOLS, // 4 — create, list, pause, delete
42
+ ...swarm_js_1.SWARM_TOOLS, // 6 — start, stop, status, memory, scores
43
+ ...framework_js_1.FRAMEWORK_TOOLS, // 6 — task packets, playbooks, sentinel, ledger
44
+ ...vault_js_1.VAULT_TOOLS, // 7 — save, read, list, search, history, diff, export
45
+ ...wallet_js_1.WALLET_TOOLS, // 2 — wallet address, telegram connect
46
+ ...twitter_js_1.TWITTER_TOOLS, // 1 — post tweet
47
+ ...miroshark_js_1.MIROSHARK_TOOLS, // 2 — simulate, status
48
+ ...humanizer_js_1.HUMANIZER_TOOLS, // 1 — humanize_text
49
+ // total: 46
50
+ ];
51
+ exports.server = new index_js_1.Server({ name: "noelclaw", version: "2.1.0" }, { capabilities: { tools: {} } });
52
+ exports.server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => ({ tools: exports.ALL_TOOLS }));
53
+ exports.server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
54
+ const { name, arguments: args } = request.params;
55
+ if (containsSensitiveRequest(args))
56
+ return PRIVATE_KEY_RESPONSE;
57
+ try {
58
+ const result = await (0, market_js_1.handleMarketTool)(name, args) ??
59
+ await (0, news_js_1.handleNewsTool)(name, args) ??
60
+ await (0, research_js_1.handleResearchTool)(name, args) ??
61
+ await (0, defi_js_1.handleDefiTool)(name, args) ??
62
+ await (0, automation_js_1.handleAutomationTool)(name, args) ??
63
+ await (0, swarm_js_1.handleSwarmTool)(name, args) ??
64
+ await (0, framework_js_1.handleFrameworkTool)(name, args) ??
65
+ await (0, vault_js_1.handleVaultTool)(name, args) ??
66
+ await (0, wallet_js_1.handleWalletTool)(name, args) ??
67
+ await (0, insight_js_1.handleInsightTool)(name, args) ??
68
+ await (0, twitter_js_1.handleTwitterTool)(name, args) ??
69
+ await (0, miroshark_js_1.handleMirosharkTool)(name, args) ??
70
+ await (0, humanizer_js_1.handleHumanizerTool)(name, args);
71
+ if (result)
72
+ return result;
73
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
74
+ }
75
+ catch (err) {
76
+ if (err instanceof convex_js_1.PaymentRequiredError) {
77
+ const d = err.details?.paymentDetails;
78
+ const lines = [
79
+ "⚠️ **Payment Required**", "",
80
+ "This tool requires a USDC micropayment on Base mainnet.",
81
+ ...(d ? [
82
+ ``, `Amount: **${d.amount} USDC**`, `To: \`${d.address}\``, `Request ID: \`${d.requestId}\``, ``,
83
+ "**To pay:**",
84
+ `1. Send ${d.amount} USDC to \`${d.address}\` on Base mainnet`,
85
+ `2. Copy the transaction hash`,
86
+ `3. Set env var: \`NOELCLAW_PAYMENT_HEADER=${(0, convex_js_1.buildPaymentHeader)("<txHash>", d.requestId)}\``,
87
+ ` (replace \`<txHash>\` with the actual transaction hash)`,
88
+ `4. Retry the tool call`, ``,
89
+ "**Or bypass with a session token:**",
90
+ "Set `NOELCLAW_SESSION_TOKEN` with your Noelclaw session token from noelclaw.xyz",
91
+ ] : []),
92
+ ];
93
+ return { content: [{ type: "text", text: lines.join("\n") }], isError: true };
94
+ }
95
+ return { content: [{ type: "text", text: `Error: ${err.message}` }], isError: true };
96
+ }
97
+ });
98
+ async function startServer() {
99
+ const transport = new stdio_js_1.StdioServerTransport();
100
+ await exports.server.connect(transport);
101
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AUTOMATION_TOOLS = void 0;
4
+ exports.handleAutomationTool = handleAutomationTool;
5
+ const zod_1 = require("zod");
6
+ const convex_js_1 = require("../convex.js");
7
+ exports.AUTOMATION_TOOLS = [
8
+ {
9
+ name: "create_automation",
10
+ description: "Create an automation in plain English. Supports DCA, price alerts, conditional buys/sells, and recurring market updates.",
11
+ inputSchema: {
12
+ type: "object",
13
+ properties: { rawInput: { type: "string", description: "Plain English description of the automation" } },
14
+ required: ["rawInput"],
15
+ },
16
+ },
17
+ {
18
+ name: "list_automations",
19
+ description: "List all your automations — active, paused, and completed — with status, run counts, and next scheduled run.",
20
+ inputSchema: { type: "object", properties: {}, required: [] },
21
+ },
22
+ {
23
+ name: "pause_automation",
24
+ description: "Pause or resume an automation by ID.",
25
+ inputSchema: {
26
+ type: "object",
27
+ properties: { automationId: { type: "string", description: "Automation ID (from list_automations)" } },
28
+ required: ["automationId"],
29
+ },
30
+ },
31
+ {
32
+ name: "delete_automation",
33
+ description: "Permanently delete an automation. Cannot be undone.",
34
+ inputSchema: {
35
+ type: "object",
36
+ properties: { automationId: { type: "string", description: "Automation ID (from list_automations)" } },
37
+ required: ["automationId"],
38
+ },
39
+ },
40
+ ];
41
+ const CreateAutomationSchema = zod_1.z.object({ rawInput: zod_1.z.string().min(1) });
42
+ const AutomationIdSchema = zod_1.z.object({ automationId: zod_1.z.string().min(1) });
43
+ async function handleAutomationTool(name, args) {
44
+ switch (name) {
45
+ case "create_automation": {
46
+ const parsed = CreateAutomationSchema.safeParse(args);
47
+ if (!parsed.success)
48
+ return { content: [{ type: "text", text: `Invalid input: rawInput ${parsed.error.issues[0].message}` }], isError: true };
49
+ const data = await (0, convex_js_1.callConvex)("/automations/create", "POST", { rawInput: parsed.data.rawInput }, "create_automation");
50
+ if (!data.success)
51
+ return { content: [{ type: "text", text: `Failed: ${data.error}` }], isError: true };
52
+ const triggerLabel = {
53
+ schedule: "⏰ Schedule", price_drop_pct: "📉 Price Drop %", price_rise_pct: "📈 Price Rise %",
54
+ price_below: "⬇️ Price Below", price_above: "⬆️ Price Above",
55
+ dominance_below: "📊 Dominance Below", dominance_above: "📊 Dominance Above",
56
+ };
57
+ const actionLabel = { swap: "💱 Swap", send: "📤 Send", alert: "🔔 Alert" };
58
+ return {
59
+ content: [{
60
+ type: "text",
61
+ text: [
62
+ `✅ **Automation Created**`, ``,
63
+ `**Name:** ${data.name}`, `**ID:** \`${data.automationId}\``,
64
+ `**Trigger:** ${triggerLabel[data.triggerType] ?? data.triggerType}`,
65
+ `**Action:** ${actionLabel[data.actionType] ?? data.actionType}`,
66
+ data.priceBaselineUsd ? `**Baseline price:** $${Number(data.priceBaselineUsd).toLocaleString()}` : ``,
67
+ ``, `Use \`list_automations\` to see all your automations.`,
68
+ ].filter(Boolean).join("\n"),
69
+ }],
70
+ };
71
+ }
72
+ case "list_automations": {
73
+ const data = await (0, convex_js_1.callConvex)("/automations/list", "GET", undefined, "list_automations");
74
+ if (data.error)
75
+ return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
76
+ const automations = data.automations ?? [];
77
+ if (!automations.length)
78
+ return { content: [{ type: "text", text: "No automations yet. Use `create_automation` to create one." }] };
79
+ const statusIcon = { active: "🟢", paused: "⏸️", completed: "✅", error: "❌" };
80
+ const lines = [`**Your Automations** (${automations.length})`, ""];
81
+ for (const auto of automations) {
82
+ lines.push(`${statusIcon[auto.status] ?? "•"} **${auto.name}** — \`${auto._id}\``);
83
+ lines.push(` Trigger: ${auto.triggerType} | Action: ${auto.actionType} | Runs: ${auto.totalRuns}`);
84
+ if (auto.totalSpentUsd > 0)
85
+ lines.push(` Total spent: $${Number(auto.totalSpentUsd).toFixed(2)}`);
86
+ if (auto.nextRunAt && auto.status === "active")
87
+ lines.push(` Next run: ${new Date(auto.nextRunAt).toUTCString()}`);
88
+ if (auto.lastError)
89
+ lines.push(` ⚠️ Last error: ${auto.lastError}`);
90
+ lines.push("");
91
+ }
92
+ return { content: [{ type: "text", text: lines.join("\n") }] };
93
+ }
94
+ case "pause_automation": {
95
+ const parsed = AutomationIdSchema.safeParse(args);
96
+ if (!parsed.success)
97
+ return { content: [{ type: "text", text: `Invalid input: automationId ${parsed.error.issues[0].message}` }], isError: true };
98
+ const data = await (0, convex_js_1.callConvex)("/automations/pause", "POST", { automationId: parsed.data.automationId }, "pause_automation");
99
+ if (data.error)
100
+ return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
101
+ const icon = data.status === "active" ? "▶️ Resumed" : "⏸️ Paused";
102
+ return { content: [{ type: "text", text: `${icon} successfully.` }] };
103
+ }
104
+ case "delete_automation": {
105
+ const parsed = AutomationIdSchema.safeParse(args);
106
+ if (!parsed.success)
107
+ return { content: [{ type: "text", text: `Invalid input: automationId ${parsed.error.issues[0].message}` }], isError: true };
108
+ const data = await (0, convex_js_1.callConvex)("/automations/delete", "POST", { automationId: parsed.data.automationId }, "delete_automation");
109
+ if (data.error)
110
+ return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
111
+ return { content: [{ type: "text", text: "🗑️ Automation deleted." }] };
112
+ }
113
+ default:
114
+ return null;
115
+ }
116
+ }