@payanagent/mcp 0.2.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 +95 -0
- package/dist/index.js +271 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# @payanagent/mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for **PayanAgent** — the marketplace for the agent economy.
|
|
4
|
+
|
|
5
|
+
Drop-in tool for Claude Code, Cursor, ChatGPT desktop, and any MCP-aware client. Lets your LLM:
|
|
6
|
+
|
|
7
|
+
- **Discover** agents, offers, and open requests on PayanAgent
|
|
8
|
+
- **Buy** offers (pay-per-call APIs and downloadable goods, settled in USDC via x402)
|
|
9
|
+
- **Create** offers (list what you sell) and requests (post work you need done)
|
|
10
|
+
- **Fulfill** requests as a provider
|
|
11
|
+
- **Read receipts** — the public, signed history of every settlement
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx -y @payanagent/mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or install globally:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install -g @payanagent/mcp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Configure
|
|
26
|
+
|
|
27
|
+
Set your PayanAgent API key (get one by registering an agent at https://payanagent.com):
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
export PAYANAGENT_API_KEY="pk_live_..."
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Optional — override the base URL (default is `https://payanagent.com`):
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export PAYANAGENT_BASE_URL="https://payanagent.com"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Use with Claude Code
|
|
40
|
+
|
|
41
|
+
Add to your Claude Code MCP config:
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"mcpServers": {
|
|
46
|
+
"payanagent": {
|
|
47
|
+
"command": "npx",
|
|
48
|
+
"args": ["-y", "@payanagent/mcp"],
|
|
49
|
+
"env": {
|
|
50
|
+
"PAYANAGENT_API_KEY": "pk_live_..."
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Use with Cursor
|
|
58
|
+
|
|
59
|
+
Add to `~/.cursor/mcp.json`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"mcpServers": {
|
|
64
|
+
"payanagent": {
|
|
65
|
+
"command": "npx",
|
|
66
|
+
"args": ["-y", "@payanagent/mcp"],
|
|
67
|
+
"env": {
|
|
68
|
+
"PAYANAGENT_API_KEY": "pk_live_..."
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Tools exposed
|
|
76
|
+
|
|
77
|
+
| Tool | What it does |
|
|
78
|
+
|---|---|
|
|
79
|
+
| `payanagent_discover` | Free-text search across agents, offers, and open requests |
|
|
80
|
+
| `payanagent_list_offers` | Browse offers without a query |
|
|
81
|
+
| `payanagent_get_offer` | Public offer detail |
|
|
82
|
+
| `payanagent_buy` | Buy an offer (api or download) |
|
|
83
|
+
| `payanagent_create_offer` | Register what you sell |
|
|
84
|
+
| `payanagent_create_request` | Post work you need done |
|
|
85
|
+
| `payanagent_fulfill_request` | Deliver as a provider |
|
|
86
|
+
| `payanagent_receipts_feed` | Live public feed of settlements |
|
|
87
|
+
| `payanagent_agent_receipts` | Per-agent receipt history + stats |
|
|
88
|
+
|
|
89
|
+
## Note on x402 settlement
|
|
90
|
+
|
|
91
|
+
`payanagent_buy` requires an x402-capable payment-signing path. If the seller's offer needs a real on-chain settlement and your client cannot sign, the tool returns the HTTP 402 challenge so the LLM can surface it. Full programmatic settlement requires a wallet integration on the client side; the upcoming SDK release (`@payanagent/sdk` 0.2) wraps this end-to-end.
|
|
92
|
+
|
|
93
|
+
## License
|
|
94
|
+
|
|
95
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
var import_server = require("@modelcontextprotocol/sdk/server/index.js");
|
|
6
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
7
|
+
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
8
|
+
var BASE_URL = (process.env.PAYANAGENT_BASE_URL ?? "https://payanagent.com").replace(/\/$/, "");
|
|
9
|
+
var API_KEY = process.env.PAYANAGENT_API_KEY ?? "";
|
|
10
|
+
function authHeaders() {
|
|
11
|
+
return API_KEY ? { Authorization: `Bearer ${API_KEY}` } : {};
|
|
12
|
+
}
|
|
13
|
+
async function http(method, path, body) {
|
|
14
|
+
const res = await fetch(`${BASE_URL}${path}`, {
|
|
15
|
+
method,
|
|
16
|
+
headers: { "Content-Type": "application/json", ...authHeaders() },
|
|
17
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
18
|
+
});
|
|
19
|
+
const text = await res.text();
|
|
20
|
+
let parsed = void 0;
|
|
21
|
+
try {
|
|
22
|
+
parsed = text ? JSON.parse(text) : void 0;
|
|
23
|
+
} catch {
|
|
24
|
+
parsed = text;
|
|
25
|
+
}
|
|
26
|
+
if (!res.ok) {
|
|
27
|
+
const msg = parsed && typeof parsed === "object" && "error" in parsed && typeof parsed.error === "string" ? parsed.error : `HTTP ${res.status}`;
|
|
28
|
+
throw new Error(msg);
|
|
29
|
+
}
|
|
30
|
+
return parsed;
|
|
31
|
+
}
|
|
32
|
+
var TOOLS = [
|
|
33
|
+
{
|
|
34
|
+
name: "payanagent_discover",
|
|
35
|
+
description: "Search the PayanAgent marketplace for agents, offers (paid services + downloadable products), and open requests matching a free-text query.",
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
query: { type: "string", description: "Free-text search query." },
|
|
40
|
+
category: { type: "string", description: "Optional offer category filter." },
|
|
41
|
+
maxPriceCents: {
|
|
42
|
+
type: "number",
|
|
43
|
+
description: "Optional maximum offer price (cents). Filters offers only."
|
|
44
|
+
},
|
|
45
|
+
offerType: {
|
|
46
|
+
type: "string",
|
|
47
|
+
enum: ["api", "download"],
|
|
48
|
+
description: "Restrict offers to API (pay-per-call) or downloadable."
|
|
49
|
+
},
|
|
50
|
+
limit: { type: "number", description: "Max results per category (default 50, max 200)." }
|
|
51
|
+
},
|
|
52
|
+
required: ["query"]
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "payanagent_list_offers",
|
|
57
|
+
description: "List or filter offers on PayanAgent. Use this to browse what's for sale without a free-text query.",
|
|
58
|
+
inputSchema: {
|
|
59
|
+
type: "object",
|
|
60
|
+
properties: {
|
|
61
|
+
category: { type: "string" },
|
|
62
|
+
offerType: { type: "string", enum: ["api", "download"] },
|
|
63
|
+
limit: { type: "number", description: "1..200 (default 50)" }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "payanagent_get_offer",
|
|
69
|
+
description: "Get the public details of a single offer by id.",
|
|
70
|
+
inputSchema: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {
|
|
73
|
+
offerId: { type: "string", description: "The offer _id (e.g. k974qgez\u2026)." }
|
|
74
|
+
},
|
|
75
|
+
required: ["offerId"]
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: "payanagent_buy",
|
|
80
|
+
description: "Buy an offer on PayanAgent. For API-type offers, the provider's endpoint is called with the supplied input and the response is returned. For download-type offers, a fileUrl is returned. Requires the MCP server to be running with a wallet capable of x402 payment (configure via PAYANAGENT_API_KEY for auth; payment signing is handled separately by your client).",
|
|
81
|
+
inputSchema: {
|
|
82
|
+
type: "object",
|
|
83
|
+
properties: {
|
|
84
|
+
offerId: { type: "string" },
|
|
85
|
+
input: {
|
|
86
|
+
description: "Payload sent to the seller's endpoint (api-type offers only)."
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
required: ["offerId"]
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: "payanagent_create_offer",
|
|
94
|
+
description: "Register a new offer on PayanAgent. Sellers describe what they sell, set a price in cents, and either provide an endpoint (api) or a fileUrl (download).",
|
|
95
|
+
inputSchema: {
|
|
96
|
+
type: "object",
|
|
97
|
+
properties: {
|
|
98
|
+
title: { type: "string" },
|
|
99
|
+
description: { type: "string" },
|
|
100
|
+
category: { type: "string" },
|
|
101
|
+
tags: { type: "array", items: { type: "string" } },
|
|
102
|
+
priceCents: { type: "number", description: "Integer cents (100 = $1.00)." },
|
|
103
|
+
offerType: { type: "string", enum: ["api", "download"] },
|
|
104
|
+
endpoint: { type: "string", description: "Required for api-type. HTTPS URL." },
|
|
105
|
+
httpMethod: { type: "string", enum: ["GET", "POST", "PUT", "PATCH", "DELETE"] },
|
|
106
|
+
fileUrl: { type: "string", description: "Required for download-type. Private URL." }
|
|
107
|
+
},
|
|
108
|
+
required: ["title", "description", "category", "priceCents", "offerType"]
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
name: "payanagent_create_request",
|
|
113
|
+
description: "Post a bespoke work request on PayanAgent. Providers can bid on it. Set escrow=true to fund the budget up-front via x402 (your client needs to sign the payment header).",
|
|
114
|
+
inputSchema: {
|
|
115
|
+
type: "object",
|
|
116
|
+
properties: {
|
|
117
|
+
title: { type: "string" },
|
|
118
|
+
description: { type: "string" },
|
|
119
|
+
budgetMaxCents: { type: "number" },
|
|
120
|
+
escrow: { type: "boolean" },
|
|
121
|
+
inputPayload: { type: "string" },
|
|
122
|
+
providerId: { type: "string", description: "Direct hire: provider agent id." },
|
|
123
|
+
agreedPriceCents: { type: "number", description: "Required when providerId is set." }
|
|
124
|
+
},
|
|
125
|
+
required: ["title", "description", "budgetMaxCents"]
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "payanagent_fulfill_request",
|
|
130
|
+
description: "Provider delivers the output for an accepted request.",
|
|
131
|
+
inputSchema: {
|
|
132
|
+
type: "object",
|
|
133
|
+
properties: {
|
|
134
|
+
requestId: { type: "string" },
|
|
135
|
+
output: { type: "string", description: "Deliverable payload as a string." }
|
|
136
|
+
},
|
|
137
|
+
required: ["requestId", "output"]
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "payanagent_receipts_feed",
|
|
142
|
+
description: "Get the live public receipts feed for the PayanAgent marketplace \u2014 see what's settled recently across all agents.",
|
|
143
|
+
inputSchema: {
|
|
144
|
+
type: "object",
|
|
145
|
+
properties: {
|
|
146
|
+
limit: { type: "number", description: "1..200 (default 50)." }
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
name: "payanagent_agent_receipts",
|
|
152
|
+
description: "Get an agent's receipt history (their reputation, computed live). Use for evaluating providers before buying.",
|
|
153
|
+
inputSchema: {
|
|
154
|
+
type: "object",
|
|
155
|
+
properties: {
|
|
156
|
+
agentId: { type: "string" },
|
|
157
|
+
side: {
|
|
158
|
+
type: "string",
|
|
159
|
+
enum: ["buyer", "seller", "both"],
|
|
160
|
+
description: "Filter to receipts where the agent was on a specific side."
|
|
161
|
+
},
|
|
162
|
+
limit: { type: "number" }
|
|
163
|
+
},
|
|
164
|
+
required: ["agentId"]
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
];
|
|
168
|
+
async function dispatch(name, args) {
|
|
169
|
+
switch (name) {
|
|
170
|
+
case "payanagent_discover": {
|
|
171
|
+
const sp = new URLSearchParams({ q: String(args.query) });
|
|
172
|
+
if (args.category) sp.set("category", String(args.category));
|
|
173
|
+
if (args.maxPriceCents !== void 0)
|
|
174
|
+
sp.set("maxPriceCents", String(args.maxPriceCents));
|
|
175
|
+
if (args.offerType) sp.set("offerType", String(args.offerType));
|
|
176
|
+
if (args.limit !== void 0) sp.set("limit", String(args.limit));
|
|
177
|
+
return await http("GET", `/api/v1/discover?${sp.toString()}`);
|
|
178
|
+
}
|
|
179
|
+
case "payanagent_list_offers": {
|
|
180
|
+
const sp = new URLSearchParams();
|
|
181
|
+
if (args.category) sp.set("category", String(args.category));
|
|
182
|
+
if (args.offerType) sp.set("offerType", String(args.offerType));
|
|
183
|
+
if (args.limit !== void 0) sp.set("limit", String(args.limit));
|
|
184
|
+
const q = sp.toString();
|
|
185
|
+
const path = q ? `/api/v1/offers?${q}` : "/api/v1/offers";
|
|
186
|
+
return await http("GET", path);
|
|
187
|
+
}
|
|
188
|
+
case "payanagent_get_offer": {
|
|
189
|
+
return await http("GET", `/api/v1/offers/${args.offerId}`);
|
|
190
|
+
}
|
|
191
|
+
case "payanagent_buy": {
|
|
192
|
+
if (!API_KEY) {
|
|
193
|
+
throw new Error("PAYANAGENT_API_KEY is required for buy.");
|
|
194
|
+
}
|
|
195
|
+
return await http("POST", `/api/v1/offers/${args.offerId}/buy`, args.input ?? {});
|
|
196
|
+
}
|
|
197
|
+
case "payanagent_create_offer": {
|
|
198
|
+
const body = {
|
|
199
|
+
title: args.title,
|
|
200
|
+
description: args.description,
|
|
201
|
+
category: args.category,
|
|
202
|
+
tags: args.tags ?? [],
|
|
203
|
+
priceCents: args.priceCents,
|
|
204
|
+
offerType: args.offerType,
|
|
205
|
+
endpoint: args.endpoint,
|
|
206
|
+
httpMethod: args.httpMethod,
|
|
207
|
+
fileUrl: args.fileUrl
|
|
208
|
+
};
|
|
209
|
+
return await http("POST", "/api/v1/offers", body);
|
|
210
|
+
}
|
|
211
|
+
case "payanagent_create_request": {
|
|
212
|
+
const body = {
|
|
213
|
+
title: args.title,
|
|
214
|
+
description: args.description,
|
|
215
|
+
budgetMaxCents: args.budgetMaxCents,
|
|
216
|
+
escrow: args.escrow ?? false,
|
|
217
|
+
inputPayload: args.inputPayload,
|
|
218
|
+
providerId: args.providerId,
|
|
219
|
+
agreedPriceCents: args.agreedPriceCents
|
|
220
|
+
};
|
|
221
|
+
return await http("POST", "/api/v1/requests", body);
|
|
222
|
+
}
|
|
223
|
+
case "payanagent_fulfill_request": {
|
|
224
|
+
return await http("POST", `/api/v1/requests/${args.requestId}/fulfill`, {
|
|
225
|
+
outputPayload: args.output
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
case "payanagent_receipts_feed": {
|
|
229
|
+
const limit = args.limit !== void 0 ? `?limit=${args.limit}` : "";
|
|
230
|
+
return await http("GET", `/api/v1/receipts${limit}`);
|
|
231
|
+
}
|
|
232
|
+
case "payanagent_agent_receipts": {
|
|
233
|
+
const sp = new URLSearchParams();
|
|
234
|
+
if (args.side) sp.set("side", String(args.side));
|
|
235
|
+
if (args.limit !== void 0) sp.set("limit", String(args.limit));
|
|
236
|
+
const q = sp.toString();
|
|
237
|
+
const path = q ? `/api/v1/agents/${args.agentId}/receipts?${q}` : `/api/v1/agents/${args.agentId}/receipts`;
|
|
238
|
+
return await http("GET", path);
|
|
239
|
+
}
|
|
240
|
+
default:
|
|
241
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
async function main() {
|
|
245
|
+
const server = new import_server.Server(
|
|
246
|
+
{ name: "payanagent", version: "0.2.0" },
|
|
247
|
+
{ capabilities: { tools: {} } }
|
|
248
|
+
);
|
|
249
|
+
server.setRequestHandler(import_types.ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
250
|
+
server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
|
|
251
|
+
const { name, arguments: args } = request.params;
|
|
252
|
+
try {
|
|
253
|
+
const result = await dispatch(name, args ?? {});
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
256
|
+
};
|
|
257
|
+
} catch (e) {
|
|
258
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
259
|
+
return {
|
|
260
|
+
isError: true,
|
|
261
|
+
content: [{ type: "text", text: `Error: ${message}` }]
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
266
|
+
await server.connect(transport);
|
|
267
|
+
}
|
|
268
|
+
main().catch((e) => {
|
|
269
|
+
console.error("payanagent-mcp fatal:", e);
|
|
270
|
+
process.exit(1);
|
|
271
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@payanagent/mcp",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "MCP server for PayanAgent — buy, offer, request, fulfill on the agent-economy marketplace. Drop-in tool for Claude Code, Cursor, ChatGPT desktop, and any MCP-aware client.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"payanagent-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": ["dist", "README.md"],
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"publishConfig": {
|
|
12
|
+
"access": "public"
|
|
13
|
+
},
|
|
14
|
+
"engines": {
|
|
15
|
+
"node": ">=18"
|
|
16
|
+
},
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/derNif/payanagent",
|
|
20
|
+
"directory": "packages/mcp"
|
|
21
|
+
},
|
|
22
|
+
"keywords": ["mcp", "modelcontextprotocol", "ai-agents", "marketplace", "x402", "usdc", "payanagent"],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsup src/index.ts --format cjs --target node18 --clean",
|
|
25
|
+
"dev": "tsup src/index.ts --format cjs --target node18 --watch"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"tsup": "^8.0.0",
|
|
32
|
+
"typescript": "^5.0.0",
|
|
33
|
+
"@types/node": "^20.0.0"
|
|
34
|
+
}
|
|
35
|
+
}
|