@arcpaylabs/arbitrum-mcp 0.1.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 ADDED
@@ -0,0 +1,53 @@
1
+ # ArcPay Arbitrum MCP
2
+
3
+ Local MCP server for ArcPay Arbitrum. It exposes safe developer tools for Arbitrum Sepolia deployments, x402 payment gates, invoice IDs, claim hashes, privacy commitments, and repeatable demo paths.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install -g @arcpaylabs/arbitrum-mcp
9
+ ```
10
+
11
+ ## Claude Desktop
12
+
13
+ Add this to your Claude Desktop MCP config:
14
+
15
+ ```json
16
+ {
17
+ "mcpServers": {
18
+ "arcpay-arbitrum": {
19
+ "command": "arcpay-arbitrum-mcp"
20
+ }
21
+ }
22
+ }
23
+ ```
24
+
25
+ Restart Claude Desktop after editing the config.
26
+
27
+ ## Tools
28
+
29
+ - `get_deployment`
30
+ - `derive_agent_id`
31
+ - `derive_invoice_id`
32
+ - `derive_claim_hash`
33
+ - `derive_privacy_commitment`
34
+ - `privacy_intent_guide`
35
+ - `invoice_guide`
36
+ - `x402_guide`
37
+ - `execution_handoff`
38
+ - `gmx_execution_plan`
39
+ - `zerodev_session_policy`
40
+ - `dune_evidence_spec`
41
+ - `fhenix_privacy_boundary`
42
+ - `demo_path`
43
+ - `smoke_commands`
44
+
45
+ ## Hosted Surfaces
46
+
47
+ - App: https://arcpay-arbitrum.vercel.app
48
+ - Docs: https://arcpay-arbitrum.vercel.app/docs/overview
49
+ - OpenAPI: https://arcpay-arbitrum.vercel.app/openapi.json
50
+ - llms.txt: https://arcpay-arbitrum.vercel.app/llms.txt
51
+ - x402: https://arcpay-arbitrum.vercel.app/api
52
+
53
+ The MCP server does not sign transactions or mutate treasury state. It only returns deterministic IDs, integration guidance, and public deployment metadata.
@@ -0,0 +1,25 @@
1
+ {
2
+ "network": "arbitrum-sepolia",
3
+ "chainId": 421614,
4
+ "deployer": "0xB883e76A4f6841E72cAF1C28ba00f78df974f448",
5
+ "deployedAt": "2026-05-30T14:05:55.746Z",
6
+ "contracts": {
7
+ "AgentRegistry": "0x5F5b8109c832BB6609178F0bb2e6A597387dA17E",
8
+ "TreasuryPolicy": "0x3F8bc2b46E7b71632CdADd1f00d4FD6BB11d8283",
9
+ "AgentTreasury": "0xe472A6367ab66C271aa47cA5882E919c0DEA0ff2",
10
+ "AgentOrderBook": "0x3587fd962d40433165d5f2a3dFc60636ebD11e59",
11
+ "OperatorControls": "0x0cbafFF48ac25178bd10D1cE851C04CCa4Fe387e",
12
+ "ArbitrumAgentRiskOracle": "0x176018C6C8c445807FE3688f463487E4b01C8ae3",
13
+ "AgentSpendCardVault": "0x7C7304bC2D7bB39800eFE7Cdd9c79C7Afd04acF0",
14
+ "ArbitrumPrivacyVault": "0xCBa6Fa24a02F11fE0cd9F16B50e883fE1B4D40Eb",
15
+ "AgentInvoiceBook": "0x487CbD73e298721a83ff460Eb56645C61BEb0f79",
16
+ "AgentReputationBook": "0xDdbe6aD2652BD5d0Ab4D8a6D2ab8798Cf294D9dD",
17
+ "AgentIdentity8004": "0xA6c4C9c5479553450F60663E5D8046f9E2CBF37D",
18
+ "ArbitrumExecutionRouter": "0x463152158F32aFeedCe58a6BbD19F8ECfA702d8e",
19
+ "MockUSDC": "0xd4Ae4c23A308024e2F2d7531cF395365eF67dE20",
20
+ "MockArbitrumAgentPlatform": "0x2D8bb0EBAa850626d2cEFA15bB3A7761B7F86196"
21
+ },
22
+ "arbitrumAgentPlatform": "0x2D8bb0EBAa850626d2cEFA15bB3A7761B7F86196",
23
+ "arbitrumRiskAgentId": "13174292974160097713",
24
+ "usdcToken": "0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d"
25
+ }
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@arcpaylabs/arbitrum-mcp",
3
+ "version": "0.1.0",
4
+ "private": false,
5
+ "description": "MCP server for ArcPay Arbitrum contracts, x402, privacy intents, invoices, and demo flows.",
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "author": "Henry Sam Marfo <jasonneil4040@gmail.com>",
9
+ "homepage": "https://arcpay-arbitrum.vercel.app/docs/mcp",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/ArcPayLabs/arcpay-arbitrum.git",
13
+ "directory": "apps/mcp"
14
+ },
15
+ "bin": {
16
+ "arcpay-arbitrum-mcp": "server.mjs"
17
+ },
18
+ "files": [
19
+ "README.md",
20
+ "server.mjs",
21
+ "deployment.json"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
26
+ "scripts": {
27
+ "start": "node server.mjs",
28
+ "pack:dry": "npm pack --dry-run"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.18.2",
32
+ "ethers": "^6.13.5",
33
+ "zod": "^3.25.76"
34
+ },
35
+ "overrides": {
36
+ "ws": "^8.20.1"
37
+ }
38
+ }
package/server.mjs ADDED
@@ -0,0 +1,303 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import { id, keccak256, toUtf8Bytes } from "ethers";
8
+ import { z } from "zod";
9
+
10
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ const root = path.resolve(__dirname, "../..");
12
+ const deploymentPath = path.join(root, "deployments", "arbitrum-sepolia.json");
13
+ const packagedDeploymentPath = path.join(__dirname, "deployment.json");
14
+
15
+ function readDeployment() {
16
+ const file = fs.existsSync(deploymentPath) ? deploymentPath : packagedDeploymentPath;
17
+ return JSON.parse(fs.readFileSync(file, "utf8"));
18
+ }
19
+
20
+ const server = new McpServer({
21
+ name: "arcpay-arbitrum",
22
+ version: "0.1.0",
23
+ });
24
+
25
+ server.tool("get_deployment", "Return Arbitrum Sepolia contract addresses and network metadata.", {}, async () => ({
26
+ content: [{ type: "text", text: JSON.stringify(readDeployment(), null, 2) }],
27
+ }));
28
+
29
+ server.tool("derive_agent_id", "Derive the bytes32 agent id used by AgentRegistry.", {
30
+ slug: z.string().min(1),
31
+ }, async ({ slug }) => ({
32
+ content: [{ type: "text", text: id(slug) }],
33
+ }));
34
+
35
+ server.tool("derive_invoice_id", "Derive the bytes32 invoice id used by AgentInvoiceBook.", {
36
+ publicId: z.string().min(1),
37
+ }, async ({ publicId }) => ({
38
+ content: [{ type: "text", text: keccak256(toUtf8Bytes(publicId)) }],
39
+ }));
40
+
41
+ server.tool("derive_claim_hash", "Derive the on-chain claim-code hash for OperatorControls.", {
42
+ code: z.string().min(1),
43
+ }, async ({ code }) => ({
44
+ content: [{ type: "text", text: keccak256(toUtf8Bytes(code)) }],
45
+ }));
46
+
47
+ server.tool("derive_privacy_commitment", "Derive a Privacy Intent commitment or nullifier from secret text.", {
48
+ secret: z.string().min(1),
49
+ }, async ({ secret }) => ({
50
+ content: [{ type: "text", text: keccak256(toUtf8Bytes(secret)) }],
51
+ }));
52
+
53
+ server.tool("privacy_intent_guide", "Return builder instructions for integrating ArcPay Privacy Intents on Arbitrum.", {}, async () => {
54
+ const deployment = readDeployment();
55
+ return {
56
+ content: [{
57
+ type: "text",
58
+ text: [
59
+ "ArcPay Privacy Intents for Arbitrum",
60
+ `Vault: ${deployment.contracts.ArbitrumPrivacyVault}`,
61
+ `USDC: ${deployment.usdcToken}`,
62
+ "commitment = keccak256(secret)",
63
+ "nullifier = keccak256(releaseSecret)",
64
+ "USDC flow: approve vault, then createTokenIntent(commitment, USDC, amount, encryptedMemoUri).",
65
+ "ETH flow: createNativeIntent(commitment, encryptedMemoUri) with msg.value.",
66
+ "Release: releaseIntent(commitment, nullifier, recipient).",
67
+ "Boundary: this hides metadata/recipient during intent phase, not a full shielded pool.",
68
+ ].join("\n"),
69
+ }],
70
+ };
71
+ });
72
+
73
+ server.tool("invoice_guide", "Return builder instructions for ArcPay ETH/USDC invoices on Arbitrum.", {}, async () => {
74
+ const deployment = readDeployment();
75
+ return {
76
+ content: [{
77
+ type: "text",
78
+ text: [
79
+ "ArcPay Arbitrum Invoices",
80
+ `InvoiceBook: ${deployment.contracts.AgentInvoiceBook}`,
81
+ `USDC: ${deployment.usdcToken}`,
82
+ "invoiceId = keccak256(publicInvoiceId)",
83
+ "Create ETH invoice: createInvoice(invoiceId, payerOrZero, address(0), amountWei, metadataUri).",
84
+ "Create USDC invoice: createInvoice(invoiceId, payerOrZero, USDC, amountBaseUnits, metadataUri).",
85
+ "Pay ETH: payNativeInvoice(invoiceId) with exact msg.value.",
86
+ "Pay USDC: approve InvoiceBook, then payTokenInvoice(invoiceId).",
87
+ "Cancel unpaid: issuer calls cancelInvoice(invoiceId).",
88
+ "Proof: npm run smoke:live includes on-chain invoice settlement.",
89
+ ].join("\n"),
90
+ }],
91
+ };
92
+ });
93
+
94
+ server.tool("x402_guide", "Return builder instructions for the ArcPay Arbitrum x402 payment-gated agent server.", {}, async () => {
95
+ const deployment = readDeployment();
96
+ return {
97
+ content: [{
98
+ type: "text",
99
+ text: [
100
+ "ArcPay Arbitrum x402",
101
+ `OrderBook: ${deployment.contracts.AgentOrderBook}`,
102
+ `Registry: ${deployment.contracts.AgentRegistry}`,
103
+ "Run: npm run x402",
104
+ "Protected resource: GET /agent/:slug/work",
105
+ "No order returns HTTP 402 with exact ETH payment requirements.",
106
+ "Pay by calling AgentOrderBook.createOrder(agentId, requestUri) with quoted msg.value.",
107
+ "Verify: POST /x402/verify with { orderId, agentSlug }.",
108
+ "Unlock: GET /agent/:slug/work?orderId=... after Fulfilled or Settled.",
109
+ "Proof: npm run smoke:x402.",
110
+ ].join("\n"),
111
+ }],
112
+ };
113
+ });
114
+
115
+ server.tool("execution_handoff", "Return an Arbitrum execution handoff payload for GMX, Stylus policy checks, ZeroDev smart accounts, Dune evidence, or manual execution.", {
116
+ strategyName: z.string().optional(),
117
+ agentSlug: z.string().optional(),
118
+ budgetEth: z.string().optional(),
119
+ adapter: z.string().optional(),
120
+ }, async ({ strategyName = "arcpay-arbitrum-cfo", agentSlug = "treasury-router", budgetEth = "0.02", adapter = "GMX execution intent" }) => {
121
+ const deployment = readDeployment();
122
+ return {
123
+ content: [{
124
+ type: "text",
125
+ text: JSON.stringify({
126
+ protocol: "arcpay-arbitrum-execution-handoff",
127
+ chain: "arbitrum-sepolia",
128
+ chainId: 421614,
129
+ adapter,
130
+ executionAddress: "set-after-wallet-or-smart-account-connection",
131
+ primaryVenue: "GMX",
132
+ strategyName,
133
+ agentSlug,
134
+ objective: "Execute only policy-approved Arbitrum treasury work through ArcPay x402, escrow, privacy, invoice, reputation, and audit modules.",
135
+ constraints: {
136
+ maxBudgetEth: budgetEth,
137
+ allowedAssets: ["ETH", "USDC", "WETH"],
138
+ allowedVenues: ["GMX", "Stylus policy module", "ZeroDev smart account", "Dune evidence", "Manual signer"],
139
+ requireArcPayPolicy: true,
140
+ requireOperatorApprovalForLeverage: true,
141
+ requireExecutionEvidence: true,
142
+ requireArbiscanTxHashForCompletion: true,
143
+ noCompletionWithoutTxHashOrOrderEvidence: true,
144
+ },
145
+ endpoints: {
146
+ x402Gateway: "https://arcpay-arbitrum.vercel.app/api",
147
+ protectedResource: `https://arcpay-arbitrum.vercel.app/api/agent/${encodeURIComponent(agentSlug)}/work`,
148
+ status: "https://arcpay-arbitrum.vercel.app/api/status",
149
+ openapi: "https://arcpay-arbitrum.vercel.app/openapi.json",
150
+ },
151
+ contracts: {
152
+ registry: deployment.contracts.AgentRegistry,
153
+ orderBook: deployment.contracts.AgentOrderBook,
154
+ policy: deployment.contracts.TreasuryPolicy,
155
+ privacyVault: deployment.contracts.ArbitrumPrivacyVault,
156
+ reputation: deployment.contracts.AgentReputationBook,
157
+ identity8004: deployment.contracts.AgentIdentity8004,
158
+ executionRouter: deployment.contracts.ArbitrumExecutionRouter,
159
+ },
160
+ setup: [
161
+ "Register or select an ArcPay agent identity.",
162
+ "Choose an execution adapter: GMX intent, Stylus policy check, ZeroDev smart account, Dune evidence, or manual signer.",
163
+ "Create the x402 quote or escrow order before work starts.",
164
+ "Execute only after policy approval and budget checks.",
165
+ "Attach Arbiscan tx hash, x402 verification, Dune query link, or signed result evidence before marking the work complete.",
166
+ ],
167
+ }, null, 2),
168
+ }],
169
+ };
170
+ });
171
+
172
+ server.tool("gmx_execution_plan", "Create a policy-bounded GMX execution plan for an Arbitrum agent before any trade or hedge is signed.", {
173
+ market: z.string().optional(),
174
+ collateral: z.string().optional(),
175
+ sizeUsd: z.string().optional(),
176
+ maxLeverage: z.string().optional(),
177
+ }, async ({ market = "ETH/USD", collateral = "USDC", sizeUsd = "25", maxLeverage = "1.2x" }) => {
178
+ const deployment = readDeployment();
179
+ return {
180
+ content: [{
181
+ type: "text",
182
+ text: JSON.stringify({
183
+ protocol: "arcpay-gmx-execution-plan",
184
+ chain: "arbitrum-sepolia",
185
+ venue: "GMX",
186
+ market,
187
+ collateral,
188
+ sizeUsd,
189
+ maxLeverage,
190
+ controls: {
191
+ requireArcPayPolicy: true,
192
+ requireExecutionRouterIntent: true,
193
+ requireOperatorApprovalForLeverage: true,
194
+ requireArbiscanTxHash: true,
195
+ requireDuneEvidenceLink: true,
196
+ },
197
+ contracts: {
198
+ executionRouter: deployment.contracts.ArbitrumExecutionRouter,
199
+ policy: deployment.contracts.TreasuryPolicy,
200
+ orderBook: deployment.contracts.AgentOrderBook,
201
+ },
202
+ }, null, 2),
203
+ }],
204
+ };
205
+ });
206
+
207
+ server.tool("zerodev_session_policy", "Return a ZeroDev smart-account session policy for bounded ArcPay agent actions.", {
208
+ agentSlug: z.string().optional(),
209
+ budgetEth: z.string().optional(),
210
+ expiresInMinutes: z.number().optional(),
211
+ }, async ({ agentSlug = "treasury-router", budgetEth = "0.02", expiresInMinutes = 60 }) => {
212
+ const deployment = readDeployment();
213
+ return {
214
+ content: [{
215
+ type: "text",
216
+ text: JSON.stringify({
217
+ protocol: "arcpay-zerodev-session-policy",
218
+ chain: "arbitrum-sepolia",
219
+ agentSlug,
220
+ accountAbstraction: "ZeroDev",
221
+ sessionScope: {
222
+ allowedContracts: [
223
+ deployment.contracts.AgentOrderBook,
224
+ deployment.contracts.TreasuryPolicy,
225
+ deployment.contracts.ArbitrumExecutionRouter,
226
+ deployment.contracts.ArbitrumPrivacyVault,
227
+ ],
228
+ maxBudgetEth: budgetEth,
229
+ expiresInMinutes,
230
+ blockedActions: ["unbounded leverage", "unknown target contract", "execution without evidence URI"],
231
+ },
232
+ }, null, 2),
233
+ }],
234
+ };
235
+ });
236
+
237
+ server.tool("dune_evidence_spec", "Return the Dune dashboard/query schema ArcPay expects for public Arbitrum proof analytics.", {}, async () => ({
238
+ content: [{
239
+ type: "text",
240
+ text: JSON.stringify({
241
+ protocol: "arcpay-dune-evidence",
242
+ chain: "arbitrum-sepolia",
243
+ eventFamilies: [
244
+ "AgentIdentityRegistered",
245
+ "AgentRegistered",
246
+ "OrderCreated/OrderStatusChanged/OrderFulfilled",
247
+ "ExecutionIntentProposed/Approved/Executed",
248
+ "SpendRecorded",
249
+ "Privacy intent events",
250
+ "ReputationRecorded",
251
+ ],
252
+ dashboardCards: ["active agents", "x402 order volume", "execution intents by adapter", "policy approvals", "privacy intent lifecycle", "reputation scores"],
253
+ }, null, 2),
254
+ }],
255
+ }));
256
+
257
+ server.tool("fhenix_privacy_boundary", "Return the Fhenix confidential-compute boundary for ArcPay private treasury metadata.", {}, async () => ({
258
+ content: [{
259
+ type: "text",
260
+ text: JSON.stringify({
261
+ protocol: "arcpay-fhenix-privacy-boundary",
262
+ chain: "arbitrum",
263
+ privateInputs: ["counterparty notes", "agent prompt fragments", "risk memo", "invoice memo", "treasury strategy rationale"],
264
+ publicOutputs: ["commitment", "nullifier", "evidence URI", "execution intent id", "Arbiscan tx hash"],
265
+ boundary: "ArcPay PrivacyVault handles commitment/nullifier settlement; Fhenix is the confidential-compute adapter for encrypted policy and risk computation.",
266
+ }, null, 2),
267
+ }],
268
+ }));
269
+
270
+ server.tool("demo_path", "Return the operator demo path for ArcPay Arbitrum.", {}, async () => ({
271
+ content: [{
272
+ type: "text",
273
+ text: [
274
+ "Connect an EVM wallet to Arbitrum Sepolia.",
275
+ "Register an agent on /agents.",
276
+ "Set policy and allowlist the agent on /policies.",
277
+ "Create and settle an escrowed agent order on /orders.",
278
+ "Create/redeem claim codes and trigger webhook breaker on /operator.",
279
+ "Request and fulfill risk oracle result on /oracle.",
280
+ "Create and release encrypted Privacy Intents with nullifiers on /privacy.",
281
+ "Create, pay, cancel, and sync ETH/USDC invoices on /invoices.",
282
+ "Show /audit and /proofs.",
283
+ ].join("\n"),
284
+ }],
285
+ }));
286
+
287
+ server.tool("smoke_commands", "Return the verification commands operators can run locally and against Arbitrum Sepolia.", {}, async () => ({
288
+ content: [{
289
+ type: "text",
290
+ text: [
291
+ "npm run build:frontend",
292
+ "npm test",
293
+ "npm run check:worker",
294
+ "npm run check:x402",
295
+ "npm run smoke:auth",
296
+ "npm run smoke:live",
297
+ "npm run smoke:x402",
298
+ ].join("\n"),
299
+ }],
300
+ }));
301
+
302
+ const transport = new StdioServerTransport();
303
+ await server.connect(transport);