@aibtc/mcp-server 1.76.1 → 1.77.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 CHANGED
@@ -524,6 +524,21 @@ For autonomous agents, use `pillar_direct_*` tools (no browser needed).
524
524
  | `scaffold_x402_endpoint` | Generate x402 Cloudflare Worker project |
525
525
  | `scaffold_x402_ai_endpoint` | Generate x402 AI API with OpenRouter |
526
526
 
527
+ ### TaskMarket (Work Marketplace on Base)
528
+ Read-only discovery of onchain agent work on [TaskMarket](https://taskmarket.dev) (USDC escrow on Base). The tools are public and anonymous: no wallet, no spend.
529
+
530
+ | Tool | Description |
531
+ |------|-------------|
532
+ | `taskmarket_search` | List/search open tasks (filters: status, phase, mode, tags, reward range) |
533
+ | `taskmarket_get` | Full task detail + live status by task ID |
534
+ | `taskmarket_submissions` | List a task's submissions |
535
+ | `taskmarket_stats` | Public market/agent statistics (reputation check) |
536
+
537
+ ### Inbox Messaging (aibtc.com)
538
+ | Tool | Description |
539
+ |------|-------------|
540
+ | `send_inbox_message_direct` | Send a paid x402 message to another agent's inbox (sBTC cost; STX gas is sponsored when the inbox offers it) |
541
+
527
542
  ## Usage Examples
528
543
 
529
544
  **Wallet management:**
@@ -594,6 +609,17 @@ Or use any SIP-010 token by contract ID: `SP2X...::token-name`
594
609
 
595
610
  **Note:** `CLIENT_MNEMONIC` is optional. The recommended approach is to let Claude create its own wallet. `HIRO_API_KEY` is optional but recommended for production use — without it, you may hit Hiro's public rate limits (429 responses). Get a key at [platform.hiro.so](https://platform.hiro.so).
596
611
 
612
+ **Note on Hiro rate limits:** without a key, Hiro allowed **20 requests per second and 50 per minute** per client when measured on 2026-10-23 (response headers below). The **per-minute** budget is the one an agent usually exhausts first. A single tool call can make several Hiro requests, so 50 a minute goes quickly in a busy session. Every Hiro response reports both budgets, so you can check the current values yourself:
613
+
614
+ ```
615
+ x-ratelimit-limit-stacks-second: 20
616
+ x-ratelimit-remaining-stacks-second: 19
617
+ x-ratelimit-limit-stacks-minute: 50
618
+ x-ratelimit-remaining-stacks-minute: 49
619
+ ```
620
+
621
+ On a 429 the server waits for `Retry-After` (60s if Hiro sends none, and at least 1s, 2s, then 4s) and retries up to three times before surfacing a rate-limit error (`src/services/hiro-api.ts`). Retrying before that time just returns another 429. Hiro can change these limits, so treat the numbers as a snapshot and the headers as the source of truth.
622
+
597
623
  ## Architecture
598
624
 
599
625
  ```
@@ -188,10 +188,12 @@ export declare const BITFLOW_PUBLIC_API = "https://bitflow-sdk-api-gateway-7owjs
188
188
  */
189
189
  export declare const BITFLOW_READONLY_HOST = "https://api.hiro.so";
190
190
  /**
191
- * Keeper API host for automated swap orders.
192
- * Per Bitflow SDK docs.
191
+ * Keeper API host for automated swap orders. The SDK's documented default
192
+ * (bitflow-keeper-test-7owjsmt8.uc.gateway.dev) 404s on every keeper path;
193
+ * the production keeper is keeper.bitflowapis.finance.
194
+ * Override with BITFLOW_KEEPER_API_HOST.
193
195
  */
194
- export declare const BITFLOW_KEEPER_HOST = "https://bitflow-keeper-test-7owjsmt8.uc.gateway.dev";
196
+ export declare const BITFLOW_KEEPER_HOST: string;
195
197
  /**
196
198
  * AIBTC provider address tagged onto every Bitflow swap. The SDK injects this
197
199
  * as the `provider` Clarity arg when the swap function signature accepts one,
@@ -211,10 +211,12 @@ export const BITFLOW_PUBLIC_API = "https://bitflow-sdk-api-gateway-7owjsmt8.uc.g
211
211
  */
212
212
  export const BITFLOW_READONLY_HOST = "https://api.hiro.so";
213
213
  /**
214
- * Keeper API host for automated swap orders.
215
- * Per Bitflow SDK docs.
214
+ * Keeper API host for automated swap orders. The SDK's documented default
215
+ * (bitflow-keeper-test-7owjsmt8.uc.gateway.dev) 404s on every keeper path;
216
+ * the production keeper is keeper.bitflowapis.finance.
217
+ * Override with BITFLOW_KEEPER_API_HOST.
216
218
  */
217
- export const BITFLOW_KEEPER_HOST = "https://bitflow-keeper-test-7owjsmt8.uc.gateway.dev";
219
+ export const BITFLOW_KEEPER_HOST = process.env.BITFLOW_KEEPER_API_HOST || "https://keeper.bitflowapis.finance";
218
220
  /**
219
221
  * AIBTC provider address tagged onto every Bitflow swap. The SDK injects this
220
222
  * as the `provider` Clarity arg when the swap function signature accepts one,
@@ -0,0 +1,92 @@
1
+ /**
2
+ * TaskMarket service — read-only discovery.
3
+ *
4
+ * TaskMarket (https://taskmarket.dev) is an onchain agent work marketplace on
5
+ * Base: requesters escrow USDC, workers submit deliverables, and the requester
6
+ * accepts a winner. This service reads the public, anonymous API (search, get,
7
+ * list-submissions, market-stats). It never signs or spends.
8
+ */
9
+ export interface TaskmarketTask {
10
+ id: string;
11
+ requester: string;
12
+ description: string;
13
+ reward: string;
14
+ netReward?: string;
15
+ escrowTxHash?: string;
16
+ createdAt: string;
17
+ expiryTime: string;
18
+ status: string;
19
+ phase?: string;
20
+ tags: string[];
21
+ mode?: string;
22
+ taskVisibility?: string;
23
+ submissionVisibility?: string;
24
+ submissionCount?: number;
25
+ platformFeeBps?: number;
26
+ requesterAgentId?: string;
27
+ }
28
+ export interface TaskmarketSubmission {
29
+ id: string;
30
+ taskId: string;
31
+ workerAddress: string;
32
+ workerAgentId?: string;
33
+ submittedAt: string;
34
+ rejectedAt?: string | null;
35
+ deliverableHash?: string;
36
+ submitTxHash?: string;
37
+ artifacts?: Array<{
38
+ id: string;
39
+ fileName: string;
40
+ mimeType: string;
41
+ sizeBytes?: number;
42
+ storageUri?: string;
43
+ }>;
44
+ }
45
+ /** Convert base-unit reward (e.g. "2000000") to human USDC (e.g. "2"). */
46
+ export declare function baseUnitsToUsdc(raw: string | undefined | null): string;
47
+ /** Convert human USDC (e.g. "2") to base units (e.g. "2000000"). */
48
+ export declare function usdcToBaseUnits(amount: string): string;
49
+ /**
50
+ * List/search tasks. Public, anonymous, read-only.
51
+ */
52
+ export declare function listTasks(options: {
53
+ status?: string;
54
+ phase?: string;
55
+ mode?: string;
56
+ tags?: string;
57
+ rewardMin?: string;
58
+ rewardMax?: string;
59
+ limit?: number;
60
+ signal?: AbortSignal;
61
+ }): Promise<{
62
+ tasks: TaskmarketTask[];
63
+ hasMore: boolean;
64
+ nextCursor: string | null;
65
+ }>;
66
+ /**
67
+ * Get a single task with its live status. Public, anonymous, read-only.
68
+ */
69
+ export declare function getTask(taskId: string, signal?: AbortSignal): Promise<TaskmarketTask>;
70
+ /**
71
+ * List submissions for a task so the requester can review them for real work.
72
+ * Public, anonymous, read-only. Never auto-accepts or auto-rejects anything.
73
+ */
74
+ export declare function listSubmissions(taskId: string, signal?: AbortSignal): Promise<TaskmarketSubmission[]>;
75
+ export interface TaskmarketStats {
76
+ address?: string;
77
+ agentId?: string;
78
+ completedTasks?: number;
79
+ ratedTasks?: number;
80
+ totalStars?: number;
81
+ averageRating?: number;
82
+ [key: string]: unknown;
83
+ }
84
+ /**
85
+ * Market/agent statistics. Anonymous read of a public stats endpoint.
86
+ */
87
+ export declare function getMarketStats(options: {
88
+ address?: string;
89
+ agentId?: string;
90
+ signal?: AbortSignal;
91
+ }): Promise<TaskmarketStats>;
92
+ //# sourceMappingURL=taskmarket.service.d.ts.map
@@ -0,0 +1,100 @@
1
+ /**
2
+ * TaskMarket service — read-only discovery.
3
+ *
4
+ * TaskMarket (https://taskmarket.dev) is an onchain agent work marketplace on
5
+ * Base: requesters escrow USDC, workers submit deliverables, and the requester
6
+ * accepts a winner. This service reads the public, anonymous API (search, get,
7
+ * list-submissions, market-stats). It never signs or spends.
8
+ */
9
+ const TASKMARKET_API_URL = process.env.TASKMARKET_API_URL || "https://api.taskmarket.dev";
10
+ /** Bound every read so a hung TaskMarket API cannot hold a tool call open. */
11
+ const READ_TIMEOUT_MS = 15_000;
12
+ /** Convert base-unit reward (e.g. "2000000") to human USDC (e.g. "2"). */
13
+ export function baseUnitsToUsdc(raw) {
14
+ if (!raw || !/^\d+$/.test(raw))
15
+ return "0";
16
+ const padded = raw.padStart(7, "0");
17
+ const whole = padded.slice(0, padded.length - 6) || "0";
18
+ const frac = padded.slice(padded.length - 6).replace(/0+$/, "");
19
+ return frac ? `${whole}.${frac}` : whole;
20
+ }
21
+ /** Convert human USDC (e.g. "2") to base units (e.g. "2000000"). */
22
+ export function usdcToBaseUnits(amount) {
23
+ if (!/^\d+(\.\d+)?$/.test(amount)) {
24
+ throw new Error(`Invalid USDC amount: "${amount}"`);
25
+ }
26
+ const [whole, frac = ""] = amount.split(".");
27
+ if (frac.length > 6) {
28
+ throw new Error(`USDC amount has more than 6 decimals: "${amount}"`);
29
+ }
30
+ const wholeInt = BigInt(whole || "0");
31
+ const fracPadded = frac.padEnd(6, "0");
32
+ const fracInt = fracPadded ? BigInt(fracPadded) : 0n;
33
+ return (wholeInt * 1000000n + fracInt).toString();
34
+ }
35
+ async function apiGet(path, signal) {
36
+ const response = await fetch(`${TASKMARKET_API_URL}${path}`, {
37
+ signal: signal ?? AbortSignal.timeout(READ_TIMEOUT_MS),
38
+ headers: { accept: "application/json" },
39
+ });
40
+ if (!response.ok) {
41
+ const text = await response.text().catch(() => "Unknown error");
42
+ throw new Error(`TaskMarket API error ${response.status}: ${text}`);
43
+ }
44
+ const json = (await response.json());
45
+ return (json.data ?? json);
46
+ }
47
+ /**
48
+ * List/search tasks. Public, anonymous, read-only.
49
+ */
50
+ export async function listTasks(options) {
51
+ const params = new URLSearchParams();
52
+ if (options.status)
53
+ params.set("status", options.status);
54
+ if (options.phase)
55
+ params.set("phase", options.phase);
56
+ if (options.mode)
57
+ params.set("mode", options.mode);
58
+ if (options.tags)
59
+ params.set("tags", options.tags);
60
+ if (options.rewardMin)
61
+ params.set("minReward", usdcToBaseUnits(options.rewardMin));
62
+ if (options.rewardMax)
63
+ params.set("maxReward", usdcToBaseUnits(options.rewardMax));
64
+ params.set("limit", String(options.limit ?? 20));
65
+ const result = await apiGet(`/api/tasks?${params.toString()}`, options.signal);
66
+ return {
67
+ tasks: result.tasks ?? [],
68
+ hasMore: result.hasMore ?? false,
69
+ nextCursor: result.nextCursor ?? null,
70
+ };
71
+ }
72
+ /**
73
+ * Get a single task with its live status. Public, anonymous, read-only.
74
+ */
75
+ export async function getTask(taskId, signal) {
76
+ return apiGet(`/api/tasks/${taskId}`, signal);
77
+ }
78
+ /**
79
+ * List submissions for a task so the requester can review them for real work.
80
+ * Public, anonymous, read-only. Never auto-accepts or auto-rejects anything.
81
+ */
82
+ export async function listSubmissions(taskId, signal) {
83
+ const result = await apiGet(`/api/tasks/${taskId}/submissions`, signal);
84
+ if (Array.isArray(result))
85
+ return result;
86
+ return (result.submissions ?? []);
87
+ }
88
+ /**
89
+ * Market/agent statistics. Anonymous read of a public stats endpoint.
90
+ */
91
+ export async function getMarketStats(options) {
92
+ const params = new URLSearchParams();
93
+ if (options.address)
94
+ params.set("address", options.address);
95
+ if (options.agentId)
96
+ params.set("agentId", options.agentId);
97
+ const query = params.toString();
98
+ return apiGet(`/api/agents/stats${query ? `?${query}` : ""}`, options.signal);
99
+ }
100
+ //# sourceMappingURL=taskmarket.service.js.map
@@ -169,6 +169,8 @@ export function registerInboxX402Tools(server) {
169
169
  privateKey: account.privateKey,
170
170
  network: NETWORK,
171
171
  };
172
+ // x402-stacks is CJS, so its AxiosInstance comes from axios' .d.cts
173
+ // types; ours comes from .d.ts. Same runtime object, different type.
172
174
  const api = wrapAxiosWithPayment(axios.create({ timeout: 120_000 }), stacksAccount);
173
175
  try {
174
176
  response = await api.post(inboxUrl, body, {
@@ -52,6 +52,7 @@ import { registerInboxTools } from "./inbox.tools.js";
52
52
  import { registerInboxX402Tools } from "./inbox-x402.tools.js";
53
53
  import { registerArxivResearchTools } from "./arxiv-research.tools.js";
54
54
  import { registerEarningTools } from "./earning.tools.js";
55
+ import { registerTaskmarketTools } from "./taskmarket.tools.js";
55
56
  import { getSkillForTool } from "./skill-mappings.js";
56
57
  import { isToolSelected } from "./profiles.js";
57
58
  /**
@@ -214,6 +215,8 @@ export function registerAllTools(server, selection) {
214
215
  inGroup("dev", registerArxivResearchTools);
215
216
  // Earning Opportunities (static "how to put your assets to work" menu)
216
217
  inGroup("earn", registerEarningTools);
218
+ // TaskMarket (onchain agent work marketplace on Base — read-only discovery + gated create)
219
+ inGroup("earn", registerTaskmarketTools);
217
220
  restoreRegisterTool();
218
221
  }
219
222
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,12 @@
1
+ /**
2
+ * TaskMarket Tools (https://taskmarket.dev) — onchain agent work marketplace on Base.
3
+ *
4
+ * Read tools (public, anonymous, no wallet, no spend):
5
+ * - taskmarket_search — list/search open tasks (filters: status, phase, mode, tags, reward)
6
+ * - taskmarket_get — full task detail + live status by task ID
7
+ * - taskmarket_submissions — list submissions for a task
8
+ * - taskmarket_stats — public market/agent statistics
9
+ */
10
+ import { McpServer } from "@modelcontextprotocol/server";
11
+ export declare function registerTaskmarketTools(server: McpServer): void;
12
+ //# sourceMappingURL=taskmarket.tools.d.ts.map
@@ -0,0 +1,166 @@
1
+ /**
2
+ * TaskMarket Tools (https://taskmarket.dev) — onchain agent work marketplace on Base.
3
+ *
4
+ * Read tools (public, anonymous, no wallet, no spend):
5
+ * - taskmarket_search — list/search open tasks (filters: status, phase, mode, tags, reward)
6
+ * - taskmarket_get — full task detail + live status by task ID
7
+ * - taskmarket_submissions — list submissions for a task
8
+ * - taskmarket_stats — public market/agent statistics
9
+ */
10
+ import { z } from "zod";
11
+ import { createJsonResponse, createErrorResponse } from "../utils/index.js";
12
+ import { baseUnitsToUsdc, getTask, getMarketStats, listSubmissions, listTasks, } from "../services/taskmarket.service.js";
13
+ const TASK_ID_SCHEMA = z
14
+ .string()
15
+ .regex(/^0x[0-9a-fA-F]{64}$/)
16
+ .describe("TaskMarket task ID (0x + 64 hex chars)");
17
+ export function registerTaskmarketTools(server) {
18
+ // ==========================================================================
19
+ // Read tools — no wallet required, never spends
20
+ // ==========================================================================
21
+ server.registerTool("taskmarket_search", {
22
+ description: "Search open tasks on the TaskMarket agent work marketplace (Base, USDC escrow). " +
23
+ "Public and anonymous — no wallet or payment needed. Returns tasks with ID, reward (USDC), " +
24
+ "status, submission count, deadline, and a short description so you can pick work to delegate. " +
25
+ "Never spends anything.",
26
+ inputSchema: z.object({
27
+ status: z.string().default("open").describe("Filter by status (default: open)"),
28
+ phase: z.string().optional().describe("Filter by lifecycle phase (active, in_review, awaiting_settlement, resolved)"),
29
+ mode: z.string().optional().describe("Filter by task mode (bounty, claim, pitch, benchmark, auction)"),
30
+ tags: z.string().optional().describe("Comma-separated tags to filter by (e.g. 'mcp,research')"),
31
+ rewardMin: z.string().optional().describe("Minimum reward in human USDC (e.g. 0.5)"),
32
+ rewardMax: z.string().optional().describe("Maximum reward in human USDC (e.g. 50)"),
33
+ limit: z.number().int().min(1).max(50).default(20).describe("Max results (1-50)"),
34
+ }),
35
+ }, async (args) => {
36
+ try {
37
+ const result = await listTasks({
38
+ status: args.status,
39
+ phase: args.phase,
40
+ mode: args.mode,
41
+ tags: args.tags,
42
+ rewardMin: args.rewardMin,
43
+ rewardMax: args.rewardMax,
44
+ limit: args.limit,
45
+ });
46
+ return createJsonResponse({
47
+ success: true,
48
+ network: "eip155:8453",
49
+ taskCount: result.tasks.length,
50
+ hasMore: result.hasMore,
51
+ nextCursor: result.nextCursor,
52
+ tasks: result.tasks.map((t) => ({
53
+ id: t.id,
54
+ status: t.status,
55
+ phase: t.phase ?? null,
56
+ mode: t.mode ?? "bounty",
57
+ rewardUsdc: baseUnitsToUsdc(t.reward),
58
+ submissionCount: t.submissionCount ?? 0,
59
+ deadline: t.expiryTime,
60
+ tags: t.tags ?? [],
61
+ description: t.description.slice(0, 300),
62
+ })),
63
+ });
64
+ }
65
+ catch (error) {
66
+ return createErrorResponse(error);
67
+ }
68
+ });
69
+ server.registerTool("taskmarket_get", {
70
+ description: "Get full detail and LIVE status for one TaskMarket task by ID. Public and anonymous. " +
71
+ "Returns description, reward, deadline, escrow tx, submission count, phase, and status. " +
72
+ "Use this after creating or delegating a task to check whether it is open, in review, " +
73
+ "awaiting settlement, or resolved. Never spends anything.",
74
+ inputSchema: z.object({
75
+ taskId: TASK_ID_SCHEMA,
76
+ }),
77
+ }, async ({ taskId }) => {
78
+ try {
79
+ const task = await getTask(taskId);
80
+ return createJsonResponse({
81
+ success: true,
82
+ id: task.id,
83
+ status: task.status,
84
+ phase: task.phase ?? null,
85
+ mode: task.mode ?? "bounty",
86
+ rewardUsdc: baseUnitsToUsdc(task.reward),
87
+ netRewardUsdc: task.netReward ? baseUnitsToUsdc(task.netReward) : null,
88
+ escrowTxHash: task.escrowTxHash ?? null,
89
+ requester: task.requester,
90
+ submissionCount: task.submissionCount ?? 0,
91
+ createdAt: task.createdAt,
92
+ deadline: task.expiryTime,
93
+ tags: task.tags ?? [],
94
+ link: `https://taskmarket.dev/task/${task.id}`,
95
+ description: task.description,
96
+ });
97
+ }
98
+ catch (error) {
99
+ return createErrorResponse(error);
100
+ }
101
+ });
102
+ server.registerTool("taskmarket_submissions", {
103
+ description: "List submissions on a TaskMarket task for HUMAN REVIEW. Public and anonymous. " +
104
+ "Returns each submission's worker address, submission time, deliverable file name, and " +
105
+ "hash. This tool NEVER accepts or rejects work — it only surfaces submissions so a human " +
106
+ "requester can review the deliverable before authorizing any payment.",
107
+ inputSchema: z.object({
108
+ taskId: TASK_ID_SCHEMA,
109
+ }),
110
+ }, async ({ taskId }) => {
111
+ try {
112
+ const submissions = await listSubmissions(taskId);
113
+ return createJsonResponse({
114
+ success: true,
115
+ taskId,
116
+ submissionCount: submissions.length,
117
+ submissions: submissions.map((s) => ({
118
+ id: s.id,
119
+ workerAddress: s.workerAddress,
120
+ workerAgentId: s.workerAgentId ?? null,
121
+ submittedAt: s.submittedAt,
122
+ rejectedAt: s.rejectedAt ?? null,
123
+ deliverableHash: s.deliverableHash ?? null,
124
+ submitTxHash: s.submitTxHash ?? null,
125
+ files: (s.artifacts ?? []).map((a) => ({
126
+ fileName: a.fileName,
127
+ mimeType: a.mimeType,
128
+ sizeBytes: a.sizeBytes ?? null,
129
+ })),
130
+ })),
131
+ note: "Human review required. This tool never auto-accepts or auto-rejects submissions.",
132
+ });
133
+ }
134
+ catch (error) {
135
+ return createErrorResponse(error);
136
+ }
137
+ });
138
+ server.registerTool("taskmarket_stats", {
139
+ description: "Public TaskMarket statistics for an agent address or agent ID (one is required): completed tasks, rating, " +
140
+ "total stars. Anonymous read. Use to gauge whether a worker or requester is reputable " +
141
+ "before delegating work. Never spends anything.",
142
+ inputSchema: z.object({
143
+ address: z.string().optional().describe("Wallet address to look up stats for"),
144
+ agentId: z.string().optional().describe("Agent ID to look up stats for (alternative to address)"),
145
+ }),
146
+ }, async (args) => {
147
+ try {
148
+ if (!args.address && !args.agentId) {
149
+ throw new Error("Pass an address or an agentId");
150
+ }
151
+ const stats = await getMarketStats({
152
+ address: args.address,
153
+ agentId: args.agentId,
154
+ });
155
+ return createJsonResponse({
156
+ success: true,
157
+ stats,
158
+ note: "Stats are public market data. A low rating does not guarantee work quality — review deliverables yourself.",
159
+ });
160
+ }
161
+ catch (error) {
162
+ return createErrorResponse(error);
163
+ }
164
+ });
165
+ }
166
+ //# sourceMappingURL=taskmarket.tools.js.map
@@ -48,8 +48,16 @@ export function parseArgToClarityValue(arg) {
48
48
  return boolCV(typedArg.value);
49
49
  case "principal":
50
50
  return principalCV(typedArg.value);
51
- case "buffer":
52
- return bufferCV(Buffer.from(typedArg.value, "hex"));
51
+ case "buffer": {
52
+ // Strip optional 0x/0X prefix — without this, Buffer.from("0x...", "hex")
53
+ // silently produces an empty buffer (aibtcdev/landing-page#1012 Finding 2)
54
+ const hexStr = typedArg.value.replace(/^0x/i, "");
55
+ // Buffer.from also stops at the first non-hex character or odd nibble
56
+ if (!/^([0-9a-f]{2})*$/i.test(hexStr)) {
57
+ throw new Error(`Invalid hex for buffer argument: "${typedArg.value}"`);
58
+ }
59
+ return bufferCV(Buffer.from(hexStr, "hex"));
60
+ }
53
61
  case "none":
54
62
  return noneCV();
55
63
  case "some":
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aibtc/mcp-server",
3
- "version": "1.76.1",
3
+ "version": "1.77.0",
4
4
  "description": "Bitcoin-native MCP server for AI agents: BTC/STX wallets, DeFi yield, sBTC peg, NFTs, and x402 payments.",
5
5
  "mcpName": "io.github.aibtcdev/mcp-server",
6
6
  "type": "module",
@@ -48,12 +48,12 @@
48
48
  "homepage": "https://github.com/aibtcdev/aibtc-mcp-server#readme",
49
49
  "license": "MIT",
50
50
  "dependencies": {
51
- "@aibtc/tx-schemas": "^0.7.0",
51
+ "@aibtc/tx-schemas": "^1.1.0",
52
52
  "@bitflowlabs/core-sdk": "^3.0.0",
53
53
  "@buildonspark/spark-sdk": "^0.7.14",
54
54
  "@faktoryfun/styx-sdk": "^1.3.5",
55
- "@modelcontextprotocol/client": "^2.1.0",
56
- "@modelcontextprotocol/server": "^2.1.0",
55
+ "@modelcontextprotocol/client": "^2.3.0",
56
+ "@modelcontextprotocol/server": "^2.3.0",
57
57
  "@noble/curves": "^2.0.1",
58
58
  "@noble/hashes": "^2.0.1",
59
59
  "@scure/base": "^2.0.0",
@@ -66,7 +66,7 @@
66
66
  "@stacks/transactions": "^7.6.0",
67
67
  "@stacks/wallet-sdk": "^7.2.0",
68
68
  "alex-sdk": "^3.2.1",
69
- "axios": "^1.17.0",
69
+ "axios": "^1.20.0",
70
70
  "light-bolt11-decoder": "^3.2.0",
71
71
  "micro-ordinals": "^0.3.0",
72
72
  "nostr-tools": "^2.23.3",
@@ -75,7 +75,7 @@
75
75
  "tslib": "^2.8.1",
76
76
  "ws": "^8.21.0",
77
77
  "x402-stacks": "^2.1.0",
78
- "zod": "^4.6.5"
78
+ "zod": "^4.6.7"
79
79
  },
80
80
  "devDependencies": {
81
81
  "@types/node": "^22.19.13",
@@ -84,10 +84,10 @@
84
84
  "postcss": "^8.5.18",
85
85
  "tsx": "^4.21.0",
86
86
  "typescript": "^5.9.3",
87
- "vitest": "^4.1.8"
87
+ "vitest": "^4.1.12"
88
88
  },
89
89
  "overrides": {
90
90
  "lodash": "^4.18.0",
91
- "axios": "^1.17.0"
91
+ "axios": "^1.20.0"
92
92
  }
93
93
  }
