@true402.dev/mcp-server
Advanced tools
+55
-15
@@ -39,2 +39,31 @@ import { z } from "zod"; | ||
| /** | ||
| * Pick a tool name for a stall that is unique across everything registered so far. | ||
| * | ||
| * The name used to be the last path segment alone, which broke the moment the service started | ||
| * serving the same stall on several chains: `/v1/base/token-report`, `/v1/ethereum/token-report` and | ||
| * `/v1/bsc/token-report` all collapsed to `token_report`. The MCP SDK throws on a duplicate name, so | ||
| * that did not merely lose a tool — it crashed the server at startup and took every other tool with | ||
| * it, for anyone whose copy fetched the newer spec. | ||
| * | ||
| * Order matters and is deliberate: the FIRST path to claim a bare name keeps it. The service lists | ||
| * Base before the other chains, so `token_report` stays Base — the name already published in the | ||
| * docs, the SDKs and users' agent configs. Later chains fall back to `<stall>_<chain>`, matching the | ||
| * names the service's own catalog advertises. | ||
| */ | ||
| function uniqueToolName(rel, op, taken) { | ||
| const explicit = typeof op["x-mcp-tool-name"] === "string" ? op["x-mcp-tool-name"] : ""; | ||
| const segments = rel.replace(/\/+$/, "").split("/").filter(Boolean); | ||
| const last = segments[segments.length - 1] ?? ""; | ||
| const prev = segments[segments.length - 2] ?? ""; | ||
| const norm = (s) => s.replace(/-/g, "_"); | ||
| for (const candidate of [explicit, last, prev && last ? `${last}_${prev}` : ""]) { | ||
| if (!candidate) | ||
| continue; | ||
| const name = norm(candidate); | ||
| if (!taken.has(name)) | ||
| return name; | ||
| } | ||
| return null; // every candidate taken — skip rather than crash | ||
| } | ||
| /** | ||
| * Fetch `${baseUrl}/openapi.json` and register an MCP tool for each paid POST stall. | ||
@@ -72,2 +101,3 @@ * Returns the registered tool names, or null if discovery failed (caller should fall back). | ||
| const registered = []; | ||
| const taken = new Set(); | ||
| for (const [key, ops] of Object.entries(spec.paths ?? {})) { | ||
@@ -80,3 +110,3 @@ const op = ops.post; | ||
| const rel = basePath && key.startsWith(basePath) ? key.slice(basePath.length) : key; | ||
| const toolName = (rel.replace(/\/+$/, "").split("/").pop() ?? "").replace(/-/g, "_"); | ||
| const toolName = uniqueToolName(rel, op, taken); | ||
| if (!toolName) | ||
@@ -87,16 +117,26 @@ continue; | ||
| " (PAID x402 service — USDC on Base; the MCP server needs a funded wallet to settle.)"; | ||
| registerStall(server, baseUrl, walletPrivateKey, { | ||
| toolName, | ||
| path: rel, | ||
| description, | ||
| inputSchema: bodyToShape(bodySchema), | ||
| // The discovered zod shape already mirrors the body, so pass validated args straight through. | ||
| buildBody: (args) => { | ||
| const body = {}; | ||
| for (const [k, v] of Object.entries(args ?? {})) | ||
| if (v !== undefined) | ||
| body[k] = v; | ||
| return body; | ||
| }, | ||
| }); | ||
| // Guarded per stall: one malformed or conflicting entry in a spec we do not control must never | ||
| // stop the others from registering, and must never abort startup. | ||
| try { | ||
| registerStall(server, baseUrl, walletPrivateKey, { | ||
| toolName, | ||
| path: rel, | ||
| description, | ||
| inputSchema: bodyToShape(bodySchema), | ||
| // The discovered zod shape already mirrors the body, so pass validated args straight through. | ||
| buildBody: (args) => { | ||
| const body = {}; | ||
| for (const [k, v] of Object.entries(args ?? {})) | ||
| if (v !== undefined) | ||
| body[k] = v; | ||
| return body; | ||
| }, | ||
| }); | ||
| } | ||
| catch (err) { | ||
| const msg = err instanceof Error ? err.message : String(err); | ||
| console.error(`true402 MCP: skipping stall ${rel} (${msg})`); | ||
| continue; | ||
| } | ||
| taken.add(toolName); | ||
| registered.push(toolName); | ||
@@ -103,0 +143,0 @@ } |
+2
-2
| { | ||
| "name": "@true402.dev/mcp-server", | ||
| "version": "1.0.5", | ||
| "version": "1.0.6", | ||
| "mcpName": "dev.true402/mcp-server", | ||
| "description": "MCP server for the true402 machine-native marketplace \u2014 pay-per-call AI + web + Base on-chain tools over x402 (USDC on Base): LLM inference, SEO/GEO audit, web extract, link preview, robots/AI-crawler check, security headers, and on-chain DeFi trading signals (token rug/honeypot safety, new token pairs, liquidity-pull/rug alerts, whale swaps).", | ||
| "description": "MCP server for the true402 machine-native marketplace — pay-per-call AI + web + Base on-chain tools over x402 (USDC on Base): LLM inference, SEO/GEO audit, web extract, link preview, robots/AI-crawler check, security headers, and on-chain DeFi trading signals (token rug/honeypot safety, new token pairs, liquidity-pull/rug alerts, whale swaps).", | ||
| "type": "module", | ||
@@ -7,0 +7,0 @@ "main": "dist/index.js", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
54119
3.93%1041
4%