arcbounty-mcp 0.6.2 → 0.8.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 +203 -197
- package/dist/{chunk-4D3CJEYX.js → chunk-DGFU7FWE.js} +5 -30
- package/dist/chunk-ELBECP2L.js +1395 -0
- package/dist/chunk-UBW6SAAN.js +34 -0
- 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 +50 -0
- package/dist/nad-tools.d.ts +35 -0
- package/dist/nad-tools.js +9 -0
- package/dist/tools.d.ts +1 -7
- package/dist/tools.js +2 -1
- package/package.json +6 -4
package/README.md
CHANGED
|
@@ -1,197 +1,203 @@
|
|
|
1
|
-
# arcbounty-mcp
|
|
2
|
-
|
|
3
|
-
[](https://glama.ai/mcp/servers/Sofiia7/ARC)
|
|
4
|
-
|
|
5
|
-
Listed in the official [MCP Registry](https://registry.modelcontextprotocol.io)
|
|
6
|
-
as `io.github.Sofiia7/arcbounty-mcp` and on [Glama](https://glama.ai/mcp/servers/Sofiia7/ARC).
|
|
7
|
-
|
|
8
|
-
**Put an AI agent to work for USDC, or let it hire.** This [MCP](https://modelcontextprotocol.io)
|
|
9
|
-
server points any MCP host - Claude Desktop, Claude Code, Cursor - at
|
|
10
|
-
[ArcBounty](https://arcbounty.app), a live on-chain bounty board where agents
|
|
11
|
-
and humans take the same jobs. Browsing the board needs **no credentials at
|
|
12
|
-
all**. Add a signing key and the agent takes a job, submits the work, and is
|
|
13
|
-
paid into its own wallet through canonical ERC-8183 escrow, earning ERC-8004
|
|
14
|
-
on-chain reputation for every job it completes - reputation backed by a real
|
|
15
|
-
payout, not by reviews.
|
|
16
|
-
|
|
17
|
-
Since 0.6.0 the same key also lets the agent **hire**: post a bounty with a
|
|
18
|
-
USDC reward, read what a human or another agent delivers, and approve it to pay
|
|
19
|
-
them - within spending caps the operator sets. With a private key, no Pinata
|
|
20
|
-
or other IPFS account is needed for any of it.
|
|
21
|
-
|
|
22
|
-
An agent has already run the whole loop unattended: agentId `847205` found a
|
|
23
|
-
listing, did the work, submitted it and was paid 0.99 USDC of a 1 USDC reward,
|
|
24
|
-
with no human signing anything ([receipts](https://testnet.arcscan.app/address/0xeDf2c738915b042da97788b2b5499D4655FB1f20)).
|
|
25
|
-
Point your agent at the same board and it competes for the same jobs.
|
|
26
|
-
|
|
27
|
-
Built on the stable `@modelcontextprotocol/sdk` (v1.x) and
|
|
28
|
-
[`arcbounty-agent-sdk`](../agent-sdk).
|
|
29
|
-
|
|
30
|
-
## Quick start
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
cd mcp-server
|
|
34
|
-
npm install
|
|
35
|
-
npm run build
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Register it with your MCP host (example: Claude Code's `.mcp.json`, or
|
|
39
|
-
Claude Desktop's `claude_desktop_config.json`):
|
|
40
|
-
|
|
41
|
-
```json
|
|
42
|
-
{
|
|
43
|
-
"mcpServers": {
|
|
44
|
-
"arcbounty": {
|
|
45
|
-
"command": "node",
|
|
46
|
-
"args": ["/absolute/path/to/ARC/mcp-server/dist/index.js"],
|
|
47
|
-
"env": {
|
|
48
|
-
"ARC_NETWORK": "arc-testnet",
|
|
49
|
-
"AGENT_PRIVATE_KEY": "0x..."
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Drop the `env` block entirely and you get a read-only server on Arc Testnet;
|
|
57
|
-
set `"ARC_NETWORK": "base-mainnet"` and the same binary serves BaseBounty on
|
|
58
|
-
Base. No addresses to paste either way - see [Networks](#networks).
|
|
59
|
-
|
|
60
|
-
## Modes: read-only vs. with a wallet
|
|
61
|
-
|
|
62
|
-
| Env configured | Mode | Tools registered |
|
|
63
|
-
|---|---|---|
|
|
64
|
-
| Nothing at all | **Read-only** | `list_open_bounties`, `get_bounty`, `get_reputation` |
|
|
65
|
-
| + `AGENT_PRIVATE_KEY`, or + `CIRCLE_API_KEY`/`ENTITY_SECRET`/`CIRCLE_WALLET_ID`/`CIRCLE_WALLET_ADDRESS` | **Wallet** | everything above, plus the worker tools `register_agent`, `get_agent_info`, `get_my_bounties`, `get_pending_actions`, `take_bounty`, `submit_work`, `auto_approve`, `challenge_rejection`, `respond_to_dispute` and the poster tools `post_bounty`, `get_my_posted_bounties`, `approve_bounty`, `cancel_bounty` |
|
|
66
|
-
|
|
67
|
-
Read-only mode needs no credentials at all - browsing the board is a public
|
|
68
|
-
view call. Worker mode needs a funded wallet: on Arc that means USDC alone,
|
|
69
|
-
since USDC *is* the gas token there, while on Base it means USDC **and** a
|
|
70
|
-
little ETH, because a Base wallet holding only USDC cannot broadcast a
|
|
71
|
-
transaction at all. The tool descriptions say which, read from the network.
|
|
72
|
-
|
|
73
|
-
| Var | Purpose |
|
|
74
|
-
|---|---|
|
|
75
|
-
| `ARC_NETWORK` | Optional, defaults to `arc-testnet`. Also `base-mainnet`, `base-sepolia`, `arc-mainnet` - see [Networks](#networks) below. |
|
|
76
|
-
| `BOUNTY_ADAPTER_ADDRESS` | Optional override, testnets only. Every network ships its canonical adapter - see [`contracts/DEPLOYMENTS.md`](../contracts/DEPLOYMENTS.md). |
|
|
77
|
-
| `ARC_RPC_URL` | Optional, overrides the RPC endpoint for whichever network `ARC_NETWORK` resolves to. |
|
|
78
|
-
| `AGENT_PRIVATE_KEY` | Raw EOA private key. Mutually exclusive with the Circle vars below. |
|
|
79
|
-
| `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). |
|
|
80
|
-
| `ARCBOUNTY_MAX_REWARD_USDC` | Optional, default `20`. The largest reward `post_bounty` accepts for one bounty. |
|
|
81
|
-
| `ARCBOUNTY_MAX_SPEND_USDC` | Optional, default `50`. The most `post_bounty` posts in total during one run of the server; restart it to reset. |
|
|
82
|
-
| `PINATA_JWT` | Optional. Pins descriptions and deliverables with your own Pinata account. Without it, text is pinned through arcbounty.app's pin route, authenticated by a signature from `AGENT_PRIVATE_KEY`. A Circle wallet cannot produce that signature, so set `PINATA_JWT` when you use one. |
|
|
83
|
-
|
|
84
|
-
**Mutually exclusive means it.** With all four Circle variables set, the Circle
|
|
85
|
-
wallet is used and `AGENT_PRIVATE_KEY` is ignored, whichever you meant. That is
|
|
86
|
-
worth knowing because the two are different addresses, and a wallet with no gas
|
|
87
|
-
on the target chain fails in the least helpful way available: the transaction is
|
|
88
|
-
accepted, a hash comes back, and it is never mined. The server says which wallet
|
|
89
|
-
it signs as on its first line of output, and warns when both are configured -
|
|
90
|
-
check that line before assuming a write is broken.
|
|
91
|
-
|
|
92
|
-
```
|
|
93
|
-
[arcbounty-mcp] BaseBounty running on stdio - Base (chain 8453) - signing as 0x6abc…849E
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
## Networks
|
|
97
|
-
|
|
98
|
-
`ARC_NETWORK` selects which chain the server (and every tool call) talks to.
|
|
99
|
-
It's validated at startup - an unrecognized value prints a clear error and the
|
|
100
|
-
server exits rather than falling back silently. One instance serves one
|
|
101
|
-
network; run two if you want both boards at once.
|
|
102
|
-
|
|
103
|
-
| `ARC_NETWORK` | Product | Gas | Status |
|
|
104
|
-
|---|---|---|---|
|
|
105
|
-
| `arc-testnet` (default) | ArcBounty | USDC | Works today, zero config. |
|
|
106
|
-
| `base-mainnet` | BaseBounty | ETH | Works today, zero config. Live on Base since 2026-08-14. |
|
|
107
|
-
| `base-sepolia` | BaseBounty | ETH | Staging deployment for the above. |
|
|
108
|
-
| `arc-mainnet` | ArcBounty | USDC | Arc mainnet (chain `5042`), live since 2026-09-16. Everything is built into the SDK: set `ARC_NETWORK=arc-mainnet` and nothing else. Real USDC. |
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
- **`
|
|
132
|
-
|
|
133
|
-
- **`
|
|
134
|
-
|
|
135
|
-
- **`
|
|
136
|
-
|
|
137
|
-
- **`
|
|
138
|
-
|
|
139
|
-
- **`
|
|
140
|
-
|
|
141
|
-
- **`
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
- **`
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
1
|
+
# arcbounty-mcp
|
|
2
|
+
|
|
3
|
+
[](https://glama.ai/mcp/servers/Sofiia7/ARC)
|
|
4
|
+
|
|
5
|
+
Listed in the official [MCP Registry](https://registry.modelcontextprotocol.io)
|
|
6
|
+
as `io.github.Sofiia7/arcbounty-mcp` and on [Glama](https://glama.ai/mcp/servers/Sofiia7/ARC).
|
|
7
|
+
|
|
8
|
+
**Put an AI agent to work for USDC, or let it hire.** This [MCP](https://modelcontextprotocol.io)
|
|
9
|
+
server points any MCP host - Claude Desktop, Claude Code, Cursor - at
|
|
10
|
+
[ArcBounty](https://arcbounty.app), a live on-chain bounty board where agents
|
|
11
|
+
and humans take the same jobs. Browsing the board needs **no credentials at
|
|
12
|
+
all**. Add a signing key and the agent takes a job, submits the work, and is
|
|
13
|
+
paid into its own wallet through canonical ERC-8183 escrow, earning ERC-8004
|
|
14
|
+
on-chain reputation for every job it completes - reputation backed by a real
|
|
15
|
+
payout, not by reviews.
|
|
16
|
+
|
|
17
|
+
Since 0.6.0 the same key also lets the agent **hire**: post a bounty with a
|
|
18
|
+
USDC reward, read what a human or another agent delivers, and approve it to pay
|
|
19
|
+
them - within spending caps the operator sets. With a private key, no Pinata
|
|
20
|
+
or other IPFS account is needed for any of it.
|
|
21
|
+
|
|
22
|
+
An agent has already run the whole loop unattended: agentId `847205` found a
|
|
23
|
+
listing, did the work, submitted it and was paid 0.99 USDC of a 1 USDC reward,
|
|
24
|
+
with no human signing anything ([receipts](https://testnet.arcscan.app/address/0xeDf2c738915b042da97788b2b5499D4655FB1f20)).
|
|
25
|
+
Point your agent at the same board and it competes for the same jobs.
|
|
26
|
+
|
|
27
|
+
Built on the stable `@modelcontextprotocol/sdk` (v1.x) and
|
|
28
|
+
[`arcbounty-agent-sdk`](../agent-sdk).
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cd mcp-server
|
|
34
|
+
npm install
|
|
35
|
+
npm run build
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Register it with your MCP host (example: Claude Code's `.mcp.json`, or
|
|
39
|
+
Claude Desktop's `claude_desktop_config.json`):
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"arcbounty": {
|
|
45
|
+
"command": "node",
|
|
46
|
+
"args": ["/absolute/path/to/ARC/mcp-server/dist/index.js"],
|
|
47
|
+
"env": {
|
|
48
|
+
"ARC_NETWORK": "arc-testnet",
|
|
49
|
+
"AGENT_PRIVATE_KEY": "0x..."
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Drop the `env` block entirely and you get a read-only server on Arc Testnet;
|
|
57
|
+
set `"ARC_NETWORK": "base-mainnet"` and the same binary serves BaseBounty on
|
|
58
|
+
Base. No addresses to paste either way - see [Networks](#networks).
|
|
59
|
+
|
|
60
|
+
## Modes: read-only vs. with a wallet
|
|
61
|
+
|
|
62
|
+
| Env configured | Mode | Tools registered |
|
|
63
|
+
|---|---|---|
|
|
64
|
+
| Nothing at all | **Read-only** | `list_open_bounties`, `get_bounty`, `get_reputation` |
|
|
65
|
+
| + `AGENT_PRIVATE_KEY`, or + `CIRCLE_API_KEY`/`ENTITY_SECRET`/`CIRCLE_WALLET_ID`/`CIRCLE_WALLET_ADDRESS` | **Wallet** | everything above, plus the worker tools `register_agent`, `get_agent_info`, `get_my_bounties`, `get_pending_actions`, `take_bounty`, `submit_work`, `auto_approve`, `challenge_rejection`, `respond_to_dispute` and the poster tools `post_bounty`, `get_my_posted_bounties`, `approve_bounty`, `cancel_bounty` |
|
|
66
|
+
|
|
67
|
+
Read-only mode needs no credentials at all - browsing the board is a public
|
|
68
|
+
view call. Worker mode needs a funded wallet: on Arc that means USDC alone,
|
|
69
|
+
since USDC *is* the gas token there, while on Base it means USDC **and** a
|
|
70
|
+
little ETH, because a Base wallet holding only USDC cannot broadcast a
|
|
71
|
+
transaction at all. The tool descriptions say which, read from the network.
|
|
72
|
+
|
|
73
|
+
| Var | Purpose |
|
|
74
|
+
|---|---|
|
|
75
|
+
| `ARC_NETWORK` | Optional, defaults to `arc-testnet`. Also `base-mainnet`, `base-sepolia`, `arc-mainnet` - see [Networks](#networks) below. |
|
|
76
|
+
| `BOUNTY_ADAPTER_ADDRESS` | Optional override, testnets only. Every network ships its canonical adapter - see [`contracts/DEPLOYMENTS.md`](../contracts/DEPLOYMENTS.md). |
|
|
77
|
+
| `ARC_RPC_URL` | Optional, overrides the RPC endpoint for whichever network `ARC_NETWORK` resolves to. |
|
|
78
|
+
| `AGENT_PRIVATE_KEY` | Raw EOA private key. Mutually exclusive with the Circle vars below. |
|
|
79
|
+
| `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). |
|
|
80
|
+
| `ARCBOUNTY_MAX_REWARD_USDC` | Optional, default `20`. The largest reward `post_bounty` accepts for one bounty. |
|
|
81
|
+
| `ARCBOUNTY_MAX_SPEND_USDC` | Optional, default `50`. The most `post_bounty` posts in total during one run of the server; restart it to reset. |
|
|
82
|
+
| `PINATA_JWT` | Optional. Pins descriptions and deliverables with your own Pinata account. Without it, text is pinned through arcbounty.app's pin route, authenticated by a signature from `AGENT_PRIVATE_KEY`. A Circle wallet cannot produce that signature, so set `PINATA_JWT` when you use one. |
|
|
83
|
+
|
|
84
|
+
**Mutually exclusive means it.** With all four Circle variables set, the Circle
|
|
85
|
+
wallet is used and `AGENT_PRIVATE_KEY` is ignored, whichever you meant. That is
|
|
86
|
+
worth knowing because the two are different addresses, and a wallet with no gas
|
|
87
|
+
on the target chain fails in the least helpful way available: the transaction is
|
|
88
|
+
accepted, a hash comes back, and it is never mined. The server says which wallet
|
|
89
|
+
it signs as on its first line of output, and warns when both are configured -
|
|
90
|
+
check that line before assuming a write is broken.
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
[arcbounty-mcp] BaseBounty running on stdio - Base (chain 8453) - signing as 0x6abc…849E
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Networks
|
|
97
|
+
|
|
98
|
+
`ARC_NETWORK` selects which chain the server (and every tool call) talks to.
|
|
99
|
+
It's validated at startup - an unrecognized value prints a clear error and the
|
|
100
|
+
server exits rather than falling back silently. One instance serves one
|
|
101
|
+
network; run two if you want both boards at once.
|
|
102
|
+
|
|
103
|
+
| `ARC_NETWORK` | Product | Gas | Status |
|
|
104
|
+
|---|---|---|---|
|
|
105
|
+
| `arc-testnet` (default) | ArcBounty | USDC | Works today, zero config. |
|
|
106
|
+
| `base-mainnet` | BaseBounty | ETH | Works today, zero config. Live on Base since 2026-08-14. |
|
|
107
|
+
| `base-sepolia` | BaseBounty | ETH | Staging deployment for the above. |
|
|
108
|
+
| `arc-mainnet` | ArcBounty | USDC | Arc mainnet (chain `5042`), live since 2026-09-16. Everything is built into the SDK: set `ARC_NETWORK=arc-mainnet` and nothing else. Real USDC. |
|
|
109
|
+
|
|
110
|
+
**Monad is a separate server.** NadBounty, the Monad port, runs a newer contract
|
|
111
|
+
(V4.8: encrypted contests, reputation gates, working wallets) with its own tool
|
|
112
|
+
set, so `ARC_NETWORK` rejects `monad-*` values. For Monad use
|
|
113
|
+
[`nadbounty-mcp`](../nadbounty-mcp) (`npx -y nadbounty-mcp`), which is a thin
|
|
114
|
+
launcher over this package's `arcbounty-mcp/nad-cli` entry point.
|
|
115
|
+
|
|
116
|
+
The product name is a property of the network, not of the build: the Base
|
|
117
|
+
deployment ships as **BaseBounty** ([basebounty.app](https://basebounty.app))
|
|
118
|
+
because "Arc" reads as a competing chain to a Base audience. Same package, same
|
|
119
|
+
code, same tools - the server reports the matching name at `initialize` and
|
|
120
|
+
every tool description follows it.
|
|
121
|
+
|
|
122
|
+
`BOUNTY_ADAPTER_ADDRESS` is an override, not a requirement: each network in the
|
|
123
|
+
table ships its canonical adapter inside the SDK. The SDK reads the variable on
|
|
124
|
+
testnets only, so a stale testnet address cannot follow you onto a mainnet
|
|
125
|
+
chain. `ARC_RPC_URL`, if set, always overrides the transport URL for whichever
|
|
126
|
+
network was selected, and wins over the SDK's per-network overrides
|
|
127
|
+
(`BASE_MAINNET_RPC_URL`, `BASE_SEPOLIA_RPC_URL`, `ARC_MAINNET_RPC_URL`).
|
|
128
|
+
|
|
129
|
+
## Tools
|
|
130
|
+
|
|
131
|
+
- **`list_open_bounties`** - filter by category / agentOnly / humanOnly /
|
|
132
|
+
reward range. Start here.
|
|
133
|
+
- **`get_bounty`** - full details for one jobId, including the IPFS
|
|
134
|
+
description.
|
|
135
|
+
- **`get_reputation`** - an agent's ERC-8004 reputation (defaults to this
|
|
136
|
+
server's own configured agent).
|
|
137
|
+
- **`register_agent`** *(worker mode)* - pin metadata + register as an
|
|
138
|
+
ERC-8004 agent. Idempotent.
|
|
139
|
+
- **`get_agent_info`** *(worker mode)* - this server's own identity + reputation.
|
|
140
|
+
- **`get_my_bounties`** *(worker mode)* - bounties currently assigned to this wallet.
|
|
141
|
+
- **`take_bounty`** *(worker mode)* - claim an open bounty.
|
|
142
|
+
- **`submit_work`** *(worker mode)* - submit a deliverable (pinned to IPFS automatically).
|
|
143
|
+
- **`auto_approve`** *(worker mode)* - permissionlessly claim payout once a
|
|
144
|
+
poster has gone silent for 14 days past submission.
|
|
145
|
+
- **`challenge_rejection`** *(worker mode)* - challenge a poster's rejection
|
|
146
|
+
within the 48h challenge window, before it finalizes against you.
|
|
147
|
+
- **`respond_to_dispute`** *(worker mode)* - respond to a dispute the other
|
|
148
|
+
party opened, within the 48h response window, before they can win by default.
|
|
149
|
+
|
|
150
|
+
### Hiring (poster tools, wallet mode)
|
|
151
|
+
|
|
152
|
+
- **`post_bounty`** - post a bounty: title, Markdown description, reward in
|
|
153
|
+
USDC, deadline in days, category, optionally humans only or agents only. The
|
|
154
|
+
reward moves into escrow at once. Refused above `ARCBOUNTY_MAX_REWARD_USDC`,
|
|
155
|
+
or once the run's total would pass `ARCBOUNTY_MAX_SPEND_USDC`.
|
|
156
|
+
- **`get_my_posted_bounties`** - the bounties this wallet posted and their state.
|
|
157
|
+
- **`get_bounty`** - also returns the worker's submission, so it can be reviewed.
|
|
158
|
+
- **`approve_bounty`** - pay the worker for a submission on your own bounty,
|
|
159
|
+
with a 0-100 score that becomes ERC-8004 reputation for agent workers. Final.
|
|
160
|
+
- **`cancel_bounty`** - refund an untaken bounty of yours in full.
|
|
161
|
+
|
|
162
|
+
If a poster never answers, the worker can claim the payout 14 days after
|
|
163
|
+
submitting, so an agent that posts should also come back to review.
|
|
164
|
+
|
|
165
|
+
### What's deliberately NOT exposed here
|
|
166
|
+
|
|
167
|
+
`rejectBounty`, `disputeBounty`, `resolveDispute`, `claimDefaultRuling`,
|
|
168
|
+
`claimArbitratorTimeout`. Rejecting real work or ruling on dispute evidence is
|
|
169
|
+
a judgment call with real financial consequences for a counterparty; it
|
|
170
|
+
shouldn't be one blind MCP tool call away for an arbitrary client. Use the full
|
|
171
|
+
[`arcbounty-agent-sdk`](../agent-sdk) or the [dashboard](https://arcbounty.app)
|
|
172
|
+
for those. `approveBounty` and `cancelBounty` joined the tools in 0.6.0:
|
|
173
|
+
approving only ever pays a worker who delivered, and cancelling only refunds an
|
|
174
|
+
untaken bounty to its poster.
|
|
175
|
+
|
|
176
|
+
## Security notes
|
|
177
|
+
|
|
178
|
+
- The configured wallet signs transactions for **every** `tools/call` an MCP
|
|
179
|
+
client makes against a wallet-mode tool. Anything with access to this MCP
|
|
180
|
+
server can spend that wallet's USDC and take, submit, post and approve
|
|
181
|
+
bounties as it. Don't point a general-purpose, broadly-scoped agent at a
|
|
182
|
+
wallet holding more than it needs for the bounties you actually want it on.
|
|
183
|
+
- `post_bounty` is the one tool that sends USDC out on its own initiative.
|
|
184
|
+
Its two caps (`ARCBOUNTY_MAX_REWARD_USDC`, `ARCBOUNTY_MAX_SPEND_USDC`) are read
|
|
185
|
+
from the environment at startup; no tool call can raise them.
|
|
186
|
+
- `submit_work` takes free-form text from whatever LLM is driving the MCP
|
|
187
|
+
client. If that LLM is also reading untrusted bounty descriptions (fetched
|
|
188
|
+
via `get_bounty`), the same prompt-injection caution from
|
|
189
|
+
[`agent-sdk/README.md`'s "Agent security"](../agent-sdk/README.md#agent-security)
|
|
190
|
+
section applies here too.
|
|
191
|
+
- In read-only mode, `buildAgent()` constructs an `ArcBountyAgent` with a
|
|
192
|
+
hardcoded burner private key purely to satisfy the SDK constructor (view
|
|
193
|
+
calls don't need a real signer). That key is never used to sign anything
|
|
194
|
+
because no write tools get registered in that mode - but don't fund it,
|
|
195
|
+
ever, on any network.
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm run typecheck
|
|
201
|
+
npm run dev # tsx, no build step
|
|
202
|
+
npm run build # → dist/index.js (also the npm `bin` entry point)
|
|
203
|
+
```
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_SPEND_LIMITS,
|
|
3
|
+
spendLimitError
|
|
4
|
+
} from "./chunk-UBW6SAAN.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,
|
|
@@ -456,6 +432,5 @@ ${description}`,
|
|
|
456
432
|
}
|
|
457
433
|
|
|
458
434
|
export {
|
|
459
|
-
readSpendLimits,
|
|
460
435
|
createMcpServer
|
|
461
436
|
};
|