package/skill/SKILL.md CHANGED
@@ -4,7 +4,7 @@ description: Bitcoin L1 wallet for agents - check balances, send BTC, manage UTX
4
4
  license: MIT
5
5
  metadata:
6
6
  author: aibtcdev
7
- version: 1.76.1 # x-release-please-version
7
+ version: 1.77.0 # x-release-please-version
8
8
  npm: "@aibtc/mcp-server"
9
9
  github: https://github.com/aibtcdev/aibtc-mcp-server
10
10
  ---
@@ -242,6 +242,20 @@ unlocked wallet on the gateway's network. Every tool takes an optional `gateway`
242
242
  arg (defaults to `https://inference.aibtc.com`; use `http://localhost:8787` for
243
243
  local dev).
244
244
 
245
+ ### TaskMarket (onchain work marketplace on Base)
246
+
247
+ Browse the [TaskMarket](https://taskmarket.dev) agent work marketplace (USDC
248
+ escrow on Base). The tools are public and anonymous: no wallet, no spend.
249
+
250
+ | Tool | Description | Signed |
251
+ |------|-------------|:------:|
252
+ | `taskmarket_search` | List/search open tasks (filters, reward range) | — |
253
+ | `taskmarket_get` | Full task detail + live status + link | — |
254
+ | `taskmarket_submissions` | List a task's submissions | — |
255
+ | `taskmarket_stats` | Public agent/market stats (reputation check) | — |
256
+
257
+ See: [references/taskmarket.md](references/taskmarket.md)
258
+
245
259
  ### Prediction Market + Legions (elsalvadorstakesbtc.com)
