agoragentic-mcp 1.2.0 → 1.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/README.md +7 -7
- package/mcp-server.js +167 -396
- package/package.json +8 -8
package/README.md
CHANGED
|
@@ -87,8 +87,8 @@ File: `~/.codeium/windsurf/mcp_config.json`
|
|
|
87
87
|
npx agoragentic-mcp
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
## Available Tools
|
|
91
|
-
|
|
90
|
+
## Available Tools
|
|
91
|
+
|
|
92
92
|
| Tool | Description | Auth Required |
|
|
93
93
|
|------|-------------|---------------|
|
|
94
94
|
| `agoragentic_browse_services` | Browse stable anonymous x402 services on the dedicated edge | No |
|
|
@@ -100,11 +100,6 @@ npx agoragentic-mcp
|
|
|
100
100
|
| `agoragentic_invoke` | Invoke a capability (buy a service) | Yes |
|
|
101
101
|
| `agoragentic_vault` | View your inventory of purchased items | Yes |
|
|
102
102
|
| `agoragentic_categories` | List all marketplace categories | No |
|
|
103
|
-
| `agoragentic_memory_write` | Write to persistent agent memory | Yes |
|
|
104
|
-
| `agoragentic_memory_read` | Read from persistent agent memory | Yes |
|
|
105
|
-
| `agoragentic_secret_store` | Store an encrypted secret in your vault | Yes |
|
|
106
|
-
| `agoragentic_secret_retrieve` | Retrieve a decrypted secret | Yes |
|
|
107
|
-
| `agoragentic_passport` | Check passport info or verify a Base wallet | No/Yes |
|
|
108
103
|
|
|
109
104
|
## Stable x402 Flow
|
|
110
105
|
|
|
@@ -115,6 +110,11 @@ The simplest anonymous paid flow is:
|
|
|
115
110
|
3. `agoragentic_call_service`
|
|
116
111
|
|
|
117
112
|
The first unpaid call returns an MCP payment-required error with the decoded x402 challenge and retry instructions. Retry the same tool call with `payment_signature` to complete the paid execution and receive `Payment-Receipt` plus the JSON result.
|
|
113
|
+
| `agoragentic_memory_write` | Write to persistent agent memory | Yes |
|
|
114
|
+
| `agoragentic_memory_read` | Read from persistent agent memory | Yes |
|
|
115
|
+
| `agoragentic_secret_store` | Store an encrypted secret in your vault | Yes |
|
|
116
|
+
| `agoragentic_secret_retrieve` | Retrieve a decrypted secret | Yes |
|
|
117
|
+
| `agoragentic_wallet` | Check balance, deposit, or verify wallet | Yes |
|
|
118
118
|
|
|
119
119
|
## Getting an API Key
|
|
120
120
|
|
package/mcp-server.js
CHANGED
|
@@ -30,24 +30,22 @@
|
|
|
30
30
|
|
|
31
31
|
const { Server } = require("@modelcontextprotocol/sdk/server/index.js");
|
|
32
32
|
const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
33
|
-
const {
|
|
34
|
-
CallToolRequestSchema,
|
|
35
|
-
ListToolsRequestSchema,
|
|
36
|
-
ListResourcesRequestSchema,
|
|
37
|
-
ReadResourceRequestSchema,
|
|
38
|
-
ListPromptsRequestSchema,
|
|
39
|
-
GetPromptRequestSchema,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
const X402_EDGE_BASE = "https://x402.agoragentic.com";
|
|
45
|
-
const API_KEY = process.env.AGORAGENTIC_API_KEY || "";
|
|
33
|
+
const {
|
|
34
|
+
CallToolRequestSchema,
|
|
35
|
+
ListToolsRequestSchema,
|
|
36
|
+
ListResourcesRequestSchema,
|
|
37
|
+
ReadResourceRequestSchema,
|
|
38
|
+
ListPromptsRequestSchema,
|
|
39
|
+
GetPromptRequestSchema,
|
|
40
|
+
} = require("@modelcontextprotocol/sdk/types.js");
|
|
41
|
+
|
|
42
|
+
const AGORAGENTIC_BASE = "https://agoragentic.com";
|
|
43
|
+
const API_KEY = process.env.AGORAGENTIC_API_KEY || "";
|
|
46
44
|
|
|
47
45
|
// ─── HTTP helper ─────────────────────────────────────────
|
|
48
46
|
|
|
49
|
-
async function apiCall(method, path, body = null) {
|
|
50
|
-
const url = `${AGORAGENTIC_BASE}${path}`;
|
|
47
|
+
async function apiCall(method, path, body = null) {
|
|
48
|
+
const url = `${AGORAGENTIC_BASE}${path}`;
|
|
51
49
|
const headers = { "Content-Type": "application/json" };
|
|
52
50
|
if (API_KEY) headers["Authorization"] = `Bearer ${API_KEY}`;
|
|
53
51
|
|
|
@@ -62,145 +60,8 @@ async function apiCall(method, path, body = null) {
|
|
|
62
60
|
return resp.json();
|
|
63
61
|
} finally {
|
|
64
62
|
clearTimeout(timeout);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
async function edgeRequest(method, path, body = null, extraHeaders = {}) {
|
|
69
|
-
const url = `${X402_EDGE_BASE}${path}`;
|
|
70
|
-
const headers = { ...extraHeaders };
|
|
71
|
-
|
|
72
|
-
const controller = new AbortController();
|
|
73
|
-
const timeout = setTimeout(() => controller.abort(), 30000);
|
|
74
|
-
|
|
75
|
-
try {
|
|
76
|
-
const options = { method, headers, signal: controller.signal };
|
|
77
|
-
if (body !== null && body !== undefined) {
|
|
78
|
-
options.headers["Content-Type"] = "application/json";
|
|
79
|
-
options.body = JSON.stringify(body);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
const resp = await fetch(url, options);
|
|
83
|
-
const raw = await resp.text();
|
|
84
|
-
return { response: resp, data: parseMaybeJson(raw) };
|
|
85
|
-
} finally {
|
|
86
|
-
clearTimeout(timeout);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function parseMaybeJson(text) {
|
|
91
|
-
if (!text) return null;
|
|
92
|
-
try {
|
|
93
|
-
return JSON.parse(text);
|
|
94
|
-
} catch {
|
|
95
|
-
return text;
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function slugifyService(value) {
|
|
100
|
-
return String(value || "")
|
|
101
|
-
.trim()
|
|
102
|
-
.toLowerCase()
|
|
103
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
104
|
-
.replace(/^-+|-+$/g, "");
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function findEdgeService(services, slug) {
|
|
108
|
-
const wanted = slugifyService(slug);
|
|
109
|
-
if (!wanted) return null;
|
|
110
|
-
return (services || []).find((service) => {
|
|
111
|
-
const aliases = [service?.slug, ...(service?.route_aliases || [])]
|
|
112
|
-
.map(slugifyService)
|
|
113
|
-
.filter(Boolean);
|
|
114
|
-
return aliases.includes(wanted);
|
|
115
|
-
}) || null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function decodeBase64JsonHeader(value) {
|
|
119
|
-
if (!value || typeof value !== "string") return null;
|
|
120
|
-
try {
|
|
121
|
-
return JSON.parse(Buffer.from(value, "base64").toString("utf8"));
|
|
122
|
-
} catch {
|
|
123
|
-
return null;
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function buildMcpPaymentRequiredData({ toolName, args, response, routing = null, trust = null }) {
|
|
128
|
-
const paymentRequiredHeader = response.headers.get("payment-required") || null;
|
|
129
|
-
const decodedRequirements = decodeBase64JsonHeader(paymentRequiredHeader);
|
|
130
|
-
const challenges = Array.isArray(decodedRequirements)
|
|
131
|
-
? decodedRequirements.map((challenge, index) => ({
|
|
132
|
-
id: challenge?.extra?.quote_id || `challenge_${index + 1}`,
|
|
133
|
-
method: challenge?.scheme || "exact",
|
|
134
|
-
intent: "charge",
|
|
135
|
-
network: challenge?.network || null,
|
|
136
|
-
resource: challenge?.resource || null,
|
|
137
|
-
request: {
|
|
138
|
-
max_amount_required: challenge?.maxAmountRequired || null,
|
|
139
|
-
asset: challenge?.asset || null,
|
|
140
|
-
pay_to: challenge?.payTo || null,
|
|
141
|
-
description: challenge?.description || null,
|
|
142
|
-
extra: challenge?.extra || null,
|
|
143
|
-
},
|
|
144
|
-
}))
|
|
145
|
-
: [];
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
protocol: "x402",
|
|
149
|
-
payment_required_header: paymentRequiredHeader,
|
|
150
|
-
authenticate_header: response.headers.get("www-authenticate") || null,
|
|
151
|
-
challenges,
|
|
152
|
-
routing,
|
|
153
|
-
trust,
|
|
154
|
-
retry_tool_call: {
|
|
155
|
-
name: toolName,
|
|
156
|
-
arguments: {
|
|
157
|
-
...(args || {}),
|
|
158
|
-
payment_signature: "<PAYMENT-SIGNATURE>",
|
|
159
|
-
},
|
|
160
|
-
payment_argument: "payment_signature",
|
|
161
|
-
accepted_http_headers: ["PAYMENT-SIGNATURE", "Authorization: Payment"],
|
|
162
|
-
},
|
|
163
|
-
};
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
function buildMcpPaymentSuccessBody(response, body) {
|
|
167
|
-
return {
|
|
168
|
-
status_code: response.status,
|
|
169
|
-
payment_receipt: response.headers.get("payment-receipt") || null,
|
|
170
|
-
payment_response_header: response.headers.get("payment-response") || null,
|
|
171
|
-
body,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function summarizeEdgeService(service, options = {}) {
|
|
176
|
-
const includeSchemas = options.includeSchemas === true;
|
|
177
|
-
const includeTrust = options.includeTrust !== false;
|
|
178
|
-
return {
|
|
179
|
-
slug: service.slug,
|
|
180
|
-
name: service.name,
|
|
181
|
-
description: service.description,
|
|
182
|
-
category: service.category,
|
|
183
|
-
status: service.status,
|
|
184
|
-
price_usdc: service.price_usdc,
|
|
185
|
-
payable_url: service.payable_url,
|
|
186
|
-
route_aliases: service.route_aliases || [],
|
|
187
|
-
safe_to_retry: service.execution_contract?.safe_to_retry ?? service.trust?.safe_to_retry ?? null,
|
|
188
|
-
max_runtime_ms: service.execution_contract?.max_runtime_ms ?? service.trust?.max_runtime_ms ?? null,
|
|
189
|
-
payment_contract: service.payment_contract || null,
|
|
190
|
-
sample_input: service.sample_input || null,
|
|
191
|
-
trust: includeTrust ? (service.trust || null) : undefined,
|
|
192
|
-
input_schema: includeSchemas ? (service.input_schema || null) : undefined,
|
|
193
|
-
output_schema: includeSchemas ? (service.output_schema || null) : undefined,
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
async function loadEdgeServices() {
|
|
198
|
-
const { response, data } = await edgeRequest("GET", "/services/index.json");
|
|
199
|
-
if (!response.ok) {
|
|
200
|
-
throw new Error(`x402 edge service index failed with HTTP ${response.status}`);
|
|
201
|
-
}
|
|
202
|
-
return Array.isArray(data?.services) ? data.services : [];
|
|
203
|
-
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
204
65
|
|
|
205
66
|
// ─── MCP Server ──────────────────────────────────────────
|
|
206
67
|
|
|
@@ -211,69 +72,15 @@ const server = new Server(
|
|
|
211
72
|
|
|
212
73
|
// ─── Tools ───────────────────────────────────────────────
|
|
213
74
|
|
|
214
|
-
|
|
215
|
-
|
|
75
|
+
// Extracted so both MCP and ACP modes can share the same definitions
|
|
76
|
+
function getToolList() {
|
|
77
|
+
return [
|
|
216
78
|
// ── Core Marketplace ──
|
|
217
|
-
{
|
|
218
|
-
name: "
|
|
219
|
-
description: "
|
|
220
|
-
annotations: { title: "
|
|
221
|
-
inputSchema: {
|
|
222
|
-
type: "object",
|
|
223
|
-
properties: {
|
|
224
|
-
limit: { type: "number", default: 10, description: "Maximum number of services to return." },
|
|
225
|
-
include_schemas: { type: "boolean", default: false, description: "Include full input/output schemas in the response." },
|
|
226
|
-
include_trust: { type: "boolean", default: true, description: "Include trust and settlement metadata in the response." }
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
name: "agoragentic_quote_service",
|
|
232
|
-
description: "Quote one stable x402 service by slug. Returns price, retry behavior, trust metadata, sample input, and the exact payable URL without spending.",
|
|
233
|
-
annotations: { title: "Quote x402 Service", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
234
|
-
inputSchema: {
|
|
235
|
-
type: "object",
|
|
236
|
-
properties: {
|
|
237
|
-
slug: { type: "string", description: "Stable x402 service slug, for example text-summarizer." },
|
|
238
|
-
max_price_usdc: { type: "number", description: "Optional safety bound. The tool errors if the quoted service exceeds this price." },
|
|
239
|
-
include_schemas: { type: "boolean", default: true, description: "Include full input/output schemas in the response." },
|
|
240
|
-
include_trust: { type: "boolean", default: true, description: "Include trust and settlement metadata in the response." }
|
|
241
|
-
},
|
|
242
|
-
required: ["slug"]
|
|
243
|
-
}
|
|
244
|
-
},
|
|
245
|
-
{
|
|
246
|
-
name: "agoragentic_call_service",
|
|
247
|
-
description: "Call one stable x402 service by slug. The first unpaid attempt returns an x402 Payment Required payload. Retry the same tool call with payment_signature to complete the paid call.",
|
|
248
|
-
annotations: { title: "Call x402 Service", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
249
|
-
inputSchema: {
|
|
250
|
-
type: "object",
|
|
251
|
-
properties: {
|
|
252
|
-
slug: { type: "string", description: "Stable x402 service slug, for example text-summarizer." },
|
|
253
|
-
payload: { type: "object", description: "JSON payload sent to the stable edge route.", default: {} },
|
|
254
|
-
payment_signature: { type: "string", description: "Optional PAYMENT-SIGNATURE value used on the paid retry." },
|
|
255
|
-
max_price_usdc: { type: "number", description: "Optional safety bound. The tool errors if the quoted service exceeds this price." }
|
|
256
|
-
},
|
|
257
|
-
required: ["slug"]
|
|
258
|
-
}
|
|
259
|
-
},
|
|
260
|
-
{
|
|
261
|
-
name: "agoragentic_edge_receipt",
|
|
262
|
-
description: "Fetch one anonymous x402 edge receipt by receipt ID from x402.agoragentic.com.",
|
|
263
|
-
annotations: { title: "Get x402 Edge Receipt", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
264
|
-
inputSchema: {
|
|
265
|
-
type: "object",
|
|
266
|
-
properties: {
|
|
267
|
-
receipt_id: { type: "string", description: "Stable edge receipt identifier, usually returned in the Payment-Receipt header." }
|
|
268
|
-
},
|
|
269
|
-
required: ["receipt_id"]
|
|
270
|
-
}
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
name: "agoragentic_register",
|
|
274
|
-
description: "Register as a new agent on Agoragentic. Returns an API key and access to the Starter Pack. Starter pack rewards are fee discounts, not free credits.",
|
|
275
|
-
annotations: { title: "Register Agent", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
276
|
-
inputSchema: {
|
|
79
|
+
{
|
|
80
|
+
name: "agoragentic_register",
|
|
81
|
+
description: "Register as a new agent on Agoragentic. Returns an API key and access to the Starter Pack. Starter pack rewards are fee discounts, not free credits.",
|
|
82
|
+
annotations: { title: "Register Agent", readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
83
|
+
inputSchema: {
|
|
277
84
|
type: "object",
|
|
278
85
|
properties: {
|
|
279
86
|
agent_name: { type: "string", description: "Your agent's display name (must be unique across the marketplace)" },
|
|
@@ -404,185 +211,19 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
404
211
|
}
|
|
405
212
|
}
|
|
406
213
|
}
|
|
407
|
-
]
|
|
408
|
-
}
|
|
214
|
+
];
|
|
215
|
+
}
|
|
409
216
|
|
|
410
|
-
server.setRequestHandler(
|
|
411
|
-
const { name, arguments: args } = request.params;
|
|
217
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: getToolList() }));
|
|
412
218
|
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
.
|
|
421
|
-
.map((service) => summarizeEdgeService(service, {
|
|
422
|
-
includeSchemas: args.include_schemas === true,
|
|
423
|
-
includeTrust: args.include_trust !== false,
|
|
424
|
-
}));
|
|
425
|
-
|
|
426
|
-
return {
|
|
427
|
-
content: [{
|
|
428
|
-
type: "text",
|
|
429
|
-
text: JSON.stringify({
|
|
430
|
-
mode: "anonymous_x402_edge",
|
|
431
|
-
service_count: summaries.length,
|
|
432
|
-
base_url: X402_EDGE_BASE,
|
|
433
|
-
services: summaries,
|
|
434
|
-
}, null, 2)
|
|
435
|
-
}]
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
case "agoragentic_quote_service": {
|
|
440
|
-
const services = await loadEdgeServices();
|
|
441
|
-
const service = findEdgeService(services, args.slug);
|
|
442
|
-
if (!service) {
|
|
443
|
-
return {
|
|
444
|
-
content: [{
|
|
445
|
-
type: "text",
|
|
446
|
-
text: JSON.stringify({
|
|
447
|
-
error: "unknown_service",
|
|
448
|
-
slug: args.slug || null,
|
|
449
|
-
message: "Stable x402 service slug not found on the edge."
|
|
450
|
-
}, null, 2)
|
|
451
|
-
}],
|
|
452
|
-
isError: true
|
|
453
|
-
};
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
const quotedPrice = Number.parseFloat(service.price_usdc);
|
|
457
|
-
if (Number.isFinite(Number(args.max_price_usdc)) && Number.isFinite(quotedPrice) && quotedPrice > Number(args.max_price_usdc)) {
|
|
458
|
-
return {
|
|
459
|
-
content: [{
|
|
460
|
-
type: "text",
|
|
461
|
-
text: JSON.stringify({
|
|
462
|
-
error: "price_exceeds_max",
|
|
463
|
-
slug: service.slug,
|
|
464
|
-
quoted_price_usdc: service.price_usdc,
|
|
465
|
-
max_price_usdc: Number(args.max_price_usdc)
|
|
466
|
-
}, null, 2)
|
|
467
|
-
}],
|
|
468
|
-
isError: true
|
|
469
|
-
};
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return {
|
|
473
|
-
content: [{
|
|
474
|
-
type: "text",
|
|
475
|
-
text: JSON.stringify({
|
|
476
|
-
mode: "anonymous_x402_edge_quote",
|
|
477
|
-
...summarizeEdgeService(service, {
|
|
478
|
-
includeSchemas: args.include_schemas !== false,
|
|
479
|
-
includeTrust: args.include_trust !== false,
|
|
480
|
-
})
|
|
481
|
-
}, null, 2)
|
|
482
|
-
}]
|
|
483
|
-
};
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
case "agoragentic_call_service": {
|
|
487
|
-
const services = await loadEdgeServices();
|
|
488
|
-
const service = findEdgeService(services, args.slug);
|
|
489
|
-
if (!service) {
|
|
490
|
-
return {
|
|
491
|
-
content: [{
|
|
492
|
-
type: "text",
|
|
493
|
-
text: JSON.stringify({
|
|
494
|
-
error: "unknown_service",
|
|
495
|
-
slug: args.slug || null,
|
|
496
|
-
message: "Stable x402 service slug not found on the edge."
|
|
497
|
-
}, null, 2)
|
|
498
|
-
}],
|
|
499
|
-
isError: true
|
|
500
|
-
};
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
const quotedPrice = Number.parseFloat(service.price_usdc);
|
|
504
|
-
if (Number.isFinite(Number(args.max_price_usdc)) && Number.isFinite(quotedPrice) && quotedPrice > Number(args.max_price_usdc)) {
|
|
505
|
-
return {
|
|
506
|
-
content: [{
|
|
507
|
-
type: "text",
|
|
508
|
-
text: JSON.stringify({
|
|
509
|
-
error: "price_exceeds_max",
|
|
510
|
-
slug: service.slug,
|
|
511
|
-
quoted_price_usdc: service.price_usdc,
|
|
512
|
-
max_price_usdc: Number(args.max_price_usdc)
|
|
513
|
-
}, null, 2)
|
|
514
|
-
}],
|
|
515
|
-
isError: true
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
const requestHeaders = {};
|
|
520
|
-
if (args.payment_signature) {
|
|
521
|
-
requestHeaders["PAYMENT-SIGNATURE"] = String(args.payment_signature);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
const { response, data } = await edgeRequest(
|
|
525
|
-
"POST",
|
|
526
|
-
`/v1/${encodeURIComponent(service.slug)}`,
|
|
527
|
-
args.payload || {},
|
|
528
|
-
requestHeaders
|
|
529
|
-
);
|
|
530
|
-
|
|
531
|
-
if (response.status === 402) {
|
|
532
|
-
throw new McpError(-32042, "Payment Required", buildMcpPaymentRequiredData({
|
|
533
|
-
toolName: "agoragentic_call_service",
|
|
534
|
-
args: {
|
|
535
|
-
slug: service.slug,
|
|
536
|
-
payload: args.payload || {},
|
|
537
|
-
max_price_usdc: args.max_price_usdc
|
|
538
|
-
},
|
|
539
|
-
response,
|
|
540
|
-
routing: {
|
|
541
|
-
provider_count: 1,
|
|
542
|
-
selected_provider: service.slug,
|
|
543
|
-
route: `/v1/${service.slug}`,
|
|
544
|
-
},
|
|
545
|
-
trust: service.trust || {
|
|
546
|
-
status: service.status || "reachable",
|
|
547
|
-
method: "x402_edge_service_index",
|
|
548
|
-
}
|
|
549
|
-
}));
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
return {
|
|
553
|
-
content: [{
|
|
554
|
-
type: "text",
|
|
555
|
-
text: JSON.stringify({
|
|
556
|
-
slug: service.slug,
|
|
557
|
-
service_name: service.name,
|
|
558
|
-
payable_url: service.payable_url,
|
|
559
|
-
...buildMcpPaymentSuccessBody(response, data)
|
|
560
|
-
}, null, 2)
|
|
561
|
-
}],
|
|
562
|
-
isError: response.status >= 400
|
|
563
|
-
};
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
case "agoragentic_edge_receipt": {
|
|
567
|
-
const { response, data } = await edgeRequest(
|
|
568
|
-
"GET",
|
|
569
|
-
`/v1/receipts/${encodeURIComponent(String(args.receipt_id || ""))}`
|
|
570
|
-
);
|
|
571
|
-
return {
|
|
572
|
-
content: [{
|
|
573
|
-
type: "text",
|
|
574
|
-
text: JSON.stringify({
|
|
575
|
-
status_code: response.status,
|
|
576
|
-
receipt: data
|
|
577
|
-
}, null, 2)
|
|
578
|
-
}],
|
|
579
|
-
isError: response.status >= 400
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
case "agoragentic_register": {
|
|
584
|
-
const data = await apiCall("POST", "/api/quickstart", {
|
|
585
|
-
name: args.agent_name,
|
|
219
|
+
// Extracted so both MCP and ACP modes can share the same execution logic
|
|
220
|
+
async function executeToolCall(name, args) {
|
|
221
|
+
|
|
222
|
+
try {
|
|
223
|
+
switch (name) {
|
|
224
|
+
case "agoragentic_register": {
|
|
225
|
+
const data = await apiCall("POST", "/api/quickstart", {
|
|
226
|
+
name: args.agent_name,
|
|
586
227
|
type: args.agent_type || "both"
|
|
587
228
|
});
|
|
588
229
|
return {
|
|
@@ -840,6 +481,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
840
481
|
} catch (err) {
|
|
841
482
|
return { content: [{ type: "text", text: `Error: ${err.message}` }] };
|
|
842
483
|
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
487
|
+
const { name, arguments: args } = request.params;
|
|
488
|
+
return executeToolCall(name, args);
|
|
843
489
|
});
|
|
844
490
|
|
|
845
491
|
// ─── Resources ───────────────────────────────────────────
|
|
@@ -1004,12 +650,137 @@ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
|
1004
650
|
throw new Error(`Unknown prompt: ${name}`);
|
|
1005
651
|
});
|
|
1006
652
|
|
|
653
|
+
// ─── ACP Mode ────────────────────────────────────────────
|
|
654
|
+
//
|
|
655
|
+
// When started with --acp, the server speaks the Agent Client Protocol
|
|
656
|
+
// (JSON-RPC 2.0 over stdio) instead of MCP. This enables integration
|
|
657
|
+
// with ACP-compatible editors like Zed, JetBrains, VS Code via Copilot, etc.
|
|
658
|
+
//
|
|
659
|
+
// The ACP handshake adds: protocolVersion, agentCapabilities, agentInfo, authMethods
|
|
660
|
+
// Tool definitions and execution are identical to MCP mode.
|
|
661
|
+
|
|
662
|
+
const ACP_MODE = process.argv.includes("--acp");
|
|
663
|
+
|
|
664
|
+
function createAcpServer() {
|
|
665
|
+
const readline = require("readline");
|
|
666
|
+
|
|
667
|
+
const rl = readline.createInterface({
|
|
668
|
+
input: process.stdin,
|
|
669
|
+
output: process.stdout,
|
|
670
|
+
terminal: false,
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
function send(obj) {
|
|
674
|
+
process.stdout.write(JSON.stringify(obj) + "\n");
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
function sendResult(id, result) {
|
|
678
|
+
send({ jsonrpc: "2.0", id, result });
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function sendError(id, code, message, data) {
|
|
682
|
+
send({ jsonrpc: "2.0", id, error: { code, message, ...(data ? { data } : {}) } });
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// ACP initialize response with auth methods
|
|
686
|
+
function handleInitialize(id, params) {
|
|
687
|
+
sendResult(id, {
|
|
688
|
+
protocolVersion: params?.protocolVersion || 1,
|
|
689
|
+
agentCapabilities: {
|
|
690
|
+
loadSession: false,
|
|
691
|
+
promptCapabilities: { image: false, audio: false },
|
|
692
|
+
},
|
|
693
|
+
agentInfo: {
|
|
694
|
+
name: "agoragentic",
|
|
695
|
+
version: "2.0.0",
|
|
696
|
+
description: "Agoragentic agent marketplace — 174+ AI capabilities, USDC payments on Base L2",
|
|
697
|
+
},
|
|
698
|
+
authMethods: API_KEY
|
|
699
|
+
? [] // Already authenticated via env var
|
|
700
|
+
: [
|
|
701
|
+
{
|
|
702
|
+
type: "terminal",
|
|
703
|
+
description: "Set AGORAGENTIC_API_KEY environment variable. Get a key via the agoragentic_register tool.",
|
|
704
|
+
},
|
|
705
|
+
],
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
rl.on("line", async (line) => {
|
|
710
|
+
let msg;
|
|
711
|
+
try {
|
|
712
|
+
msg = JSON.parse(line.trim());
|
|
713
|
+
} catch {
|
|
714
|
+
sendError(null, -32700, "Parse error");
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (msg.jsonrpc !== "2.0") {
|
|
719
|
+
sendError(msg.id || null, -32600, "Invalid JSON-RPC version");
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
try {
|
|
724
|
+
switch (msg.method) {
|
|
725
|
+
case "initialize":
|
|
726
|
+
handleInitialize(msg.id, msg.params);
|
|
727
|
+
break;
|
|
728
|
+
|
|
729
|
+
case "initialized":
|
|
730
|
+
// ACP notification — no response needed
|
|
731
|
+
break;
|
|
732
|
+
|
|
733
|
+
case "tools/list":
|
|
734
|
+
sendResult(msg.id, {
|
|
735
|
+
tools: getToolList().map(t => ({
|
|
736
|
+
name: t.name,
|
|
737
|
+
description: t.description,
|
|
738
|
+
inputSchema: t.inputSchema,
|
|
739
|
+
annotations: t.annotations,
|
|
740
|
+
})),
|
|
741
|
+
});
|
|
742
|
+
break;
|
|
743
|
+
|
|
744
|
+
case "tools/call": {
|
|
745
|
+
const { name, arguments: callArgs } = msg.params || {};
|
|
746
|
+
const result = await executeToolCall(name, callArgs || {});
|
|
747
|
+
sendResult(msg.id, result);
|
|
748
|
+
break;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
case "shutdown":
|
|
752
|
+
sendResult(msg.id, { success: true });
|
|
753
|
+
setTimeout(() => process.exit(0), 100);
|
|
754
|
+
break;
|
|
755
|
+
|
|
756
|
+
default:
|
|
757
|
+
sendError(msg.id, -32601, `Method not found: ${msg.method}`);
|
|
758
|
+
}
|
|
759
|
+
} catch (err) {
|
|
760
|
+
if (err.code === -32042) {
|
|
761
|
+
// x402 Payment Required — forward structured data
|
|
762
|
+
sendError(msg.id, -32042, err.message, err.data);
|
|
763
|
+
} else {
|
|
764
|
+
sendError(msg.id, -32603, err.message || "Internal error");
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
rl.on("close", () => process.exit(0));
|
|
770
|
+
|
|
771
|
+
console.error("Agoragentic ACP Agent v2.0 running on stdio (ACP mode)");
|
|
772
|
+
}
|
|
773
|
+
|
|
1007
774
|
// ─── Start ───────────────────────────────────────────────
|
|
1008
775
|
|
|
1009
776
|
async function main() {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
777
|
+
if (ACP_MODE) {
|
|
778
|
+
createAcpServer();
|
|
779
|
+
} else {
|
|
780
|
+
const transport = new StdioServerTransport();
|
|
781
|
+
await server.connect(transport);
|
|
782
|
+
console.error("Agoragentic MCP Server v2.0 running on stdio");
|
|
783
|
+
}
|
|
1013
784
|
}
|
|
1014
785
|
|
|
1015
786
|
main().catch(console.error);
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agoragentic-mcp",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"mcpName": "io.github.rhein1/agoragentic",
|
|
5
|
-
"description": "MCP server for Agoragentic. Gives MCP
|
|
5
|
+
"description": "MCP and ACP server for the Agoragentic agent-to-agent marketplace. Gives any MCP or ACP-compatible client (Claude Desktop, VS Code, Cursor, Zed, JetBrains) access to browse, invoke, and pay for AI services settled in USDC on Base L2.",
|
|
6
6
|
"main": "mcp-server.js",
|
|
7
7
|
"bin": {
|
|
8
8
|
"agoragentic-mcp": "./mcp-server.js"
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
"claude",
|
|
22
22
|
"cursor",
|
|
23
23
|
"usdc",
|
|
24
|
-
"base-l2",
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
24
|
+
"base-l2",
|
|
25
|
+
"langchain",
|
|
26
|
+
"crewai",
|
|
27
|
+
"acp",
|
|
28
|
+
"agent-client-protocol"
|
|
29
29
|
],
|
|
30
30
|
"author": "Agoragentic <support@agoragentic.com>",
|
|
31
31
|
"license": "MIT",
|
|
@@ -50,4 +50,4 @@
|
|
|
50
50
|
"README.md",
|
|
51
51
|
"LICENSE"
|
|
52
52
|
]
|
|
53
|
-
}
|
|
53
|
+
}
|