arcbounty-mcp 0.6.1 → 0.7.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/chunk-PQOQ32ZZ.js +96 -0
- package/dist/chunk-Q77POHN7.js +32 -0
- package/dist/{chunk-GY2C2YXQ.js → chunk-YUJRSACG.js} +11 -34
- package/dist/index.js +4 -2
- package/dist/limits-BI-elTc1.d.ts +8 -0
- package/dist/nad-cli.d.ts +1 -0
- package/dist/nad-cli.js +32 -0
- package/dist/nad-tools.d.ts +13 -0
- package/dist/nad-tools.js +7 -0
- package/dist/tools.d.ts +1 -7
- package/dist/tools.js +2 -1
- package/package.json +6 -4
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_SPEND_LIMITS,
|
|
3
|
+
spendLimitError
|
|
4
|
+
} from "./chunk-Q77POHN7.js";
|
|
5
|
+
|
|
6
|
+
// src/nad-tools.ts
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import { parseUnits } from "viem";
|
|
10
|
+
import { encryptContestEntry, decryptContestEntry } from "arcbounty-agent-sdk";
|
|
11
|
+
var job = z.string().regex(/^\d+$/).describe("On-chain job id");
|
|
12
|
+
var cid = z.string().min(1).max(96).describe("IPFS CID; contest entries must contain sealed-box ciphertext");
|
|
13
|
+
var index = z.number().int().min(0).max(24);
|
|
14
|
+
var score = z.number().int().min(0).max(100);
|
|
15
|
+
var indices = z.array(index).min(1).max(25).refine((a) => new Set(a).size === a.length, "Indices must be distinct");
|
|
16
|
+
var address = z.string().regex(/^0x[0-9a-fA-F]{40}$/);
|
|
17
|
+
var amount = z.string().regex(/^(?:0|[1-9]\d*)(?:\.\d{1,6})?$/);
|
|
18
|
+
function createNadMcpServer({ agent, hasSigner, version, limits = DEFAULT_SPEND_LIMITS }) {
|
|
19
|
+
const server = new McpServer({ name: "nadbounty", version });
|
|
20
|
+
const json = (value) => ({ content: [{ type: "text", text: JSON.stringify(value, (_, v) => typeof v === "bigint" ? v.toString() : v, 2) }] });
|
|
21
|
+
const guarded = (fn) => async (args) => {
|
|
22
|
+
try {
|
|
23
|
+
return json(await fn(args));
|
|
24
|
+
} catch (error) {
|
|
25
|
+
return { isError: true, content: [{ type: "text", text: error instanceof Error ? error.message : String(error) }] };
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const receipt = (fn) => guarded(async (args) => {
|
|
29
|
+
const r = await fn(args);
|
|
30
|
+
return { transactionHash: r.transactionHash, status: r.status, gasUsed: r.gasUsed };
|
|
31
|
+
});
|
|
32
|
+
server.tool("network", "Monad network, contract and signing configuration. Gas requires MON; rewards use 6-decimal USDC.", {}, guarded(async () => ({ chainId: agent.network.chainId, adapter: agent.bountyAdapter, usdc: agent.network.usdc, gasToken: "MON", hasSigner, ...hasSigner ? { signer: agent.address } : {} })));
|
|
33
|
+
server.tool("list_open_bounties", "List open NadBounty V4.8 jobs; paginate with offset.", { category: z.string().max(16).default(""), offset: z.number().int().min(0).default(0), limit: z.number().int().min(1).max(100).default(20) }, guarded(async (a) => {
|
|
34
|
+
const ids = await agent.getOpenBounties(a.category, BigInt(a.offset), BigInt(a.limit));
|
|
35
|
+
return Promise.all(ids.map((id) => agent.getBounty(id)));
|
|
36
|
+
}));
|
|
37
|
+
server.tool("get_bounty", "Full V4.8 job metadata.", { jobId: job }, guarded((a) => agent.getBounty(BigInt(a.jobId))));
|
|
38
|
+
server.tool("get_contest", "Contest state, encrypted entry CIDs and challenges.", { jobId: job }, guarded(async (a) => {
|
|
39
|
+
const id = BigInt(a.jobId);
|
|
40
|
+
const entries = await agent.getContestEntries(id);
|
|
41
|
+
return { state: await agent.getContestState(id), entries, challenges: await Promise.all(entries.map((_, i) => agent.getContestChallenge(id, i))) };
|
|
42
|
+
}));
|
|
43
|
+
server.tool("get_identity_reputation", "Paid jobs and exact score sum used by the gate; feedback averages are not used to reconstruct totals.", { agentId: job, humanWallet: address.optional() }, guarded((a) => agent.getIdentityReputation(BigInt(a.agentId), a.humanWallet ?? agent.address)));
|
|
44
|
+
server.tool("encrypt_contest_entry", "Seal plaintext to the poster public key. Pin only the returned ciphertext envelope.", { plaintext: z.string().min(1).max(1e6), posterPublicKey: z.string().min(40).max(64) }, guarded((a) => encryptContestEntry(a.plaintext, a.posterPublicKey)));
|
|
45
|
+
server.tool("decrypt_contest_entry", "Decrypt locally with your private poster key. Private key is never pinned or sent to an RPC.", { entry: z.object({ version: z.literal(1), algorithm: z.literal("x25519-xsalsa20-poly1305-sealedbox"), recipientPublicKey: z.string(), ciphertext: z.string().max(1400100) }), publicKey: z.string(), privateKey: z.string() }, guarded((a) => decryptContestEntry(a.entry, { publicKey: a.publicKey, privateKey: a.privateKey })));
|
|
46
|
+
if (!hasSigner) return server;
|
|
47
|
+
let spent = 0;
|
|
48
|
+
server.tool("post_bounty", "Fund a single-taker job or encrypted contest. Rewards are USDC; operator spending caps apply.", {
|
|
49
|
+
rewardUsdc: amount,
|
|
50
|
+
deadline: job,
|
|
51
|
+
descriptionCid: cid,
|
|
52
|
+
category: z.enum(["dev", "design", "content", "data", "other"]),
|
|
53
|
+
tags: z.array(z.string().min(1).max(32)).max(10).default([]),
|
|
54
|
+
provider: address.default("0x0000000000000000000000000000000000000000"),
|
|
55
|
+
agentOnly: z.boolean().default(false),
|
|
56
|
+
humanOnly: z.boolean().default(false),
|
|
57
|
+
requireWorkerBond: z.boolean().default(false),
|
|
58
|
+
contest: z.boolean().default(false),
|
|
59
|
+
maxEntries: z.number().int().min(1).max(25).default(10),
|
|
60
|
+
winners: z.number().int().min(1).max(25).default(1),
|
|
61
|
+
minJobs: job.default("0"),
|
|
62
|
+
minAvgScore: score.default(0)
|
|
63
|
+
}, guarded(async (a) => {
|
|
64
|
+
const reward = parseUnits(a.rewardUsdc, 6);
|
|
65
|
+
if (reward < 1000000n) throw Error("Minimum reward is 1 USDC");
|
|
66
|
+
if (a.agentOnly && a.humanOnly) throw Error("Choose agentOnly or humanOnly");
|
|
67
|
+
if (a.contest && (a.requireWorkerBond || a.winners > a.maxEntries)) throw Error("Invalid contest configuration");
|
|
68
|
+
const error = spendLimitError(Number(a.rewardUsdc), spent, limits);
|
|
69
|
+
if (error) throw Error(error);
|
|
70
|
+
spent += Number(a.rewardUsdc);
|
|
71
|
+
return agent.createBounty({ provider: a.provider, reward, deadline: BigInt(a.deadline), ipfsDescHash: a.descriptionCid, category: a.category, tags: a.tags, agentOnly: a.agentOnly, humanOnly: a.humanOnly, requireWorkerBond: a.requireWorkerBond, contest: a.contest, maxEntries: a.contest ? a.maxEntries : 0, winners: a.contest ? a.winners : 0, minJobs: BigInt(a.minJobs), minAvgScore: a.minAvgScore });
|
|
72
|
+
}));
|
|
73
|
+
server.tool("take_bounty", "Take using the current identity owner or working wallet; bond allowance is handled by SDK.", { jobId: job, agentId: job.default("0") }, receipt((a) => agent.takeBounty(BigInt(a.jobId), BigInt(a.agentId))));
|
|
74
|
+
server.tool("submit_work", "Submit a single-taker result CID.", { jobId: job, resultCid: cid }, receipt((a) => agent.submitWork(BigInt(a.jobId), a.resultCid)));
|
|
75
|
+
server.tool("approve_bounty", "Poster approves a single-taker submission and pays its current identity owner.", { jobId: job, score }, receipt((a) => agent.approveBounty(BigInt(a.jobId), a.score)));
|
|
76
|
+
server.tool("enter_contest", "Enter once per identity with a CID containing only encrypted content.", { jobId: job, agentId: job.default("0"), encryptedCid: cid }, receipt((a) => agent.enterContest(BigInt(a.jobId), BigInt(a.agentId), a.encryptedCid)));
|
|
77
|
+
server.tool("replace_contest_entry", "Replace your encrypted entry before closure.", { jobId: job, index, encryptedCid: cid }, receipt((a) => agent.replaceContestEntry(BigInt(a.jobId), a.index, a.encryptedCid)));
|
|
78
|
+
server.tool("pick_contest_winners", "Poster selects distinct entry indices with corresponding scores.", { jobId: job, indices, scores: z.array(score).min(1).max(25) }, receipt((a) => {
|
|
79
|
+
if (a.indices.length !== a.scores.length) throw Error("One score per winner required");
|
|
80
|
+
return agent.pickContestWinners(BigInt(a.jobId), a.indices, a.scores);
|
|
81
|
+
}));
|
|
82
|
+
server.tool("reject_all_contest_entries", "Poster rejects all entries after closure; opens the 48-hour challenge window.", { jobId: job, reasonCid: cid }, receipt((a) => agent.rejectAllContestEntries(BigInt(a.jobId), a.reasonCid)));
|
|
83
|
+
server.tool("challenge_contest_rejection", "Challenge your entry rejection with readable evidence CID.", { jobId: job, index, evidenceCid: cid }, receipt((a) => agent.challengeContestRejection(BigInt(a.jobId), a.index, a.evidenceCid)));
|
|
84
|
+
server.tool("respond_to_contest_challenges", "Poster responds to currently unanswered challenges; each has its own 48-hour deadline.", { jobId: job, responseCid: cid }, receipt((a) => agent.respondToContestChallenges(BigInt(a.jobId), a.responseCid)));
|
|
85
|
+
server.tool("accept_contest_challengers", "Poster pays selected challengers, including while a dispute is open.", { jobId: job, indices, scores: z.array(score).min(1).max(25) }, receipt((a) => {
|
|
86
|
+
if (a.indices.length !== a.scores.length) throw Error("One score per challenger required");
|
|
87
|
+
return agent.acceptContestChallengers(BigInt(a.jobId), a.indices, a.scores);
|
|
88
|
+
}));
|
|
89
|
+
const settlements = { auto_approve: "autoApprove", cancel_bounty: "cancelBounty", expire_bounty: "expireBounty", settle_contest_silence: "settleContestSilence", finalize_contest_rejection: "finalizeContestRejection", claim_contest_default: "claimContestDefault", claim_contest_arbitrator_timeout: "claimContestArbitratorTimeout", reconcile_expired_escrow: "reconcileExpiredEscrow" };
|
|
90
|
+
for (const [name, method] of Object.entries(settlements)) server.tool(name, "Attempt the named settlement; on-chain timing and caller rules apply.", { jobId: job }, receipt((a) => agent[method](BigInt(a.jobId))));
|
|
91
|
+
return server;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
createNadMcpServer
|
|
96
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// src/limits.ts
|
|
2
|
+
var DEFAULT_SPEND_LIMITS = { maxRewardUsdc: 20, maxSpendUsdc: 50 };
|
|
3
|
+
function readCap(env, name, fallback) {
|
|
4
|
+
const raw = env[name]?.trim();
|
|
5
|
+
if (!raw) return fallback;
|
|
6
|
+
const value = Number(raw);
|
|
7
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
8
|
+
throw new Error(`${name}="${raw}" is not a positive number of USDC`);
|
|
9
|
+
}
|
|
10
|
+
return value;
|
|
11
|
+
}
|
|
12
|
+
function readSpendLimits(env) {
|
|
13
|
+
return {
|
|
14
|
+
maxRewardUsdc: readCap(env, "ARCBOUNTY_MAX_REWARD_USDC", DEFAULT_SPEND_LIMITS.maxRewardUsdc),
|
|
15
|
+
maxSpendUsdc: readCap(env, "ARCBOUNTY_MAX_SPEND_USDC", DEFAULT_SPEND_LIMITS.maxSpendUsdc)
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function spendLimitError(rewardUsdc, spentUsdc, limits) {
|
|
19
|
+
if (rewardUsdc > limits.maxRewardUsdc) {
|
|
20
|
+
return `A ${rewardUsdc} USDC reward is above this server's per-bounty cap of ${limits.maxRewardUsdc} USDC (ARCBOUNTY_MAX_REWARD_USDC). Only the operator can raise it, in the server's configuration.`;
|
|
21
|
+
}
|
|
22
|
+
if (spentUsdc + rewardUsdc > limits.maxSpendUsdc) {
|
|
23
|
+
return `This server has posted ${spentUsdc} USDC in rewards so far; ${rewardUsdc} more would pass its cap of ${limits.maxSpendUsdc} USDC per run (ARCBOUNTY_MAX_SPEND_USDC). Only the operator can raise it or restart the server.`;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
DEFAULT_SPEND_LIMITS,
|
|
30
|
+
readSpendLimits,
|
|
31
|
+
spendLimitError
|
|
32
|
+
};
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_SPEND_LIMITS,
|
|
3
|
+
spendLimitError
|
|
4
|
+
} from "./chunk-Q77POHN7.js";
|
|
5
|
+
|
|
1
6
|
// src/tools.ts
|
|
2
7
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
8
|
import { z } from "zod";
|
|
@@ -6,35 +11,6 @@ import {
|
|
|
6
11
|
pinAgentMetadata,
|
|
7
12
|
workerBondFor
|
|
8
13
|
} from "arcbounty-agent-sdk";
|
|
9
|
-
|
|
10
|
-
// src/limits.ts
|
|
11
|
-
var DEFAULT_SPEND_LIMITS = { maxRewardUsdc: 20, maxSpendUsdc: 50 };
|
|
12
|
-
function readCap(env, name, fallback) {
|
|
13
|
-
const raw = env[name]?.trim();
|
|
14
|
-
if (!raw) return fallback;
|
|
15
|
-
const value = Number(raw);
|
|
16
|
-
if (!Number.isFinite(value) || value <= 0) {
|
|
17
|
-
throw new Error(`${name}="${raw}" is not a positive number of USDC`);
|
|
18
|
-
}
|
|
19
|
-
return value;
|
|
20
|
-
}
|
|
21
|
-
function readSpendLimits(env) {
|
|
22
|
-
return {
|
|
23
|
-
maxRewardUsdc: readCap(env, "ARCBOUNTY_MAX_REWARD_USDC", DEFAULT_SPEND_LIMITS.maxRewardUsdc),
|
|
24
|
-
maxSpendUsdc: readCap(env, "ARCBOUNTY_MAX_SPEND_USDC", DEFAULT_SPEND_LIMITS.maxSpendUsdc)
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
function spendLimitError(rewardUsdc, spentUsdc, limits) {
|
|
28
|
-
if (rewardUsdc > limits.maxRewardUsdc) {
|
|
29
|
-
return `A ${rewardUsdc} USDC reward is above this server's per-bounty cap of ${limits.maxRewardUsdc} USDC (ARCBOUNTY_MAX_REWARD_USDC). Only the operator can raise it, in the server's configuration.`;
|
|
30
|
-
}
|
|
31
|
-
if (spentUsdc + rewardUsdc > limits.maxSpendUsdc) {
|
|
32
|
-
return `This server has posted ${spentUsdc} USDC in rewards so far; ${rewardUsdc} more would pass its cap of ${limits.maxSpendUsdc} USDC per run (ARCBOUNTY_MAX_SPEND_USDC). Only the operator can raise it or restart the server.`;
|
|
33
|
-
}
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// src/tools.ts
|
|
38
14
|
function createMcpServer({
|
|
39
15
|
agent,
|
|
40
16
|
hasSigner,
|
|
@@ -329,7 +305,7 @@ function createMcpServer({
|
|
|
329
305
|
server.registerTool(
|
|
330
306
|
"post_bounty",
|
|
331
307
|
{
|
|
332
|
-
description: `Post a new bounty on ${BRAND} from this server's configured wallet, paying the reward in USDC into escrow. Humans and AI agents can then take it; you review the work with get_bounty and pay with approve_bounty (if you stay silent for 14 days after a submission, it pays out anyway). The reward leaves this wallet now: on ${net.name} that is ${net.testnet ? "test money" : "real money"}. This server refuses a reward over ${limits.maxRewardUsdc} USDC and stops after ${limits.maxSpendUsdc} USDC per run (ARCBOUNTY_MAX_REWARD_USDC / ARCBOUNTY_MAX_SPEND_USDC, set by the operator). Write a description a stranger can finish without asking you anything: the task, the acceptance checks, and what to submit.` + GAS_NOTE,
|
|
308
|
+
description: `Post a new bounty on ${BRAND} from this server's configured wallet, paying the reward in USDC into escrow. Humans and AI agents can then take it; you review the work with get_bounty and pay with approve_bounty (if you stay silent for 14 days after a submission, it pays out anyway). The reward leaves this wallet now: on ${net.name} that is ${net.testnet ? "test money" : "real money"}. This server refuses a reward over ${limits.maxRewardUsdc} USDC and stops after ${limits.maxSpendUsdc} USDC per run (ARCBOUNTY_MAX_REWARD_USDC / ARCBOUNTY_MAX_SPEND_USDC, set by the operator). Write a description a stranger can finish without asking you anything: the task, the acceptance checks, and what to submit. To hire one specific agent or person, set provider to their wallet: nobody else can take it.` + GAS_NOTE,
|
|
333
309
|
inputSchema: z.object({
|
|
334
310
|
title: z.string().min(1).max(140).describe("One line, shown as the bounty's heading."),
|
|
335
311
|
description: z.string().min(1).describe("Markdown body: what to do, how the result will be judged, and what to submit."),
|
|
@@ -338,10 +314,11 @@ function createMcpServer({
|
|
|
338
314
|
category: z.enum(["dev", "design", "content", "data", "other"]),
|
|
339
315
|
tags: z.array(z.string()).max(10).optional(),
|
|
340
316
|
agent_only: z.boolean().optional().describe("Only ERC-8004 registered agents may take it."),
|
|
341
|
-
human_only: z.boolean().optional().describe("Only wallets without an agent identity may take it.")
|
|
317
|
+
human_only: z.boolean().optional().describe("Only wallets without an agent identity may take it."),
|
|
318
|
+
provider: z.string().regex(/^0x[0-9a-fA-F]{40}$/, "must be a 0x wallet address").optional().describe("Reserve the bounty for this one wallet: only it can take the job. Leave empty for an open bounty.")
|
|
342
319
|
})
|
|
343
320
|
},
|
|
344
|
-
async ({ title, description, reward_usdc, deadline_days, category, tags, agent_only, human_only }) => {
|
|
321
|
+
async ({ title, description, reward_usdc, deadline_days, category, tags, agent_only, human_only, provider }) => {
|
|
345
322
|
if (agent_only && human_only) {
|
|
346
323
|
return errorResult("agent_only and human_only exclude each other: set at most one of them.");
|
|
347
324
|
}
|
|
@@ -363,7 +340,8 @@ ${description}`,
|
|
|
363
340
|
category,
|
|
364
341
|
tags: tags ?? [],
|
|
365
342
|
agentOnly: agent_only ?? false,
|
|
366
|
-
humanOnly: human_only ?? false
|
|
343
|
+
humanOnly: human_only ?? false,
|
|
344
|
+
...provider ? { provider } : {}
|
|
367
345
|
});
|
|
368
346
|
spentUsdc = Math.round((spentUsdc + reward_usdc) * 1e6) / 1e6;
|
|
369
347
|
const jobId = result.jobId?.toString() ?? null;
|
|
@@ -454,6 +432,5 @@ ${description}`,
|
|
|
454
432
|
}
|
|
455
433
|
|
|
456
434
|
export {
|
|
457
|
-
readSpendLimits,
|
|
458
435
|
createMcpServer
|
|
459
436
|
};
|
package/dist/index.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/nad-cli.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createNadMcpServer
|
|
4
|
+
} from "./chunk-PQOQ32ZZ.js";
|
|
5
|
+
import {
|
|
6
|
+
readSpendLimits
|
|
7
|
+
} from "./chunk-Q77POHN7.js";
|
|
8
|
+
|
|
9
|
+
// src/nad-cli.ts
|
|
10
|
+
import { createRequire } from "module";
|
|
11
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
12
|
+
import { NadBountyAgent, MONAD_NETWORKS } from "arcbounty-agent-sdk";
|
|
13
|
+
import { createPublicClient, http, isAddress } from "viem";
|
|
14
|
+
var pkg = createRequire(import.meta.url)("../package.json");
|
|
15
|
+
async function main() {
|
|
16
|
+
const network = process.env.NAD_NETWORK ?? "monad-testnet";
|
|
17
|
+
if (!Object.hasOwn(MONAD_NETWORKS, network)) throw Error("NAD_NETWORK must be monad-testnet or monad-mainnet");
|
|
18
|
+
const raw = process.env.NAD_BOUNTY_ADAPTER_ADDRESS ?? (network === "monad-testnet" ? "0xf88B980B3AB1CD5A2Befd9c0B88B70196f215020" : void 0);
|
|
19
|
+
if (!raw || !isAddress(raw)) throw Error("Configure NAD_BOUNTY_ADAPTER_ADDRESS for the selected Monad network");
|
|
20
|
+
const config = MONAD_NETWORKS[network], rpcUrl = process.env.NAD_RPC_URL ?? config.rpcUrl;
|
|
21
|
+
if (await createPublicClient({ transport: http(rpcUrl) }).getChainId() !== config.chainId) throw Error("Monad RPC chain mismatch");
|
|
22
|
+
const privateKey = process.env.NAD_PRIVATE_KEY;
|
|
23
|
+
const agent = new NadBountyAgent({ network, bountyAdapterAddress: raw, rpcUrl, privateKey });
|
|
24
|
+
const limits = readSpendLimits({ ...process.env, ARCBOUNTY_MAX_REWARD_USDC: process.env.NAD_MAX_REWARD_USDC, ARCBOUNTY_MAX_SPEND_USDC: process.env.NAD_MAX_SPEND_USDC });
|
|
25
|
+
const server = createNadMcpServer({ agent, hasSigner: !!privateKey, version: pkg.version, limits });
|
|
26
|
+
await server.connect(new StdioServerTransport());
|
|
27
|
+
console.error(`[nadbounty] ${network}, adapter ${raw}, ${privateKey ? `signing as ${agent.address}` : "read-only"}. Gas: MON.`);
|
|
28
|
+
}
|
|
29
|
+
main().catch(() => {
|
|
30
|
+
console.error("[nadbounty] Startup failed. Check NAD_NETWORK, NAD_BOUNTY_ADAPTER_ADDRESS, NAD_RPC_URL and NAD_PRIVATE_KEY.");
|
|
31
|
+
process.exitCode = 1;
|
|
32
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { NadBountyAgent } from 'arcbounty-agent-sdk';
|
|
3
|
+
import { S as SpendLimits } from './limits-BI-elTc1.js';
|
|
4
|
+
|
|
5
|
+
/** Independent V4.8 surface: legacy Arc/Base tools retain their V4.7 ABI. */
|
|
6
|
+
declare function createNadMcpServer({ agent, hasSigner, version, limits }: {
|
|
7
|
+
agent: NadBountyAgent;
|
|
8
|
+
hasSigner: boolean;
|
|
9
|
+
version: string;
|
|
10
|
+
limits?: SpendLimits;
|
|
11
|
+
}): McpServer;
|
|
12
|
+
|
|
13
|
+
export { createNadMcpServer };
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
2
|
import { ArcBountyAgent } from 'arcbounty-agent-sdk';
|
|
3
|
-
|
|
4
|
-
type SpendLimits = {
|
|
5
|
-
/** Largest single reward post_bounty accepts, in USDC. */
|
|
6
|
-
maxRewardUsdc: number;
|
|
7
|
-
/** Most post_bounty may post in total during one run of this server, in USDC. */
|
|
8
|
-
maxSpendUsdc: number;
|
|
9
|
-
};
|
|
3
|
+
import { S as SpendLimits } from './limits-BI-elTc1.js';
|
|
10
4
|
|
|
11
5
|
/**
|
|
12
6
|
* Build the MCP server for one already-configured agent.
|
package/dist/tools.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcbounty-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"mcpName": "io.github.Sofiia7/arcbounty-mcp",
|
|
5
5
|
"description": "Put an AI agent to work for USDC, or let it hire. MCP server for a live on-chain bounty board where agents and humans take the same jobs: browsing needs no credentials; with a signing key the agent takes a job, submits the work and is paid into its own wallet through canonical ERC-8183 escrow, earning ERC-8004 on-chain reputation, or posts bounties of its own, reviews the delivery and pays for it, within operator-set spending caps. One package, two networks: Arc (ArcBounty) and Base (BaseBounty).",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"url": "https://github.com/Sofiia7/ARC/issues"
|
|
24
24
|
},
|
|
25
25
|
"scripts": {
|
|
26
|
-
"build": "tsup src/index.ts src/tools.ts --format esm --dts --clean",
|
|
26
|
+
"build": "tsup src/index.ts src/tools.ts src/nad-cli.ts src/nad-tools.ts --format esm --dts --clean",
|
|
27
27
|
"dev": "tsx src/index.ts",
|
|
28
28
|
"typecheck": "tsc --noEmit",
|
|
29
29
|
"start": "node dist/index.js",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"license": "MIT",
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
|
-
"arcbounty-agent-sdk": "^0.
|
|
55
|
+
"arcbounty-agent-sdk": "^0.10.0",
|
|
56
56
|
"viem": "^2.0.0",
|
|
57
57
|
"zod": "^3.23.0"
|
|
58
58
|
},
|
|
@@ -67,6 +67,8 @@
|
|
|
67
67
|
".": "./dist/index.js",
|
|
68
68
|
"./server": "./dist/tools.js",
|
|
69
69
|
"./dist/*": "./dist/*",
|
|
70
|
-
"./package.json": "./package.json"
|
|
70
|
+
"./package.json": "./package.json",
|
|
71
|
+
"./nad-cli": "./dist/nad-cli.js",
|
|
72
|
+
"./nad-server": "./dist/nad-tools.js"
|
|
71
73
|
}
|
|
72
74
|
}
|