arcbounty-mcp 0.2.3 → 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 CHANGED
@@ -1,15 +1,25 @@
1
- # Which Arc network to target. Optional, defaults to "arc-testnet".
2
- # "arc-mainnet" additionally requires the ARC_MAINNET_* variables below -
3
- # the server prints exactly which ones are missing and exits if you select
4
- # arc-mainnet without them (Circle has not published mainnet parameters yet).
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).
5
11
  ARC_NETWORK="arc-testnet"
6
12
 
7
- # Required always
8
- BOUNTY_ADAPTER_ADDRESS="0x538CD48789667168bfb36f838Af8476237F9409F"
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=""
9
19
 
10
20
  # Optional - overrides the RPC endpoint for whichever network ARC_NETWORK
11
- # resolves to. Defaults to the resolved network's own RPC (Arc Testnet's
12
- # public endpoint, or ARC_MAINNET_RPC_URL on arc-mainnet).
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).
13
23
  ARC_RPC_URL="https://rpc.testnet.arc.network"
14
24
 
15
25
  # Worker mode: EITHER a raw private key...
@@ -24,6 +34,14 @@ CIRCLE_WALLET_ADDRESS=""
24
34
  # With none of the above set, the server starts in read-only mode:
25
35
  # list_open_bounties / get_bounty / get_reputation only.
26
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
+
27
45
  # ── Arc MAINNET (ARC_NETWORK=arc-mainnet only; launches 2026-09-16) ──────────
28
46
  # Circle has NOT published mainnet parameters yet - do not guess them. Once
29
47
  # they appear at https://docs.arc.io/arc/references/contract-addresses, set
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
- "BOUNTY_ADAPTER_ADDRESS": "0x538CD48789667168bfb36f838Af8476237F9409F",
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
- | Just `BOUNTY_ADAPTER_ADDRESS` | **Read-only** | `list_open_bounties`, `get_bounty`, `get_reputation` |
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 (ARC/USDC gas + whatever USDC
60
- the agent wants to post bounties with, if it ever does).
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`. The other choice is `arc-mainnet` - see [Networks](#networks) below. |
65
- | `BOUNTY_ADAPTER_ADDRESS` | Required always. Canonical adapter - see [`contracts/DEPLOYMENTS.md`](../contracts/DEPLOYMENTS.md). |
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 Arc network the server (and every tool call) talks
73
- to. It's validated at startup - an unrecognized value prints a clear error
74
- and the server exits rather than falling back silently.
75
-
76
- | `ARC_NETWORK` | Status |
77
- |---|---|
78
- | `arc-testnet` (default) | Works today, zero extra config beyond `BOUNTY_ADAPTER_ADDRESS`. |
79
- | `arc-mainnet` | 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. |
80
-
81
- `BOUNTY_ADAPTER_ADDRESS` and `ARC_RPC_URL` behave the same regardless of
82
- network: `BOUNTY_ADAPTER_ADDRESS` is always required by this server (it's
83
- passed straight through as the SDK's adapter override), and `ARC_RPC_URL`,
84
- if set, always overrides the transport URL for whichever network was
85
- selected.
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 KNOWN_NETWORKS = ["arc-testnet", "arc-mainnet"];
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
- `[arcbounty-mcp] Invalid ARC_NETWORK="${raw}" - expected one of: ${KNOWN_NETWORKS.join(", ")}. Server will not start.`
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, bountyAdapterAddress, rpcUrl });
47
+ return new ArcBountyAgent({ network, privateKey, rpcUrl });
49
48
  }
50
49
  console.error(
51
- "[arcbounty-mcp] 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."
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, bountyAdapterAddress, rpcUrl });
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(`[arcbounty-mcp] ${err instanceof Error ? err.message : String(err)}`);
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 pkg = createRequire(import.meta.url)("../package.json");
96
- var server = new McpServer({ name: "arcbounty", version: pkg.version });
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: "List open (unassigned, unresolved, not-yet-expired) bounties on ArcBounty, the Arc Network bounty board. Rewards are in USDC. Use this to find work to take on, or to survey the current market.",
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: "Register this server's configured wallet as an ERC-8004 agent on Arc, 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.",
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(`[arcbounty-mcp] running on stdio${hasSigner ? "" : " (read-only mode - no signer configured)"}`);
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("[arcbounty-mcp] fatal:", err);
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.2.3",
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 ArcBounty, 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.",
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": "./dist/index.js"
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.0",
52
+ "arcbounty-agent-sdk": "^0.6.2",
49
53
  "viem": "^2.0.0",
50
54
  "zod": "^3.23.0"
51
55
  },