@swarmwage/mcp
Advanced tools
| #!/usr/bin/env node | ||
| // src/constants.ts | ||
| var VERSION = "0.7.0"; | ||
| var SETUP_URL = "https://github.com/Swarmwage/swarmwage/tree/main/packages/mcp-server#setup"; | ||
| export { SETUP_URL, VERSION }; | ||
| //# sourceMappingURL=chunk-3OE2NWZB.js.map | ||
| //# sourceMappingURL=chunk-3OE2NWZB.js.map |
| {"version":3,"sources":["../src/constants.ts"],"names":[],"mappings":";;AAIO,IAAM,OAAA,GAAU;AAEhB,IAAM,SAAA,GACX","file":"chunk-3OE2NWZB.js","sourcesContent":["// Swarmwage MCP — shared constants\n// License: MIT\n\n// keep in sync with package.json\nexport const VERSION = \"0.7.0\";\n\nexport const SETUP_URL =\n \"https://github.com/Swarmwage/swarmwage/tree/main/packages/mcp-server#setup\";\n\nexport const REGISTRY_URL_DEFAULT = \"https://api.swarmwage.com\";\n"]} |
| #!/usr/bin/env node | ||
| import { loadWallet } from './chunk-ZT7UGTAE.js'; | ||
| import { VERSION, SETUP_URL } from './chunk-3OE2NWZB.js'; | ||
| import { Server } from '@modelcontextprotocol/sdk/server/index.js'; | ||
| import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; | ||
| import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'; | ||
| import { AgentClient, InsufficientFundsError } from '@swarmwage/agent-sdk'; | ||
| // src/agentic-market.ts | ||
| var AGENTIC_MARKET_API_URL = "https://api.agentic.market"; | ||
| async function searchAgenticMarketServices(req, opts = {}) { | ||
| const fetchImpl = opts.fetchImpl ?? globalThis.fetch; | ||
| const apiUrl = opts.apiUrl ?? AGENTIC_MARKET_API_URL; | ||
| const limit = clampLimit(req.limit); | ||
| const query = (req.query ?? "").trim(); | ||
| const upstreamLimit = Math.max(limit * 3, 25); | ||
| const url = new URL( | ||
| query.length > 0 ? `${apiUrl}/v1/services/search` : `${apiUrl}/v1/services` | ||
| ); | ||
| if (query.length > 0) url.searchParams.set("q", query); | ||
| url.searchParams.set("limit", String(Math.min(upstreamLimit, 100))); | ||
| url.searchParams.set("offset", "0"); | ||
| const res = await fetchImpl(url); | ||
| if (!res.ok) { | ||
| throw new Error( | ||
| `agentic.market search failed: ${res.status} ${res.statusText}` | ||
| ); | ||
| } | ||
| const page = await res.json(); | ||
| const services = Array.isArray(page.services) ? page.services : []; | ||
| const endpoints = normalizeEndpoints(services, req).sort(compareEndpointRank).slice(0, limit); | ||
| return { | ||
| source: "agentic.market", | ||
| query, | ||
| total_services_reported: Number(page.total ?? services.length), | ||
| scanned_services: services.length, | ||
| endpoints, | ||
| filters: { | ||
| network: "Base", | ||
| currency: "USDC", | ||
| pricing_scheme: req.include_dynamic_pricing ? "exact+dynamic" : "exact", | ||
| max_price_usdc: req.max_price_usdc | ||
| }, | ||
| note: "These are external x402 endpoints from Agentic Market, not Swarmwage-verified sellers. Use call_x402_service with the returned call_hint to pay/call one; no Swarmwage receipt, verifier, or rating is attached." | ||
| }; | ||
| } | ||
| function normalizeEndpoints(services, req) { | ||
| const out = []; | ||
| const seen = /* @__PURE__ */ new Set(); | ||
| const category = (req.category ?? "").trim().toLowerCase(); | ||
| const maxPrice = parsePrice(req.max_price_usdc); | ||
| for (const svc of services) { | ||
| const svcCategory = text(svc.category); | ||
| if (category && svcCategory.toLowerCase() !== category) continue; | ||
| const endpoints = Array.isArray(svc.endpoints) ? svc.endpoints : []; | ||
| for (const endpoint of endpoints) { | ||
| const pricing = objectOrNull(endpoint.pricing); | ||
| if (!pricing) continue; | ||
| const network = text(pricing.network); | ||
| const currency = text(pricing.currency); | ||
| const scheme = text(pricing.scheme); | ||
| const amount = text(pricing.amount); | ||
| const price = parsePrice(amount); | ||
| const url = text(endpoint.url); | ||
| if (!url || price === null || price <= 0) continue; | ||
| if (!isBaseNetwork(network)) continue; | ||
| if (currency.toUpperCase() !== "USDC") continue; | ||
| if (!req.include_dynamic_pricing && scheme !== "exact") continue; | ||
| if (req.include_dynamic_pricing && scheme !== "exact" && scheme !== "upto") { | ||
| continue; | ||
| } | ||
| if (maxPrice !== null && price > maxPrice) continue; | ||
| const method = text(endpoint.method).toUpperCase() || "GET"; | ||
| const key = `${method} ${url}`; | ||
| if (seen.has(key)) continue; | ||
| seen.add(key); | ||
| const quality = objectOrNull(endpoint.quality); | ||
| const maxAmount = text(pricing.maxAmount); | ||
| const minAmount = text(pricing.minAmount); | ||
| out.push({ | ||
| source: "agentic.market", | ||
| service_id: text(svc.id), | ||
| service_name: text(svc.name) || text(svc.domain), | ||
| service_description: text(svc.description), | ||
| category: svcCategory, | ||
| domain: text(svc.domain), | ||
| provider_url: text(svc.providerUrl), | ||
| integration_type: text(svc.integrationType), | ||
| endpoint: { | ||
| url, | ||
| method, | ||
| description: text(endpoint.description), | ||
| pricing: { | ||
| amount_usdc: amount, | ||
| scheme, | ||
| network, | ||
| currency, | ||
| max_amount_usdc: maxAmount || void 0, | ||
| min_amount_usdc: minAmount || void 0 | ||
| }, | ||
| parameters: normalizeParameters(endpoint.parameters), | ||
| quality: quality ? { | ||
| last_30d_calls: integer(quality.l30DaysTotalCalls), | ||
| last_30d_unique_payers: integer(quality.l30DaysUniquePayers) | ||
| } : null | ||
| }, | ||
| call_hint: { | ||
| tool: "call_x402_service", | ||
| url, | ||
| method, | ||
| max_price_usdc: maxAmount || amount | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| return out; | ||
| } | ||
| function normalizeParameters(input) { | ||
| if (!Array.isArray(input)) return []; | ||
| return input.map((param) => ({ | ||
| group: text(param.group), | ||
| name: text(param.name), | ||
| type: text(param.type), | ||
| description: text(param.description), | ||
| example: param.example, | ||
| required: Boolean(param.required) | ||
| })); | ||
| } | ||
| function compareEndpointRank(a, b) { | ||
| const aq = a.endpoint.quality; | ||
| const bq = b.endpoint.quality; | ||
| const calls = (bq?.last_30d_calls ?? 0) - (aq?.last_30d_calls ?? 0); | ||
| if (calls !== 0) return calls; | ||
| const payers = (bq?.last_30d_unique_payers ?? 0) - (aq?.last_30d_unique_payers ?? 0); | ||
| if (payers !== 0) return payers; | ||
| return Number(a.endpoint.pricing.amount_usdc) - Number(b.endpoint.pricing.amount_usdc); | ||
| } | ||
| function clampLimit(limit) { | ||
| if (!Number.isFinite(limit)) return 10; | ||
| return Math.max(1, Math.min(Math.trunc(limit ?? 10), 25)); | ||
| } | ||
| function text(value) { | ||
| return typeof value === "string" ? value : ""; | ||
| } | ||
| function integer(value) { | ||
| const parsed = Number(value); | ||
| return Number.isFinite(parsed) ? Math.max(0, Math.trunc(parsed)) : 0; | ||
| } | ||
| function parsePrice(value) { | ||
| if (typeof value !== "string" && typeof value !== "number") return null; | ||
| const parsed = Number(value); | ||
| return Number.isFinite(parsed) ? parsed : null; | ||
| } | ||
| function isBaseNetwork(network) { | ||
| const normalized = network.toLowerCase(); | ||
| return normalized === "base" || normalized === "eip155:8453"; | ||
| } | ||
| function objectOrNull(value) { | ||
| return value && typeof value === "object" ? value : null; | ||
| } | ||
| function ok(payload) { | ||
| return { | ||
| content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] | ||
| }; | ||
| } | ||
| function errResult(message) { | ||
| return { | ||
| content: [{ type: "text", text: message }], | ||
| isError: true | ||
| }; | ||
| } | ||
| function walletRequired(toolName) { | ||
| return errResult( | ||
| `'${toolName}' requires a wallet. Run 'npx @swarmwage/mcp' once in your terminal to set one up (test wallet or paste your own key). | ||
| Details: ${SETUP_URL} | ||
| In lookup-only mode you can still use: search_agents, search_x402_services, check_reputation, get_remaining_budget, get_agent_id.` | ||
| ); | ||
| } | ||
| function insufficientFundsResult(err) { | ||
| const chainLabel = err.chain === "base" ? "Base mainnet" : "Base Sepolia testnet"; | ||
| const onramp = err.chain === "base" ? "Coinbase, Binance, or any USDC-on-Base bridge (https://bridge.base.org)" : "the Base Sepolia faucet (https://faucet.circle.com \u2014 testnet USDC, free)"; | ||
| const body = [ | ||
| `Hire could not settle: wallet ${err.agent_id} does not hold enough USDC on ${chainLabel}.`, | ||
| "", | ||
| `Action required: fund ${err.agent_id} with at least ${err.required_usdc} USDC on ${chainLabel} via ${onramp}, then call hire_agent again with the same arguments.`, | ||
| "", | ||
| "Do NOT substitute a different image / audio / data service \u2014 the Swarmwage hire will succeed once the wallet is funded. The whole point of the marketplace is that the agent you found is reachable; the only missing input is buyer-side USDC." | ||
| ].join("\n"); | ||
| return { content: [{ type: "text", text: body }], isError: true }; | ||
| } | ||
| function createToolHandler(deps) { | ||
| const { | ||
| ensureClient, | ||
| directSearch, | ||
| directReputation, | ||
| searchExternalX402Services | ||
| } = deps; | ||
| return async function handleToolCall(params) { | ||
| const { name, arguments: rawArgs } = params; | ||
| const args = rawArgs ?? {}; | ||
| try { | ||
| switch (name) { | ||
| case "search_agents": { | ||
| const searchReq = { | ||
| capability: String(args.capability), | ||
| max_price_usdc: args.max_price_usdc, | ||
| max_latency_ms: args.max_latency_ms, | ||
| min_success_rate: args.min_success_rate, | ||
| min_avg_stars: args.min_avg_stars, | ||
| limit: args.limit | ||
| }; | ||
| const response = await directSearch(searchReq); | ||
| if (response.agents.length === 0) { | ||
| return ok({ | ||
| agents: [], | ||
| match: response.match, | ||
| next_cursor: response.next_cursor, | ||
| available_capabilities: response.available_capabilities ?? [], | ||
| total_distinct_capabilities: response.total_distinct_capabilities ?? 0, | ||
| hint: `No agent found for capability '${searchReq.capability}'. Pick one of the IDs in 'available_capabilities' (the live taxonomy) and retry \u2014 do not guess variants.` | ||
| }); | ||
| } | ||
| return ok({ agents: response.agents }); | ||
| } | ||
| case "list_capabilities": { | ||
| const response = await directSearch({ | ||
| capability: "__list_capabilities__", | ||
| limit: 1 | ||
| }); | ||
| return ok({ | ||
| capabilities: response.available_capabilities ?? [], | ||
| total: response.total_distinct_capabilities ?? 0 | ||
| }); | ||
| } | ||
| case "search_x402_services": { | ||
| const response = await searchExternalX402Services({ | ||
| query: args.query, | ||
| category: args.category, | ||
| max_price_usdc: args.max_price_usdc, | ||
| limit: args.limit, | ||
| include_dynamic_pricing: Boolean(args.include_dynamic_pricing ?? false) | ||
| }); | ||
| return ok(response); | ||
| } | ||
| case "check_reputation": { | ||
| const client = await ensureClient(); | ||
| const agentId = args.agent_id; | ||
| const rep = client ? await client.getReputation(agentId) : await directReputation(agentId); | ||
| return ok(rep); | ||
| } | ||
| case "get_remaining_budget": { | ||
| const client = await ensureClient(); | ||
| return ok({ | ||
| remaining_usdc: client ? client.remainingBudget() : "0.00" | ||
| }); | ||
| } | ||
| case "get_agent_id": { | ||
| const client = await ensureClient(); | ||
| return ok({ agent_id: client ? client.agentId : null }); | ||
| } | ||
| case "hire_agent": { | ||
| const client = await ensureClient(); | ||
| if (!client) return walletRequired("hire_agent"); | ||
| const response = await client.hire({ | ||
| capability: String(args.capability), | ||
| params: args.params ?? {}, | ||
| max_price_usdc: String(args.max_price_usdc), | ||
| agent_id: args.agent_id, | ||
| max_latency_ms: args.max_latency_ms | ||
| }); | ||
| return ok({ | ||
| result: response.result, | ||
| receipt: response.receipt, | ||
| verification: response.verification, | ||
| rating_token: response.rating_token, | ||
| remaining_budget_usdc: client.remainingBudget() | ||
| }); | ||
| } | ||
| case "rate_agent": { | ||
| const client = await ensureClient(); | ||
| if (!client) return walletRequired("rate_agent"); | ||
| await client.rate(String(args.rating_token), { | ||
| stars: Number(args.stars), | ||
| comment: args.comment | ||
| }); | ||
| return ok({ success: true }); | ||
| } | ||
| case "publish_listing": | ||
| case "update_listing": { | ||
| const client = await ensureClient(); | ||
| if (!client) return walletRequired(name); | ||
| const listing = await client.publishListing({ | ||
| capability: String(args.capability), | ||
| price_usdc: String(args.price_usdc), | ||
| endpoint: String(args.endpoint), | ||
| max_latency_ms: Number(args.max_latency_ms), | ||
| first_call_free: Boolean(args.first_call_free ?? false), | ||
| currency: args.currency ?? "USDC", | ||
| chain: args.chain ?? "base" | ||
| }); | ||
| return ok({ listing }); | ||
| } | ||
| case "list_my_listings": { | ||
| const client = await ensureClient(); | ||
| if (!client) return walletRequired("list_my_listings"); | ||
| const listings = await client.getMyListings(); | ||
| return ok({ count: listings.length, listings }); | ||
| } | ||
| case "get_my_receipts": { | ||
| const client = await ensureClient(); | ||
| if (!client) return walletRequired("get_my_receipts"); | ||
| const receipts = await client.getMyReceipts({ | ||
| limit: args.limit | ||
| }); | ||
| return ok({ count: receipts.length, receipts }); | ||
| } | ||
| case "call_x402_service": { | ||
| const client = await ensureClient(); | ||
| if (!client) return walletRequired("call_x402_service"); | ||
| const response = await client.payX402({ | ||
| url: String(args.url), | ||
| method: args.method, | ||
| body: args.body, | ||
| headers: args.headers, | ||
| max_price_usdc: args.max_price_usdc | ||
| }); | ||
| return ok({ | ||
| url: response.url, | ||
| status: response.status, | ||
| data: response.data, | ||
| tx_hash: response.tx_hash, | ||
| amount_paid_usdc: response.amount_paid_usdc, | ||
| latency_ms: response.latency_ms, | ||
| remaining_budget_usdc: client.remainingBudget() | ||
| }); | ||
| } | ||
| default: | ||
| return errResult(`Unknown tool: ${name}`); | ||
| } | ||
| } catch (e) { | ||
| if (e instanceof InsufficientFundsError) { | ||
| return insufficientFundsResult(e); | ||
| } | ||
| const error = e; | ||
| return errResult( | ||
| `${error.code ? `[${error.code}] ` : ""}${error.message ?? "Unknown error"}` | ||
| ); | ||
| } | ||
| }; | ||
| } | ||
| // src/tools.ts | ||
| var tools = [ | ||
| { | ||
| name: "search_agents", | ||
| description: "Search the Swarmwage registry for agents that can perform a given capability. Returns a ranked list with prices, latency, and reputation. Use this when you need to find an agent for hire \u2014 e.g. when you encounter a task you cannot perform natively (image generation, audio transcription, specialized data lookup, niche translations, etc.).\n\nIMPORTANT: capability IDs follow a strict taxonomy (e.g. `code.execute.sandboxed`, NOT `code.execute.python.sandbox`). If your call returns zero agents, the response includes `available_capabilities` (the live taxonomy) and `total_distinct_capabilities`. Use one of those exact strings on retry \u2014 do not guess variants. When unsure, call `list_capabilities` first.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { | ||
| type: "string", | ||
| description: "The capability ID, e.g. 'image.generate.photorealistic.png', 'audio.transcribe.it.json-with-timestamps', 'text.translate.en.it.business'. See https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md for the full taxonomy." | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Maximum price willing to pay per call, in USDC as a decimal string, e.g. '1.50'. Optional." | ||
| }, | ||
| max_latency_ms: { | ||
| type: "number", | ||
| description: "Maximum acceptable latency in milliseconds. Optional. Use 5000-15000 for sync calls." | ||
| }, | ||
| min_success_rate: { | ||
| type: "number", | ||
| description: "Minimum success rate (0.0-1.0). Defaults to 0.95 if you care about reliability." | ||
| }, | ||
| min_avg_stars: { | ||
| type: "number", | ||
| description: "Minimum average rating (1-5). Defaults to 4.0." | ||
| }, | ||
| limit: { | ||
| type: "number", | ||
| description: "Max results to return. Default 10." | ||
| } | ||
| }, | ||
| required: ["capability"] | ||
| } | ||
| }, | ||
| { | ||
| name: "hire_agent", | ||
| description: "Hire an agent to execute a capability. Returns the result synchronously. Payment is in USDC via x402 direct settlement (the live default): funds move from your wallet to the seller when the x402 payment succeeds, BEFORE the output is verified. The SDK runs the capability's verifier before returning a successful result; if verification fails the call fails \u2014 but direct mode does NOT refund a failed or bad output, and there is no escrow. Once payment succeeds the spend is final. Use this after you've found a suitable agent via search_agents (or pass agent_id=null to auto-pick the best match). Requires a wallet.\n\nMAX_PRICE_USDC semantics: the parameter is BOTH a search filter and a willingness-to-pay cap. Two valid patterns:\n (a) `max_price_usdc='0'` (or '0.00') \u2014 \"free-hire intent\": the SDK searches without the price filter and accepts only listings with `first_call_free: true`. Use this when get_remaining_budget returns '0.00' and you want to try a free-tier listing.\n (b) `max_price_usdc='X.YZ'` (positive) \u2014 \"cap intent\": the SDK filters listings priced \u2264 X.YZ and proceeds with payment. The listing's actual price (which may be lower) is what gets charged.\nPicking pattern (a) when you intend free-tier hires is critical: passing `'0.00'` to mean \"I have no budget\" used to filter out positive-price first_call_free listings; v0.5.1+ of the SDK now handles this correctly and returns a clear error if no free-tier listing exists for the capability.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { | ||
| type: "string", | ||
| description: "The capability ID to hire for, e.g. 'image.generate.photorealistic.png'." | ||
| }, | ||
| params: { | ||
| type: "object", | ||
| description: "Capability-specific input parameters. Schema depends on the capability. Example for image.generate.photorealistic.png: { prompt: string, width: int, height: int, seed?: int }.", | ||
| additionalProperties: true | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Maximum price per call, USDC decimal string. Pass '0' (or '0.00') to require a free-tier hire (first_call_free listings only \u2014 the SDK searches without the price filter in this mode). Pass a positive value (e.g. '0.10') to set an upper-bound cap. See tool description for full semantics." | ||
| }, | ||
| agent_id: { | ||
| type: "string", | ||
| description: "Specific agent to hire (0x-prefixed address). If omitted, the SDK picks the best match by price + reputation." | ||
| }, | ||
| max_latency_ms: { | ||
| type: "number", | ||
| description: "Maximum acceptable latency in ms. Optional." | ||
| } | ||
| }, | ||
| required: ["capability", "params", "max_price_usdc"] | ||
| } | ||
| }, | ||
| { | ||
| name: "check_reputation", | ||
| description: "Look up reputation stats for a specific agent: success rate, average latency, hire count, ratings. Use this to vet an agent before a high-stakes hire.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| agent_id: { | ||
| type: "string", | ||
| description: "0x-prefixed agent address." | ||
| } | ||
| }, | ||
| required: ["agent_id"] | ||
| } | ||
| }, | ||
| { | ||
| name: "rate_agent", | ||
| description: "Submit a rating after a hire. Use the rating_token returned in the hire receipt. Single-use per receipt. Provide honest stars (1-5) \u2014 your ratings power the reputation system that benefits everyone. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| rating_token: { type: "string", description: "The rating_token from a previous hire response." }, | ||
| stars: { type: "number", description: "Rating 1-5 (integer).", minimum: 1, maximum: 5 }, | ||
| comment: { type: "string", description: "Optional short comment." } | ||
| }, | ||
| required: ["rating_token", "stars"] | ||
| } | ||
| }, | ||
| { | ||
| name: "get_remaining_budget", | ||
| description: "Return how much USDC remains in the operator-authorized budget for this session. Returns '0.00' if no budget is loaded or no wallet is configured.\n\nIMPORTANT: a '0.00' return value does NOT block hires of listings with `first_call_free: true`. The SDK skips the budget check entirely for free listings, so try-it-free hires succeed even at zero budget. Only paid hires require positive remaining budget.", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "get_agent_id", | ||
| description: "Return the agent ID (0x-prefixed wallet address) of this MCP server. Returns null in lookup-only mode (no wallet configured).", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "publish_listing", | ||
| description: "Publish (or update) a listing on the Swarmwage registry, advertising a capability this agent can fulfill. After publishing, buyers can discover and hire you via `search_agents` and `hire_agent`. The listing is idempotent on (agent_id, capability) \u2014 calling again replaces price, endpoint, latency, etc. Your agent must already be running an HTTP server that accepts x402 payments at `endpoint`. Returns the signed listing. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { type: "string", description: "Capability ID this listing serves." }, | ||
| price_usdc: { type: "string", description: "Price per call in USDC, e.g. '0.02'." }, | ||
| endpoint: { | ||
| type: "string", | ||
| description: "Public HTTPS URL of your seller hire endpoint." | ||
| }, | ||
| max_latency_ms: { type: "number", description: "Worst-case latency, in ms." }, | ||
| first_call_free: { type: "boolean", description: "Whether the first call is free." }, | ||
| currency: { type: "string", enum: ["USDC"] }, | ||
| chain: { | ||
| type: "string", | ||
| enum: ["base"], | ||
| description: "Settlement chain for this listing. Only 'base' (Base mainnet) is accepted by the public registry." | ||
| } | ||
| }, | ||
| required: ["capability", "price_usdc", "endpoint", "max_latency_ms"] | ||
| } | ||
| }, | ||
| { | ||
| name: "update_listing", | ||
| description: "Alias of `publish_listing` \u2014 same idempotent upsert. Use this when changing price, endpoint, or max_latency_ms of a capability you already publish. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { type: "string" }, | ||
| price_usdc: { type: "string" }, | ||
| endpoint: { type: "string" }, | ||
| max_latency_ms: { type: "number" }, | ||
| first_call_free: { type: "boolean" }, | ||
| currency: { type: "string", enum: ["USDC"] }, | ||
| chain: { | ||
| type: "string", | ||
| enum: ["base"], | ||
| description: "Settlement chain for this listing. Only 'base' (Base mainnet) is accepted by the public registry." | ||
| } | ||
| }, | ||
| required: ["capability", "price_usdc", "endpoint", "max_latency_ms"] | ||
| } | ||
| }, | ||
| { | ||
| name: "list_my_listings", | ||
| description: "Return all active listings this agent has published to the registry. Read-only. Requires a wallet.", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "get_my_receipts", | ||
| description: "Return recent receipts this agent has submitted to the registry (seller-side view). Read-only. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| limit: { type: "number", description: "How many to return. Default 50, max 200." } | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| name: "list_capabilities", | ||
| description: "Return all capability IDs currently live on the Swarmwage registry, plus the total distinct count. Use this BEFORE `search_agents` whenever you don't already know the exact capability name \u2014 the taxonomy is strict (e.g. `code.execute.sandboxed`, not `code.execute.python.sandbox`). Calling this first prevents wasted search round-trips on guessed IDs. Read-only, no wallet required.", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "search_x402_services", | ||
| description: "Search Agentic Market for third-party x402-enabled HTTP endpoints your agent can pay/call directly with `call_x402_service`. Use this when Swarmwage-native `search_agents` has no suitable seller, or when you need a raw external API/service (web search, data enrichment, inference gateway, media API, etc.). Read-only, no wallet required.\n\nIMPORTANT: returned services are EXTERNAL x402 endpoints, not Swarmwage-verified sellers. They do not have Swarmwage receipts, capability verification, or ratings. The response includes a `call_hint` containing the exact `url`, `method`, and `max_price_usdc` to pass to `call_x402_service`. By default this tool returns only Base USDC endpoints with exact fixed pricing, because those are the safest to pay from a Swarmwage wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| query: { | ||
| type: "string", | ||
| description: "Search text, e.g. 'exa search', 'email enrichment', 'stock quote', 'screenshot', 'transcription'. Omit to browse top services." | ||
| }, | ||
| category: { | ||
| type: "string", | ||
| description: "Optional Agentic Market category filter such as Search, Data, Inference, Media, Social, Infra, Storage, Travel, or Trading." | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Optional fixed-price ceiling in USDC decimal string. Endpoints priced above this are omitted." | ||
| }, | ||
| limit: { | ||
| type: "number", | ||
| description: "Maximum endpoints to return. Default 10, max 25." | ||
| }, | ||
| include_dynamic_pricing: { | ||
| type: "boolean", | ||
| description: "Default false. When true, also include Agentic Market endpoints marked with dynamic `upto` pricing; keep false unless the user explicitly accepts variable pricing." | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| name: "call_x402_service", | ||
| description: "Pay for and call ANY x402-enabled HTTP endpoint directly from this agent's wallet \u2014 including third-party services NOT listed on the Swarmwage registry (e.g. an external x402 catalog). Use this when you already know the exact endpoint URL of a paid service and want to call it with its own native request shape, rather than discovering a Swarmwage seller via search_agents/hire_agent.\n\nDifference from hire_agent: hire_agent targets a Swarmwage-protocol seller (capability + verified output + rating). call_x402_service makes a raw paid HTTP request to an arbitrary x402 URL and returns its raw JSON response \u2014 there is no capability verification or rating. The SDK handles the 402 \u2192 payment \u2192 retry dance, forces payment onto Base, and refuses to pay above max_price_usdc. If the wallet lacks USDC, returns a fund-the-wallet instruction (do NOT substitute another service). Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| url: { | ||
| type: "string", | ||
| description: "Absolute URL of the x402-enabled endpoint, e.g. 'https://api.example.com/search'." | ||
| }, | ||
| method: { | ||
| type: "string", | ||
| description: "HTTP method. Defaults to 'POST' when `body` is provided, else 'GET'." | ||
| }, | ||
| body: { | ||
| type: "object", | ||
| description: "JSON request body in the service's OWN native shape (not a Swarmwage envelope). Omit for GET endpoints.", | ||
| additionalProperties: true | ||
| }, | ||
| headers: { | ||
| type: "object", | ||
| description: "Optional extra request headers.", | ||
| additionalProperties: { type: "string" } | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Willingness-to-pay cap per call, USDC decimal string, e.g. '0.05'. The SDK refuses to sign a payment above this. Defaults to '1.00'." | ||
| } | ||
| }, | ||
| required: ["url"] | ||
| } | ||
| } | ||
| ]; | ||
| // src/update-check.ts | ||
| var NPM_REGISTRY_URL = "https://registry.npmjs.org/@swarmwage/mcp/latest"; | ||
| var TIMEOUT_MS = 2e3; | ||
| function isOptedOut() { | ||
| const raw = process.env.SWARMWAGE_NO_UPDATE_CHECK; | ||
| if (!raw) return false; | ||
| return /^(1|true|on|yes)$/i.test(raw.trim()); | ||
| } | ||
| function compareSemver(a, b) { | ||
| if (!/^\d+\.\d+\.\d+/.test(a) || !/^\d+\.\d+\.\d+/.test(b)) return 0; | ||
| const pa = a.split(".").map((n) => parseInt(n, 10)); | ||
| const pb = b.split(".").map((n) => parseInt(n, 10)); | ||
| for (let i = 0; i < 3; i++) { | ||
| const da = pa[i] ?? 0; | ||
| const db = pb[i] ?? 0; | ||
| if (da !== db) return da > db ? 1 : -1; | ||
| } | ||
| return 0; | ||
| } | ||
| async function checkForUpdate() { | ||
| if (isOptedOut()) return; | ||
| try { | ||
| const ctrl = new AbortController(); | ||
| const timer = setTimeout(() => ctrl.abort(), TIMEOUT_MS); | ||
| let res; | ||
| try { | ||
| res = await fetch(NPM_REGISTRY_URL, { | ||
| signal: ctrl.signal, | ||
| headers: { Accept: "application/json" } | ||
| }); | ||
| } finally { | ||
| clearTimeout(timer); | ||
| } | ||
| if (!res.ok) return; | ||
| const data = await res.json(); | ||
| const latest = data.version; | ||
| if (typeof latest !== "string") return; | ||
| if (compareSemver(latest, VERSION) <= 0) return; | ||
| process.stderr.write( | ||
| `swarmwage-mcp: update available ${VERSION} \u2192 ${latest}. Run: npx -y @swarmwage/mcp@latest --init to refresh, or pin the new version in your host config. | ||
| (set SWARMWAGE_NO_UPDATE_CHECK=1 to silence this notice) | ||
| ` | ||
| ); | ||
| } catch { | ||
| } | ||
| } | ||
| // src/server.ts | ||
| async function runServer() { | ||
| const REGISTRY_URL = process.env.SWARMWAGE_REGISTRY_URL ?? "https://api.swarmwage.com"; | ||
| const NETWORK = process.env.SWARMWAGE_NETWORK ?? "base"; | ||
| const envKey = process.env.SWARMWAGE_PRIVATE_KEY; | ||
| let budget; | ||
| if (process.env.SWARMWAGE_BUDGET_TOKEN) { | ||
| try { | ||
| budget = JSON.parse(process.env.SWARMWAGE_BUDGET_TOKEN); | ||
| } catch (err) { | ||
| process.stderr.write( | ||
| `swarmwage-mcp: SWARMWAGE_BUDGET_TOKEN is not valid JSON: ${err.message} | ||
| ` | ||
| ); | ||
| process.exit(1); | ||
| } | ||
| } | ||
| async function directSearch(req) { | ||
| const res = await fetch(`${REGISTRY_URL}/v1/search`, { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify(req) | ||
| }); | ||
| if (!res.ok) { | ||
| throw new Error( | ||
| `registry search failed: ${res.status} ${res.statusText}` | ||
| ); | ||
| } | ||
| return await res.json(); | ||
| } | ||
| async function directReputation(agentId) { | ||
| const res = await fetch( | ||
| `${REGISTRY_URL}/v1/agents/${agentId}/reputation` | ||
| ); | ||
| if (!res.ok) { | ||
| throw new Error( | ||
| `registry reputation failed: ${res.status} ${res.statusText}` | ||
| ); | ||
| } | ||
| return await res.json(); | ||
| } | ||
| async function searchExternalX402Services(req) { | ||
| return searchAgenticMarketServices(req); | ||
| } | ||
| let clientPromise = null; | ||
| function ensureClient() { | ||
| if (!clientPromise) { | ||
| clientPromise = (async () => { | ||
| const fileKey = envKey ? null : await loadWallet(); | ||
| const PRIVATE_KEY = envKey ?? fileKey ?? void 0; | ||
| if (!PRIVATE_KEY) return void 0; | ||
| return new AgentClient({ | ||
| privateKey: PRIVATE_KEY, | ||
| registryUrl: REGISTRY_URL, | ||
| budget, | ||
| network: NETWORK | ||
| }); | ||
| })(); | ||
| } | ||
| return clientPromise; | ||
| } | ||
| const server = new Server( | ||
| { name: "swarmwage", version: VERSION }, | ||
| // `tools.listChanged: true` signals that the tool list is dynamic and | ||
| // the host should re-read on `notifications/tools/list_changed`. We | ||
| // never actually mutate the list at runtime today, but advertising the | ||
| // capability makes harnesses with stricter cache-invalidation behavior | ||
| // re-query on retry instead of pinning a stale empty list. | ||
| { capabilities: { tools: { listChanged: true } } } | ||
| ); | ||
| server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools })); | ||
| const handleToolCall = createToolHandler({ | ||
| ensureClient, | ||
| directSearch, | ||
| directReputation, | ||
| searchExternalX402Services | ||
| }); | ||
| server.setRequestHandler( | ||
| CallToolRequestSchema, | ||
| async (request) => handleToolCall(request.params) | ||
| ); | ||
| const transport = new StdioServerTransport(); | ||
| await server.connect(transport); | ||
| process.stderr.write(`swarmwage-mcp v${VERSION} listening on stdio | ||
| `); | ||
| void ensureClient().then((client) => { | ||
| if (client) { | ||
| const source = envKey ? "env" : "config"; | ||
| process.stderr.write( | ||
| `swarmwage-mcp v${VERSION} wallet ready (agent_id=${client.agentId}, source=${source}) | ||
| ` | ||
| ); | ||
| } else { | ||
| process.stderr.write( | ||
| `swarmwage-mcp v${VERSION} lookup-only (no wallet) | ||
| Enabled: search_agents, search_x402_services, list_capabilities, check_reputation, get_remaining_budget, get_agent_id | ||
| Setup wallet: npx @swarmwage/mcp | ||
| ` | ||
| ); | ||
| } | ||
| }); | ||
| void checkForUpdate(); | ||
| } | ||
| export { runServer }; | ||
| //# sourceMappingURL=server-YHR6QJVH.js.map | ||
| //# sourceMappingURL=server-YHR6QJVH.js.map |
Sorry, the diff of this file is too big to display
| #!/usr/bin/env node | ||
| import { loadConfig, saveWallet, saveConfig } from './chunk-ZT7UGTAE.js'; | ||
| import { VERSION, SETUP_URL } from './chunk-3OE2NWZB.js'; | ||
| import { spawn } from 'child_process'; | ||
| import { access, readFile, mkdir, writeFile } from 'fs/promises'; | ||
| import { homedir } from 'os'; | ||
| import { join, dirname } from 'path'; | ||
| import readline from 'readline'; | ||
| import { privateKeyToAddress, generatePrivateKey } from 'viem/accounts'; | ||
| var colorEnabled = Boolean(process.stdout.isTTY) && process.env.NO_COLOR !== "1"; | ||
| var c = { | ||
| violet: (s) => colorEnabled ? `\x1B[38;5;141m${s}\x1B[0m` : s, | ||
| softViolet: (s) => colorEnabled ? `\x1B[38;5;183m${s}\x1B[0m` : s, | ||
| bold: (s) => colorEnabled ? `\x1B[1m${s}\x1B[0m` : s, | ||
| dim: (s) => colorEnabled ? `\x1B[2m${s}\x1B[0m` : s, | ||
| green: (s) => colorEnabled ? `\x1B[32m${s}\x1B[0m` : s, | ||
| red: (s) => colorEnabled ? `\x1B[31m${s}\x1B[0m` : s, | ||
| cyan: (s) => colorEnabled ? `\x1B[36m${s}\x1B[0m` : s, | ||
| yellow: (s) => colorEnabled ? `\x1B[33m${s}\x1B[0m` : s | ||
| }; | ||
| function printArt() { | ||
| const art = [ | ||
| "", | ||
| " \u2572\u2571\u2572\u2571\u2572\u2571\u2572", | ||
| " \u2571\u2572\u2571\u2572\u2571\u2572\u2571 " + c.bold("swarmwage") + c.dim(" \xB7 v" + VERSION), | ||
| " \u2572\u2571\u2572\u2571\u2572\u2571\u2572 " + c.dim("the agent hire protocol"), | ||
| " \u2571\u2572\u2571\u2572\u2571\u2572\u2571", | ||
| "" | ||
| ]; | ||
| for (const line of art) { | ||
| console.log(c.violet(line.startsWith(" \u2572") || line.startsWith(" \u2571") ? line : line)); | ||
| } | ||
| } | ||
| function printWelcome() { | ||
| console.log( | ||
| c.dim(" Free, open protocol for AI agents to discover, hire, and rate each other.") | ||
| ); | ||
| console.log(c.dim(" Settlement in USDC on Base. Zero token, zero KYC, zero protocol fee.")); | ||
| console.log(""); | ||
| console.log(c.bold(" Setup takes 30 seconds. Press Ctrl-C any time to abort.")); | ||
| console.log(""); | ||
| } | ||
| function question(q) { | ||
| const rl = readline.createInterface({ | ||
| input: process.stdin, | ||
| output: process.stdout | ||
| }); | ||
| return new Promise((resolve) => { | ||
| rl.question(q, (ans) => { | ||
| rl.close(); | ||
| resolve(ans.trim()); | ||
| }); | ||
| }); | ||
| } | ||
| async function select(prompt, options) { | ||
| console.log(c.bold(prompt)); | ||
| console.log(""); | ||
| options.forEach((opt, i) => { | ||
| console.log(` ${c.violet(`[${i + 1}]`)} ${c.bold(opt.label)}`); | ||
| if (opt.description) { | ||
| console.log(` ${c.dim(opt.description)}`); | ||
| } | ||
| }); | ||
| console.log(""); | ||
| while (true) { | ||
| const ans = await question( | ||
| `${c.violet("?")} Enter choice ${c.dim(`(1-${options.length})`)} ` | ||
| ); | ||
| const idx = parseInt(ans, 10); | ||
| if (Number.isFinite(idx) && idx >= 1 && idx <= options.length) { | ||
| return options[idx - 1].value; | ||
| } | ||
| console.log(c.red(` Invalid input. Enter a number 1-${options.length}.`)); | ||
| } | ||
| } | ||
| async function confirm(prompt, defaultYes = true) { | ||
| const suffix = c.dim(defaultYes ? "(Y/n)" : "(y/N)"); | ||
| const ans = await question(`${c.violet("?")} ${prompt} ${suffix} `); | ||
| if (!ans) return defaultYes; | ||
| return /^y/i.test(ans); | ||
| } | ||
| async function promptPrivateKey() { | ||
| console.log(""); | ||
| console.log( | ||
| c.dim(" Paste your 0x-prefixed 32-byte private key. It will be saved to") | ||
| ); | ||
| console.log(c.dim(" ~/.swarmwage/wallet.key with 0600 permissions (user-readable only).")); | ||
| console.log( | ||
| c.yellow(" \u26A0 Use a dedicated key. Do not paste the main key of a wallet holding real funds.") | ||
| ); | ||
| console.log(""); | ||
| while (true) { | ||
| const ans = await question(c.violet("? ") + "Private key: "); | ||
| if (/^0x[a-fA-F0-9]{64}$/.test(ans)) { | ||
| return ans; | ||
| } | ||
| console.log(c.red(" Invalid format. Expected 0x followed by 64 hex chars (32 bytes).")); | ||
| } | ||
| } | ||
| function generateTestWallet() { | ||
| const key = generatePrivateKey(); | ||
| const address = privateKeyToAddress(key); | ||
| return { key, address }; | ||
| } | ||
| function easterEgg(addr) { | ||
| const last4 = addr.slice(-4).toLowerCase(); | ||
| const memorable = { | ||
| beef: "vanity address detected: ...beef", | ||
| cafe: "vanity address detected: ...cafe", | ||
| dead: "vanity address detected: ...dead", | ||
| face: "vanity address detected: ...face", | ||
| feed: "vanity address detected: ...feed", | ||
| babe: "vanity address detected: ...babe", | ||
| f00d: "vanity address detected: ...f00d", | ||
| "1337": "vanity address detected: ...1337" | ||
| }; | ||
| return memorable[last4] ?? null; | ||
| } | ||
| function printGeneratedWallet(address) { | ||
| console.log(""); | ||
| console.log(c.green(" \u2713 Generated a fresh test wallet:")); | ||
| console.log(""); | ||
| console.log(` ${c.bold(c.cyan(address))}`); | ||
| console.log(""); | ||
| console.log(c.dim(" This wallet has zero USDC. To start spending on hires, fund it on Base:")); | ||
| console.log(c.dim(" https://www.coinbase.com/onramp \u2192 send USDC to the address above")); | ||
| console.log(c.dim(" You don't need ETH for gas \u2014 the Swarmwage facilitator covers it.")); | ||
| console.log(""); | ||
| const egg = easterEgg(address); | ||
| if (egg) { | ||
| console.log(c.softViolet(` \u2728 ${egg}`)); | ||
| console.log(""); | ||
| } | ||
| } | ||
| function detectClaudeCode() { | ||
| return new Promise((resolve) => { | ||
| const proc = spawn("which", ["claude"], { stdio: "ignore" }); | ||
| proc.on("close", (code) => resolve(code === 0)); | ||
| proc.on("error", () => resolve(false)); | ||
| }); | ||
| } | ||
| async function detectClaudeDesktop() { | ||
| const platform = process.platform; | ||
| let path; | ||
| if (platform === "darwin") { | ||
| path = join( | ||
| homedir(), | ||
| "Library", | ||
| "Application Support", | ||
| "Claude", | ||
| "claude_desktop_config.json" | ||
| ); | ||
| } else if (platform === "win32") { | ||
| path = join( | ||
| process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), | ||
| "Claude", | ||
| "claude_desktop_config.json" | ||
| ); | ||
| } else { | ||
| path = join(homedir(), ".config", "Claude", "claude_desktop_config.json"); | ||
| } | ||
| try { | ||
| await access(path); | ||
| return path; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| function registerWithClaudeCode() { | ||
| return new Promise((resolve) => { | ||
| const proc = spawn( | ||
| "claude", | ||
| [ | ||
| "mcp", | ||
| "add", | ||
| "--scope", | ||
| "user", | ||
| "swarmwage", | ||
| "--", | ||
| "npx", | ||
| "-y", | ||
| "@swarmwage/mcp", | ||
| "--server" | ||
| ], | ||
| { stdio: "inherit" } | ||
| ); | ||
| proc.on("close", (code) => resolve(code === 0)); | ||
| proc.on("error", () => resolve(false)); | ||
| }); | ||
| } | ||
| async function patchClaudeDesktopConfig(configPath) { | ||
| let cfg = {}; | ||
| try { | ||
| const data = await readFile(configPath, "utf-8"); | ||
| cfg = JSON.parse(data); | ||
| } catch { | ||
| } | ||
| if (!cfg.mcpServers) cfg.mcpServers = {}; | ||
| cfg.mcpServers.swarmwage = { | ||
| command: "npx", | ||
| args: ["-y", "@swarmwage/mcp", "--server"] | ||
| }; | ||
| await mkdir(dirname(configPath), { recursive: true }); | ||
| await writeFile(configPath, JSON.stringify(cfg, null, 2), "utf-8"); | ||
| } | ||
| function printManualClaudeCode() { | ||
| console.log(""); | ||
| console.log(c.bold(" Add to Claude Code manually:")); | ||
| console.log(""); | ||
| console.log( | ||
| c.cyan(" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server") | ||
| ); | ||
| console.log(""); | ||
| } | ||
| function printManualClaudeDesktop(configPath) { | ||
| console.log(""); | ||
| console.log(c.bold(" Add to Claude Desktop manually:")); | ||
| console.log(c.dim(` Edit ${configPath} and add under "mcpServers":`)); | ||
| console.log(""); | ||
| const snippet = ` "swarmwage": { | ||
| "command": "npx", | ||
| "args": ["-y", "@swarmwage/mcp", "--server"] | ||
| }`; | ||
| console.log(c.cyan(snippet)); | ||
| console.log(""); | ||
| console.log(c.dim(" Then restart Claude Desktop.")); | ||
| console.log(""); | ||
| } | ||
| function printAllManualConfigs() { | ||
| console.log(""); | ||
| console.log(c.bold(" Manual setup snippets:")); | ||
| console.log(""); | ||
| console.log(c.dim(" Claude Code:")); | ||
| console.log( | ||
| c.cyan(" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server") | ||
| ); | ||
| console.log(""); | ||
| console.log(c.dim(" Claude Desktop / Cursor / Cline (claude_desktop_config.json):")); | ||
| const snippet = ` "swarmwage": { | ||
| "command": "npx", | ||
| "args": ["-y", "@swarmwage/mcp", "--server"] | ||
| }`; | ||
| console.log(c.cyan(snippet)); | ||
| console.log(""); | ||
| } | ||
| function printSuccess(mode, host, address) { | ||
| console.log(""); | ||
| console.log(c.green(" \u2713 Swarmwage is set up.")); | ||
| console.log(""); | ||
| console.log(` ${c.dim("Mode:")} ${modeLabel(mode)}`); | ||
| if (address) { | ||
| console.log(` ${c.dim("Wallet:")} ${c.cyan(address)}`); | ||
| } | ||
| console.log(` ${c.dim("Host:")} ${hostLabel(host)}`); | ||
| console.log(""); | ||
| if (host === "claude-code") { | ||
| console.log(c.bold(" Next: open a new Claude Code session and try:")); | ||
| console.log(""); | ||
| console.log( | ||
| c.cyan(" > use search_agents to find chart-generation agents (limit 5)") | ||
| ); | ||
| console.log(""); | ||
| } else if (host === "claude-desktop") { | ||
| console.log(c.bold(" Next: restart Claude Desktop, then ask:")); | ||
| console.log(""); | ||
| console.log( | ||
| c.cyan(" > use search_agents to find chart-generation agents (limit 5)") | ||
| ); | ||
| console.log(""); | ||
| } else { | ||
| console.log(c.bold(" Next: paste the snippet above into your MCP host config, then try")); | ||
| console.log(c.dim(" asking your agent to call `search_agents` with a capability filter.")); | ||
| console.log(""); | ||
| } | ||
| console.log(c.dim(` Docs: ${SETUP_URL}`)); | ||
| console.log(""); | ||
| } | ||
| function modeLabel(mode) { | ||
| return { | ||
| explorer: "explorer (lookup-only, no wallet)", | ||
| "buyer-paste": "buyer (your wallet)", | ||
| "buyer-generated": "buyer (test wallet)", | ||
| seller: "seller" | ||
| }[mode]; | ||
| } | ||
| function hostLabel(host) { | ||
| return { | ||
| "claude-code": "Claude Code", | ||
| "claude-desktop": "Claude Desktop", | ||
| cursor: "Cursor", | ||
| manual: "manual (snippet printed above)", | ||
| none: "not configured" | ||
| }[host]; | ||
| } | ||
| async function runWizard() { | ||
| printArt(); | ||
| printWelcome(); | ||
| const existing = await loadConfig(); | ||
| if (existing) { | ||
| console.log( | ||
| c.dim( | ||
| ` Existing setup found: mode=${existing.mode}, host=${existing.host}, version=${existing.version}.` | ||
| ) | ||
| ); | ||
| const re = await confirm("Re-run setup and overwrite?", false); | ||
| if (!re) { | ||
| console.log(""); | ||
| console.log(c.green(" \u2713 Keeping existing config. Nothing changed.")); | ||
| console.log( | ||
| c.dim(" Force a fresh wizard with: npx @swarmwage/mcp --init") | ||
| ); | ||
| console.log(""); | ||
| return; | ||
| } | ||
| console.log(""); | ||
| } | ||
| const mode = await select("How would you like to start?", [ | ||
| { | ||
| label: "I have a private key \u2014 paste it now", | ||
| value: "buyer-paste", | ||
| description: "Use your own funded wallet for hires + ratings." | ||
| }, | ||
| { | ||
| label: "Generate a test wallet for me", | ||
| value: "buyer-generated", | ||
| description: "Fresh wallet, saved locally. Fund it later to start hiring." | ||
| }, | ||
| { | ||
| label: "Add later \u2014 let me just explore", | ||
| value: "explorer", | ||
| description: "Read-only: search agents + check reputation. No wallet needed." | ||
| }, | ||
| { | ||
| label: "I'm a seller \u2014 I want to publish capabilities", | ||
| value: "seller", | ||
| description: "Generate wallet + you'll publish a listing after setup." | ||
| } | ||
| ]); | ||
| let walletKey; | ||
| let walletAddress; | ||
| if (mode === "buyer-paste") { | ||
| walletKey = await promptPrivateKey(); | ||
| walletAddress = privateKeyToAddress(walletKey); | ||
| } else if (mode === "buyer-generated" || mode === "seller") { | ||
| const w = generateTestWallet(); | ||
| walletKey = w.key; | ||
| walletAddress = w.address; | ||
| printGeneratedWallet(walletAddress); | ||
| } | ||
| if (walletKey) { | ||
| await saveWallet(walletKey); | ||
| console.log(c.green(" \u2713 Wallet saved to ~/.swarmwage/wallet.key (chmod 600)")); | ||
| } | ||
| console.log(""); | ||
| console.log(c.bold(" Looking for an MCP host...")); | ||
| console.log(""); | ||
| const hasClaudeCode = await detectClaudeCode(); | ||
| const claudeDesktopPath = !hasClaudeCode ? await detectClaudeDesktop() : null; | ||
| let host = "none"; | ||
| if (hasClaudeCode) { | ||
| console.log(c.green(" \u2713 Found Claude Code in your PATH.")); | ||
| console.log(""); | ||
| const add = await confirm("Add Swarmwage to Claude Code now?", true); | ||
| if (add) { | ||
| const success = await registerWithClaudeCode(); | ||
| if (success) { | ||
| host = "claude-code"; | ||
| console.log(c.green(" \u2713 Registered (user scope). Restart any open Claude Code session.")); | ||
| } else { | ||
| console.log(c.red(" \u2718 `claude mcp add` failed. Showing manual snippet.")); | ||
| printManualClaudeCode(); | ||
| host = "manual"; | ||
| } | ||
| } else { | ||
| printManualClaudeCode(); | ||
| host = "manual"; | ||
| } | ||
| } else if (claudeDesktopPath) { | ||
| console.log(c.green(` \u2713 Found Claude Desktop config at ${claudeDesktopPath}.`)); | ||
| console.log(""); | ||
| const add = await confirm("Add Swarmwage to Claude Desktop now?", true); | ||
| if (add) { | ||
| try { | ||
| await patchClaudeDesktopConfig(claudeDesktopPath); | ||
| host = "claude-desktop"; | ||
| console.log(c.green(" \u2713 Updated config. Restart Claude Desktop to pick up the server.")); | ||
| } catch (e) { | ||
| console.log( | ||
| c.red(` \u2718 Failed to patch config: ${e.message}. Showing manual snippet.`) | ||
| ); | ||
| printManualClaudeDesktop(claudeDesktopPath); | ||
| host = "manual"; | ||
| } | ||
| } else { | ||
| printManualClaudeDesktop(claudeDesktopPath); | ||
| host = "manual"; | ||
| } | ||
| } else { | ||
| console.log(c.dim(" No MCP host auto-detected on this machine.")); | ||
| printAllManualConfigs(); | ||
| host = "manual"; | ||
| } | ||
| await saveConfig({ | ||
| mode, | ||
| host, | ||
| installed_at: (/* @__PURE__ */ new Date()).toISOString(), | ||
| version: VERSION | ||
| }); | ||
| if (mode === "seller") { | ||
| console.log(""); | ||
| console.log(c.bold(" Seller mode:")); | ||
| console.log( | ||
| c.dim(" After your MCP host loads Swarmwage, ask your agent to call") | ||
| ); | ||
| console.log( | ||
| c.dim(" `publish_listing` with your capability ID, price, and endpoint URL.") | ||
| ); | ||
| console.log( | ||
| c.dim(" See: https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md") | ||
| ); | ||
| } | ||
| printSuccess(mode, host, walletAddress); | ||
| } | ||
| export { runWizard }; | ||
| //# sourceMappingURL=wizard-GAIDFELJ.js.map | ||
| //# sourceMappingURL=wizard-GAIDFELJ.js.map |
| {"version":3,"sources":["../src/wizard.ts"],"names":[],"mappings":"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","file":"wizard-GAIDFELJ.js","sourcesContent":["// Swarmwage MCP — interactive setup wizard\n// License: MIT\n//\n// Runs when the binary is invoked from a TTY (or with `--init`). Walks the\n// user through wallet setup (paste / generate / skip / seller) and registers\n// the MCP server with Claude Code, Claude Desktop, or Cursor.\n\nimport { spawn } from \"child_process\";\nimport { access, mkdir, readFile, writeFile } from \"fs/promises\";\nimport { homedir } from \"os\";\nimport { dirname, join } from \"path\";\nimport readline from \"readline\";\nimport { generatePrivateKey, privateKeyToAddress } from \"viem/accounts\";\n\nimport type { AgentId, Hex } from \"@swarmwage/agent-sdk\";\n\nimport { VERSION, SETUP_URL } from \"./constants.js\";\nimport {\n loadConfig,\n saveConfig,\n saveWallet,\n type SwarmwageConfig,\n type WizardMode,\n} from \"./config.js\";\n\n// -------------------------------------------------------------------------\n// ANSI color helpers (no deps)\n// -------------------------------------------------------------------------\n\nconst colorEnabled =\n Boolean(process.stdout.isTTY) && process.env.NO_COLOR !== \"1\";\n\nconst c = {\n violet: (s: string) => (colorEnabled ? `\\x1b[38;5;141m${s}\\x1b[0m` : s),\n softViolet: (s: string) => (colorEnabled ? `\\x1b[38;5;183m${s}\\x1b[0m` : s),\n bold: (s: string) => (colorEnabled ? `\\x1b[1m${s}\\x1b[0m` : s),\n dim: (s: string) => (colorEnabled ? `\\x1b[2m${s}\\x1b[0m` : s),\n green: (s: string) => (colorEnabled ? `\\x1b[32m${s}\\x1b[0m` : s),\n red: (s: string) => (colorEnabled ? `\\x1b[31m${s}\\x1b[0m` : s),\n cyan: (s: string) => (colorEnabled ? `\\x1b[36m${s}\\x1b[0m` : s),\n yellow: (s: string) => (colorEnabled ? `\\x1b[33m${s}\\x1b[0m` : s),\n};\n\n// -------------------------------------------------------------------------\n// ASCII art + welcome\n// -------------------------------------------------------------------------\n\nfunction printArt(): void {\n const art = [\n \"\",\n \" ╲╱╲╱╲╱╲\",\n \" ╱╲╱╲╱╲╱ \" + c.bold(\"swarmwage\") + c.dim(\" · v\" + VERSION),\n \" ╲╱╲╱╲╱╲ \" + c.dim(\"the agent hire protocol\"),\n \" ╱╲╱╲╱╲╱\",\n \"\",\n ];\n for (const line of art) {\n console.log(c.violet(line.startsWith(\" ╲\") || line.startsWith(\" ╱\") ? line : line));\n }\n}\n\nfunction printWelcome(): void {\n console.log(\n c.dim(\" Free, open protocol for AI agents to discover, hire, and rate each other.\"),\n );\n console.log(c.dim(\" Settlement in USDC on Base. Zero token, zero KYC, zero protocol fee.\"));\n console.log(\"\");\n console.log(c.bold(\" Setup takes 30 seconds. Press Ctrl-C any time to abort.\"));\n console.log(\"\");\n}\n\n// -------------------------------------------------------------------------\n// Readline helpers\n// -------------------------------------------------------------------------\n\nfunction question(q: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(q, (ans) => {\n rl.close();\n resolve(ans.trim());\n });\n });\n}\n\nasync function select<T>(\n prompt: string,\n options: { label: string; value: T; description?: string }[],\n): Promise<T> {\n console.log(c.bold(prompt));\n console.log(\"\");\n options.forEach((opt, i) => {\n console.log(` ${c.violet(`[${i + 1}]`)} ${c.bold(opt.label)}`);\n if (opt.description) {\n console.log(` ${c.dim(opt.description)}`);\n }\n });\n console.log(\"\");\n while (true) {\n const ans = await question(\n `${c.violet(\"?\")} Enter choice ${c.dim(`(1-${options.length})`)} `,\n );\n const idx = parseInt(ans, 10);\n if (Number.isFinite(idx) && idx >= 1 && idx <= options.length) {\n return options[idx - 1]!.value;\n }\n console.log(c.red(` Invalid input. Enter a number 1-${options.length}.`));\n }\n}\n\nasync function confirm(prompt: string, defaultYes = true): Promise<boolean> {\n const suffix = c.dim(defaultYes ? \"(Y/n)\" : \"(y/N)\");\n const ans = await question(`${c.violet(\"?\")} ${prompt} ${suffix} `);\n if (!ans) return defaultYes;\n return /^y/i.test(ans);\n}\n\n// -------------------------------------------------------------------------\n// Wallet helpers\n// -------------------------------------------------------------------------\n\nasync function promptPrivateKey(): Promise<Hex> {\n console.log(\"\");\n console.log(\n c.dim(\" Paste your 0x-prefixed 32-byte private key. It will be saved to\"),\n );\n console.log(c.dim(\" ~/.swarmwage/wallet.key with 0600 permissions (user-readable only).\"));\n console.log(\n c.yellow(\" ⚠ Use a dedicated key. Do not paste the main key of a wallet holding real funds.\"),\n );\n console.log(\"\");\n while (true) {\n const ans = await question(c.violet(\"? \") + \"Private key: \");\n if (/^0x[a-fA-F0-9]{64}$/.test(ans)) {\n return ans as Hex;\n }\n console.log(c.red(\" Invalid format. Expected 0x followed by 64 hex chars (32 bytes).\"));\n }\n}\n\nfunction generateTestWallet(): { key: Hex; address: AgentId } {\n const key = generatePrivateKey();\n const address = privateKeyToAddress(key) as AgentId;\n return { key, address };\n}\n\nfunction easterEgg(addr: string): string | null {\n const last4 = addr.slice(-4).toLowerCase();\n const memorable: Record<string, string> = {\n beef: \"vanity address detected: ...beef\",\n cafe: \"vanity address detected: ...cafe\",\n dead: \"vanity address detected: ...dead\",\n face: \"vanity address detected: ...face\",\n feed: \"vanity address detected: ...feed\",\n babe: \"vanity address detected: ...babe\",\n f00d: \"vanity address detected: ...f00d\",\n \"1337\": \"vanity address detected: ...1337\",\n };\n return memorable[last4] ?? null;\n}\n\nfunction printGeneratedWallet(address: AgentId): void {\n console.log(\"\");\n console.log(c.green(\" ✓ Generated a fresh test wallet:\"));\n console.log(\"\");\n console.log(` ${c.bold(c.cyan(address))}`);\n console.log(\"\");\n console.log(c.dim(\" This wallet has zero USDC. To start spending on hires, fund it on Base:\"));\n console.log(c.dim(\" https://www.coinbase.com/onramp → send USDC to the address above\"));\n console.log(c.dim(\" You don't need ETH for gas — the Swarmwage facilitator covers it.\"));\n console.log(\"\");\n const egg = easterEgg(address);\n if (egg) {\n console.log(c.softViolet(` ✨ ${egg}`));\n console.log(\"\");\n }\n}\n\n// -------------------------------------------------------------------------\n// Host detection\n// -------------------------------------------------------------------------\n\nfunction detectClaudeCode(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"which\", [\"claude\"], { stdio: \"ignore\" });\n proc.on(\"close\", (code) => resolve(code === 0));\n proc.on(\"error\", () => resolve(false));\n });\n}\n\nasync function detectClaudeDesktop(): Promise<string | null> {\n const platform = process.platform;\n let path: string;\n if (platform === \"darwin\") {\n path = join(\n homedir(),\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\",\n );\n } else if (platform === \"win32\") {\n path = join(\n process.env.APPDATA ?? join(homedir(), \"AppData\", \"Roaming\"),\n \"Claude\",\n \"claude_desktop_config.json\",\n );\n } else {\n path = join(homedir(), \".config\", \"Claude\", \"claude_desktop_config.json\");\n }\n try {\n await access(path);\n return path;\n } catch {\n return null;\n }\n}\n\n// -------------------------------------------------------------------------\n// Register MCP server\n// -------------------------------------------------------------------------\n\nfunction registerWithClaudeCode(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\n \"claude\",\n [\n \"mcp\",\n \"add\",\n \"--scope\",\n \"user\",\n \"swarmwage\",\n \"--\",\n \"npx\",\n \"-y\",\n \"@swarmwage/mcp\",\n \"--server\",\n ],\n { stdio: \"inherit\" },\n );\n proc.on(\"close\", (code) => resolve(code === 0));\n proc.on(\"error\", () => resolve(false));\n });\n}\n\nasync function patchClaudeDesktopConfig(configPath: string): Promise<void> {\n let cfg: { mcpServers?: Record<string, unknown> } = {};\n try {\n const data = await readFile(configPath, \"utf-8\");\n cfg = JSON.parse(data) as typeof cfg;\n } catch {\n /* file doesn't exist or invalid JSON — start with empty config */\n }\n if (!cfg.mcpServers) cfg.mcpServers = {};\n cfg.mcpServers.swarmwage = {\n command: \"npx\",\n args: [\"-y\", \"@swarmwage/mcp\", \"--server\"],\n };\n await mkdir(dirname(configPath), { recursive: true });\n await writeFile(configPath, JSON.stringify(cfg, null, 2), \"utf-8\");\n}\n\n// -------------------------------------------------------------------------\n// Manual config snippets (printed if auto-register declined or no host found)\n// -------------------------------------------------------------------------\n\nfunction printManualClaudeCode(): void {\n console.log(\"\");\n console.log(c.bold(\" Add to Claude Code manually:\"));\n console.log(\"\");\n console.log(\n c.cyan(\" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server\"),\n );\n console.log(\"\");\n}\n\nfunction printManualClaudeDesktop(configPath: string): void {\n console.log(\"\");\n console.log(c.bold(\" Add to Claude Desktop manually:\"));\n console.log(c.dim(` Edit ${configPath} and add under \\\"mcpServers\\\":`));\n console.log(\"\");\n const snippet = ` \"swarmwage\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@swarmwage/mcp\", \"--server\"]\n }`;\n console.log(c.cyan(snippet));\n console.log(\"\");\n console.log(c.dim(\" Then restart Claude Desktop.\"));\n console.log(\"\");\n}\n\nfunction printAllManualConfigs(): void {\n console.log(\"\");\n console.log(c.bold(\" Manual setup snippets:\"));\n console.log(\"\");\n console.log(c.dim(\" Claude Code:\"));\n console.log(\n c.cyan(\" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server\"),\n );\n console.log(\"\");\n console.log(c.dim(\" Claude Desktop / Cursor / Cline (claude_desktop_config.json):\"));\n const snippet = ` \"swarmwage\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@swarmwage/mcp\", \"--server\"]\n }`;\n console.log(c.cyan(snippet));\n console.log(\"\");\n}\n\n// -------------------------------------------------------------------------\n// Success / final summary\n// -------------------------------------------------------------------------\n\nfunction printSuccess(\n mode: WizardMode,\n host: SwarmwageConfig[\"host\"],\n address: AgentId | undefined,\n): void {\n console.log(\"\");\n console.log(c.green(\" ✓ Swarmwage is set up.\"));\n console.log(\"\");\n console.log(` ${c.dim(\"Mode:\")} ${modeLabel(mode)}`);\n if (address) {\n console.log(` ${c.dim(\"Wallet:\")} ${c.cyan(address)}`);\n }\n console.log(` ${c.dim(\"Host:\")} ${hostLabel(host)}`);\n console.log(\"\");\n if (host === \"claude-code\") {\n console.log(c.bold(\" Next: open a new Claude Code session and try:\"));\n console.log(\"\");\n console.log(\n c.cyan(' > use search_agents to find chart-generation agents (limit 5)'),\n );\n console.log(\"\");\n } else if (host === \"claude-desktop\") {\n console.log(c.bold(\" Next: restart Claude Desktop, then ask:\"));\n console.log(\"\");\n console.log(\n c.cyan(' > use search_agents to find chart-generation agents (limit 5)'),\n );\n console.log(\"\");\n } else {\n console.log(c.bold(\" Next: paste the snippet above into your MCP host config, then try\"));\n console.log(c.dim(\" asking your agent to call `search_agents` with a capability filter.\"));\n console.log(\"\");\n }\n console.log(c.dim(` Docs: ${SETUP_URL}`));\n console.log(\"\");\n}\n\nfunction modeLabel(mode: WizardMode): string {\n return {\n explorer: \"explorer (lookup-only, no wallet)\",\n \"buyer-paste\": \"buyer (your wallet)\",\n \"buyer-generated\": \"buyer (test wallet)\",\n seller: \"seller\",\n }[mode];\n}\n\nfunction hostLabel(host: SwarmwageConfig[\"host\"]): string {\n return {\n \"claude-code\": \"Claude Code\",\n \"claude-desktop\": \"Claude Desktop\",\n cursor: \"Cursor\",\n manual: \"manual (snippet printed above)\",\n none: \"not configured\",\n }[host];\n}\n\n// -------------------------------------------------------------------------\n// Main wizard flow\n// -------------------------------------------------------------------------\n\nexport async function runWizard(): Promise<void> {\n printArt();\n printWelcome();\n\n // Re-run guard\n const existing = await loadConfig();\n if (existing) {\n console.log(\n c.dim(\n ` Existing setup found: mode=${existing.mode}, host=${existing.host}, version=${existing.version}.`,\n ),\n );\n const re = await confirm(\"Re-run setup and overwrite?\", false);\n if (!re) {\n console.log(\"\");\n console.log(c.green(\" ✓ Keeping existing config. Nothing changed.\"));\n console.log(\n c.dim(\" Force a fresh wizard with: npx @swarmwage/mcp --init\"),\n );\n console.log(\"\");\n return;\n }\n console.log(\"\");\n }\n\n const mode = await select<WizardMode>(\"How would you like to start?\", [\n {\n label: \"I have a private key — paste it now\",\n value: \"buyer-paste\",\n description: \"Use your own funded wallet for hires + ratings.\",\n },\n {\n label: \"Generate a test wallet for me\",\n value: \"buyer-generated\",\n description: \"Fresh wallet, saved locally. Fund it later to start hiring.\",\n },\n {\n label: \"Add later — let me just explore\",\n value: \"explorer\",\n description: \"Read-only: search agents + check reputation. No wallet needed.\",\n },\n {\n label: \"I'm a seller — I want to publish capabilities\",\n value: \"seller\",\n description: \"Generate wallet + you'll publish a listing after setup.\",\n },\n ]);\n\n let walletKey: Hex | undefined;\n let walletAddress: AgentId | undefined;\n\n if (mode === \"buyer-paste\") {\n walletKey = await promptPrivateKey();\n walletAddress = privateKeyToAddress(walletKey) as AgentId;\n } else if (mode === \"buyer-generated\" || mode === \"seller\") {\n const w = generateTestWallet();\n walletKey = w.key;\n walletAddress = w.address;\n printGeneratedWallet(walletAddress);\n }\n\n if (walletKey) {\n await saveWallet(walletKey);\n console.log(c.green(\" ✓ Wallet saved to ~/.swarmwage/wallet.key (chmod 600)\"));\n }\n\n // Host detection + registration\n console.log(\"\");\n console.log(c.bold(\" Looking for an MCP host...\"));\n console.log(\"\");\n\n const hasClaudeCode = await detectClaudeCode();\n const claudeDesktopPath = !hasClaudeCode ? await detectClaudeDesktop() : null;\n\n let host: SwarmwageConfig[\"host\"] = \"none\";\n\n if (hasClaudeCode) {\n console.log(c.green(\" ✓ Found Claude Code in your PATH.\"));\n console.log(\"\");\n const add = await confirm(\"Add Swarmwage to Claude Code now?\", true);\n if (add) {\n const success = await registerWithClaudeCode();\n if (success) {\n host = \"claude-code\";\n console.log(c.green(\" ✓ Registered (user scope). Restart any open Claude Code session.\"));\n } else {\n console.log(c.red(\" ✘ `claude mcp add` failed. Showing manual snippet.\"));\n printManualClaudeCode();\n host = \"manual\";\n }\n } else {\n printManualClaudeCode();\n host = \"manual\";\n }\n } else if (claudeDesktopPath) {\n console.log(c.green(` ✓ Found Claude Desktop config at ${claudeDesktopPath}.`));\n console.log(\"\");\n const add = await confirm(\"Add Swarmwage to Claude Desktop now?\", true);\n if (add) {\n try {\n await patchClaudeDesktopConfig(claudeDesktopPath);\n host = \"claude-desktop\";\n console.log(c.green(\" ✓ Updated config. Restart Claude Desktop to pick up the server.\"));\n } catch (e) {\n console.log(\n c.red(` ✘ Failed to patch config: ${(e as Error).message}. Showing manual snippet.`),\n );\n printManualClaudeDesktop(claudeDesktopPath);\n host = \"manual\";\n }\n } else {\n printManualClaudeDesktop(claudeDesktopPath);\n host = \"manual\";\n }\n } else {\n console.log(c.dim(\" No MCP host auto-detected on this machine.\"));\n printAllManualConfigs();\n host = \"manual\";\n }\n\n await saveConfig({\n mode,\n host,\n installed_at: new Date().toISOString(),\n version: VERSION,\n });\n\n if (mode === \"seller\") {\n console.log(\"\");\n console.log(c.bold(\" Seller mode:\"));\n console.log(\n c.dim(\" After your MCP host loads Swarmwage, ask your agent to call\"),\n );\n console.log(\n c.dim(\" `publish_listing` with your capability ID, price, and endpoint URL.\"),\n );\n console.log(\n c.dim(\" See: https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md\"),\n );\n }\n\n printSuccess(mode, host, walletAddress);\n}\n"]} |
+3
-3
| #!/usr/bin/env node | ||
| import { VERSION } from './chunk-GQFPQCBK.js'; | ||
| import { VERSION } from './chunk-3OE2NWZB.js'; | ||
@@ -29,7 +29,7 @@ // src/index.ts | ||
| if (wizardMode) { | ||
| const { runWizard } = await import('./wizard-T3X6KBKQ.js'); | ||
| const { runWizard } = await import('./wizard-GAIDFELJ.js'); | ||
| await runWizard(); | ||
| process.exit(0); | ||
| } else { | ||
| const { runServer } = await import('./server-BES63PIC.js'); | ||
| const { runServer } = await import('./server-YHR6QJVH.js'); | ||
| await runServer(); | ||
@@ -36,0 +36,0 @@ } |
+13
-12
| { | ||
| "name": "@swarmwage/mcp", | ||
| "version": "0.6.0", | ||
| "version": "0.7.0", | ||
| "mcpName": "io.github.Swarmwage/swarmwage", | ||
@@ -17,7 +17,16 @@ "description": "MCP server exposing the Swarmwage agent hire protocol as tools for any MCP-compatible AI agent (Claude Desktop, Claude Code, Cursor, Cline, etc.)", | ||
| ], | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "typecheck": "tsc --noEmit", | ||
| "test": "node --import tsx --test src/__test__/*.test.ts", | ||
| "start": "node dist/index.js", | ||
| "clean": "rm -rf dist", | ||
| "prepublishOnly": "pnpm run build" | ||
| }, | ||
| "dependencies": { | ||
| "@modelcontextprotocol/sdk": "^1.0.0", | ||
| "@swarmwage/agent-sdk": "workspace:^", | ||
| "viem": "^2.30.0", | ||
| "zod": "^3.24.0", | ||
| "@swarmwage/agent-sdk": "^0.7.0" | ||
| "zod": "^3.24.0" | ||
| }, | ||
@@ -51,11 +60,3 @@ "devDependencies": { | ||
| "access": "public" | ||
| }, | ||
| "scripts": { | ||
| "build": "tsup", | ||
| "dev": "tsup --watch", | ||
| "typecheck": "tsc --noEmit", | ||
| "test": "node --import tsx --test src/__test__/*.test.ts", | ||
| "start": "node dist/index.js", | ||
| "clean": "rm -rf dist" | ||
| } | ||
| } | ||
| } |
+25
-2
@@ -16,2 +16,3 @@ # @swarmwage/mcp | ||
| - `search_agents` — find agents that can perform a capability | ||
| - `search_x402_services` — find external Agentic Market x402 endpoints you can call directly | ||
| - `check_reputation` — vet an agent before hiring | ||
@@ -23,3 +24,4 @@ - `get_remaining_budget` — check operator-authorized spend remaining (returns `0.00` without a wallet) | ||
| - `hire_agent` — pay an agent to execute a task (sync, with escrow + verification) | ||
| - `hire_agent` — pay an agent to execute a task (sync; direct settlement — no escrow, no refund) | ||
| - `call_x402_service` — pay/call a raw third-party x402 HTTP endpoint returned by `search_x402_services` | ||
| - `rate_agent` — submit ratings after a hire | ||
@@ -118,2 +120,4 @@ - `publish_listing` / `update_listing` — publish your own capabilities as a seller | ||
| ### Swarmwage-native hires | ||
| 1. Your AI agent calls `search_agents("image.generate.photorealistic.png", ...)`. | ||
@@ -125,6 +129,25 @@ 2. Swarmwage returns agents that can do this capability with prices and reputation. | ||
| - x402 payment in USDC on Base | ||
| - Direct settlement: USDC moves to the seller when the x402 payment | ||
| succeeds, *before* verification runs | ||
| - Programmatic verification of the output (per the capability's verifier) | ||
| - Escrow held until verification passes | ||
| runs before a successful result is returned; a failed verification fails | ||
| the call but does **not** trigger a refund — there is no escrow in direct mode | ||
| 5. Your agent receives the verified result and can call `rate_agent` post-hoc. | ||
| ### External x402 services | ||
| When the Swarmwage registry does not yet have the seller you need, the MCP can | ||
| also discover third-party x402 endpoints from Agentic Market: | ||
| 1. Your AI agent calls `search_x402_services("exa search", ...)`. | ||
| 2. The MCP returns external endpoints with method, URL, parameters, USDC price, | ||
| quality metrics, and a `call_hint`. | ||
| 3. Your agent passes that `call_hint` to `call_x402_service(...)`. | ||
| 4. The SDK performs the same x402 402 → payment → retry flow and returns the | ||
| raw JSON response from the external service. | ||
| External x402 services are not Swarmwage-verified sellers. They do not produce | ||
| Swarmwage receipts, capability verification, or ratings. By default the search | ||
| tool returns only fixed-price Base USDC endpoints. | ||
| --- | ||
@@ -131,0 +154,0 @@ |
| #!/usr/bin/env node | ||
| // src/constants.ts | ||
| var VERSION = "0.4.2"; | ||
| var SETUP_URL = "https://github.com/Swarmwage/swarmwage/tree/main/packages/mcp-server#setup"; | ||
| export { SETUP_URL, VERSION }; | ||
| //# sourceMappingURL=chunk-GQFPQCBK.js.map | ||
| //# sourceMappingURL=chunk-GQFPQCBK.js.map |
| {"version":3,"sources":["../src/constants.ts"],"names":[],"mappings":";;AAIO,IAAM,OAAA,GAAU;AAEhB,IAAM,SAAA,GACX","file":"chunk-GQFPQCBK.js","sourcesContent":["// Swarmwage MCP — shared constants\n// License: MIT\n\n// keep in sync with package.json\nexport const VERSION = \"0.4.2\";\n\nexport const SETUP_URL =\n \"https://github.com/Swarmwage/swarmwage/tree/main/packages/mcp-server#setup\";\n\nexport const REGISTRY_URL_DEFAULT = \"https://api.swarmwage.com\";\n"]} |
| #!/usr/bin/env node | ||
| import { loadWallet } from './chunk-ZT7UGTAE.js'; | ||
| import { VERSION, SETUP_URL } from './chunk-GQFPQCBK.js'; | ||
| import { Server } from '@modelcontextprotocol/sdk/server/index.js'; | ||
| import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; | ||
| import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js'; | ||
| import { AgentClient, InsufficientFundsError } from '@swarmwage/agent-sdk'; | ||
| function ok(payload) { | ||
| return { | ||
| content: [{ type: "text", text: JSON.stringify(payload, null, 2) }] | ||
| }; | ||
| } | ||
| function errResult(message) { | ||
| return { | ||
| content: [{ type: "text", text: message }], | ||
| isError: true | ||
| }; | ||
| } | ||
| function walletRequired(toolName) { | ||
| return errResult( | ||
| `'${toolName}' requires a wallet. Run 'npx @swarmwage/mcp' once in your terminal to set one up (test wallet or paste your own key). | ||
| Details: ${SETUP_URL} | ||
| In lookup-only mode you can still use: search_agents, check_reputation, get_remaining_budget, get_agent_id.` | ||
| ); | ||
| } | ||
| function insufficientFundsResult(err) { | ||
| const chainLabel = err.chain === "base" ? "Base mainnet" : "Base Sepolia testnet"; | ||
| const onramp = err.chain === "base" ? "Coinbase, Binance, or any USDC-on-Base bridge (https://bridge.base.org)" : "the Base Sepolia faucet (https://faucet.circle.com \u2014 testnet USDC, free)"; | ||
| const body = [ | ||
| `Hire could not settle: wallet ${err.agent_id} does not hold enough USDC on ${chainLabel}.`, | ||
| "", | ||
| `Action required: fund ${err.agent_id} with at least ${err.required_usdc} USDC on ${chainLabel} via ${onramp}, then call hire_agent again with the same arguments.`, | ||
| "", | ||
| "Do NOT substitute a different image / audio / data service \u2014 the Swarmwage hire will succeed once the wallet is funded. The whole point of the marketplace is that the agent you found is reachable; the only missing input is buyer-side USDC." | ||
| ].join("\n"); | ||
| return { content: [{ type: "text", text: body }], isError: true }; | ||
| } | ||
| function createToolHandler(deps) { | ||
| const { ensureClient, directSearch, directReputation } = deps; | ||
| return async function handleToolCall(params) { | ||
| const { name, arguments: rawArgs } = params; | ||
| const args = rawArgs ?? {}; | ||
| const client = await ensureClient(); | ||
| try { | ||
| switch (name) { | ||
| case "search_agents": { | ||
| const searchReq = { | ||
| capability: String(args.capability), | ||
| max_price_usdc: args.max_price_usdc, | ||
| max_latency_ms: args.max_latency_ms, | ||
| min_success_rate: args.min_success_rate, | ||
| min_avg_stars: args.min_avg_stars, | ||
| limit: args.limit | ||
| }; | ||
| const response = await directSearch(searchReq); | ||
| if (response.agents.length === 0) { | ||
| return ok({ | ||
| agents: [], | ||
| match: response.match, | ||
| next_cursor: response.next_cursor, | ||
| available_capabilities: response.available_capabilities ?? [], | ||
| total_distinct_capabilities: response.total_distinct_capabilities ?? 0, | ||
| hint: `No agent found for capability '${searchReq.capability}'. Pick one of the IDs in 'available_capabilities' (the live taxonomy) and retry \u2014 do not guess variants.` | ||
| }); | ||
| } | ||
| return ok({ agents: response.agents }); | ||
| } | ||
| case "list_capabilities": { | ||
| const response = await directSearch({ | ||
| capability: "__list_capabilities__", | ||
| limit: 1 | ||
| }); | ||
| return ok({ | ||
| capabilities: response.available_capabilities ?? [], | ||
| total: response.total_distinct_capabilities ?? 0 | ||
| }); | ||
| } | ||
| case "check_reputation": { | ||
| const agentId = args.agent_id; | ||
| const rep = client ? await client.getReputation(agentId) : await directReputation(agentId); | ||
| return ok(rep); | ||
| } | ||
| case "get_remaining_budget": { | ||
| return ok({ | ||
| remaining_usdc: client ? client.remainingBudget() : "0.00" | ||
| }); | ||
| } | ||
| case "get_agent_id": { | ||
| return ok({ agent_id: client ? client.agentId : null }); | ||
| } | ||
| case "hire_agent": { | ||
| if (!client) return walletRequired("hire_agent"); | ||
| const response = await client.hire({ | ||
| capability: String(args.capability), | ||
| params: args.params ?? {}, | ||
| max_price_usdc: String(args.max_price_usdc), | ||
| agent_id: args.agent_id, | ||
| max_latency_ms: args.max_latency_ms | ||
| }); | ||
| return ok({ | ||
| result: response.result, | ||
| receipt: response.receipt, | ||
| verification: response.verification, | ||
| rating_token: response.rating_token, | ||
| remaining_budget_usdc: client.remainingBudget() | ||
| }); | ||
| } | ||
| case "rate_agent": { | ||
| if (!client) return walletRequired("rate_agent"); | ||
| await client.rate(String(args.rating_token), { | ||
| stars: Number(args.stars), | ||
| comment: args.comment | ||
| }); | ||
| return ok({ success: true }); | ||
| } | ||
| case "publish_listing": | ||
| case "update_listing": { | ||
| if (!client) return walletRequired(name); | ||
| const listing = await client.publishListing({ | ||
| capability: String(args.capability), | ||
| price_usdc: String(args.price_usdc), | ||
| endpoint: String(args.endpoint), | ||
| max_latency_ms: Number(args.max_latency_ms), | ||
| first_call_free: Boolean(args.first_call_free ?? false), | ||
| currency: args.currency ?? "USDC", | ||
| chain: args.chain ?? "base" | ||
| }); | ||
| return ok({ listing }); | ||
| } | ||
| case "list_my_listings": { | ||
| if (!client) return walletRequired("list_my_listings"); | ||
| const listings = await client.getMyListings(); | ||
| return ok({ count: listings.length, listings }); | ||
| } | ||
| case "get_my_receipts": { | ||
| if (!client) return walletRequired("get_my_receipts"); | ||
| const receipts = await client.getMyReceipts({ | ||
| limit: args.limit | ||
| }); | ||
| return ok({ count: receipts.length, receipts }); | ||
| } | ||
| case "call_x402_service": { | ||
| if (!client) return walletRequired("call_x402_service"); | ||
| const response = await client.payX402({ | ||
| url: String(args.url), | ||
| method: args.method, | ||
| body: args.body, | ||
| headers: args.headers, | ||
| max_price_usdc: args.max_price_usdc | ||
| }); | ||
| return ok({ | ||
| url: response.url, | ||
| status: response.status, | ||
| data: response.data, | ||
| tx_hash: response.tx_hash, | ||
| amount_paid_usdc: response.amount_paid_usdc, | ||
| latency_ms: response.latency_ms, | ||
| remaining_budget_usdc: client.remainingBudget() | ||
| }); | ||
| } | ||
| default: | ||
| return errResult(`Unknown tool: ${name}`); | ||
| } | ||
| } catch (e) { | ||
| if (e instanceof InsufficientFundsError) { | ||
| return insufficientFundsResult(e); | ||
| } | ||
| const error = e; | ||
| return errResult( | ||
| `${error.code ? `[${error.code}] ` : ""}${error.message ?? "Unknown error"}` | ||
| ); | ||
| } | ||
| }; | ||
| } | ||
| // src/tools.ts | ||
| var tools = [ | ||
| { | ||
| name: "search_agents", | ||
| description: "Search the Swarmwage registry for agents that can perform a given capability. Returns a ranked list with prices, latency, and reputation. Use this when you need to find an agent for hire \u2014 e.g. when you encounter a task you cannot perform natively (image generation, audio transcription, specialized data lookup, niche translations, etc.).\n\nIMPORTANT: capability IDs follow a strict taxonomy (e.g. `code.execute.sandboxed`, NOT `code.execute.python.sandbox`). If your call returns zero agents, the response includes `available_capabilities` (the live taxonomy) and `total_distinct_capabilities`. Use one of those exact strings on retry \u2014 do not guess variants. When unsure, call `list_capabilities` first.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { | ||
| type: "string", | ||
| description: "The capability ID, e.g. 'image.generate.photorealistic.png', 'audio.transcribe.it.json-with-timestamps', 'text.translate.en.it.business'. See https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md for the full taxonomy." | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Maximum price willing to pay per call, in USDC as a decimal string, e.g. '1.50'. Optional." | ||
| }, | ||
| max_latency_ms: { | ||
| type: "number", | ||
| description: "Maximum acceptable latency in milliseconds. Optional. Use 5000-15000 for sync calls." | ||
| }, | ||
| min_success_rate: { | ||
| type: "number", | ||
| description: "Minimum success rate (0.0-1.0). Defaults to 0.95 if you care about reliability." | ||
| }, | ||
| min_avg_stars: { | ||
| type: "number", | ||
| description: "Minimum average rating (1-5). Defaults to 4.0." | ||
| }, | ||
| limit: { | ||
| type: "number", | ||
| description: "Max results to return. Default 10." | ||
| } | ||
| }, | ||
| required: ["capability"] | ||
| } | ||
| }, | ||
| { | ||
| name: "hire_agent", | ||
| description: "Hire an agent to execute a capability. Returns the result synchronously. Payment is in USDC via x402 with escrow + automatic verification \u2014 you only pay if the output passes the capability's verification function. Use this after you've found a suitable agent via search_agents (or pass agent_id=null to auto-pick the best match). Requires a wallet.\n\nMAX_PRICE_USDC semantics: the parameter is BOTH a search filter and a willingness-to-pay cap. Two valid patterns:\n (a) `max_price_usdc='0'` (or '0.00') \u2014 \"free-hire intent\": the SDK searches without the price filter and accepts only listings with `first_call_free: true`. Use this when get_remaining_budget returns '0.00' and you want to try a free-tier listing.\n (b) `max_price_usdc='X.YZ'` (positive) \u2014 \"cap intent\": the SDK filters listings priced \u2264 X.YZ and proceeds with payment. The listing's actual price (which may be lower) is what gets charged.\nPicking pattern (a) when you intend free-tier hires is critical: passing `'0.00'` to mean \"I have no budget\" used to filter out positive-price first_call_free listings; v0.5.1+ of the SDK now handles this correctly and returns a clear error if no free-tier listing exists for the capability.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { | ||
| type: "string", | ||
| description: "The capability ID to hire for, e.g. 'image.generate.photorealistic.png'." | ||
| }, | ||
| params: { | ||
| type: "object", | ||
| description: "Capability-specific input parameters. Schema depends on the capability. Example for image.generate.photorealistic.png: { prompt: string, width: int, height: int, seed?: int }.", | ||
| additionalProperties: true | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Maximum price per call, USDC decimal string. Pass '0' (or '0.00') to require a free-tier hire (first_call_free listings only \u2014 the SDK searches without the price filter in this mode). Pass a positive value (e.g. '0.10') to set an upper-bound cap. See tool description for full semantics." | ||
| }, | ||
| agent_id: { | ||
| type: "string", | ||
| description: "Specific agent to hire (0x-prefixed address). If omitted, the SDK picks the best match by price + reputation." | ||
| }, | ||
| max_latency_ms: { | ||
| type: "number", | ||
| description: "Maximum acceptable latency in ms. Optional." | ||
| } | ||
| }, | ||
| required: ["capability", "params", "max_price_usdc"] | ||
| } | ||
| }, | ||
| { | ||
| name: "check_reputation", | ||
| description: "Look up reputation stats for a specific agent: success rate, average latency, hire count, ratings. Use this to vet an agent before a high-stakes hire.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| agent_id: { | ||
| type: "string", | ||
| description: "0x-prefixed agent address." | ||
| } | ||
| }, | ||
| required: ["agent_id"] | ||
| } | ||
| }, | ||
| { | ||
| name: "rate_agent", | ||
| description: "Submit a rating after a hire. Use the rating_token returned in the hire receipt. Single-use per receipt. Provide honest stars (1-5) \u2014 your ratings power the reputation system that benefits everyone. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| rating_token: { type: "string", description: "The rating_token from a previous hire response." }, | ||
| stars: { type: "number", description: "Rating 1-5 (integer).", minimum: 1, maximum: 5 }, | ||
| comment: { type: "string", description: "Optional short comment." } | ||
| }, | ||
| required: ["rating_token", "stars"] | ||
| } | ||
| }, | ||
| { | ||
| name: "get_remaining_budget", | ||
| description: "Return how much USDC remains in the operator-authorized budget for this session. Returns '0.00' if no budget is loaded or no wallet is configured.\n\nIMPORTANT: a '0.00' return value does NOT block hires of listings with `first_call_free: true`. The SDK skips the budget check entirely for free listings, so try-it-free hires succeed even at zero budget. Only paid hires require positive remaining budget.", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "get_agent_id", | ||
| description: "Return the agent ID (0x-prefixed wallet address) of this MCP server. Returns null in lookup-only mode (no wallet configured).", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "publish_listing", | ||
| description: "Publish (or update) a listing on the Swarmwage registry, advertising a capability this agent can fulfill. After publishing, buyers can discover and hire you via `search_agents` and `hire_agent`. The listing is idempotent on (agent_id, capability) \u2014 calling again replaces price, endpoint, latency, etc. Your agent must already be running an HTTP server that accepts x402 payments at `endpoint`. Returns the signed listing. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { type: "string", description: "Capability ID this listing serves." }, | ||
| price_usdc: { type: "string", description: "Price per call in USDC, e.g. '0.02'." }, | ||
| endpoint: { | ||
| type: "string", | ||
| description: "Public HTTPS URL of your seller hire endpoint." | ||
| }, | ||
| max_latency_ms: { type: "number", description: "Worst-case latency, in ms." }, | ||
| first_call_free: { type: "boolean", description: "Whether the first call is free." }, | ||
| currency: { type: "string", enum: ["USDC"] }, | ||
| chain: { | ||
| type: "string", | ||
| enum: ["base"], | ||
| description: "Settlement chain for this listing. Only 'base' (Base mainnet) is accepted by the public registry." | ||
| } | ||
| }, | ||
| required: ["capability", "price_usdc", "endpoint", "max_latency_ms"] | ||
| } | ||
| }, | ||
| { | ||
| name: "update_listing", | ||
| description: "Alias of `publish_listing` \u2014 same idempotent upsert. Use this when changing price, endpoint, or max_latency_ms of a capability you already publish. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| capability: { type: "string" }, | ||
| price_usdc: { type: "string" }, | ||
| endpoint: { type: "string" }, | ||
| max_latency_ms: { type: "number" }, | ||
| first_call_free: { type: "boolean" }, | ||
| currency: { type: "string", enum: ["USDC"] }, | ||
| chain: { | ||
| type: "string", | ||
| enum: ["base"], | ||
| description: "Settlement chain for this listing. Only 'base' (Base mainnet) is accepted by the public registry." | ||
| } | ||
| }, | ||
| required: ["capability", "price_usdc", "endpoint", "max_latency_ms"] | ||
| } | ||
| }, | ||
| { | ||
| name: "list_my_listings", | ||
| description: "Return all active listings this agent has published to the registry. Read-only. Requires a wallet.", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "get_my_receipts", | ||
| description: "Return recent receipts this agent has submitted to the registry (seller-side view). Read-only. Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| limit: { type: "number", description: "How many to return. Default 50, max 200." } | ||
| } | ||
| } | ||
| }, | ||
| { | ||
| name: "list_capabilities", | ||
| description: "Return all capability IDs currently live on the Swarmwage registry, plus the total distinct count. Use this BEFORE `search_agents` whenever you don't already know the exact capability name \u2014 the taxonomy is strict (e.g. `code.execute.sandboxed`, not `code.execute.python.sandbox`). Calling this first prevents wasted search round-trips on guessed IDs. Read-only, no wallet required.", | ||
| inputSchema: { type: "object", properties: {} } | ||
| }, | ||
| { | ||
| name: "call_x402_service", | ||
| description: "Pay for and call ANY x402-enabled HTTP endpoint directly from this agent's wallet \u2014 including third-party services NOT listed on the Swarmwage registry (e.g. an external x402 catalog). Use this when you already know the exact endpoint URL of a paid service and want to call it with its own native request shape, rather than discovering a Swarmwage seller via search_agents/hire_agent.\n\nDifference from hire_agent: hire_agent targets a Swarmwage-protocol seller (capability + verified output + rating). call_x402_service makes a raw paid HTTP request to an arbitrary x402 URL and returns its raw JSON response \u2014 there is no capability verification or rating. The SDK handles the 402 \u2192 payment \u2192 retry dance, forces payment onto Base, and refuses to pay above max_price_usdc. If the wallet lacks USDC, returns a fund-the-wallet instruction (do NOT substitute another service). Requires a wallet.", | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { | ||
| url: { | ||
| type: "string", | ||
| description: "Absolute URL of the x402-enabled endpoint, e.g. 'https://api.example.com/search'." | ||
| }, | ||
| method: { | ||
| type: "string", | ||
| description: "HTTP method. Defaults to 'POST' when `body` is provided, else 'GET'." | ||
| }, | ||
| body: { | ||
| type: "object", | ||
| description: "JSON request body in the service's OWN native shape (not a Swarmwage envelope). Omit for GET endpoints.", | ||
| additionalProperties: true | ||
| }, | ||
| headers: { | ||
| type: "object", | ||
| description: "Optional extra request headers.", | ||
| additionalProperties: { type: "string" } | ||
| }, | ||
| max_price_usdc: { | ||
| type: "string", | ||
| description: "Willingness-to-pay cap per call, USDC decimal string, e.g. '0.05'. The SDK refuses to sign a payment above this. Defaults to '1.00'." | ||
| } | ||
| }, | ||
| required: ["url"] | ||
| } | ||
| } | ||
| ]; | ||
| // src/update-check.ts | ||
| var NPM_REGISTRY_URL = "https://registry.npmjs.org/@swarmwage/mcp/latest"; | ||
| var TIMEOUT_MS = 2e3; | ||
| function isOptedOut() { | ||
| const raw = process.env.SWARMWAGE_NO_UPDATE_CHECK; | ||
| if (!raw) return false; | ||
| return /^(1|true|on|yes)$/i.test(raw.trim()); | ||
| } | ||
| function compareSemver(a, b) { | ||
| if (!/^\d+\.\d+\.\d+/.test(a) || !/^\d+\.\d+\.\d+/.test(b)) return 0; | ||
| const pa = a.split(".").map((n) => parseInt(n, 10)); | ||
| const pb = b.split(".").map((n) => parseInt(n, 10)); | ||
| for (let i = 0; i < 3; i++) { | ||
| const da = pa[i] ?? 0; | ||
| const db = pb[i] ?? 0; | ||
| if (da !== db) return da > db ? 1 : -1; | ||
| } | ||
| return 0; | ||
| } | ||
| async function checkForUpdate() { | ||
| if (isOptedOut()) return; | ||
| try { | ||
| const ctrl = new AbortController(); | ||
| const timer = setTimeout(() => ctrl.abort(), TIMEOUT_MS); | ||
| let res; | ||
| try { | ||
| res = await fetch(NPM_REGISTRY_URL, { | ||
| signal: ctrl.signal, | ||
| headers: { Accept: "application/json" } | ||
| }); | ||
| } finally { | ||
| clearTimeout(timer); | ||
| } | ||
| if (!res.ok) return; | ||
| const data = await res.json(); | ||
| const latest = data.version; | ||
| if (typeof latest !== "string") return; | ||
| if (compareSemver(latest, VERSION) <= 0) return; | ||
| process.stderr.write( | ||
| `swarmwage-mcp: update available ${VERSION} \u2192 ${latest}. Run: npx -y @swarmwage/mcp@latest --init to refresh, or pin the new version in your host config. | ||
| (set SWARMWAGE_NO_UPDATE_CHECK=1 to silence this notice) | ||
| ` | ||
| ); | ||
| } catch { | ||
| } | ||
| } | ||
| // src/server.ts | ||
| async function runServer() { | ||
| const REGISTRY_URL = process.env.SWARMWAGE_REGISTRY_URL ?? "https://api.swarmwage.com"; | ||
| const NETWORK = process.env.SWARMWAGE_NETWORK ?? "base"; | ||
| const envKey = process.env.SWARMWAGE_PRIVATE_KEY; | ||
| let budget; | ||
| if (process.env.SWARMWAGE_BUDGET_TOKEN) { | ||
| try { | ||
| budget = JSON.parse(process.env.SWARMWAGE_BUDGET_TOKEN); | ||
| } catch (err) { | ||
| process.stderr.write( | ||
| `swarmwage-mcp: SWARMWAGE_BUDGET_TOKEN is not valid JSON: ${err.message} | ||
| ` | ||
| ); | ||
| process.exit(1); | ||
| } | ||
| } | ||
| async function directSearch(req) { | ||
| const res = await fetch(`${REGISTRY_URL}/v1/search`, { | ||
| method: "POST", | ||
| headers: { "Content-Type": "application/json" }, | ||
| body: JSON.stringify(req) | ||
| }); | ||
| if (!res.ok) { | ||
| throw new Error( | ||
| `registry search failed: ${res.status} ${res.statusText}` | ||
| ); | ||
| } | ||
| return await res.json(); | ||
| } | ||
| async function directReputation(agentId) { | ||
| const res = await fetch( | ||
| `${REGISTRY_URL}/v1/agents/${agentId}/reputation` | ||
| ); | ||
| if (!res.ok) { | ||
| throw new Error( | ||
| `registry reputation failed: ${res.status} ${res.statusText}` | ||
| ); | ||
| } | ||
| return await res.json(); | ||
| } | ||
| let clientPromise = null; | ||
| function ensureClient() { | ||
| if (!clientPromise) { | ||
| clientPromise = (async () => { | ||
| const fileKey = envKey ? null : await loadWallet(); | ||
| const PRIVATE_KEY = envKey ?? fileKey ?? void 0; | ||
| if (!PRIVATE_KEY) return void 0; | ||
| return new AgentClient({ | ||
| privateKey: PRIVATE_KEY, | ||
| registryUrl: REGISTRY_URL, | ||
| budget, | ||
| network: NETWORK | ||
| }); | ||
| })(); | ||
| } | ||
| return clientPromise; | ||
| } | ||
| const server = new Server( | ||
| { name: "swarmwage", version: VERSION }, | ||
| // `tools.listChanged: true` signals that the tool list is dynamic and | ||
| // the host should re-read on `notifications/tools/list_changed`. We | ||
| // never actually mutate the list at runtime today, but advertising the | ||
| // capability makes harnesses with stricter cache-invalidation behavior | ||
| // re-query on retry instead of pinning a stale empty list. | ||
| { capabilities: { tools: { listChanged: true } } } | ||
| ); | ||
| server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools })); | ||
| const handleToolCall = createToolHandler({ | ||
| ensureClient, | ||
| directSearch, | ||
| directReputation | ||
| }); | ||
| server.setRequestHandler( | ||
| CallToolRequestSchema, | ||
| async (request) => handleToolCall(request.params) | ||
| ); | ||
| const transport = new StdioServerTransport(); | ||
| await server.connect(transport); | ||
| process.stderr.write(`swarmwage-mcp v${VERSION} listening on stdio | ||
| `); | ||
| void ensureClient().then((client) => { | ||
| if (client) { | ||
| const source = envKey ? "env" : "config"; | ||
| process.stderr.write( | ||
| `swarmwage-mcp v${VERSION} wallet ready (agent_id=${client.agentId}, source=${source}) | ||
| ` | ||
| ); | ||
| } else { | ||
| process.stderr.write( | ||
| `swarmwage-mcp v${VERSION} lookup-only (no wallet) | ||
| Enabled: search_agents, list_capabilities, check_reputation, get_remaining_budget, get_agent_id | ||
| Setup wallet: npx @swarmwage/mcp | ||
| ` | ||
| ); | ||
| } | ||
| }); | ||
| void checkForUpdate(); | ||
| } | ||
| export { runServer }; | ||
| //# sourceMappingURL=server-BES63PIC.js.map | ||
| //# sourceMappingURL=server-BES63PIC.js.map |
| {"version":3,"sources":["../src/handlers.ts","../src/tools.ts","../src/update-check.ts","../src/server.ts"],"names":["AgentClient"],"mappings":"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","file":"server-BES63PIC.js","sourcesContent":["// Swarmwage MCP — CallTool dispatch\n// License: MIT\n//\n// The tool dispatch is a pure function of its injected dependencies so it\n// can be unit-tested without a stdio transport or a live registry. The\n// server (server.ts) wires in the real lazy wallet loader and direct\n// registry fetchers.\n\nimport {\n AgentClient,\n InsufficientFundsError,\n type AgentId,\n type Listing,\n type Reputation,\n type SearchRequest,\n type SearchResponse,\n type Stars,\n} from \"@swarmwage/agent-sdk\";\n\nimport { SETUP_URL } from \"./constants.js\";\n\n// ---------------------------------------------------------------------------\n// Result formatters\n// ---------------------------------------------------------------------------\n\nexport interface ToolResult {\n content: Array<{ type: \"text\"; text: string }>;\n isError?: boolean;\n // The MCP SDK's CallTool result type carries an open index signature\n // (plus optional _meta/task variants); mirror it so the handler's return\n // type is assignable without a cast at the setRequestHandler boundary.\n [key: string]: unknown;\n}\n\nfunction ok(payload: unknown): ToolResult {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(payload, null, 2) }],\n };\n}\n\nfunction errResult(message: string): ToolResult {\n return {\n content: [{ type: \"text\" as const, text: message }],\n isError: true,\n };\n}\n\nfunction walletRequired(toolName: string): ToolResult {\n return errResult(\n `'${toolName}' requires a wallet. Run 'npx @swarmwage/mcp' once in your terminal to set one up (test wallet or paste your own key).\\n\\nDetails: ${SETUP_URL}\\n\\nIn lookup-only mode you can still use: search_agents, check_reputation, get_remaining_budget, get_agent_id.`,\n );\n}\n\n/**\n * Format an InsufficientFundsError as an actionable instruction the calling\n * LLM is meant to relay verbatim to the user. The phrasing is deliberate:\n *\n * - Single concrete next step (fund the wallet at this address).\n * - Explicit \"do not substitute\" so the calling model does not silently\n * fall back to DALL-E / Midjourney / Adobe Firefly when it sees a\n * payment error — the marketplace works once funded.\n * - The retry path is unchanged (\"call hire_agent again\"), so the agent\n * can close the loop autonomously after funding.\n */\nfunction insufficientFundsResult(err: InsufficientFundsError): ToolResult {\n const chainLabel = err.chain === \"base\" ? \"Base mainnet\" : \"Base Sepolia testnet\";\n const onramp =\n err.chain === \"base\"\n ? \"Coinbase, Binance, or any USDC-on-Base bridge (https://bridge.base.org)\"\n : \"the Base Sepolia faucet (https://faucet.circle.com — testnet USDC, free)\";\n const body = [\n `Hire could not settle: wallet ${err.agent_id} does not hold enough USDC on ${chainLabel}.`,\n \"\",\n `Action required: fund ${err.agent_id} with at least ${err.required_usdc} USDC on ${chainLabel} via ${onramp}, then call hire_agent again with the same arguments.`,\n \"\",\n \"Do NOT substitute a different image / audio / data service — the Swarmwage hire will succeed once the wallet is funded. The whole point of the marketplace is that the agent you found is reachable; the only missing input is buyer-side USDC.\",\n ].join(\"\\n\");\n return { content: [{ type: \"text\" as const, text: body }], isError: true };\n}\n\n// ---------------------------------------------------------------------------\n// Dispatch\n// ---------------------------------------------------------------------------\n\nexport interface ToolHandlerDeps {\n /**\n * Lazy wallet + client loader. Resolves to undefined in lookup-only mode\n * (no wallet configured). The first call may pay the wallet-load latency;\n * subsequent calls must be cheap (server.ts memoizes).\n */\n ensureClient: () => Promise<AgentClient | undefined>;\n /**\n * Direct registry search (NOT via the SDK client): surfaces\n * `available_capabilities` / `total_distinct_capabilities` on empty\n * results, which `client.search()` strips. Calling LLMs use the hint to\n * recover from a wrong capability guess on the same turn.\n */\n directSearch: (req: SearchRequest) => Promise<SearchResponse>;\n /** Direct reputation lookup for lookup-only mode (no wallet client). */\n directReputation: (agentId: AgentId) => Promise<Reputation>;\n}\n\nexport interface CallToolParams {\n name: string;\n arguments?: Record<string, unknown>;\n}\n\nexport function createToolHandler(deps: ToolHandlerDeps) {\n const { ensureClient, directSearch, directReputation } = deps;\n\n return async function handleToolCall(\n params: CallToolParams,\n ): Promise<ToolResult> {\n const { name, arguments: rawArgs } = params;\n const args = (rawArgs ?? {}) as Record<string, unknown>;\n\n // Resolve the cached client promise. First call across the process pays\n // the wallet load once; every subsequent call is sync. Read-only tools\n // (search_agents, list_capabilities) work even when this returns\n // undefined.\n const client = await ensureClient();\n\n try {\n switch (name) {\n case \"search_agents\": {\n const searchReq: SearchRequest = {\n capability: String(args.capability),\n max_price_usdc: args.max_price_usdc as string | undefined,\n max_latency_ms: args.max_latency_ms as number | undefined,\n min_success_rate: args.min_success_rate as number | undefined,\n min_avg_stars: args.min_avg_stars as number | undefined,\n limit: args.limit as number | undefined,\n };\n const response = await directSearch(searchReq);\n if (response.agents.length === 0) {\n return ok({\n agents: [],\n match: response.match,\n next_cursor: response.next_cursor,\n available_capabilities: response.available_capabilities ?? [],\n total_distinct_capabilities:\n response.total_distinct_capabilities ?? 0,\n hint: `No agent found for capability '${searchReq.capability}'. Pick one of the IDs in 'available_capabilities' (the live taxonomy) and retry — do not guess variants.`,\n });\n }\n return ok({ agents: response.agents });\n }\n\n case \"list_capabilities\": {\n // Reuse the search-empty fallback as the data source: a sentinel\n // capability ID returns the live `available_capabilities` list.\n const response = await directSearch({\n capability: \"__list_capabilities__\",\n limit: 1,\n });\n return ok({\n capabilities: response.available_capabilities ?? [],\n total: response.total_distinct_capabilities ?? 0,\n });\n }\n\n case \"check_reputation\": {\n const agentId = args.agent_id as AgentId;\n const rep = client\n ? await client.getReputation(agentId)\n : await directReputation(agentId);\n return ok(rep);\n }\n\n case \"get_remaining_budget\": {\n return ok({\n remaining_usdc: client ? client.remainingBudget() : \"0.00\",\n });\n }\n\n case \"get_agent_id\": {\n return ok({ agent_id: client ? client.agentId : null });\n }\n\n case \"hire_agent\": {\n if (!client) return walletRequired(\"hire_agent\");\n const response = await client.hire({\n capability: String(args.capability),\n params: (args.params ?? {}) as Record<string, unknown>,\n max_price_usdc: String(args.max_price_usdc),\n agent_id: args.agent_id as AgentId | undefined,\n max_latency_ms: args.max_latency_ms as number | undefined,\n });\n return ok({\n result: response.result,\n receipt: response.receipt,\n verification: response.verification,\n rating_token: response.rating_token,\n remaining_budget_usdc: client.remainingBudget(),\n });\n }\n\n case \"rate_agent\": {\n if (!client) return walletRequired(\"rate_agent\");\n await client.rate(String(args.rating_token), {\n stars: Number(args.stars) as Stars,\n comment: args.comment as string | undefined,\n });\n return ok({ success: true });\n }\n\n case \"publish_listing\":\n case \"update_listing\": {\n if (!client) return walletRequired(name);\n const listing = await client.publishListing({\n capability: String(args.capability),\n price_usdc: String(args.price_usdc),\n endpoint: String(args.endpoint),\n max_latency_ms: Number(args.max_latency_ms),\n first_call_free: Boolean(args.first_call_free ?? false),\n currency: (args.currency as \"USDC\" | undefined) ?? \"USDC\",\n chain: (args.chain as Listing[\"chain\"] | undefined) ?? \"base\",\n } as Omit<Listing, \"agent_id\" | \"signature\">);\n return ok({ listing });\n }\n\n case \"list_my_listings\": {\n if (!client) return walletRequired(\"list_my_listings\");\n const listings = await client.getMyListings();\n return ok({ count: listings.length, listings });\n }\n\n case \"get_my_receipts\": {\n if (!client) return walletRequired(\"get_my_receipts\");\n const receipts = await client.getMyReceipts({\n limit: args.limit as number | undefined,\n });\n return ok({ count: receipts.length, receipts });\n }\n\n case \"call_x402_service\": {\n if (!client) return walletRequired(\"call_x402_service\");\n const response = await client.payX402({\n url: String(args.url),\n method: args.method as string | undefined,\n body: args.body,\n headers: args.headers as Record<string, string> | undefined,\n max_price_usdc: args.max_price_usdc as string | undefined,\n });\n return ok({\n url: response.url,\n status: response.status,\n data: response.data,\n tx_hash: response.tx_hash,\n amount_paid_usdc: response.amount_paid_usdc,\n latency_ms: response.latency_ms,\n remaining_budget_usdc: client.remainingBudget(),\n });\n }\n\n default:\n return errResult(`Unknown tool: ${name}`);\n }\n } catch (e) {\n if (e instanceof InsufficientFundsError) {\n return insufficientFundsResult(e);\n }\n const error = e as Error & { code?: string };\n return errResult(\n `${error.code ? `[${error.code}] ` : \"\"}${error.message ?? \"Unknown error\"}`,\n );\n }\n };\n}\n","// Swarmwage MCP — tool catalog\n// License: MIT\n//\n// The MCP tool definitions exposed by the server. Descriptions are written\n// for the calling LLM, not for humans: they encode recovery strategies\n// (empty-search hints, free-hire semantics) the model needs at call time.\n\nimport type { Tool } from \"@modelcontextprotocol/sdk/types.js\";\n\nexport const tools: Tool[] = [\n {\n name: \"search_agents\",\n description:\n \"Search the Swarmwage registry for agents that can perform a given capability. Returns a ranked list with prices, latency, and reputation. Use this when you need to find an agent for hire — e.g. when you encounter a task you cannot perform natively (image generation, audio transcription, specialized data lookup, niche translations, etc.).\\n\\nIMPORTANT: capability IDs follow a strict taxonomy (e.g. `code.execute.sandboxed`, NOT `code.execute.python.sandbox`). If your call returns zero agents, the response includes `available_capabilities` (the live taxonomy) and `total_distinct_capabilities`. Use one of those exact strings on retry — do not guess variants. When unsure, call `list_capabilities` first.\",\n inputSchema: {\n type: \"object\",\n properties: {\n capability: {\n type: \"string\",\n description:\n \"The capability ID, e.g. 'image.generate.photorealistic.png', 'audio.transcribe.it.json-with-timestamps', 'text.translate.en.it.business'. See https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md for the full taxonomy.\",\n },\n max_price_usdc: {\n type: \"string\",\n description:\n \"Maximum price willing to pay per call, in USDC as a decimal string, e.g. '1.50'. Optional.\",\n },\n max_latency_ms: {\n type: \"number\",\n description:\n \"Maximum acceptable latency in milliseconds. Optional. Use 5000-15000 for sync calls.\",\n },\n min_success_rate: {\n type: \"number\",\n description:\n \"Minimum success rate (0.0-1.0). Defaults to 0.95 if you care about reliability.\",\n },\n min_avg_stars: {\n type: \"number\",\n description: \"Minimum average rating (1-5). Defaults to 4.0.\",\n },\n limit: {\n type: \"number\",\n description: \"Max results to return. Default 10.\",\n },\n },\n required: [\"capability\"],\n },\n },\n {\n name: \"hire_agent\",\n description:\n \"Hire an agent to execute a capability. Returns the result synchronously. Payment is in USDC via x402 with escrow + automatic verification — you only pay if the output passes the capability's verification function. Use this after you've found a suitable agent via search_agents (or pass agent_id=null to auto-pick the best match). Requires a wallet.\\n\\nMAX_PRICE_USDC semantics: the parameter is BOTH a search filter and a willingness-to-pay cap. Two valid patterns:\\n (a) `max_price_usdc='0'` (or '0.00') — \\\"free-hire intent\\\": the SDK searches without the price filter and accepts only listings with `first_call_free: true`. Use this when get_remaining_budget returns '0.00' and you want to try a free-tier listing.\\n (b) `max_price_usdc='X.YZ'` (positive) — \\\"cap intent\\\": the SDK filters listings priced ≤ X.YZ and proceeds with payment. The listing's actual price (which may be lower) is what gets charged.\\nPicking pattern (a) when you intend free-tier hires is critical: passing `'0.00'` to mean \\\"I have no budget\\\" used to filter out positive-price first_call_free listings; v0.5.1+ of the SDK now handles this correctly and returns a clear error if no free-tier listing exists for the capability.\",\n inputSchema: {\n type: \"object\",\n properties: {\n capability: {\n type: \"string\",\n description: \"The capability ID to hire for, e.g. 'image.generate.photorealistic.png'.\",\n },\n params: {\n type: \"object\",\n description:\n \"Capability-specific input parameters. Schema depends on the capability. Example for image.generate.photorealistic.png: { prompt: string, width: int, height: int, seed?: int }.\",\n additionalProperties: true,\n },\n max_price_usdc: {\n type: \"string\",\n description:\n \"Maximum price per call, USDC decimal string. Pass '0' (or '0.00') to require a free-tier hire (first_call_free listings only — the SDK searches without the price filter in this mode). Pass a positive value (e.g. '0.10') to set an upper-bound cap. See tool description for full semantics.\",\n },\n agent_id: {\n type: \"string\",\n description:\n \"Specific agent to hire (0x-prefixed address). If omitted, the SDK picks the best match by price + reputation.\",\n },\n max_latency_ms: {\n type: \"number\",\n description: \"Maximum acceptable latency in ms. Optional.\",\n },\n },\n required: [\"capability\", \"params\", \"max_price_usdc\"],\n },\n },\n {\n name: \"check_reputation\",\n description:\n \"Look up reputation stats for a specific agent: success rate, average latency, hire count, ratings. Use this to vet an agent before a high-stakes hire.\",\n inputSchema: {\n type: \"object\",\n properties: {\n agent_id: {\n type: \"string\",\n description: \"0x-prefixed agent address.\",\n },\n },\n required: [\"agent_id\"],\n },\n },\n {\n name: \"rate_agent\",\n description:\n \"Submit a rating after a hire. Use the rating_token returned in the hire receipt. Single-use per receipt. Provide honest stars (1-5) — your ratings power the reputation system that benefits everyone. Requires a wallet.\",\n inputSchema: {\n type: \"object\",\n properties: {\n rating_token: { type: \"string\", description: \"The rating_token from a previous hire response.\" },\n stars: { type: \"number\", description: \"Rating 1-5 (integer).\", minimum: 1, maximum: 5 },\n comment: { type: \"string\", description: \"Optional short comment.\" },\n },\n required: [\"rating_token\", \"stars\"],\n },\n },\n {\n name: \"get_remaining_budget\",\n description:\n \"Return how much USDC remains in the operator-authorized budget for this session. Returns '0.00' if no budget is loaded or no wallet is configured.\\n\\nIMPORTANT: a '0.00' return value does NOT block hires of listings with `first_call_free: true`. The SDK skips the budget check entirely for free listings, so try-it-free hires succeed even at zero budget. Only paid hires require positive remaining budget.\",\n inputSchema: { type: \"object\", properties: {} },\n },\n {\n name: \"get_agent_id\",\n description:\n \"Return the agent ID (0x-prefixed wallet address) of this MCP server. Returns null in lookup-only mode (no wallet configured).\",\n inputSchema: { type: \"object\", properties: {} },\n },\n {\n name: \"publish_listing\",\n description:\n \"Publish (or update) a listing on the Swarmwage registry, advertising a capability this agent can fulfill. After publishing, buyers can discover and hire you via `search_agents` and `hire_agent`. The listing is idempotent on (agent_id, capability) — calling again replaces price, endpoint, latency, etc. Your agent must already be running an HTTP server that accepts x402 payments at `endpoint`. Returns the signed listing. Requires a wallet.\",\n inputSchema: {\n type: \"object\",\n properties: {\n capability: { type: \"string\", description: \"Capability ID this listing serves.\" },\n price_usdc: { type: \"string\", description: \"Price per call in USDC, e.g. '0.02'.\" },\n endpoint: {\n type: \"string\",\n description: \"Public HTTPS URL of your seller hire endpoint.\",\n },\n max_latency_ms: { type: \"number\", description: \"Worst-case latency, in ms.\" },\n first_call_free: { type: \"boolean\", description: \"Whether the first call is free.\" },\n currency: { type: \"string\", enum: [\"USDC\"] },\n chain: {\n type: \"string\",\n enum: [\"base\"],\n description:\n \"Settlement chain for this listing. Only 'base' (Base mainnet) is accepted by the public registry.\",\n },\n },\n required: [\"capability\", \"price_usdc\", \"endpoint\", \"max_latency_ms\"],\n },\n },\n {\n name: \"update_listing\",\n description:\n \"Alias of `publish_listing` — same idempotent upsert. Use this when changing price, endpoint, or max_latency_ms of a capability you already publish. Requires a wallet.\",\n inputSchema: {\n type: \"object\",\n properties: {\n capability: { type: \"string\" },\n price_usdc: { type: \"string\" },\n endpoint: { type: \"string\" },\n max_latency_ms: { type: \"number\" },\n first_call_free: { type: \"boolean\" },\n currency: { type: \"string\", enum: [\"USDC\"] },\n chain: {\n type: \"string\",\n enum: [\"base\"],\n description:\n \"Settlement chain for this listing. Only 'base' (Base mainnet) is accepted by the public registry.\",\n },\n },\n required: [\"capability\", \"price_usdc\", \"endpoint\", \"max_latency_ms\"],\n },\n },\n {\n name: \"list_my_listings\",\n description:\n \"Return all active listings this agent has published to the registry. Read-only. Requires a wallet.\",\n inputSchema: { type: \"object\", properties: {} },\n },\n {\n name: \"get_my_receipts\",\n description:\n \"Return recent receipts this agent has submitted to the registry (seller-side view). Read-only. Requires a wallet.\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: { type: \"number\", description: \"How many to return. Default 50, max 200.\" },\n },\n },\n },\n {\n name: \"list_capabilities\",\n description:\n \"Return all capability IDs currently live on the Swarmwage registry, plus the total distinct count. Use this BEFORE `search_agents` whenever you don't already know the exact capability name — the taxonomy is strict (e.g. `code.execute.sandboxed`, not `code.execute.python.sandbox`). Calling this first prevents wasted search round-trips on guessed IDs. Read-only, no wallet required.\",\n inputSchema: { type: \"object\", properties: {} },\n },\n {\n name: \"call_x402_service\",\n description:\n \"Pay for and call ANY x402-enabled HTTP endpoint directly from this agent's wallet — including third-party services NOT listed on the Swarmwage registry (e.g. an external x402 catalog). Use this when you already know the exact endpoint URL of a paid service and want to call it with its own native request shape, rather than discovering a Swarmwage seller via search_agents/hire_agent.\\n\\nDifference from hire_agent: hire_agent targets a Swarmwage-protocol seller (capability + verified output + rating). call_x402_service makes a raw paid HTTP request to an arbitrary x402 URL and returns its raw JSON response — there is no capability verification or rating. The SDK handles the 402 → payment → retry dance, forces payment onto Base, and refuses to pay above max_price_usdc. If the wallet lacks USDC, returns a fund-the-wallet instruction (do NOT substitute another service). Requires a wallet.\",\n inputSchema: {\n type: \"object\",\n properties: {\n url: {\n type: \"string\",\n description:\n \"Absolute URL of the x402-enabled endpoint, e.g. 'https://api.example.com/search'.\",\n },\n method: {\n type: \"string\",\n description:\n \"HTTP method. Defaults to 'POST' when `body` is provided, else 'GET'.\",\n },\n body: {\n type: \"object\",\n description:\n \"JSON request body in the service's OWN native shape (not a Swarmwage envelope). Omit for GET endpoints.\",\n additionalProperties: true,\n },\n headers: {\n type: \"object\",\n description: \"Optional extra request headers.\",\n additionalProperties: { type: \"string\" },\n },\n max_price_usdc: {\n type: \"string\",\n description:\n \"Willingness-to-pay cap per call, USDC decimal string, e.g. '0.05'. The SDK refuses to sign a payment above this. Defaults to '1.00'.\",\n },\n },\n required: [\"url\"],\n },\n },\n];\n","// Swarmwage MCP — boot-time update notifier\n// License: MIT\n//\n// Fetches the latest published version of @swarmwage/mcp from the npm\n// registry once at startup, compares it to the running version, and\n// writes a one-line stderr notice if a newer version exists. Strictly\n// non-blocking: the MCP stdio loop never waits on this, and every\n// error path is swallowed silently — a flaky network must not break a\n// working MCP server.\n//\n// Opt-out: set env SWARMWAGE_NO_UPDATE_CHECK=1 (also accepts: true, on, yes).\n\nimport { VERSION } from \"./constants.js\";\n\nconst NPM_REGISTRY_URL = \"https://registry.npmjs.org/@swarmwage/mcp/latest\";\nconst TIMEOUT_MS = 2_000;\n\nfunction isOptedOut(): boolean {\n const raw = process.env.SWARMWAGE_NO_UPDATE_CHECK;\n if (!raw) return false;\n return /^(1|true|on|yes)$/i.test(raw.trim());\n}\n\n/** Compare two `x.y.z` strings. Returns +1, 0, -1. Returns 0 on parse failure. */\nfunction compareSemver(a: string, b: string): number {\n if (!/^\\d+\\.\\d+\\.\\d+/.test(a) || !/^\\d+\\.\\d+\\.\\d+/.test(b)) return 0;\n const pa = a.split(\".\").map((n) => parseInt(n, 10));\n const pb = b.split(\".\").map((n) => parseInt(n, 10));\n for (let i = 0; i < 3; i++) {\n const da = pa[i] ?? 0;\n const db = pb[i] ?? 0;\n if (da !== db) return da > db ? 1 : -1;\n }\n return 0;\n}\n\n/**\n * Fire-and-forget update probe. Caller does not await. Resolves after at most\n * `TIMEOUT_MS` regardless of network state. Never throws.\n */\nexport async function checkForUpdate(): Promise<void> {\n if (isOptedOut()) return;\n try {\n const ctrl = new AbortController();\n const timer = setTimeout(() => ctrl.abort(), TIMEOUT_MS);\n let res: Response;\n try {\n res = await fetch(NPM_REGISTRY_URL, {\n signal: ctrl.signal,\n headers: { Accept: \"application/json\" },\n });\n } finally {\n clearTimeout(timer);\n }\n if (!res.ok) return;\n const data = (await res.json()) as { version?: string };\n const latest = data.version;\n if (typeof latest !== \"string\") return;\n if (compareSemver(latest, VERSION) <= 0) return;\n process.stderr.write(\n `swarmwage-mcp: update available ${VERSION} → ${latest}. ` +\n `Run: npx -y @swarmwage/mcp@latest --init to refresh, or pin the new version in your host config.\\n` +\n `(set SWARMWAGE_NO_UPDATE_CHECK=1 to silence this notice)\\n`,\n );\n } catch {\n // Silent: no network, npm down, slow, malformed JSON — never block.\n }\n}\n","// Swarmwage MCP — server (stdio MCP transport)\n// License: MIT\n\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport {\n AgentClient,\n type AgentId,\n type BudgetToken,\n type Hex,\n type Reputation,\n type SearchRequest,\n type SearchResponse,\n} from \"@swarmwage/agent-sdk\";\n\nimport { loadWallet } from \"./config.js\";\nimport { VERSION } from \"./constants.js\";\nimport { createToolHandler } from \"./handlers.js\";\nimport { tools } from \"./tools.js\";\nimport { checkForUpdate } from \"./update-check.js\";\n\nexport async function runServer(): Promise<void> {\n // Pure-config inputs we can read sync. Anything that does I/O (file read,\n // network) is deferred so the transport handshake is not blocked.\n const REGISTRY_URL =\n process.env.SWARMWAGE_REGISTRY_URL ?? \"https://api.swarmwage.com\";\n const NETWORK: \"base\" | \"base-sepolia\" =\n (process.env.SWARMWAGE_NETWORK as \"base\" | \"base-sepolia\" | undefined) ??\n \"base\";\n const envKey = process.env.SWARMWAGE_PRIVATE_KEY as Hex | undefined;\n\n let budget: BudgetToken | undefined;\n if (process.env.SWARMWAGE_BUDGET_TOKEN) {\n try {\n budget = JSON.parse(process.env.SWARMWAGE_BUDGET_TOKEN) as BudgetToken;\n } catch (err) {\n process.stderr.write(\n `swarmwage-mcp: SWARMWAGE_BUDGET_TOKEN is not valid JSON: ${(err as Error).message}\\n`,\n );\n process.exit(1);\n }\n }\n\n // Direct fetch so we can surface registry metadata (`available_capabilities`\n // and `total_distinct_capabilities`) on empty results — the SDK's\n // `client.search()` strips those fields. Calling LLMs use the hint to\n // recover from a wrong capability guess on the same turn instead of\n // hallucinating a different ID.\n async function directSearch(req: SearchRequest): Promise<SearchResponse> {\n const res = await fetch(`${REGISTRY_URL}/v1/search`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(req),\n });\n if (!res.ok) {\n throw new Error(\n `registry search failed: ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as SearchResponse;\n }\n\n async function directReputation(agentId: AgentId): Promise<Reputation> {\n const res = await fetch(\n `${REGISTRY_URL}/v1/agents/${agentId}/reputation`,\n );\n if (!res.ok) {\n throw new Error(\n `registry reputation failed: ${res.status} ${res.statusText}`,\n );\n }\n return (await res.json()) as Reputation;\n }\n\n // Lazy wallet + client load — kicked off in the background AFTER the\n // transport handshake so `tools/list` is never blocked by file I/O or viem\n // wallet client init. Calling LLMs see the tool catalog immediately;\n // wallet-only tools (hire_agent, publish_listing, etc.) await this promise\n // at call time and the first call waits ~50-200ms once. Read-only tools\n // (search_agents, check_reputation, list_capabilities, get_agent_id with\n // null fallback, get_remaining_budget with '0.00' fallback) never wait.\n //\n // This eliminates the race condition where slow MCP-host harnesses close\n // their deferred-tool index before our pre-connect setup completes.\n let clientPromise: Promise<AgentClient | undefined> | null = null;\n function ensureClient(): Promise<AgentClient | undefined> {\n if (!clientPromise) {\n clientPromise = (async () => {\n const fileKey = envKey ? null : await loadWallet();\n const PRIVATE_KEY: Hex | undefined = envKey ?? fileKey ?? undefined;\n if (!PRIVATE_KEY) return undefined;\n return new AgentClient({\n privateKey: PRIVATE_KEY,\n registryUrl: REGISTRY_URL,\n budget,\n network: NETWORK,\n });\n })();\n }\n return clientPromise;\n }\n\n const server = new Server(\n { name: \"swarmwage\", version: VERSION },\n // `tools.listChanged: true` signals that the tool list is dynamic and\n // the host should re-read on `notifications/tools/list_changed`. We\n // never actually mutate the list at runtime today, but advertising the\n // capability makes harnesses with stricter cache-invalidation behavior\n // re-query on retry instead of pinning a stale empty list.\n { capabilities: { tools: { listChanged: true } } },\n );\n\n server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));\n\n const handleToolCall = createToolHandler({\n ensureClient,\n directSearch,\n directReputation,\n });\n server.setRequestHandler(CallToolRequestSchema, async (request) =>\n handleToolCall(request.params),\n );\n\n // Connect the transport IMMEDIATELY — before any file I/O or wallet init.\n // `tools/list` is now answerable from the moment the host sends it. This\n // fixes the race where slow MCP hosts close their deferred-tool index\n // before the pre-connect setup finished (observed in Claude Code on\n // cold-start of a session that had `npx -y @swarmwage/mcp` registered).\n const transport = new StdioServerTransport();\n await server.connect(transport);\n process.stderr.write(`swarmwage-mcp v${VERSION} listening on stdio\\n`);\n\n // Now kick off wallet preload in the background. Tool calls that need a\n // wallet will await this same promise; calls that don't (search, list,\n // reputation) never touch it.\n void ensureClient().then((client) => {\n if (client) {\n const source = envKey ? \"env\" : \"config\";\n process.stderr.write(\n `swarmwage-mcp v${VERSION} wallet ready (agent_id=${client.agentId}, source=${source})\\n`,\n );\n } else {\n process.stderr.write(\n `swarmwage-mcp v${VERSION} lookup-only (no wallet)\\n` +\n ` Enabled: search_agents, list_capabilities, check_reputation, get_remaining_budget, get_agent_id\\n` +\n ` Setup wallet: npx @swarmwage/mcp\\n`,\n );\n }\n });\n\n // Fire-and-forget update probe. The MCP loop above is already serving\n // requests; this writes one stderr line if an update is available, then\n // exits silently on any error or network slowness.\n void checkForUpdate();\n}\n"]} |
| #!/usr/bin/env node | ||
| import { loadConfig, saveWallet, saveConfig } from './chunk-ZT7UGTAE.js'; | ||
| import { VERSION, SETUP_URL } from './chunk-GQFPQCBK.js'; | ||
| import { spawn } from 'child_process'; | ||
| import { access, readFile, mkdir, writeFile } from 'fs/promises'; | ||
| import { homedir } from 'os'; | ||
| import { join, dirname } from 'path'; | ||
| import readline from 'readline'; | ||
| import { privateKeyToAddress, generatePrivateKey } from 'viem/accounts'; | ||
| var colorEnabled = Boolean(process.stdout.isTTY) && process.env.NO_COLOR !== "1"; | ||
| var c = { | ||
| violet: (s) => colorEnabled ? `\x1B[38;5;141m${s}\x1B[0m` : s, | ||
| softViolet: (s) => colorEnabled ? `\x1B[38;5;183m${s}\x1B[0m` : s, | ||
| bold: (s) => colorEnabled ? `\x1B[1m${s}\x1B[0m` : s, | ||
| dim: (s) => colorEnabled ? `\x1B[2m${s}\x1B[0m` : s, | ||
| green: (s) => colorEnabled ? `\x1B[32m${s}\x1B[0m` : s, | ||
| red: (s) => colorEnabled ? `\x1B[31m${s}\x1B[0m` : s, | ||
| cyan: (s) => colorEnabled ? `\x1B[36m${s}\x1B[0m` : s, | ||
| yellow: (s) => colorEnabled ? `\x1B[33m${s}\x1B[0m` : s | ||
| }; | ||
| function printArt() { | ||
| const art = [ | ||
| "", | ||
| " \u2572\u2571\u2572\u2571\u2572\u2571\u2572", | ||
| " \u2571\u2572\u2571\u2572\u2571\u2572\u2571 " + c.bold("swarmwage") + c.dim(" \xB7 v" + VERSION), | ||
| " \u2572\u2571\u2572\u2571\u2572\u2571\u2572 " + c.dim("the agent hire protocol"), | ||
| " \u2571\u2572\u2571\u2572\u2571\u2572\u2571", | ||
| "" | ||
| ]; | ||
| for (const line of art) { | ||
| console.log(c.violet(line.startsWith(" \u2572") || line.startsWith(" \u2571") ? line : line)); | ||
| } | ||
| } | ||
| function printWelcome() { | ||
| console.log( | ||
| c.dim(" Free, open protocol for AI agents to discover, hire, and rate each other.") | ||
| ); | ||
| console.log(c.dim(" Settlement in USDC on Base. Zero token, zero KYC, zero protocol fee.")); | ||
| console.log(""); | ||
| console.log(c.bold(" Setup takes 30 seconds. Press Ctrl-C any time to abort.")); | ||
| console.log(""); | ||
| } | ||
| function question(q) { | ||
| const rl = readline.createInterface({ | ||
| input: process.stdin, | ||
| output: process.stdout | ||
| }); | ||
| return new Promise((resolve) => { | ||
| rl.question(q, (ans) => { | ||
| rl.close(); | ||
| resolve(ans.trim()); | ||
| }); | ||
| }); | ||
| } | ||
| async function select(prompt, options) { | ||
| console.log(c.bold(prompt)); | ||
| console.log(""); | ||
| options.forEach((opt, i) => { | ||
| console.log(` ${c.violet(`[${i + 1}]`)} ${c.bold(opt.label)}`); | ||
| if (opt.description) { | ||
| console.log(` ${c.dim(opt.description)}`); | ||
| } | ||
| }); | ||
| console.log(""); | ||
| while (true) { | ||
| const ans = await question( | ||
| `${c.violet("?")} Enter choice ${c.dim(`(1-${options.length})`)} ` | ||
| ); | ||
| const idx = parseInt(ans, 10); | ||
| if (Number.isFinite(idx) && idx >= 1 && idx <= options.length) { | ||
| return options[idx - 1].value; | ||
| } | ||
| console.log(c.red(` Invalid input. Enter a number 1-${options.length}.`)); | ||
| } | ||
| } | ||
| async function confirm(prompt, defaultYes = true) { | ||
| const suffix = c.dim(defaultYes ? "(Y/n)" : "(y/N)"); | ||
| const ans = await question(`${c.violet("?")} ${prompt} ${suffix} `); | ||
| if (!ans) return defaultYes; | ||
| return /^y/i.test(ans); | ||
| } | ||
| async function promptPrivateKey() { | ||
| console.log(""); | ||
| console.log( | ||
| c.dim(" Paste your 0x-prefixed 32-byte private key. It will be saved to") | ||
| ); | ||
| console.log(c.dim(" ~/.swarmwage/wallet.key with 0600 permissions (user-readable only).")); | ||
| console.log( | ||
| c.yellow(" \u26A0 Use a dedicated key. Do not paste the main key of a wallet holding real funds.") | ||
| ); | ||
| console.log(""); | ||
| while (true) { | ||
| const ans = await question(c.violet("? ") + "Private key: "); | ||
| if (/^0x[a-fA-F0-9]{64}$/.test(ans)) { | ||
| return ans; | ||
| } | ||
| console.log(c.red(" Invalid format. Expected 0x followed by 64 hex chars (32 bytes).")); | ||
| } | ||
| } | ||
| function generateTestWallet() { | ||
| const key = generatePrivateKey(); | ||
| const address = privateKeyToAddress(key); | ||
| return { key, address }; | ||
| } | ||
| function easterEgg(addr) { | ||
| const last4 = addr.slice(-4).toLowerCase(); | ||
| const memorable = { | ||
| beef: "vanity address detected: ...beef", | ||
| cafe: "vanity address detected: ...cafe", | ||
| dead: "vanity address detected: ...dead", | ||
| face: "vanity address detected: ...face", | ||
| feed: "vanity address detected: ...feed", | ||
| babe: "vanity address detected: ...babe", | ||
| f00d: "vanity address detected: ...f00d", | ||
| "1337": "vanity address detected: ...1337" | ||
| }; | ||
| return memorable[last4] ?? null; | ||
| } | ||
| function printGeneratedWallet(address) { | ||
| console.log(""); | ||
| console.log(c.green(" \u2713 Generated a fresh test wallet:")); | ||
| console.log(""); | ||
| console.log(` ${c.bold(c.cyan(address))}`); | ||
| console.log(""); | ||
| console.log(c.dim(" This wallet has zero USDC. To start spending on hires, fund it on Base:")); | ||
| console.log(c.dim(" https://www.coinbase.com/onramp \u2192 send USDC to the address above")); | ||
| console.log(c.dim(" You don't need ETH for gas \u2014 the Swarmwage facilitator covers it.")); | ||
| console.log(""); | ||
| const egg = easterEgg(address); | ||
| if (egg) { | ||
| console.log(c.softViolet(` \u2728 ${egg}`)); | ||
| console.log(""); | ||
| } | ||
| } | ||
| function detectClaudeCode() { | ||
| return new Promise((resolve) => { | ||
| const proc = spawn("which", ["claude"], { stdio: "ignore" }); | ||
| proc.on("close", (code) => resolve(code === 0)); | ||
| proc.on("error", () => resolve(false)); | ||
| }); | ||
| } | ||
| async function detectClaudeDesktop() { | ||
| const platform = process.platform; | ||
| let path; | ||
| if (platform === "darwin") { | ||
| path = join( | ||
| homedir(), | ||
| "Library", | ||
| "Application Support", | ||
| "Claude", | ||
| "claude_desktop_config.json" | ||
| ); | ||
| } else if (platform === "win32") { | ||
| path = join( | ||
| process.env.APPDATA ?? join(homedir(), "AppData", "Roaming"), | ||
| "Claude", | ||
| "claude_desktop_config.json" | ||
| ); | ||
| } else { | ||
| path = join(homedir(), ".config", "Claude", "claude_desktop_config.json"); | ||
| } | ||
| try { | ||
| await access(path); | ||
| return path; | ||
| } catch { | ||
| return null; | ||
| } | ||
| } | ||
| function registerWithClaudeCode() { | ||
| return new Promise((resolve) => { | ||
| const proc = spawn( | ||
| "claude", | ||
| [ | ||
| "mcp", | ||
| "add", | ||
| "--scope", | ||
| "user", | ||
| "swarmwage", | ||
| "--", | ||
| "npx", | ||
| "-y", | ||
| "@swarmwage/mcp", | ||
| "--server" | ||
| ], | ||
| { stdio: "inherit" } | ||
| ); | ||
| proc.on("close", (code) => resolve(code === 0)); | ||
| proc.on("error", () => resolve(false)); | ||
| }); | ||
| } | ||
| async function patchClaudeDesktopConfig(configPath) { | ||
| let cfg = {}; | ||
| try { | ||
| const data = await readFile(configPath, "utf-8"); | ||
| cfg = JSON.parse(data); | ||
| } catch { | ||
| } | ||
| if (!cfg.mcpServers) cfg.mcpServers = {}; | ||
| cfg.mcpServers.swarmwage = { | ||
| command: "npx", | ||
| args: ["-y", "@swarmwage/mcp", "--server"] | ||
| }; | ||
| await mkdir(dirname(configPath), { recursive: true }); | ||
| await writeFile(configPath, JSON.stringify(cfg, null, 2), "utf-8"); | ||
| } | ||
| function printManualClaudeCode() { | ||
| console.log(""); | ||
| console.log(c.bold(" Add to Claude Code manually:")); | ||
| console.log(""); | ||
| console.log( | ||
| c.cyan(" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server") | ||
| ); | ||
| console.log(""); | ||
| } | ||
| function printManualClaudeDesktop(configPath) { | ||
| console.log(""); | ||
| console.log(c.bold(" Add to Claude Desktop manually:")); | ||
| console.log(c.dim(` Edit ${configPath} and add under "mcpServers":`)); | ||
| console.log(""); | ||
| const snippet = ` "swarmwage": { | ||
| "command": "npx", | ||
| "args": ["-y", "@swarmwage/mcp", "--server"] | ||
| }`; | ||
| console.log(c.cyan(snippet)); | ||
| console.log(""); | ||
| console.log(c.dim(" Then restart Claude Desktop.")); | ||
| console.log(""); | ||
| } | ||
| function printAllManualConfigs() { | ||
| console.log(""); | ||
| console.log(c.bold(" Manual setup snippets:")); | ||
| console.log(""); | ||
| console.log(c.dim(" Claude Code:")); | ||
| console.log( | ||
| c.cyan(" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server") | ||
| ); | ||
| console.log(""); | ||
| console.log(c.dim(" Claude Desktop / Cursor / Cline (claude_desktop_config.json):")); | ||
| const snippet = ` "swarmwage": { | ||
| "command": "npx", | ||
| "args": ["-y", "@swarmwage/mcp", "--server"] | ||
| }`; | ||
| console.log(c.cyan(snippet)); | ||
| console.log(""); | ||
| } | ||
| function printSuccess(mode, host, address) { | ||
| console.log(""); | ||
| console.log(c.green(" \u2713 Swarmwage is set up.")); | ||
| console.log(""); | ||
| console.log(` ${c.dim("Mode:")} ${modeLabel(mode)}`); | ||
| if (address) { | ||
| console.log(` ${c.dim("Wallet:")} ${c.cyan(address)}`); | ||
| } | ||
| console.log(` ${c.dim("Host:")} ${hostLabel(host)}`); | ||
| console.log(""); | ||
| if (host === "claude-code") { | ||
| console.log(c.bold(" Next: open a new Claude Code session and try:")); | ||
| console.log(""); | ||
| console.log( | ||
| c.cyan(" > use search_agents to find chart-generation agents (limit 5)") | ||
| ); | ||
| console.log(""); | ||
| } else if (host === "claude-desktop") { | ||
| console.log(c.bold(" Next: restart Claude Desktop, then ask:")); | ||
| console.log(""); | ||
| console.log( | ||
| c.cyan(" > use search_agents to find chart-generation agents (limit 5)") | ||
| ); | ||
| console.log(""); | ||
| } else { | ||
| console.log(c.bold(" Next: paste the snippet above into your MCP host config, then try")); | ||
| console.log(c.dim(" asking your agent to call `search_agents` with a capability filter.")); | ||
| console.log(""); | ||
| } | ||
| console.log(c.dim(` Docs: ${SETUP_URL}`)); | ||
| console.log(""); | ||
| } | ||
| function modeLabel(mode) { | ||
| return { | ||
| explorer: "explorer (lookup-only, no wallet)", | ||
| "buyer-paste": "buyer (your wallet)", | ||
| "buyer-generated": "buyer (test wallet)", | ||
| seller: "seller" | ||
| }[mode]; | ||
| } | ||
| function hostLabel(host) { | ||
| return { | ||
| "claude-code": "Claude Code", | ||
| "claude-desktop": "Claude Desktop", | ||
| cursor: "Cursor", | ||
| manual: "manual (snippet printed above)", | ||
| none: "not configured" | ||
| }[host]; | ||
| } | ||
| async function runWizard() { | ||
| printArt(); | ||
| printWelcome(); | ||
| const existing = await loadConfig(); | ||
| if (existing) { | ||
| console.log( | ||
| c.dim( | ||
| ` Existing setup found: mode=${existing.mode}, host=${existing.host}, version=${existing.version}.` | ||
| ) | ||
| ); | ||
| const re = await confirm("Re-run setup and overwrite?", false); | ||
| if (!re) { | ||
| console.log(""); | ||
| console.log(c.green(" \u2713 Keeping existing config. Nothing changed.")); | ||
| console.log( | ||
| c.dim(" Force a fresh wizard with: npx @swarmwage/mcp --init") | ||
| ); | ||
| console.log(""); | ||
| return; | ||
| } | ||
| console.log(""); | ||
| } | ||
| const mode = await select("How would you like to start?", [ | ||
| { | ||
| label: "I have a private key \u2014 paste it now", | ||
| value: "buyer-paste", | ||
| description: "Use your own funded wallet for hires + ratings." | ||
| }, | ||
| { | ||
| label: "Generate a test wallet for me", | ||
| value: "buyer-generated", | ||
| description: "Fresh wallet, saved locally. Fund it later to start hiring." | ||
| }, | ||
| { | ||
| label: "Add later \u2014 let me just explore", | ||
| value: "explorer", | ||
| description: "Read-only: search agents + check reputation. No wallet needed." | ||
| }, | ||
| { | ||
| label: "I'm a seller \u2014 I want to publish capabilities", | ||
| value: "seller", | ||
| description: "Generate wallet + you'll publish a listing after setup." | ||
| } | ||
| ]); | ||
| let walletKey; | ||
| let walletAddress; | ||
| if (mode === "buyer-paste") { | ||
| walletKey = await promptPrivateKey(); | ||
| walletAddress = privateKeyToAddress(walletKey); | ||
| } else if (mode === "buyer-generated" || mode === "seller") { | ||
| const w = generateTestWallet(); | ||
| walletKey = w.key; | ||
| walletAddress = w.address; | ||
| printGeneratedWallet(walletAddress); | ||
| } | ||
| if (walletKey) { | ||
| await saveWallet(walletKey); | ||
| console.log(c.green(" \u2713 Wallet saved to ~/.swarmwage/wallet.key (chmod 600)")); | ||
| } | ||
| console.log(""); | ||
| console.log(c.bold(" Looking for an MCP host...")); | ||
| console.log(""); | ||
| const hasClaudeCode = await detectClaudeCode(); | ||
| const claudeDesktopPath = !hasClaudeCode ? await detectClaudeDesktop() : null; | ||
| let host = "none"; | ||
| if (hasClaudeCode) { | ||
| console.log(c.green(" \u2713 Found Claude Code in your PATH.")); | ||
| console.log(""); | ||
| const add = await confirm("Add Swarmwage to Claude Code now?", true); | ||
| if (add) { | ||
| const success = await registerWithClaudeCode(); | ||
| if (success) { | ||
| host = "claude-code"; | ||
| console.log(c.green(" \u2713 Registered (user scope). Restart any open Claude Code session.")); | ||
| } else { | ||
| console.log(c.red(" \u2718 `claude mcp add` failed. Showing manual snippet.")); | ||
| printManualClaudeCode(); | ||
| host = "manual"; | ||
| } | ||
| } else { | ||
| printManualClaudeCode(); | ||
| host = "manual"; | ||
| } | ||
| } else if (claudeDesktopPath) { | ||
| console.log(c.green(` \u2713 Found Claude Desktop config at ${claudeDesktopPath}.`)); | ||
| console.log(""); | ||
| const add = await confirm("Add Swarmwage to Claude Desktop now?", true); | ||
| if (add) { | ||
| try { | ||
| await patchClaudeDesktopConfig(claudeDesktopPath); | ||
| host = "claude-desktop"; | ||
| console.log(c.green(" \u2713 Updated config. Restart Claude Desktop to pick up the server.")); | ||
| } catch (e) { | ||
| console.log( | ||
| c.red(` \u2718 Failed to patch config: ${e.message}. Showing manual snippet.`) | ||
| ); | ||
| printManualClaudeDesktop(claudeDesktopPath); | ||
| host = "manual"; | ||
| } | ||
| } else { | ||
| printManualClaudeDesktop(claudeDesktopPath); | ||
| host = "manual"; | ||
| } | ||
| } else { | ||
| console.log(c.dim(" No MCP host auto-detected on this machine.")); | ||
| printAllManualConfigs(); | ||
| host = "manual"; | ||
| } | ||
| await saveConfig({ | ||
| mode, | ||
| host, | ||
| installed_at: (/* @__PURE__ */ new Date()).toISOString(), | ||
| version: VERSION | ||
| }); | ||
| if (mode === "seller") { | ||
| console.log(""); | ||
| console.log(c.bold(" Seller mode:")); | ||
| console.log( | ||
| c.dim(" After your MCP host loads Swarmwage, ask your agent to call") | ||
| ); | ||
| console.log( | ||
| c.dim(" `publish_listing` with your capability ID, price, and endpoint URL.") | ||
| ); | ||
| console.log( | ||
| c.dim(" See: https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md") | ||
| ); | ||
| } | ||
| printSuccess(mode, host, walletAddress); | ||
| } | ||
| export { runWizard }; | ||
| //# sourceMappingURL=wizard-T3X6KBKQ.js.map | ||
| //# sourceMappingURL=wizard-T3X6KBKQ.js.map |
| {"version":3,"sources":["../src/wizard.ts"],"names":[],"mappings":"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","file":"wizard-T3X6KBKQ.js","sourcesContent":["// Swarmwage MCP — interactive setup wizard\n// License: MIT\n//\n// Runs when the binary is invoked from a TTY (or with `--init`). Walks the\n// user through wallet setup (paste / generate / skip / seller) and registers\n// the MCP server with Claude Code, Claude Desktop, or Cursor.\n\nimport { spawn } from \"child_process\";\nimport { access, mkdir, readFile, writeFile } from \"fs/promises\";\nimport { homedir } from \"os\";\nimport { dirname, join } from \"path\";\nimport readline from \"readline\";\nimport { generatePrivateKey, privateKeyToAddress } from \"viem/accounts\";\n\nimport type { AgentId, Hex } from \"@swarmwage/agent-sdk\";\n\nimport { VERSION, SETUP_URL } from \"./constants.js\";\nimport {\n loadConfig,\n saveConfig,\n saveWallet,\n type SwarmwageConfig,\n type WizardMode,\n} from \"./config.js\";\n\n// -------------------------------------------------------------------------\n// ANSI color helpers (no deps)\n// -------------------------------------------------------------------------\n\nconst colorEnabled =\n Boolean(process.stdout.isTTY) && process.env.NO_COLOR !== \"1\";\n\nconst c = {\n violet: (s: string) => (colorEnabled ? `\\x1b[38;5;141m${s}\\x1b[0m` : s),\n softViolet: (s: string) => (colorEnabled ? `\\x1b[38;5;183m${s}\\x1b[0m` : s),\n bold: (s: string) => (colorEnabled ? `\\x1b[1m${s}\\x1b[0m` : s),\n dim: (s: string) => (colorEnabled ? `\\x1b[2m${s}\\x1b[0m` : s),\n green: (s: string) => (colorEnabled ? `\\x1b[32m${s}\\x1b[0m` : s),\n red: (s: string) => (colorEnabled ? `\\x1b[31m${s}\\x1b[0m` : s),\n cyan: (s: string) => (colorEnabled ? `\\x1b[36m${s}\\x1b[0m` : s),\n yellow: (s: string) => (colorEnabled ? `\\x1b[33m${s}\\x1b[0m` : s),\n};\n\n// -------------------------------------------------------------------------\n// ASCII art + welcome\n// -------------------------------------------------------------------------\n\nfunction printArt(): void {\n const art = [\n \"\",\n \" ╲╱╲╱╲╱╲\",\n \" ╱╲╱╲╱╲╱ \" + c.bold(\"swarmwage\") + c.dim(\" · v\" + VERSION),\n \" ╲╱╲╱╲╱╲ \" + c.dim(\"the agent hire protocol\"),\n \" ╱╲╱╲╱╲╱\",\n \"\",\n ];\n for (const line of art) {\n console.log(c.violet(line.startsWith(\" ╲\") || line.startsWith(\" ╱\") ? line : line));\n }\n}\n\nfunction printWelcome(): void {\n console.log(\n c.dim(\" Free, open protocol for AI agents to discover, hire, and rate each other.\"),\n );\n console.log(c.dim(\" Settlement in USDC on Base. Zero token, zero KYC, zero protocol fee.\"));\n console.log(\"\");\n console.log(c.bold(\" Setup takes 30 seconds. Press Ctrl-C any time to abort.\"));\n console.log(\"\");\n}\n\n// -------------------------------------------------------------------------\n// Readline helpers\n// -------------------------------------------------------------------------\n\nfunction question(q: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n return new Promise((resolve) => {\n rl.question(q, (ans) => {\n rl.close();\n resolve(ans.trim());\n });\n });\n}\n\nasync function select<T>(\n prompt: string,\n options: { label: string; value: T; description?: string }[],\n): Promise<T> {\n console.log(c.bold(prompt));\n console.log(\"\");\n options.forEach((opt, i) => {\n console.log(` ${c.violet(`[${i + 1}]`)} ${c.bold(opt.label)}`);\n if (opt.description) {\n console.log(` ${c.dim(opt.description)}`);\n }\n });\n console.log(\"\");\n while (true) {\n const ans = await question(\n `${c.violet(\"?\")} Enter choice ${c.dim(`(1-${options.length})`)} `,\n );\n const idx = parseInt(ans, 10);\n if (Number.isFinite(idx) && idx >= 1 && idx <= options.length) {\n return options[idx - 1]!.value;\n }\n console.log(c.red(` Invalid input. Enter a number 1-${options.length}.`));\n }\n}\n\nasync function confirm(prompt: string, defaultYes = true): Promise<boolean> {\n const suffix = c.dim(defaultYes ? \"(Y/n)\" : \"(y/N)\");\n const ans = await question(`${c.violet(\"?\")} ${prompt} ${suffix} `);\n if (!ans) return defaultYes;\n return /^y/i.test(ans);\n}\n\n// -------------------------------------------------------------------------\n// Wallet helpers\n// -------------------------------------------------------------------------\n\nasync function promptPrivateKey(): Promise<Hex> {\n console.log(\"\");\n console.log(\n c.dim(\" Paste your 0x-prefixed 32-byte private key. It will be saved to\"),\n );\n console.log(c.dim(\" ~/.swarmwage/wallet.key with 0600 permissions (user-readable only).\"));\n console.log(\n c.yellow(\" ⚠ Use a dedicated key. Do not paste the main key of a wallet holding real funds.\"),\n );\n console.log(\"\");\n while (true) {\n const ans = await question(c.violet(\"? \") + \"Private key: \");\n if (/^0x[a-fA-F0-9]{64}$/.test(ans)) {\n return ans as Hex;\n }\n console.log(c.red(\" Invalid format. Expected 0x followed by 64 hex chars (32 bytes).\"));\n }\n}\n\nfunction generateTestWallet(): { key: Hex; address: AgentId } {\n const key = generatePrivateKey();\n const address = privateKeyToAddress(key) as AgentId;\n return { key, address };\n}\n\nfunction easterEgg(addr: string): string | null {\n const last4 = addr.slice(-4).toLowerCase();\n const memorable: Record<string, string> = {\n beef: \"vanity address detected: ...beef\",\n cafe: \"vanity address detected: ...cafe\",\n dead: \"vanity address detected: ...dead\",\n face: \"vanity address detected: ...face\",\n feed: \"vanity address detected: ...feed\",\n babe: \"vanity address detected: ...babe\",\n f00d: \"vanity address detected: ...f00d\",\n \"1337\": \"vanity address detected: ...1337\",\n };\n return memorable[last4] ?? null;\n}\n\nfunction printGeneratedWallet(address: AgentId): void {\n console.log(\"\");\n console.log(c.green(\" ✓ Generated a fresh test wallet:\"));\n console.log(\"\");\n console.log(` ${c.bold(c.cyan(address))}`);\n console.log(\"\");\n console.log(c.dim(\" This wallet has zero USDC. To start spending on hires, fund it on Base:\"));\n console.log(c.dim(\" https://www.coinbase.com/onramp → send USDC to the address above\"));\n console.log(c.dim(\" You don't need ETH for gas — the Swarmwage facilitator covers it.\"));\n console.log(\"\");\n const egg = easterEgg(address);\n if (egg) {\n console.log(c.softViolet(` ✨ ${egg}`));\n console.log(\"\");\n }\n}\n\n// -------------------------------------------------------------------------\n// Host detection\n// -------------------------------------------------------------------------\n\nfunction detectClaudeCode(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\"which\", [\"claude\"], { stdio: \"ignore\" });\n proc.on(\"close\", (code) => resolve(code === 0));\n proc.on(\"error\", () => resolve(false));\n });\n}\n\nasync function detectClaudeDesktop(): Promise<string | null> {\n const platform = process.platform;\n let path: string;\n if (platform === \"darwin\") {\n path = join(\n homedir(),\n \"Library\",\n \"Application Support\",\n \"Claude\",\n \"claude_desktop_config.json\",\n );\n } else if (platform === \"win32\") {\n path = join(\n process.env.APPDATA ?? join(homedir(), \"AppData\", \"Roaming\"),\n \"Claude\",\n \"claude_desktop_config.json\",\n );\n } else {\n path = join(homedir(), \".config\", \"Claude\", \"claude_desktop_config.json\");\n }\n try {\n await access(path);\n return path;\n } catch {\n return null;\n }\n}\n\n// -------------------------------------------------------------------------\n// Register MCP server\n// -------------------------------------------------------------------------\n\nfunction registerWithClaudeCode(): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn(\n \"claude\",\n [\n \"mcp\",\n \"add\",\n \"--scope\",\n \"user\",\n \"swarmwage\",\n \"--\",\n \"npx\",\n \"-y\",\n \"@swarmwage/mcp\",\n \"--server\",\n ],\n { stdio: \"inherit\" },\n );\n proc.on(\"close\", (code) => resolve(code === 0));\n proc.on(\"error\", () => resolve(false));\n });\n}\n\nasync function patchClaudeDesktopConfig(configPath: string): Promise<void> {\n let cfg: { mcpServers?: Record<string, unknown> } = {};\n try {\n const data = await readFile(configPath, \"utf-8\");\n cfg = JSON.parse(data) as typeof cfg;\n } catch {\n /* file doesn't exist or invalid JSON — start with empty config */\n }\n if (!cfg.mcpServers) cfg.mcpServers = {};\n cfg.mcpServers.swarmwage = {\n command: \"npx\",\n args: [\"-y\", \"@swarmwage/mcp\", \"--server\"],\n };\n await mkdir(dirname(configPath), { recursive: true });\n await writeFile(configPath, JSON.stringify(cfg, null, 2), \"utf-8\");\n}\n\n// -------------------------------------------------------------------------\n// Manual config snippets (printed if auto-register declined or no host found)\n// -------------------------------------------------------------------------\n\nfunction printManualClaudeCode(): void {\n console.log(\"\");\n console.log(c.bold(\" Add to Claude Code manually:\"));\n console.log(\"\");\n console.log(\n c.cyan(\" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server\"),\n );\n console.log(\"\");\n}\n\nfunction printManualClaudeDesktop(configPath: string): void {\n console.log(\"\");\n console.log(c.bold(\" Add to Claude Desktop manually:\"));\n console.log(c.dim(` Edit ${configPath} and add under \\\"mcpServers\\\":`));\n console.log(\"\");\n const snippet = ` \"swarmwage\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@swarmwage/mcp\", \"--server\"]\n }`;\n console.log(c.cyan(snippet));\n console.log(\"\");\n console.log(c.dim(\" Then restart Claude Desktop.\"));\n console.log(\"\");\n}\n\nfunction printAllManualConfigs(): void {\n console.log(\"\");\n console.log(c.bold(\" Manual setup snippets:\"));\n console.log(\"\");\n console.log(c.dim(\" Claude Code:\"));\n console.log(\n c.cyan(\" claude mcp add --scope user swarmwage -- npx -y @swarmwage/mcp --server\"),\n );\n console.log(\"\");\n console.log(c.dim(\" Claude Desktop / Cursor / Cline (claude_desktop_config.json):\"));\n const snippet = ` \"swarmwage\": {\n \"command\": \"npx\",\n \"args\": [\"-y\", \"@swarmwage/mcp\", \"--server\"]\n }`;\n console.log(c.cyan(snippet));\n console.log(\"\");\n}\n\n// -------------------------------------------------------------------------\n// Success / final summary\n// -------------------------------------------------------------------------\n\nfunction printSuccess(\n mode: WizardMode,\n host: SwarmwageConfig[\"host\"],\n address: AgentId | undefined,\n): void {\n console.log(\"\");\n console.log(c.green(\" ✓ Swarmwage is set up.\"));\n console.log(\"\");\n console.log(` ${c.dim(\"Mode:\")} ${modeLabel(mode)}`);\n if (address) {\n console.log(` ${c.dim(\"Wallet:\")} ${c.cyan(address)}`);\n }\n console.log(` ${c.dim(\"Host:\")} ${hostLabel(host)}`);\n console.log(\"\");\n if (host === \"claude-code\") {\n console.log(c.bold(\" Next: open a new Claude Code session and try:\"));\n console.log(\"\");\n console.log(\n c.cyan(' > use search_agents to find chart-generation agents (limit 5)'),\n );\n console.log(\"\");\n } else if (host === \"claude-desktop\") {\n console.log(c.bold(\" Next: restart Claude Desktop, then ask:\"));\n console.log(\"\");\n console.log(\n c.cyan(' > use search_agents to find chart-generation agents (limit 5)'),\n );\n console.log(\"\");\n } else {\n console.log(c.bold(\" Next: paste the snippet above into your MCP host config, then try\"));\n console.log(c.dim(\" asking your agent to call `search_agents` with a capability filter.\"));\n console.log(\"\");\n }\n console.log(c.dim(` Docs: ${SETUP_URL}`));\n console.log(\"\");\n}\n\nfunction modeLabel(mode: WizardMode): string {\n return {\n explorer: \"explorer (lookup-only, no wallet)\",\n \"buyer-paste\": \"buyer (your wallet)\",\n \"buyer-generated\": \"buyer (test wallet)\",\n seller: \"seller\",\n }[mode];\n}\n\nfunction hostLabel(host: SwarmwageConfig[\"host\"]): string {\n return {\n \"claude-code\": \"Claude Code\",\n \"claude-desktop\": \"Claude Desktop\",\n cursor: \"Cursor\",\n manual: \"manual (snippet printed above)\",\n none: \"not configured\",\n }[host];\n}\n\n// -------------------------------------------------------------------------\n// Main wizard flow\n// -------------------------------------------------------------------------\n\nexport async function runWizard(): Promise<void> {\n printArt();\n printWelcome();\n\n // Re-run guard\n const existing = await loadConfig();\n if (existing) {\n console.log(\n c.dim(\n ` Existing setup found: mode=${existing.mode}, host=${existing.host}, version=${existing.version}.`,\n ),\n );\n const re = await confirm(\"Re-run setup and overwrite?\", false);\n if (!re) {\n console.log(\"\");\n console.log(c.green(\" ✓ Keeping existing config. Nothing changed.\"));\n console.log(\n c.dim(\" Force a fresh wizard with: npx @swarmwage/mcp --init\"),\n );\n console.log(\"\");\n return;\n }\n console.log(\"\");\n }\n\n const mode = await select<WizardMode>(\"How would you like to start?\", [\n {\n label: \"I have a private key — paste it now\",\n value: \"buyer-paste\",\n description: \"Use your own funded wallet for hires + ratings.\",\n },\n {\n label: \"Generate a test wallet for me\",\n value: \"buyer-generated\",\n description: \"Fresh wallet, saved locally. Fund it later to start hiring.\",\n },\n {\n label: \"Add later — let me just explore\",\n value: \"explorer\",\n description: \"Read-only: search agents + check reputation. No wallet needed.\",\n },\n {\n label: \"I'm a seller — I want to publish capabilities\",\n value: \"seller\",\n description: \"Generate wallet + you'll publish a listing after setup.\",\n },\n ]);\n\n let walletKey: Hex | undefined;\n let walletAddress: AgentId | undefined;\n\n if (mode === \"buyer-paste\") {\n walletKey = await promptPrivateKey();\n walletAddress = privateKeyToAddress(walletKey) as AgentId;\n } else if (mode === \"buyer-generated\" || mode === \"seller\") {\n const w = generateTestWallet();\n walletKey = w.key;\n walletAddress = w.address;\n printGeneratedWallet(walletAddress);\n }\n\n if (walletKey) {\n await saveWallet(walletKey);\n console.log(c.green(\" ✓ Wallet saved to ~/.swarmwage/wallet.key (chmod 600)\"));\n }\n\n // Host detection + registration\n console.log(\"\");\n console.log(c.bold(\" Looking for an MCP host...\"));\n console.log(\"\");\n\n const hasClaudeCode = await detectClaudeCode();\n const claudeDesktopPath = !hasClaudeCode ? await detectClaudeDesktop() : null;\n\n let host: SwarmwageConfig[\"host\"] = \"none\";\n\n if (hasClaudeCode) {\n console.log(c.green(\" ✓ Found Claude Code in your PATH.\"));\n console.log(\"\");\n const add = await confirm(\"Add Swarmwage to Claude Code now?\", true);\n if (add) {\n const success = await registerWithClaudeCode();\n if (success) {\n host = \"claude-code\";\n console.log(c.green(\" ✓ Registered (user scope). Restart any open Claude Code session.\"));\n } else {\n console.log(c.red(\" ✘ `claude mcp add` failed. Showing manual snippet.\"));\n printManualClaudeCode();\n host = \"manual\";\n }\n } else {\n printManualClaudeCode();\n host = \"manual\";\n }\n } else if (claudeDesktopPath) {\n console.log(c.green(` ✓ Found Claude Desktop config at ${claudeDesktopPath}.`));\n console.log(\"\");\n const add = await confirm(\"Add Swarmwage to Claude Desktop now?\", true);\n if (add) {\n try {\n await patchClaudeDesktopConfig(claudeDesktopPath);\n host = \"claude-desktop\";\n console.log(c.green(\" ✓ Updated config. Restart Claude Desktop to pick up the server.\"));\n } catch (e) {\n console.log(\n c.red(` ✘ Failed to patch config: ${(e as Error).message}. Showing manual snippet.`),\n );\n printManualClaudeDesktop(claudeDesktopPath);\n host = \"manual\";\n }\n } else {\n printManualClaudeDesktop(claudeDesktopPath);\n host = \"manual\";\n }\n } else {\n console.log(c.dim(\" No MCP host auto-detected on this machine.\"));\n printAllManualConfigs();\n host = \"manual\";\n }\n\n await saveConfig({\n mode,\n host,\n installed_at: new Date().toISOString(),\n version: VERSION,\n });\n\n if (mode === \"seller\") {\n console.log(\"\");\n console.log(c.bold(\" Seller mode:\"));\n console.log(\n c.dim(\" After your MCP host loads Swarmwage, ask your agent to call\"),\n );\n console.log(\n c.dim(\" `publish_listing` with your capability ID, price, and endpoint URL.\"),\n );\n console.log(\n c.dim(\" See: https://github.com/Swarmwage/swarmwage/blob/main/packages/protocol/CAPABILITIES.md\"),\n );\n }\n\n printSuccess(mode, host, walletAddress);\n}\n"]} |
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
166453
23%1260
20.11%168
15.86%1
Infinity%6
50%- Removed
- Removed
- Removed
- Removed