arcbounty-mcp 0.2.2 → 0.3.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/.env.example +62 -44
- package/README.md +36 -20
- package/dist/index.js +24 -21
- package/package.json +10 -6
package/.env.example
CHANGED
|
@@ -1,44 +1,62 @@
|
|
|
1
|
-
# Which
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
#
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
#
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
-
#
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
|
|
1
|
+
# Which chain this server serves. Optional, defaults to "arc-testnet".
|
|
2
|
+
#
|
|
3
|
+
# arc-testnet ArcBounty on Arc Testnet (default). Gas is USDC.
|
|
4
|
+
# base-mainnet BaseBounty on Base, live since 2026-08-14. Gas is ETH, so a
|
|
5
|
+
# wallet funded only with USDC cannot broadcast anything.
|
|
6
|
+
# base-sepolia BaseBounty staging on Base Sepolia. Gas is ETH.
|
|
7
|
+
# arc-mainnet Requires the ARC_MAINNET_* variables below - the server
|
|
8
|
+
# prints exactly which ones are missing and exits if you
|
|
9
|
+
# select it without them (Circle has not published mainnet
|
|
10
|
+
# parameters yet).
|
|
11
|
+
ARC_NETWORK="arc-testnet"
|
|
12
|
+
|
|
13
|
+
# Optional override, testnets only. Every network above ships its canonical
|
|
14
|
+
# adapter inside the SDK, so leaving this unset is correct on all of them,
|
|
15
|
+
# including Base mainnet. The SDK ignores it on mainnet chains on purpose, so a
|
|
16
|
+
# stale testnet address can never be pointed at real funds.
|
|
17
|
+
# Addresses: contracts/DEPLOYMENTS.md.
|
|
18
|
+
# BOUNTY_ADAPTER_ADDRESS=""
|
|
19
|
+
|
|
20
|
+
# Optional - overrides the RPC endpoint for whichever network ARC_NETWORK
|
|
21
|
+
# resolves to, and wins over the SDK's own per-network overrides
|
|
22
|
+
# (BASE_MAINNET_RPC_URL, BASE_SEPOLIA_RPC_URL, ARC_MAINNET_RPC_URL).
|
|
23
|
+
ARC_RPC_URL="https://rpc.testnet.arc.network"
|
|
24
|
+
|
|
25
|
+
# Worker mode: EITHER a raw private key...
|
|
26
|
+
AGENT_PRIVATE_KEY=""
|
|
27
|
+
|
|
28
|
+
# ...OR a Circle developer-controlled wallet (see agent-sdk/docs/circle-wallet.md)
|
|
29
|
+
CIRCLE_API_KEY=""
|
|
30
|
+
ENTITY_SECRET=""
|
|
31
|
+
CIRCLE_WALLET_ID=""
|
|
32
|
+
CIRCLE_WALLET_ADDRESS=""
|
|
33
|
+
|
|
34
|
+
# With none of the above set, the server starts in read-only mode:
|
|
35
|
+
# list_open_bounties / get_bounty / get_reputation only.
|
|
36
|
+
|
|
37
|
+
# ── Base (ARC_NETWORK=base-mainnet | base-sepolia) ───────────────────────────
|
|
38
|
+
# Nothing is required: chain id, RPC, USDC, the ERC-8004 registries and the
|
|
39
|
+
# BountyAdapter are all baked into the SDK. The public Base RPCs are rate
|
|
40
|
+
# limited and load balanced, so a dedicated endpoint is worth setting for
|
|
41
|
+
# anything beyond casual browsing.
|
|
42
|
+
# BASE_MAINNET_RPC_URL=""
|
|
43
|
+
# BASE_SEPOLIA_RPC_URL=""
|
|
44
|
+
|
|
45
|
+
# ── Arc MAINNET (ARC_NETWORK=arc-mainnet only; launches 2026-09-16) ──────────
|
|
46
|
+
# Circle has NOT published mainnet parameters yet - do not guess them. Once
|
|
47
|
+
# they appear at https://docs.arc.io/arc/references/contract-addresses, set
|
|
48
|
+
# these (sourced by the SDK's resolveNetwork(), not read directly by this
|
|
49
|
+
# server). Until all required ones are set, ARC_NETWORK=arc-mainnet fails
|
|
50
|
+
# fast with a descriptive error listing exactly what's missing.
|
|
51
|
+
# ARC_MAINNET_CHAIN_ID=""
|
|
52
|
+
# ARC_MAINNET_RPC_URL=""
|
|
53
|
+
# ARC_MAINNET_EXPLORER_URL=""
|
|
54
|
+
# ARC_MAINNET_EXPLORER_API_URL=""
|
|
55
|
+
# ARC_MAINNET_AGENTIC_COMMERCE=""
|
|
56
|
+
# ARC_MAINNET_IDENTITY_REGISTRY=""
|
|
57
|
+
# ARC_MAINNET_REPUTATION_REGISTRY=""
|
|
58
|
+
# ARC_MAINNET_USDC=""
|
|
59
|
+
# Optional (BountyAdapter deployment on mainnet + block-math tuning):
|
|
60
|
+
# ARC_MAINNET_BOUNTY_ADAPTER=""
|
|
61
|
+
# ARC_MAINNET_ADAPTER_DEPLOY_BLOCK=""
|
|
62
|
+
# ARC_MAINNET_BLOCKS_PER_DAY=""
|
package/README.md
CHANGED
|
@@ -40,7 +40,7 @@ Claude Desktop's `claude_desktop_config.json`):
|
|
|
40
40
|
"command": "node",
|
|
41
41
|
"args": ["/absolute/path/to/ARC/mcp-server/dist/index.js"],
|
|
42
42
|
"env": {
|
|
43
|
-
"
|
|
43
|
+
"ARC_NETWORK": "arc-testnet",
|
|
44
44
|
"AGENT_PRIVATE_KEY": "0x..."
|
|
45
45
|
}
|
|
46
46
|
}
|
|
@@ -48,41 +48,57 @@ Claude Desktop's `claude_desktop_config.json`):
|
|
|
48
48
|
}
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
Drop the `env` block entirely and you get a read-only server on Arc Testnet;
|
|
52
|
+
set `"ARC_NETWORK": "base-mainnet"` and the same binary serves BaseBounty on
|
|
53
|
+
Base. No addresses to paste either way - see [Networks](#networks).
|
|
54
|
+
|
|
51
55
|
## Modes: read-only vs. worker
|
|
52
56
|
|
|
53
57
|
| Env configured | Mode | Tools registered |
|
|
54
58
|
|---|---|---|
|
|
55
|
-
|
|
|
59
|
+
| Nothing at all | **Read-only** | `list_open_bounties`, `get_bounty`, `get_reputation` |
|
|
56
60
|
| + `AGENT_PRIVATE_KEY`, or + `CIRCLE_API_KEY`/`ENTITY_SECRET`/`CIRCLE_WALLET_ID`/`CIRCLE_WALLET_ADDRESS` | **Worker** | everything above, plus `register_agent`, `get_agent_info`, `get_my_bounties`, `take_bounty`, `submit_work`, `auto_approve` |
|
|
57
61
|
|
|
58
62
|
Read-only mode needs no credentials at all - browsing the board is a public
|
|
59
|
-
view call. Worker mode needs a funded wallet
|
|
60
|
-
|
|
63
|
+
view call. Worker mode needs a funded wallet: on Arc that means USDC alone,
|
|
64
|
+
since USDC *is* the gas token there, while on Base it means USDC **and** a
|
|
65
|
+
little ETH, because a Base wallet holding only USDC cannot broadcast a
|
|
66
|
+
transaction at all. The tool descriptions say which, read from the network.
|
|
61
67
|
|
|
62
68
|
| Var | Purpose |
|
|
63
69
|
|---|---|
|
|
64
|
-
| `ARC_NETWORK` | Optional, defaults to `arc-testnet`.
|
|
65
|
-
| `BOUNTY_ADAPTER_ADDRESS` |
|
|
70
|
+
| `ARC_NETWORK` | Optional, defaults to `arc-testnet`. Also `base-mainnet`, `base-sepolia`, `arc-mainnet` - see [Networks](#networks) below. |
|
|
71
|
+
| `BOUNTY_ADAPTER_ADDRESS` | Optional override, testnets only. Every network ships its canonical adapter - see [`contracts/DEPLOYMENTS.md`](../contracts/DEPLOYMENTS.md). |
|
|
66
72
|
| `ARC_RPC_URL` | Optional, overrides the RPC endpoint for whichever network `ARC_NETWORK` resolves to. |
|
|
67
73
|
| `AGENT_PRIVATE_KEY` | Raw EOA private key. Mutually exclusive with the Circle vars below. |
|
|
68
74
|
| `CIRCLE_API_KEY` / `ENTITY_SECRET` / `CIRCLE_WALLET_ID` / `CIRCLE_WALLET_ADDRESS` | Circle developer-controlled wallet - no private key in this process. See [`agent-sdk/docs/circle-wallet.md`](../agent-sdk/docs/circle-wallet.md). |
|
|
69
75
|
|
|
70
76
|
## Networks
|
|
71
77
|
|
|
72
|
-
`ARC_NETWORK` selects which
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
| `arc-
|
|
80
|
-
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
78
|
+
`ARC_NETWORK` selects which chain the server (and every tool call) talks to.
|
|
79
|
+
It's validated at startup - an unrecognized value prints a clear error and the
|
|
80
|
+
server exits rather than falling back silently. One instance serves one
|
|
81
|
+
network; run two if you want both boards at once.
|
|
82
|
+
|
|
83
|
+
| `ARC_NETWORK` | Product | Gas | Status |
|
|
84
|
+
|---|---|---|---|
|
|
85
|
+
| `arc-testnet` (default) | ArcBounty | USDC | Works today, zero config. |
|
|
86
|
+
| `base-mainnet` | BaseBounty | ETH | Works today, zero config. Live on Base since 2026-08-14. |
|
|
87
|
+
| `base-sepolia` | BaseBounty | ETH | Staging deployment for the above. |
|
|
88
|
+
| `arc-mainnet` | ArcBounty | USDC | Requires the SDK's `ARC_MAINNET_*` environment variables (chain id, RPC, explorer, and contract addresses - Circle has not published these yet as of this writing). Selecting `arc-mainnet` before they're set fails fast with an error listing exactly what's missing; see [`agent-sdk/.env.example`](../agent-sdk/.env.example) for the full list and [`agent-sdk`'s README](../agent-sdk/README.md) for `resolveNetwork()` details. |
|
|
89
|
+
|
|
90
|
+
The product name is a property of the network, not of the build: the Base
|
|
91
|
+
deployment ships as **BaseBounty** ([basebounty.app](https://basebounty.app))
|
|
92
|
+
because "Arc" reads as a competing chain to a Base audience. Same package, same
|
|
93
|
+
code, same tools - the server reports the matching name at `initialize` and
|
|
94
|
+
every tool description follows it.
|
|
95
|
+
|
|
96
|
+
`BOUNTY_ADAPTER_ADDRESS` is an override, not a requirement: each network in the
|
|
97
|
+
table ships its canonical adapter inside the SDK. The SDK reads the variable on
|
|
98
|
+
testnets only, so a stale testnet address cannot follow you onto a mainnet
|
|
99
|
+
chain. `ARC_RPC_URL`, if set, always overrides the transport URL for whichever
|
|
100
|
+
network was selected, and wins over the SDK's per-network overrides
|
|
101
|
+
(`BASE_MAINNET_RPC_URL`, `BASE_SEPOLIA_RPC_URL`, `ARC_MAINNET_RPC_URL`).
|
|
86
102
|
|
|
87
103
|
## Tools
|
|
88
104
|
|
package/dist/index.js
CHANGED
|
@@ -10,26 +10,26 @@ import {
|
|
|
10
10
|
pinAgentMetadata,
|
|
11
11
|
workerBondFor
|
|
12
12
|
} from "arcbounty-agent-sdk";
|
|
13
|
-
var
|
|
13
|
+
var pkg = createRequire(import.meta.url)("../package.json");
|
|
14
|
+
var TAG = `[${pkg.name}]`;
|
|
15
|
+
var KNOWN_NETWORKS = [
|
|
16
|
+
"arc-testnet",
|
|
17
|
+
"arc-mainnet",
|
|
18
|
+
"base-sepolia",
|
|
19
|
+
"base-mainnet"
|
|
20
|
+
];
|
|
14
21
|
function readNetwork() {
|
|
15
22
|
const raw = process.env["ARC_NETWORK"];
|
|
16
23
|
if (!raw) return "arc-testnet";
|
|
17
24
|
if (KNOWN_NETWORKS.includes(raw)) return raw;
|
|
18
25
|
console.error(
|
|
19
|
-
|
|
26
|
+
`${TAG} Invalid ARC_NETWORK="${raw}" - expected one of: ${KNOWN_NETWORKS.join(", ")}. Server will not start.`
|
|
20
27
|
);
|
|
21
28
|
return null;
|
|
22
29
|
}
|
|
23
30
|
function buildAgent() {
|
|
24
31
|
const network = readNetwork();
|
|
25
32
|
if (!network) return null;
|
|
26
|
-
const bountyAdapterAddress = process.env["BOUNTY_ADAPTER_ADDRESS"];
|
|
27
|
-
if (!bountyAdapterAddress) {
|
|
28
|
-
console.error(
|
|
29
|
-
"[arcbounty-mcp] BOUNTY_ADAPTER_ADDRESS not set - server will not start. See contracts/DEPLOYMENTS.md for the canonical address."
|
|
30
|
-
);
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
33
|
const rpcUrl = process.env["ARC_RPC_URL"];
|
|
34
34
|
const circleApiKey = process.env["CIRCLE_API_KEY"];
|
|
35
35
|
const entitySecret = process.env["ENTITY_SECRET"];
|
|
@@ -40,24 +40,23 @@ function buildAgent() {
|
|
|
40
40
|
return new ArcBountyAgent({
|
|
41
41
|
network,
|
|
42
42
|
circleWallet: { apiKey: circleApiKey, entitySecret, walletId: circleWalletId, address: circleWalletAddress },
|
|
43
|
-
bountyAdapterAddress,
|
|
44
43
|
rpcUrl
|
|
45
44
|
});
|
|
46
45
|
}
|
|
47
46
|
if (privateKey) {
|
|
48
|
-
return new ArcBountyAgent({ network, privateKey,
|
|
47
|
+
return new ArcBountyAgent({ network, privateKey, rpcUrl });
|
|
49
48
|
}
|
|
50
49
|
console.error(
|
|
51
|
-
|
|
50
|
+
`${TAG} No signer configured (AGENT_PRIVATE_KEY or CIRCLE_API_KEY+ENTITY_SECRET+CIRCLE_WALLET_ID+CIRCLE_WALLET_ADDRESS) - starting in READ-ONLY mode. take_bounty/submit_work/register_agent/etc. will not be registered.`
|
|
52
51
|
);
|
|
53
52
|
const burner = "0x0000000000000000000000000000000000000000000000000000000000000001";
|
|
54
|
-
return new ArcBountyAgent({ network, privateKey: burner,
|
|
53
|
+
return new ArcBountyAgent({ network, privateKey: burner, rpcUrl });
|
|
55
54
|
}
|
|
56
55
|
var agent;
|
|
57
56
|
try {
|
|
58
57
|
agent = buildAgent();
|
|
59
58
|
} catch (err) {
|
|
60
|
-
console.error(
|
|
59
|
+
console.error(`${TAG} ${err instanceof Error ? err.message : String(err)}`);
|
|
61
60
|
agent = null;
|
|
62
61
|
}
|
|
63
62
|
if (!agent) process.exit(1);
|
|
@@ -92,12 +91,14 @@ function errorResult(err) {
|
|
|
92
91
|
const message = err instanceof Error ? err.message : String(err);
|
|
93
92
|
return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
|
|
94
93
|
}
|
|
95
|
-
var
|
|
96
|
-
var
|
|
94
|
+
var net = agent.network;
|
|
95
|
+
var BRAND = net.brand.name;
|
|
96
|
+
var GAS_NOTE = net.nativeCurrency.isUsdc ? "" : ` Gas on ${net.name} is paid in ${net.nativeCurrency.symbol}, not USDC: this wallet needs a little ${net.nativeCurrency.symbol} on top of any USDC, or the transaction cannot be broadcast at all.`;
|
|
97
|
+
var server = new McpServer({ name: BRAND.toLowerCase(), version: pkg.version });
|
|
97
98
|
server.registerTool(
|
|
98
99
|
"list_open_bounties",
|
|
99
100
|
{
|
|
100
|
-
description:
|
|
101
|
+
description: `List open (unassigned, unresolved, not-yet-expired) bounties on ${BRAND}, the on-chain bounty board running on ${net.name}. Rewards are in USDC. Use this to find work to take on, or to survey the current market.`,
|
|
101
102
|
inputSchema: z.object({
|
|
102
103
|
category: z.enum(["dev", "design", "content", "data", "other"]).optional().describe("Filter by category. Omit for all categories."),
|
|
103
104
|
agentOnly: z.boolean().optional().describe("If true, only bounties restricted to ERC-8004 agents."),
|
|
@@ -169,7 +170,7 @@ if (hasSigner) {
|
|
|
169
170
|
server.registerTool(
|
|
170
171
|
"register_agent",
|
|
171
172
|
{
|
|
172
|
-
description:
|
|
173
|
+
description: `Register this server's configured wallet as an ERC-8004 agent on ${net.name}, pinning the given metadata to IPFS first. Idempotent - if this wallet already has an agentId, returns the existing one without a new on-chain transaction.` + GAS_NOTE,
|
|
173
174
|
inputSchema: z.object({
|
|
174
175
|
name: z.string(),
|
|
175
176
|
description: z.string(),
|
|
@@ -256,7 +257,7 @@ if (hasSigner) {
|
|
|
256
257
|
server.registerTool(
|
|
257
258
|
"take_bounty",
|
|
258
259
|
{
|
|
259
|
-
description: "Claim an open bounty as this server's configured wallet. On-chain and atomic - fails if someone else already took it. Do this only after reviewing the bounty with get_bounty. If the bounty has requireWorkerBond, a refundable USDC bond (workerBondUsdc) is approved and pulled automatically - it is returned in full at submit_work, so only take bonded bounties you intend to finish.",
|
|
260
|
+
description: "Claim an open bounty as this server's configured wallet. On-chain and atomic - fails if someone else already took it. Do this only after reviewing the bounty with get_bounty. If the bounty has requireWorkerBond, a refundable USDC bond (workerBondUsdc) is approved and pulled automatically - it is returned in full at submit_work, so only take bonded bounties you intend to finish." + GAS_NOTE,
|
|
260
261
|
inputSchema: z.object({ jobId: z.string() })
|
|
261
262
|
},
|
|
262
263
|
async ({ jobId }) => {
|
|
@@ -305,9 +306,11 @@ if (hasSigner) {
|
|
|
305
306
|
async function main() {
|
|
306
307
|
const transport = new StdioServerTransport();
|
|
307
308
|
await server.connect(transport);
|
|
308
|
-
console.error(
|
|
309
|
+
console.error(
|
|
310
|
+
`${TAG} ${BRAND} running on stdio - ${net.name} (chain ${net.chainId})${hasSigner ? "" : " - read-only mode, no signer configured"}`
|
|
311
|
+
);
|
|
309
312
|
}
|
|
310
313
|
main().catch((err) => {
|
|
311
|
-
console.error(
|
|
314
|
+
console.error(`${TAG} fatal:`, err);
|
|
312
315
|
process.exit(1);
|
|
313
316
|
});
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arcbounty-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"mcpName": "io.github.Sofiia7/arcbounty-mcp",
|
|
5
|
-
"description": "Put an AI agent to work for USDC. MCP server for
|
|
5
|
+
"description": "Put an AI agent to work for USDC. MCP server for a live on-chain bounty board where agents and humans take the same jobs: browsing needs no credentials, and 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 for every completed job. One package, two networks: Arc (ArcBounty) and Base (BaseBounty).",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"arcbounty-mcp": "
|
|
8
|
+
"arcbounty-mcp": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"main": "./dist/index.js",
|
|
11
11
|
"files": [
|
|
@@ -27,7 +27,8 @@
|
|
|
27
27
|
"dev": "tsx src/index.ts",
|
|
28
28
|
"typecheck": "tsc --noEmit",
|
|
29
29
|
"start": "node dist/index.js",
|
|
30
|
-
"pack:mcpb": "npm run build && rm -rf build-mcpb && mkdir -p build-mcpb/server && cp manifest.json build-mcpb/ && cp -r dist build-mcpb/server/ && cp package.json build-mcpb/server/ && npm install --omit=dev --no-package-lock --prefix build-mcpb/server && npx @anthropic-ai/mcpb pack build-mcpb arcbounty-mcp.mcpb && node patch-mcpb.mjs arcbounty-mcp.mcpb manifest.smithery.json arcbounty-mcp-smithery.mcpb"
|
|
30
|
+
"pack:mcpb": "npm run build && node sync-manifests.mjs && rm -rf build-mcpb && mkdir -p build-mcpb/server && cp manifest.json build-mcpb/ && cp -r dist build-mcpb/server/ && cp package.json build-mcpb/server/ && npm install --omit=dev --no-package-lock --prefix build-mcpb/server && npx @anthropic-ai/mcpb pack build-mcpb arcbounty-mcp.mcpb && node patch-mcpb.mjs arcbounty-mcp.mcpb manifest.smithery.json arcbounty-mcp-smithery.mcpb",
|
|
31
|
+
"sync:manifests": "node sync-manifests.mjs"
|
|
31
32
|
},
|
|
32
33
|
"keywords": [
|
|
33
34
|
"mcp",
|
|
@@ -40,12 +41,15 @@
|
|
|
40
41
|
"agent-payments",
|
|
41
42
|
"autonomous-agents",
|
|
42
43
|
"usdc",
|
|
43
|
-
"x402"
|
|
44
|
+
"x402",
|
|
45
|
+
"base",
|
|
46
|
+
"basebounty",
|
|
47
|
+
"arcbounty"
|
|
44
48
|
],
|
|
45
49
|
"license": "MIT",
|
|
46
50
|
"dependencies": {
|
|
47
51
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
-
"arcbounty-agent-sdk": "^0.6.
|
|
52
|
+
"arcbounty-agent-sdk": "^0.6.2",
|
|
49
53
|
"viem": "^2.0.0",
|
|
50
54
|
"zod": "^3.23.0"
|
|
51
55
|
},
|