caddie-mcp 0.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/dist/guide.js ADDED
@@ -0,0 +1,351 @@
1
+ export const GUIDE_URI = "b3os://guide";
2
+ export const GUIDE_CONTENT = `# B3OS Platform Guide
3
+
4
+ B3OS is a workflow automation platform for blockchain operations. Users create
5
+ automated workflows triggered by blockchain events, schedules, webhooks, or
6
+ manual execution. Workflows combine 560+ actions across DeFi, social, data,
7
+ and on-chain operations.
8
+
9
+ ---
10
+
11
+ ## Workflow Definition Anatomy
12
+
13
+ A workflow definition is a JSON object with a single \`nodes\` map. Each key is a
14
+ node ID, and the value describes that node's type, configuration, and connections.
15
+
16
+ \`\`\`json
17
+ {
18
+ "nodes": {
19
+ "root": {
20
+ "type": "cronjob",
21
+ "payload": { "rrule": "DTSTART:20260101T090000Z\\nRRULE:FREQ=MINUTELY;INTERVAL=5" },
22
+ "children": ["fetch_price"]
23
+ },
24
+ "fetch_price": {
25
+ "type": "coingecko-get-token-price",
26
+ "payload": { "coinId": "ethereum" },
27
+ "children": ["check_drop"]
28
+ },
29
+ "check_drop": {
30
+ "type": "if",
31
+ "payload": {
32
+ "condition": { "$and": [{ "{{fetch_price.result.price}}": { "$lte": 2000 } }] }
33
+ },
34
+ "children": ["send_alert", "do_nothing"]
35
+ },
36
+ "send_alert": {
37
+ "type": "slack-send-message",
38
+ "branch": "then",
39
+ "payload": {
40
+ "conversation": "{{ask.slack_channel}}",
41
+ "text": "ETH dropped to \${{fetch_price.result.price}}"
42
+ },
43
+ "connector": { "type": "slack" },
44
+ "children": []
45
+ },
46
+ "do_nothing": {
47
+ "type": "log",
48
+ "branch": "else",
49
+ "payload": { "message": "Price OK: {{fetch_price.result.price}}" },
50
+ "children": []
51
+ }
52
+ }
53
+ }
54
+ \`\`\`
55
+
56
+ ### Key Structural Rules
57
+
58
+ - **\`root\` is always the trigger node.** The workflow engine starts execution from \`root\`.
59
+ - **\`children\`** is an ordered array of node IDs that execute after the parent completes.
60
+ - **\`branch\`** is required on children of \`if\` nodes (\`"then"\` or \`"else"\`) and \`wait\` nodes (\`"resumed"\` or \`"timed_out"\`).
61
+ - **\`payload\`** contains the node's configuration. Supports \`{{}}\` template expressions.
62
+ - **\`connector\`** references an OAuth credential: \`{ "type": "slack" }\` or \`{ "type": "slack", "id": "conn_abc" }\`. Only needed for actions that interact with external services.
63
+ - **\`loopBody\`** (on \`for-each\` nodes) is an array of node IDs that run per iteration — these go in \`loopBody\`, not \`children\`.
64
+ - **\`description\`** and **\`titleOverride\`** are optional display labels.
65
+
66
+ ---
67
+
68
+ ## Expression Syntax Reference
69
+
70
+ Template expressions use \`{{ }}\` syntax and are resolved at runtime.
71
+
72
+ | Pattern | Example | Resolves To |
73
+ |---------|---------|-------------|
74
+ | Node result | \`{{fetch_data.result.items}}\` | Output field from an upstream node |
75
+ | Nested path | \`{{fetch_data.result.data.price}}\` | Nested field access |
76
+ | Node payload | \`{{root.payload.chainId}}\` | Config value from another node |
77
+ | Trigger input | \`{{root.result.body.userId}}\` | Webhook body data |
78
+ | User input (ASK) | \`{{ask.wallet_address}}\` | Creates a UI widget for user input at setup time |
79
+ | Props | \`{{$props.chainId}}\` | Workflow properties, inlined at creation time |
80
+ | Block inputs | \`{{$inputs.coinId}}\` | Inputs passed into a reusable block |
81
+ | Loop item | \`{{$item.name}}\` | Current for-each iteration item |
82
+ | Loop index | \`{{$index}}\` | Current for-each iteration index (0-based) |
83
+ | Parent loop | \`{{$parent_item}}\` | Parent for-each item (nested loops) |
84
+ | Ancestor loop | \`{{$for.outer_loop.item}}\` | Named ancestor for-each (3+ nesting) |
85
+ | Workflow ID | \`{{$workflowId}}\` | Current workflow's ID |
86
+ | Fallback | \`{{node.result.count \\|\\| 0}}\` | Use 0 if the variable is nil |
87
+
88
+ **Important:** Expressions can only reference ancestor nodes — nodes that have already
89
+ executed before the current node in the DAG. You cannot reference sibling or descendant nodes.
90
+
91
+ ---
92
+
93
+ ## Node Types Quick Reference
94
+
95
+ ### Triggers (always the \`root\` node)
96
+
97
+ **Core triggers:**
98
+
99
+ | Type | Description | Key Payload Fields |
100
+ |------|-------------|-------------------|
101
+ | \`cronjob\` | Schedule-based | \`rrule\` (two-line DTSTART+RRULE string) |
102
+ | \`manual\` | User clicks "Run" or webhook POST | (none — also serves as webhook endpoint) |
103
+ | \`erc20-receive\` | ERC-20 token received | \`chainId\`, \`tokenAddress\`, \`walletAddress\` |
104
+ | \`erc20-send\` | ERC-20 token sent | \`chainId\`, \`tokenAddress\`, \`walletAddress\` |
105
+ | \`eth-receive\` | Native ETH received | \`chainId\`, \`walletAddress\`, \`minAmount\` (wei) |
106
+ | \`eth-send\` | Native ETH sent | \`chainId\`, \`walletAddress\` |
107
+ | \`evm-log\` | Smart contract event | \`chainId\`, \`contractAddress\`, \`eventName\`, \`abi\` |
108
+ | \`token-price-cexes\` | Real-time price monitor | \`asset\`, \`condition\`, \`threshold\` |
109
+ | \`solana-transaction\` | Solana tx event | \`address\`, \`network\` |
110
+
111
+ **Polymarket triggers:**
112
+
113
+ | Type | Description |
114
+ |------|-------------|
115
+ | \`polymarket-user-bet\` | A specific user places a bet |
116
+ | \`polymarket-market-trade\` | Any trade on a market (CLOB WebSocket) |
117
+ | \`polymarket-new-market\` | New market created |
118
+ | \`polymarket-market-close\` | Market resolves |
119
+
120
+ **Social/messaging triggers:**
121
+
122
+ | Type | Description |
123
+ |------|-------------|
124
+ | \`telegram-channel\` | New Telegram message |
125
+ | \`slack-mentions\` | Slack mention detection |
126
+ | \`slack-new-message-in-channels\` | New message in Slack channel |
127
+ | \`farcaster-new-cast\` | New Farcaster cast |
128
+ | \`x-new-tweet\` | New tweet (requires username or keywords filter) |
129
+ | \`gmail-new-email-received\` | Gmail inbox (OAuth) |
130
+ | \`email-new-email-received\` | Disposable inbox |
131
+
132
+ **Other triggers:**
133
+
134
+ | Type | Description |
135
+ |------|-------------|
136
+ | \`exchange-listing\` | New trading pair on CEX (Binance, Coinbase, etc.) |
137
+ | \`stripe-payment-receive\` | Stripe payment received |
138
+ | \`shopify-order-created\` | Shopify order created |
139
+ | \`coinbase-payment-received\` | Coinbase Commerce payment |
140
+
141
+ Use \`b3os_list_triggers\` to see all available trigger types and their payload schemas.
142
+
143
+ ### Logic Nodes (built-in, no connector needed)
144
+
145
+ | Type | Description | Key Fields |
146
+ |------|-------------|------------|
147
+ | \`if\` | Conditional branch | \`payload.condition\` (object with \`$and\`/\`$or\`). Children use \`branch: "then"/"else"\` |
148
+ | \`for-each\` | Loop over array | \`payload.array\` (expression). Loop nodes go in \`loopBody\`, not \`children\` |
149
+ | \`filter\` | Filter array | \`payload.array\`, \`payload.condition\` |
150
+ | \`pluck\` | Extract fields | \`payload.array\`, \`payload.fields\` |
151
+ | \`delay\` | Wait for duration | \`payload.delayMs\` (milliseconds) |
152
+ | \`log\` | Log a message | \`payload.message\` (supports templates) |
153
+ | \`code-transform\` | Run JavaScript | \`payload.code\` (must be \`function transform(input) {...}\`), \`payload.input\`, \`payload.outputType\` |
154
+ | \`regex\` | Regex extraction | \`payload.input\`, \`payload.pattern\` |
155
+ | \`wait\` | Pause until event | \`payload.triggerType\`, \`payload.triggerConfig\`, \`payload.timeoutMs\`. Children use \`branch: "resumed"/"timed_out"\` |
156
+ | \`send-webhook\` | HTTP POST | \`payload.url\`, \`payload.headers\`, \`payload.body\` |
157
+
158
+ ### Dynamic Actions (560+ from catalog)
159
+
160
+ Use \`b3os_search_actions\` to find actions by keyword, then \`b3os_get_action\` to get
161
+ the full payload and result schemas. Common examples:
162
+
163
+ - **Token ops:** \`send-erc20-token\`, \`send-native-token\`, \`approve-erc20\`
164
+ - **Swaps:** \`0x-swap\`, \`cow-swap-gasless\`, \`relay-swap\`, \`swapkit-swap\`
165
+ - **DeFi:** \`morpho-deposit\`, \`morpho-withdraw\`, \`v3-add-liquidity\`
166
+ - **Data:** \`coingecko-get-token-price\`, \`coinglass-get-funding-rate\`
167
+ - **Messaging:** \`slack-send-message\`, \`slack-send-block-kit-message\`, \`discord-send-message\`, \`telegram-send-message\`
168
+ - **Polymarket:** \`polymarket-place-bet\`, \`polymarket-redeem\`
169
+
170
+ ---
171
+
172
+ ## Connector Rules
173
+
174
+ Actions that interact with external services require a \`connector\` field:
175
+
176
+ \`\`\`json
177
+ "connector": { "type": "slack" }
178
+ \`\`\`
179
+
180
+ Or with a specific connector ID:
181
+
182
+ \`\`\`json
183
+ "connector": { "type": "slack", "id": "conn_abc123" }
184
+ \`\`\`
185
+
186
+ **Connector types:** \`slack\`, \`discord\`, \`telegram\`, \`gmail\`, \`google_sheets\`, \`wallet\` (HSM wallet), \`db\` (database).
187
+
188
+ **Logic nodes NEVER need connectors:** \`if\`, \`for-each\`, \`filter\`, \`pluck\`, \`delay\`, \`log\`, \`code-transform\`, \`regex\`, \`wait\`, \`send-webhook\`.
189
+
190
+ Connectors must be pre-configured in the B3OS UI before workflows can use them.
191
+ If the connector ID is unknown at build time, use \`{{ask.connector_id}}\` or leave
192
+ only the \`type\` field — the user will select the connector in the B3OS UI.
193
+
194
+ ---
195
+
196
+ ## If Condition Format
197
+
198
+ The \`if\` node uses a JSON condition object. The top-level key MUST be \`$and\` or \`$or\`:
199
+
200
+ \`\`\`json
201
+ {
202
+ "condition": {
203
+ "$and": [
204
+ { "{{fetch_price.result.price}}": { "$lte": 2000 } },
205
+ { "{{fetch_price.result.volume}}": { "$gte": 1000000 } }
206
+ ]
207
+ }
208
+ }
209
+ \`\`\`
210
+
211
+ **Operators:** \`$eq\`, \`$ne\`, \`$gt\`, \`$gte\`, \`$lt\`, \`$lte\`, \`$contains\`, \`$notContains\`,
212
+ \`$startsWith\`, \`$endsWith\`, \`$exists\`, \`$notExists\`, \`$in\`, \`$notIn\`.
213
+
214
+ ---
215
+
216
+ ## Common Workflow Patterns
217
+
218
+ **Pattern A — Monitor + Alert:** \`cronjob → fetch data → if condition → send notification\`
219
+ Most common pattern. Schedule a check, fetch external data, conditionally alert.
220
+
221
+ **Pattern B — Webhook + Transform:** \`webhook → code-transform → send-webhook / action\`
222
+ Receive external data, transform it, take action. Used for API integrations.
223
+
224
+ **Pattern C — Trigger + Loop + Action:** \`trigger → fetch list → for-each → action per item\`
225
+ Batch processing. Trigger fetches a list, loops over items, processes each.
226
+
227
+ **Pattern D — Approval Flow:** \`trigger → slack-send-block-kit-message → wait → if approve/reject → action\`
228
+ Human-in-the-loop. Post approval buttons, wait for click, branch on decision.
229
+
230
+ ---
231
+
232
+ ## Numeric Conventions
233
+
234
+ **On-chain amounts are strings in raw units (wei/atomic):**
235
+ - 1 ETH = \`"1000000000000000000"\` (18 decimals)
236
+ - 1 USDC = \`"1000000"\` (6 decimals)
237
+ - 1 WBTC = \`"100000000"\` (8 decimals)
238
+
239
+ NEVER pass human-readable decimals to send/swap/approve actions. Always convert
240
+ to the token's raw unit string. Look up token decimals — never hardcode them.
241
+
242
+ **Prices and display values are numbers:** \`2000.50\`, \`0.65\`, \`1500000\`
243
+ These are used in conditions and display, not on-chain transactions.
244
+
245
+ ---
246
+
247
+ ## ASK Widget Patterns
248
+
249
+ \`{{ask.fieldName}}\` creates a user-input widget in the B3OS UI. Use it for values
250
+ the user should provide at setup time:
251
+
252
+ \`\`\`json
253
+ "walletAddress": "{{ask.wallet_address}}",
254
+ "conversation": "{{ask.slack_channel}}",
255
+ "threshold": "{{ask.price_threshold}}"
256
+ \`\`\`
257
+
258
+ **Rich widget types** are available for common fields. Use the matching field name
259
+ pattern and the B3OS UI will render the appropriate widget:
260
+ - \`wallet_address\` → Wallet selector
261
+ - \`token_address\` / \`token_addresses\` → Token contract picker (with chain)
262
+ - \`chain_id\` / \`chain_ids\` → Network selector
263
+ - \`connector_id\` → Connector account picker
264
+ - \`slack_channel\` → Slack channel picker
265
+ - \`telegram_chat\` → Telegram chat picker
266
+ - \`token_amount\` → Token amount with decimals
267
+ - \`recipient_address\` → Recipient wallet address
268
+ - \`contract_address\` → Smart contract address
269
+ - \`network\` / \`networks\` → Network selector (alternative)
270
+ - \`boolean\`, \`number\`, \`select\`, \`multiselect\`, \`textarea\`, \`date\`, \`color\` → Basic types
271
+
272
+ ---
273
+
274
+ ## How to Use B3OS Tools
275
+
276
+ ### Building a Workflow
277
+ Use \`b3os_build_workflow\` to delegate to Caddie, the B3OS AI agent. Caddie has
278
+ deep domain knowledge, address verification, and 30+ specialized tools.
279
+
280
+ 1. Gather prerequisites: \`b3os_list_connectors\`, \`b3os_list_wallets\` → present options
281
+ 2. Describe the workflow in natural language to \`b3os_build_workflow\`
282
+ 3. Review the returned definition with the user
283
+ 4. Save: \`b3os_create_workflow\` (new) or \`b3os_update_workflow\` (existing)
284
+ 5. Confirm with user → deploy: \`b3os_publish_workflow\`
285
+
286
+ To modify an existing workflow, pass its \`workflowId\` to \`b3os_build_workflow\`.
287
+
288
+ ### Debugging a Failure
289
+ Use \`b3os_debug_run\` to delegate diagnosis to Caddie:
290
+
291
+ 1. \`b3os_list_runs\` (status: "failure") → find failed runs
292
+ 2. \`b3os_debug_run\` (runId) → Caddie diagnoses + suggests fixes
293
+ 3. Apply fix: \`b3os_update_workflow\` → \`b3os_publish_workflow\`
294
+
295
+ For manual inspection: \`b3os_get_run\` with nodeIds to see per-node input, result, and error.
296
+
297
+ ### Data Queries (no workflow needed)
298
+ Use named lookup tools for common queries:
299
+ - Token info: \`b3os_token_lookup\` (network + address, or coinId)
300
+ - Prices: \`b3os_price_lookup\` (coinIds)
301
+ - Balances: \`b3os_balance_lookup\` (address, chainIds, limit)
302
+ - DeFi positions: \`b3os_defi_lookup\` (address, chainId)
303
+ - Tx debugging: \`b3os_debug_transaction\` (txHash, chainId)
304
+ - Polymarket: \`b3os_polymarket_lookup\` (query, slug, or marketUrl)
305
+ - Any other action: \`b3os_query_action\` (generic fallback — use \`b3os_search_actions\` to find action types first)
306
+
307
+ ### One-Shot Execution (no save)
308
+ - \`b3os_run_action\` for single-action execution
309
+ - \`b3os_run_ephemeral\` for multi-step definitions (max 20 nodes, 60s timeout)
310
+
311
+ ---
312
+
313
+ ## Key Gotchas
314
+
315
+ **Workflow lifecycle:**
316
+ - **Workflows start in "draft" status** — must call \`b3os_publish_workflow\` to make them live
317
+ - **Connectors must be set up in B3OS UI first** — Slack, Discord, Google Sheets, etc.
318
+ - **On-chain actions require a funded org wallet** with sufficient balance and gas
319
+
320
+ **Scheduling:**
321
+ - **Cronjob rrule must be two-line format:** \`"DTSTART:YYYYMMDDTHHmmSSZ\\nRRULE:FREQ=..."\`. A bare RRULE without DTSTART will break scheduling. Encode desired time in DTSTART, NOT in BYHOUR/BYMINUTE.
322
+ - **DTSTART must use current UTC timestamp** — a future DTSTART means the cron won't fire until then.
323
+
324
+ **Conditions and expressions:**
325
+ - **If condition format:** top-level key MUST be \`$and\` or \`$or\` — a bare comparison won't work.
326
+ - **Regex matches** are a map with string keys: use \`{{node.result.matches.1}}\` (dot notation), never \`{{node.result.matches[1]}}\`.
327
+ - **code-transform output** is at \`{{nodeId.result.output}}\`, not \`{{nodeId.result}}\`. The function must be named \`transform(input)\`.
328
+
329
+ **Integrations:**
330
+ - **Slack Block Kit \`blocks\` must be a JSON string**, not an object. Stringify the JSON array before setting the field.
331
+ - **Slack action results** are nested under \`data.ret\`: use \`{{node.result.data.ret.ts}}\`, NOT \`{{node.result.data.ts}}\`.
332
+ - **Google Sheets worksheetId** must be an integer, never a sheet name string.
333
+ - **Gmail vs email triggers:** \`gmail-new-email-*\` polls a real Gmail inbox via OAuth. \`email-new-email-*\` creates a disposable inbox. If the user wants to watch their inbox, use \`gmail-*\`.
334
+ - **x-new-tweet requires at least one filter** — empty payload is invalid. Must include username or keywords.
335
+
336
+ **On-chain:**
337
+ - **approve-erc20 is for smart contracts only** (DEX routers, DeFi protocols). For sending tokens to a wallet, use \`send-erc20-token\` directly — no approval step needed.
338
+ - **Use \`amountFormatted\` in notifications**, \`amount\` for raw precision in on-chain calls.
339
+
340
+ **Wait nodes:**
341
+ - **Wait node timeout:** default 5 min is too short for human approval. Set \`timeoutMs\` to at least 86400000 (24h). Always include a \`timed_out\` branch child.
342
+ - **Wait node uses \`waitPayloadSchema\`**, NOT the trigger's \`payloadSchema\`. For slack-new-interaction-event, valid fields are actionId, messageTs, userIds.
343
+
344
+ **Database:**
345
+ - **db-query results are always wrapped in a \`rows\` array** — access as \`{{node.result.rows.0.field}}\`, NEVER \`{{node.result.field}}\`.
346
+ - **Use COALESCE for first-run safety:** \`SELECT COALESCE((SELECT spent FROM budgets WHERE id = ?), 0)\` — prevents row[0] IndexOutOfBounds.
347
+
348
+ **Polymarket:**
349
+ - **polymarket-redeem: add an if guard** checking \`{{redeem.result.redeemedAmount}}\` > 0 before downstream actions — redeemedAmount is ZERO for losing outcomes.
350
+ - **Minimum bet amounts:** $1 for market orders (FAK/FOK), $5 for limit orders (GTC).
351
+ `;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createServer } from "./server.js";
4
+ const server = createServer();
5
+ const transport = new StdioServerTransport();
6
+ await server.connect(transport);
@@ -0,0 +1,2 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function createServer(): McpServer;
package/dist/server.js ADDED
@@ -0,0 +1,107 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerOrgTools } from "./tools/org.js";
3
+ import { registerConnectorTools } from "./tools/connectors.js";
4
+ import { registerCatalogTools } from "./tools/catalog.js";
5
+ import { registerWorkflowTools } from "./tools/workflows.js";
6
+ import { registerRunTools } from "./tools/runs.js";
7
+ import { registerBlockchainTools } from "./tools/blockchain.js";
8
+ import { registerDatabaseTools } from "./tools/database.js";
9
+ import { registerLookupTools } from "./tools/lookups.js";
10
+ import { registerCaddieTools } from "./tools/caddie.js";
11
+ import { GUIDE_URI, GUIDE_CONTENT } from "./guide.js";
12
+ const INSTRUCTIONS = `You have access to B3OS, a workflow automation platform for blockchain operations.
13
+
14
+ CRITICAL RULES:
15
+
16
+ 1. GATHER ALL PREREQUISITES FIRST — Before building any workflow, collect every user
17
+ input needed (connector choice, wallet, chat IDs, addresses, thresholds, etc.).
18
+ Ask all questions in ONE message, not one at a time. Use these tools to discover
19
+ options: b3os_list_connectors, b3os_list_wallets, b3os_list_telegram_chats,
20
+ b3os_list_slack_channels. Present the available options to the user and let them choose.
21
+
22
+ CONNECTOR SETUP: If b3os_list_connectors returns no connectors of the type needed
23
+ (e.g., no "slack" connector for a Slack workflow), tell the user to set one up at
24
+ https://b3os.org/connectors BEFORE proceeding. Do NOT build a workflow with
25
+ placeholder connector IDs — it will fail at runtime.
26
+
27
+ 2. CONFIRM BEFORE SENSITIVE OPERATIONS — Always ask for explicit user confirmation
28
+ before: b3os_publish_workflow, b3os_delete_workflow, b3os_run_workflow,
29
+ b3os_run_ephemeral, b3os_cancel_run, or b3os_query_database with
30
+ INSERT/UPDATE/DELETE/CREATE/ALTER/DROP.
31
+ Show a summary of what will happen and wait for approval.
32
+
33
+ HOW TO BUILD WORKFLOWS:
34
+
35
+ Use b3os_build_workflow to construct workflows. It delegates to Caddie, the B3OS AI
36
+ agent which has deep domain knowledge, address verification, and repair capabilities.
37
+
38
+ 1. Gather prerequisites: b3os_list_connectors, b3os_list_wallets → present options
39
+ 2. Describe the workflow in natural language to b3os_build_workflow
40
+ 3. Review the returned definition with the user
41
+ 4. Save: b3os_create_workflow (new) or b3os_update_workflow (existing)
42
+ 5. Confirm with user → then deploy: b3os_publish_workflow
43
+
44
+ To modify an existing workflow, pass its workflowId to b3os_build_workflow.
45
+
46
+ DEBUGGING FAILED RUNS:
47
+
48
+ Use b3os_debug_run to diagnose failures. Caddie will analyze the execution state,
49
+ identify the root cause, and suggest definition fixes.
50
+
51
+ 1. b3os_list_runs (status: "failure") → find failed runs
52
+ 2. b3os_debug_run (runId) → Caddie diagnoses + suggests fixes
53
+ 3. Apply fix: b3os_update_workflow → b3os_publish_workflow
54
+
55
+ DATA QUERIES (use named lookup tools for common queries):
56
+
57
+ - Token info: b3os_token_lookup (network + address, or coinId)
58
+ - Prices: b3os_price_lookup (coinIds)
59
+ - Wallet balances: b3os_balance_lookup (address, chainIds, limit)
60
+ - DeFi positions: b3os_defi_lookup (address, chainId)
61
+ - Tx debugging: b3os_debug_transaction (txHash, chainId)
62
+ - Polymarket: b3os_polymarket_lookup (query, slug, or marketUrl)
63
+ - Any other read-only query: b3os_query_action (use b3os_search_actions to find action types first)
64
+
65
+ ONE-SHOT EXECUTION (no save):
66
+ - b3os_run_action for single-action lookups (simpler than ephemeral)
67
+ - b3os_run_ephemeral for multi-step definitions (max 20 nodes, 60s timeout)
68
+
69
+ DATABASE (org's SQLite-compatible database):
70
+ - ALWAYS call b3os_list_tables FIRST to check what already exists before creating tables
71
+ - b3os_get_table_schema → inspect column definitions of existing tables
72
+ - b3os_query_database → execute SQL (SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, DROP TABLE)
73
+ - Use parameterized queries: sql="SELECT * FROM t WHERE id = ?", params=["val"]
74
+ - Reuse existing tables when possible — check schema and data before creating new ones
75
+
76
+ BLOCK EXPLORER RULE: NEVER fetch from basescan.org, etherscan.io, or other block
77
+ explorers. Use b3os_debug_transaction or b3os_query_action instead.
78
+
79
+ RESOURCES: Read b3os://guide for workflow definition anatomy, expression syntax, node
80
+ types, and common patterns.`;
81
+ export function createServer() {
82
+ // The MCP spec defines server `instructions` (§ 5.2.1) but the SDK types
83
+ // don't expose it yet. Cast to satisfy the compiler.
84
+ // https://spec.modelcontextprotocol.io/specification/2025-03-26/server/utilities/instructions/
85
+ const server = new McpServer({ name: "b3os", version: "1.0.0" }, { instructions: INSTRUCTIONS });
86
+ // Register all tools
87
+ registerOrgTools(server);
88
+ registerConnectorTools(server);
89
+ registerCatalogTools(server);
90
+ registerWorkflowTools(server);
91
+ registerRunTools(server);
92
+ registerBlockchainTools(server);
93
+ registerDatabaseTools(server);
94
+ registerLookupTools(server);
95
+ registerCaddieTools(server);
96
+ // Register the platform guide resource
97
+ server.resource("guide", GUIDE_URI, { mimeType: "text/markdown" }, async () => ({
98
+ contents: [
99
+ {
100
+ uri: GUIDE_URI,
101
+ mimeType: "text/markdown",
102
+ text: GUIDE_CONTENT,
103
+ },
104
+ ],
105
+ }));
106
+ return server;
107
+ }
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Merge new tool entries into permissions.allow idempotently.
4
+ * Does not touch disk. Mutates the input config in place and returns it.
5
+ */
6
+ export declare function mergeAllowedTools(config: Record<string, unknown>, tools: readonly string[]): {
7
+ config: Record<string, unknown>;
8
+ added: number;
9
+ };