246
260
 
247
261
  A market on one bit of Bitcoin history — did twenty frozen El Salvador reserve
@@ -0,0 +1,26 @@
1
+ # TaskMarket (onchain work marketplace on Base)
2
+
3
+ TaskMarket (https://taskmarket.dev) is an onchain agent work marketplace on
4
+ Base. Requesters escrow USDC, workers submit deliverables, and the requester
5
+ reviews submissions and accepts a winner. This server exposes TaskMarket
6
+ through MCP tools.
7
+
8
+ ## What works here
9
+
10
+ | Tool | Type | Notes |
11
+ |------|------|-------|
12
+ | `taskmarket_search` | read | Public, anonymous. Filters: status, phase, mode, tags, reward range. |
13
+ | `taskmarket_get` | read | Public, anonymous. Full detail + live status + link. |
14
+ | `taskmarket_submissions` | read | Public, anonymous. Lists submissions; never accepts or rejects work. |
15
+ | `taskmarket_stats` | read | Public, anonymous. Agent/market stats for reputation checks. |
16
+
17
+ ## Review submissions
18
+
19
+ `taskmarket_submissions` lists a task's submissions (worker address, agent ID,
20
+ deliverable files, hashes). This tool never accepts or rejects work.
21
+
22
+ ## Safety
23
+
24
+ - Every tool is a read against the public API. Nothing signs, spends or
25
+ needs a wallet.
26
+ - No private keys, seeds, tokens, or cookies are requested, stored, or logged.