toll402-mcp 0.4.2 → 0.5.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 +8 -0
- package/dist/mcp.js +34 -8
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,12 +16,20 @@ Or with a wallet (x402):
|
|
|
16
16
|
```json
|
|
17
17
|
{ "mcpServers": { "toll402": { "command": "npx", "args": ["-y", "toll402-mcp"], "env": { "TOLL402_WALLET_KEY": "0x...", "TOLL402_MAX_USD": "0.25" } } } }
|
|
18
18
|
```
|
|
19
|
+
Remote, no install: `https://toll402.dev/mcp` (send `x-toll402-key` as a header, `?key=tk_…` in the URL for clients without headers, or x402 headers). Per-client setup for Claude Code, Cursor, Codex, ChatGPT, Windsurf, VS Code, Gemini CLI, Hermes, OpenClaw and more: https://toll402.dev/#connect
|
|
20
|
+
|
|
19
21
|
You are charged only when a call succeeds (2xx). Catalog and prices: https://toll402.dev/v1/catalog · Docs for agents: https://toll402.dev/llms.txt
|
|
20
22
|
|
|
21
23
|
## Tools
|
|
22
24
|
|
|
23
25
|
16 first-party tools, 167 community-forged tools and 2,466 provider API endpoints, all exposed as MCP tools (the provider endpoints through `find` and `do`). Prices are per call; charged only on success.
|
|
24
26
|
|
|
27
|
+
### Account tools (free, need `TOLL402_API_KEY`)
|
|
28
|
+
|
|
29
|
+
- **toll402_review**: rate a paid call you just used (`callId`, `useful`, optional `reason`). Reviews move tool ranking for every agent.
|
|
30
|
+
- **toll402_job**: check an image or video generation task by `jobId`; returns the result URLs when done. Failed tasks are refunded.
|
|
31
|
+
- **toll402_history**: this key's recent paid calls with cost, input summary and links to the stored answers (24 h).
|
|
32
|
+
|
|
25
33
|
### First-party
|
|
26
34
|
|
|
27
35
|
- **read_url** ($0.002): Fetch any public web page (or PDF) and return clean, LLM-ready Markdown with title, metadata and links.
|
package/dist/mcp.js
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* TOLL402_URL base URL of the Toll402 server (default https://toll402.dev)
|
|
8
8
|
* TOLL402_WALLET_KEY 0x-prefixed EVM private key holding USDC on Base (omit for free instances)
|
|
9
9
|
* TOLL402_MAX_USD max USD per single payment (default 0.25)
|
|
10
|
+
* TOLL402_API_KEY prepaid-credits key (tk_…) instead of a wallet; enables toll402_review, toll402_job, toll402_history
|
|
10
11
|
*/
|
|
11
12
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
12
13
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
@@ -38,21 +39,38 @@ async function main() {
|
|
|
38
39
|
else {
|
|
39
40
|
console.error("toll402-mcp: TOLL402_WALLET_KEY not set — calls will fail with 402 unless the server is free");
|
|
40
41
|
}
|
|
41
|
-
const server = new Server({ name: "toll402", version: "0.
|
|
42
|
+
const server = new Server({ name: "toll402", version: "0.5.0" }, { capabilities: { tools: {} }, instructions: INSTRUCTIONS });
|
|
43
|
+
const META = [
|
|
44
|
+
{ name: "toll402_review", description: "Rate a paid Toll402 call you just used: was the answer useful? Reviews move tool ranking for every agent. Free. Needs TOLL402_API_KEY.", inputSchema: { type: "object", properties: { callId: { type: "number", description: "The call id shown after a charged call" }, useful: { type: "boolean" }, reason: { type: "string" } }, required: ["callId", "useful"] } },
|
|
45
|
+
{ name: "toll402_job", description: "Check an async Toll402 task (image or video generation) by job id: status, and result URLs when done. Free. Poll every 30-60 s.", inputSchema: { type: "object", properties: { jobId: { type: "string" } }, required: ["jobId"] } },
|
|
46
|
+
{ name: "toll402_history", description: "Recent paid Toll402 calls of this key with cost, input summary and links to stored answers (24 h). Free.", inputSchema: { type: "object", properties: { days: { type: "number" }, tool: { type: "string" }, limit: { type: "number" } } } },
|
|
47
|
+
];
|
|
48
|
+
const keyed = (path, init = {}) => fetch(`${BASE}${path}`, { ...init, headers: { "content-type": "application/json", "user-agent": "toll402-mcp/0.5.0", ...(API_KEY ? { "x-toll402-key": API_KEY } : {}) } });
|
|
49
|
+
const meta = async (name, a) => {
|
|
50
|
+
if (!API_KEY)
|
|
51
|
+
return { isError: true, content: [{ type: "text", text: `${name} needs TOLL402_API_KEY (prepaid credits from ${BASE}/credits).` }] };
|
|
52
|
+
const r = name === "toll402_review" ? await keyed(`/v1/calls/${encodeURIComponent(String(a.callId ?? ""))}/review`, { method: "POST", body: JSON.stringify({ useful: a.useful, reason: a.reason }) })
|
|
53
|
+
: name === "toll402_job" ? await keyed(`/v1/jobs/${encodeURIComponent(String(a.jobId ?? ""))}`)
|
|
54
|
+
: await keyed(`/v1/calls?${new URLSearchParams(Object.entries({ days: a.days, tool: a.tool, limit: a.limit ?? 20 }).filter(([, v]) => v !== undefined && v !== null && v !== "").map(([k, v]) => [k, String(v)]))}`);
|
|
55
|
+
const t = await r.text();
|
|
56
|
+
return { isError: !r.ok, content: [{ type: "text", text: r.ok ? t.slice(0, 20_000) : `HTTP ${r.status}: ${t.slice(0, 800)}` }] };
|
|
57
|
+
};
|
|
42
58
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
43
|
-
tools: catalog.tools.map((t) => ({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
59
|
+
tools: [...META, ...catalog.tools.map((t) => ({
|
|
60
|
+
name: t.name,
|
|
61
|
+
description: `[${t.kind ?? "tool"}] ${t.description} (costs ${t.price} per call, paid automatically: from your wallet via x402 or from prepaid credits (API key))`,
|
|
62
|
+
inputSchema: t.inputSchema,
|
|
63
|
+
}))],
|
|
48
64
|
}));
|
|
49
65
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
66
|
+
if (req.params.name.startsWith("toll402_"))
|
|
67
|
+
return meta(req.params.name, (req.params.arguments ?? {}));
|
|
50
68
|
const t = byName.get(req.params.name);
|
|
51
69
|
if (!t)
|
|
52
70
|
return { isError: true, content: [{ type: "text", text: `Unknown tool ${req.params.name}` }] };
|
|
53
71
|
const r = await paidFetch(`${BASE}${t.path}`, {
|
|
54
72
|
method: "POST",
|
|
55
|
-
headers: { "content-type": "application/json", "user-agent": "toll402-mcp/0.
|
|
73
|
+
headers: { "content-type": "application/json", "user-agent": "toll402-mcp/0.5.0", ...(API_KEY ? { "x-toll402-key": API_KEY } : {}), ...(process.env.TOLL402_REF ? { "x-toll402-ref": process.env.TOLL402_REF } : {}), ...(KEY ? { "x-toll402-agent": privateKeyToAccount(KEY).address } : {}) },
|
|
56
74
|
body: JSON.stringify(req.params.arguments ?? {}),
|
|
57
75
|
});
|
|
58
76
|
const text = await r.text();
|
|
@@ -66,7 +84,15 @@ async function main() {
|
|
|
66
84
|
catch {
|
|
67
85
|
/* leave as-is */
|
|
68
86
|
}
|
|
69
|
-
const
|
|
87
|
+
const callId = r.headers.get("x-toll402-call-id");
|
|
88
|
+
let jobHint = "";
|
|
89
|
+
try {
|
|
90
|
+
const jid = JSON.parse(text).result?.job?.id;
|
|
91
|
+
if (jid)
|
|
92
|
+
jobHint = `\n[async task: check it with toll402_job {"jobId": "${jid}"} in about 60 s]`;
|
|
93
|
+
}
|
|
94
|
+
catch { /* not JSON */ }
|
|
95
|
+
const paid = (r.headers.get("payment-response") ? `\n\n[paid ${t.price} via x402]` : r.headers.get("x-toll402-charged") ? `\n\n[charged $${r.headers.get("x-toll402-charged")} from credits · balance $${r.headers.get("x-toll402-balance")}${callId ? ` · call id ${callId}: after using the answer, rate it with toll402_review` : ""}]` : "") + jobHint;
|
|
70
96
|
return { content: [{ type: "text", text: out + paid }] };
|
|
71
97
|
});
|
|
72
98
|
await server.connect(new StdioServerTransport());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toll402-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "MCP server for Toll402: 2,600+ pay-per-call tools for AI agents (web, PDF, provenance, verified business directory, ID validators, SEO/social/enrichment/ads/market-data provider APIs). Pay per call with USDC via x402 (no account) or with prepaid credits bought by card (API key). Charged only on success.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|