@nonagon-link/mcp
v0.3.7
Published
NONAGON LINK MCP server — let AI agents discover and pay for APIs with USDC (x402)
Maintainers
Readme
@nonagon-link/mcp
MCP (Model Context Protocol) server for NONAGON LINK — lets AI agents discover paid APIs and pay for them over the x402 protocol with USDC on Solana, and — when you configure an EVM wallet — with the official JPYC on Polygon / Ethereum (TEST_JPYSC on Sepolia for testing), and — only when you also set an EVM USDC cap — with EVM USDC. A 402 that asks for any other asset, a different network, or a payTo outside your allow-list is rejected without signing.
Tools
| Tool | Description |
|---|---|
| search_listings | Search and compare paid APIs by keyword, network, currency, budget, MCP payment compatibility, health, and settled-payment rating evidence. Returns a summary of each candidate with its providerId and listingId (no call target) |
| get_listing | For one listing chosen from search_listings, return the proxyUrl, httpMethod and funnelAttribution to pass to pay_and_call, how to call it (parameters, querySchema, requestBodySchema, requestGuide, queryExample), response samples and schema, and the successor listing. It fetches only that listing's OpenAPI. On failure it returns how to pick the next candidate |
| pay_and_call | Call a paid API endpoint, automatically handling the x402 payment flow (402 → sign → retry). Every response carries paymentStatus (paid / not_paid / unknown — see Payment status). When paid, paymentInfo has currency (USDC, JPYC, or TEST_JPYSC), amount in that currency, amountUsdc (USDC on Solana or EVM; null for yen tokens), txSignature, network, payer, and paidAt. txSignature is the tx the payee reported; the MCP does not verify it on-chain. For USDC on Solana, payer is the paying wallet as reported in the PAYMENT-RESPONSE header (the counterparty's claim); for EVM payments (JPYC and EVM USDC), amount, network and payer are the values this server actually signed |
| get_active_tokens | List active access tokens for this session (masked summary only). Note: standard inline payments via pay_and_call do not issue an access token, so this list can be empty even after a successful payment — use get_payment_history / get_spending to review spending |
| get_payment_history | List this server's recent payments (inline payments included). With an EVM wallet configured, the Solana wallet's and the EVM wallet's payments are merged into one list and each row says which wallet paid. Requires NONAGON_LINK_BASE_URL |
| get_spending | Aggregate spending by period (day/week/month/all), with a per-currency breakdown. With an EVM wallet configured, also returns per-wallet results and an assets list (one entry per wallet × currency; amounts are never added across wallets or currencies). Requires NONAGON_LINK_BASE_URL |
get_payment_historyandget_spendingauthenticate to NONAGON LINK on your behalf via the standard agent challenge/verify flow: with the Solana key (NONAGON_PRIVATE_KEY), and — whenNONAGON_EVM_PRIVATE_KEYis set — separately with the EVM key, which signs only a fixed EIP-712AgentChallengemessage (purpose: "agent-challenge"and the server's UUID nonce) on a network of this server's family. The access tokens are held in memory per wallet only and are never logged or returned to the model.With an EVM wallet the response also has
wallets(one entry per wallet withstatus: "ok"orstatus: "error"and a fixederror.kind/error.message). If one wallet fails, the other wallet's result is still returned withpartial: true(inget_payment_history,pagination.totalis thennull); if both fail the tool returns an error. Inget_spending, the top-leveltotal/count/byStatus/byCurrency/period/fromkeep meaning the Solana wallet (total/count/byStatusare the server's USDC-only headline); readassetsorwallets[].byCurrencyfor JPYC and for the EVM wallet. Each wallet has a 20-second deadline per call. If EVM agent authentication fails (not enabled on the server, sanctions, revoked agent, rate limits), the server is not asked again for that wallet for 60 seconds (10 minutes when the cause will not clear quickly: not enabled, sanctions, or an API 401 whose server code isAGENT_REVOKED), so the Solana side keeps working. An attempt stopped by the 20-second deadline before the server answered does not start this wait (once the server's status has arrived, the wait follows that status; this includes an unreadable 400 that is still the latest answer when the deadline stops a later network's request; once a later network answers, with 200 or with "not enabled", the earlier 400 no longer sets the wait), so a consistently slow server can see one attempt per call; EVM calls for the same wallet still run one at a time, so at most one attempt is in flight. With an EVM wallet each call uses two of the per-IP agent-token requests (about 30 calls per minute per IP).These two tools report activity for the server's wallets (
NONAGON_PRIVATE_KEY, andNONAGON_EVM_PRIVATE_KEYwhen set), which are process-wide. In HTTP mode (--transport http), every client connected to the same server shares those wallets, so they all see the same payment history and spending. This matches the one-wallet-per-server model — run a separate server per wallet if you need isolation. The EVM wallet's history includes every payment made with that key, also outside this server.
search_listings inputs
| Input | Values / default | Purpose |
|---|---|---|
| q | string, up to 200 characters | 2–5 short words for the kind of data, its subject area, or its source, separated by spaces (Japanese and English both work). Listings whose name, description, or category contains any word are returned, those matching more words first. Leave out dates, numbers, and the values to send to the API |
| category | string, up to 40 characters | Filter by category |
| chain | solana or ethereum | Filter by payment chain |
| networkId | CAIP-2 solana:<genesis> or eip155:<chainId> | Filter by an exact payment network |
| currency | USDC, JPYC, or TEST_JPYSC | Filter by payment asset; required with maxPrice. SBI JPYSC is a separate, unsupported asset. |
| maxPrice | greater than 0 and at most 1000 | Maximum price per call, denominated in currency |
| health | healthy, unhealthy, or unknown | Filter by the most recent bounded upstream probe; results become unknown after 45 minutes |
| minRatingCount | integer from 1 to 1,000,000 | Require at least this many settled-payment ratings |
| payableViaMcpOnly | boolean; default false | Keep only listings this server is expected to pay and call (the call target is confirmed by get_listing): USDC on its Solana NONAGON_NETWORK and, with an EVM wallet configured, JPYC / TEST_JPYSC priced at or below the yen cap, plus EVM USDC priced at or below MCP_MAX_PAYMENT_EVM_USDC_CAP when that cap is set |
| sort | updated_at, price_usdc, name, rating_score, rating_count, uptime_percent, or decision_readiness; default decision_readiness | Choose the catalog ordering |
| order | asc or desc; default desc | Choose the direction; decision_readiness always remains highest first |
| limit | integer from 1 to 10; default 5 | Limit the number of returned listings |
Split the request into words that find the API and values that the API receives. For "tomorrow's weather in Tokyo", search with q: "天気 weather forecast" and pass the date and place to pay_and_call as query. For "Reddit posts about pasta", search with q: "Reddit search" and pass {"query": "pasta"}. Values go to query for a GET listing and to body for a POST listing. Words that are only dates or numbers, single-character letters or digits, and words made only of symbols are not used for matching; the result lists them in ignoredSearchTerms (if every word is dropped, the search is not narrowed). If no listing matches a q, the result carries searchHint explaining how to search again. A q over 200 characters is rejected with the same guidance.
search_listings returns summaries only (from 0.3.7). Pass the chosen listing's providerId and listingId to get_listing for the call target and call guide. If get_listing fails, remember that listingId, pick another summary, or search again with the same filters and a larger limit; stop and report if limit 10 gives no untried listing.
For GET listings, get_listing returns both parameters and querySchema. Validate the complete query object against querySchema before paying: individual parameters cannot express rules such as exactly one of tweet_id or url. The schema is supplied by the provider and is returned only if it fits the MCP safety limits. If a saved schema cannot be exposed, querySchema is null and decisionGaps includes query_schema_unavailable. If the OpenAPI cannot be fetched, get_listing returns an error instead; the tool does not infer missing constraints from a description.
For proxy listings, get_listing also returns an opaque signed funnelAttribution value. Pass it unchanged to the optional funnelAttribution input of pay_and_call; the tool forwards it as X-Nonagon-Funnel-Attribution so discovery, payment, and upstream outcome remain one privacy-safe server-side flow. It contains no wallet, IP, request payload, query value, or API key.
ratingScore (1–5 or null) and ratingCount (0 for unrated) summarize ratings tied to settled payments; ratingBasis is settled_payment. A provider can still buy through a separate wallet, so these ratings are one signal for purchase decisions, not a guarantee of data quality. The score and count are part of the summary, so they do not depend on the listing's OpenAPI.
Use currency together with maxPrice to set a budget; the tool rejects an unqualified price because USDC, JPYC, and the Sepolia test token are different units. payableViaMcpOnly: true returns only listings pay_and_call is expected to pay and call on this server (it skips listings whose public call target or method cannot be called; it does not fetch each listing's OpenAPI, so get_listing confirms the call target and can still fail). It keeps your chain / networkId / currency / maxPrice. Within one currency and network the catalog order is kept as-is; when several currencies or networks are payable, results interleave them one listing at a time (not a single overall ranking — ranking says so). total counts matching listings before unpayable ones are removed. A yen listing priced above the cap reports payableViaMcp: false with the decision gap mcp_payment_limit_too_low. health: "healthy" requires a successful upstream probe within 45 minutes, and minRatingCount requires settled-payment rating evidence. When q has words, listings matching more of them come first and the chosen sort orders listings with the same number of matches (with several currencies or networks, that holds within each one). The default decision_readiness order prioritizes current health, provider-supplied metadata completeness, rating evidence, and recency. This order measures how much can be inspected before purchase. It does not establish response correctness, data freshness, or provider trustworthiness; check each result's decisionGaps, upstreamHealth, ratingCount, response schema/sample, and coverage before paying.
Paying in JPYC (EVM)
pay_and_call pays yen-denominated listings with the official JPYC via EIP-3009 transferWithAuthorization (gas is paid by NONAGON LINK; your wallet only needs the token balance — no approve, no ETH/POL).
| This server's NONAGON_NETWORK | EVM networks paid | Asset |
|---|---|---|
| Solana mainnet | Polygon (eip155:137), Ethereum (eip155:1) | JPYC |
| Solana devnet | Sepolia (eip155:11155111) | TEST_JPYSC (test token) |
- Set
NONAGON_EVM_PRIVATE_KEYto a dedicated EVM wallet with a small balance (0x+ 64 hex). It is only used to sign typed data (the signer cannot sign transactions). It works only whenNONAGON_NETWORKis Solana mainnet or devnet, which selects the EVM networks in the table above; with any other network the server refuses to start. - Set
NONAGON_EVM_PAY_TOto the NONAGON LINK EVM treasury (see NONAGON LINK payees — never copy it from an untrusted 402). Unset = every EVM payment is refused. - Pass
maxPaymentJpytopay_and_call(at most 4 decimals). Without it a yen 402 is not signed: the tool returnsPAYMENT_EXCEEDS_LIMITwithmax: nulland the required amount. The ceiling is 100 by default; raise it withMCP_MAX_PAYMENT_JPY_CAP(100–1000; below 100 the server does not start). Polygon JPYC listings start at 1 and Ethereum JPYC listings start at 300, so Ethereum ones need a cap of 300 or more. Payments from 1 Polygon JPYC are supported from 0.3.2; 0.3.1 and earlier require at least 10.
Before signing, the server checks that the 402's network, asset (the pinned JPYC contract), EIP-712 domain, amount range, exact + eip3009 method, maxTimeoutSeconds (≤ 300) and payTo all match; otherwise it returns PAYMENT_REQUIREMENT_REJECTED without signing. Without an EVM wallet a JPYC listing returns EVM_WALLET_NOT_CONFIGURED. EVM USDC is covered in Paying in EVM USDC.
Every option a 402 offers is checked, not just the one that would be paid. If a 402 also offers an option this server does not handle (another network or scheme), pay_and_call refuses the whole 402 with PAYMENT_REQUIREMENT_REJECTED and reason: "candidate" (paymentStatus: "not_paid") instead of silently paying one of the other options. This applies to every configuration, including Solana-only servers: a 402 offering Solana USDC together with an unhandled option is refused too. NONAGON LINK listings offer exactly one option, so they are not affected.
search_listings reports a JPYC / TEST_JPYSC listing as payableViaMcp: true only when its price is inside the asset's allowed range and at or below your yen cap. A price outside the asset's range reports mcp_payment_unsupported (pay_and_call would refuse it); a price inside the range but above the cap reports mcp_payment_limit_too_low.
Paying in EVM USDC
EVM USDC listings are priced 2–10 USDC, about 100 times the Solana USDC listings (0.001–0.1 USDC), so EVM USDC is off by default and has its own limits. Nothing changes for an existing configuration: without the new cap, an EVM USDC 402 is never signed, even with MCP_MAX_PAYMENT_USDC_CAP=10 and an EVM wallet. It is paid the same way as JPYC (EIP-3009 transferWithAuthorization; gas is paid by NONAGON LINK, your wallet only needs USDC — no approve, no ETH/POL).
| This server's NONAGON_NETWORK | EVM USDC networks paid |
|---|---|
| Solana mainnet | Ethereum (eip155:1), Polygon (eip155:137), Base (eip155:8453) |
| Solana devnet | Sepolia (eip155:11155111), Polygon Amoy (eip155:80002), Base Sepolia (eip155:84532) |
This MCP server does not know which of these networks NONAGON LINK has enabled and does not check: once EVM USDC is set up, it signs any host's EVM USDC 402 on a network listed here, as long as the 402 matches the pinned USDC asset, your NONAGON_EVM_PAY_TO allowlist and your caps. NONAGON LINK's own listings only use the networks NONAGON LINK has enabled, so a 402 on another listed network can only come from a different host (see the known limitation below).
Three settings are needed, plus one argument per call:
NONAGON_EVM_PRIVATE_KEY— the dedicated EVM wallet (same as for JPYC).NONAGON_EVM_PAY_TO— the NONAGON LINK EVM treasury (same as for JPYC).MCP_MAX_PAYMENT_EVM_USDC_CAP— the most this server may pay per EVM USDC call, written in decimal notation with at most 6 fractional digits. The allowed range comes from the pinned USDC price range of this server's network family (2–10 USDC today). Unset or empty = EVM USDC is never paid. In the.mcpbsettings this is "EVM USDC payment cap".- Pass
maxPaymentEvmUsdc(USDC, at most 6 decimals, at most the cap) topay_and_call.maxPaymentUsdcapplies to Solana USDC only and is never used for EVM USDC.
| Situation | Response (paymentStatus: "not_paid", paymentSignatureSent:false for these pre-signing errors) |
|---|---|
| Cap not set | EVM_NOT_SUPPORTED with reason: "evm_usdc_not_enabled" and a hint naming the settings (only when setting them would make the 402 payable) |
| Cap set, no EVM wallet | EVM_WALLET_NOT_CONFIGURED with currency: "USDC" |
| maxPaymentEvmUsdc missing or too low | PAYMENT_EXCEEDS_LIMIT with currency: "USDC", network, required, max (null when missing). It has no requiredUsdc / maxPaymentUsdc — raising maxPaymentUsdc does not help. When the price is above MCP_MAX_PAYMENT_EVM_USDC_CAP, the hint asks you to raise the cap (and restart the server) instead, because maxPaymentEvmUsdc cannot exceed it |
| Wrong network / asset / domain / amount / validity / payTo | PAYMENT_REQUIREMENT_REJECTED (same checks as JPYC) |
The cap is checked again right before signing, so a call that bypasses the tool's input validation still cannot sign above it. search_listings reports an EVM USDC listing as payableViaMcp: true only when the cap is set and its price is inside the pinned range and at or below the cap; above the cap it reports mcp_payment_limit_too_low (on a USDC row this gap always refers to the EVM USDC cap). When payableViaMcpOnly filters can only match EVM USDC and EVM USDC is not set up, the search returns an error naming the settings.
There is no session or daily total limit. Each call is limited separately, and only your wallet balance stops repeated calls. With every cap raised to its maximum, one call can pay up to 10 USDC (EVM USDC), 10 USDC (Solana USDC) or 1000 JPYC. Keep each cap as low as you need and the wallets small.
Known limitation: a signed authorization can be executed by a third party. If a prompt steers the agent to call an untrusted proxyUrl whose host returns a 402 with the NONAGON LINK treasury as payTo, that host can execute the signed EIP-3009 authorization itself. The money can only be sent to the treasury address set in NONAGON_EVM_PAY_TO, but you receive no service and no payment record is created; you can lose up to your EVM USDC cap per call. The same applies to a 402 on a listed network NONAGON LINK has not enabled. In both cases the USDC reaches the treasury address, whose key NONAGON LINK holds, so NONAGON LINK can recover it; but without a payment record it cannot be matched to your call automatically, and there is no documented procedure yet for matching such a deposit to you and refunding it. Do not pay_and_call URLs you do not trust, and keep MCP_MAX_PAYMENT_EVM_USDC_CAP as low as you need. A structural fix (switching to an authorization only the recipient can execute, or matching and refunding such deposits) is tracked separately.
MCP_MAX_PAYMENT_USDC_CAP and MCP_MAX_PAYMENT_JPY_CAP are now validated the same way as the EVM USDC cap: plain decimal notation only (0.5, 10, 300.5). Exponent (1e1), hex, sign, surrounding spaces, .5 / 5. and too many fractional digits stop the server at startup with a message saying how to write the value.
Payment status
GET listings take query (an object of strings, finite numbers or booleans); POST takes body (any JSON object / array / scalar / null). Map get_listing httpMethod to method. GET body, nonempty POST query, duplicate decoded keys and collisions with existing URL keys are rejected before any request; POST query:{} is treated as omitted. Existing URL encoding is preserved; query is limited to 64 parameters and 4096 serialized characters including existing values. Example: {"method":"GET","query":{"query":"日本語 & + %","page":0,"include":false}}. Only an unsigned GET402 whose final URL has zero query parameters is checked against an available queryParams schema before signing. If schema is absent, invalid, unsupported or over budget, validation is skipped and the existing payment policy still applies; payment proceeds as before. Nonempty queries use the gateway validation, including page-size clamping.
not_paid means the MCP can determine that payment was not executed. Every executed tool result includes boolean paymentSignatureSent; not_paid is not synonymous with unsigned. Classifying a signed GET422 as not_paid requires NONAGON_LINK_BASE_URL to be configured with an official (nnglink.ai / *.nnglink.ai) or local (localhost / 127.0.0.1) host, the same origin, the exact /api/proxy/{providerSlug}/{listingSlug} route, a complete JSON body within 8 KiB with code SCHEMA_VALIDATION_FAILED / QUERY_TOO_LARGE / SCHEMA_UNSUPPORTED, and no PAYMENT-RESPONSE, X-PAYMENT-RESPONSE (including the saved receipt) or X-Proxy-Payment-Id. This is the configured gateway's rejection before payment execution; correct query and retry. Any other signed failure is also not_paid when the configured gateway (same host, origin and exact proxy route conditions as above) returns X-Nonagon-Payment-Status: not_paid and X-Nonagon-Do-Not-Pay-Again: false with none of the three receipts above (@nonagon-link/mcp 0.3.5 or later; older versions keep showing unknown). The body paymentStatus is never used. Retry with a new signature at most once and stop if it fails again; do not execute the old authorization yourself. For EVM retain authorization (network / asset / from / nonce / validBefore): it remains valid until validBefore. A signed not_paid result does not independently prove on-chain non-execution. Other signed failures and communication failures retain paid / unknown according to the receipt; on unknown do not retry automatically and check authorizationState(from, nonce).
NONAGON LINK can reject an unsigned request before issuing a nonce: payment-option policy is checked first (409 PAYMENT_OPTION_DISABLED / 503 PAYMENT_OPTIONS_UNAVAILABLE), then EVM native readiness. Gas uses POL on Polygon or ETH on Ethereum / Base, separately from USDC / JPYC. A readiness snapshot does not reserve a USD budget or guarantee a later settlement.
| HTTP | Code | Fixed message |
|---|---|---|
| 503 | EVM_NATIVE_BALANCE_INSUFFICIENT | Native gas balance is insufficient |
| 503 | EVM_NATIVE_READINESS_UNAVAILABLE | Native gas readiness is unavailable |
| 503 | EVM_GAS_LIMIT_EXCEEDED | Estimated gas exceeds the supported limit |
| 503 | EVM_TRANSACTION_ESTIMATE_UNAVAILABLE | Gas estimation is unavailable |
Existing GAS_LIMIT_EXCEEDED is the USD per-transaction cap, distinct from the EVM gas quantity limit. GAS_ESTIMATE_UNAVAILABLE, DAILY_GAS_CAP, GAS_BUDGET_UNAVAILABLE, TX_TIMEOUT, TX_FAILED and EVM_SETTLE_FAILED remain. The MCP classifies a request that sent no signed payment as not_paid; after submission only the configured gateway pre-payment GET422 contract or the gateway's not_paid outcome headers described below can be classified as not_paid. These 503 errors retain the existing receipt-based classification.
| paymentStatus | Meaning | What to do |
|---|---|---|
| not_paid | MCP can determine payment was not executed (including a configured gateway pre-payment query rejection after signing) | Fix the cause and retry |
| paid | The paid request's response carried a successful receipt (even if the API itself then returned an error) | Retrying is a new payment |
| unknown | A signed payment was sent but the result is not confirmed (timeout, connection loss, error response, missing receipt). The response body is not trusted — the host could claim anything | Do not retry automatically (a retry signs a new authorization and can pay twice). For EVM payments (JPYC and EVM USDC) the response includes authorization (network, asset, from, nonce, validBefore): call authorizationState(from, nonce) on the token contract. It can never execute only after validBefore has passed and authorizationState is false. reportedTransaction, if any, is the host's unverified claim: independently check its receipt on the saved network and require transactionHash to equal the requested hash before reading status. A missing / different-hash receipt does not prove non-payment. Keep the original authorization lookup fields and check again after validBefore; a false state before expiry is insufficient. Do not reuse the authorization or automatically create another payment |
Payments made with the EVM wallet appear in get_payment_history / get_spending as the ethereum wallet. For an EVM payment, a missing history row does not prove the authorization was not executed (the server may not have recorded a failed payment, and anyone holding the authorization can execute it): when paymentStatus is unknown, check authorizationState as described above instead of retrying after looking at the history.
Quick start (Claude Code / Claude Desktop)
Add to your MCP client config (e.g. .claude/settings.json or claude_desktop_config.json):
{
"mcpServers": {
"nonagon-link": {
"command": "npx",
"args": ["-y", "--ignore-scripts", "@nonagon-link/[email protected]"],
"env": {
"NONAGON_PRIVATE_KEY": "<Base58 Solana secret key>",
"NONAGON_LINK_BASE_URL": "https://api.nnglink.ai",
"NONAGON_PAY_TO": "8yXpNyyPg9iGdMST8BRyz7HEJVbQG81VP6kHBCKXrdH8"
}
}
}
}Always pin an exact version (
@nonagon-link/[email protected]). Never use an unversioned@nonagon-link/mcp— your private key is passed to the process environment, so an unpinned install would expose it to whatever the latest published version is.--ignore-scriptsadditionally prevents dependency install scripts from running with your environment.Set
NONAGON_PAY_TOto the NONAGON LINK Solana platform wallet (see NONAGON LINK payees) — do not copypayTofrom an untrusted 402. Unset = every Solana USDC payment is refused. EVM payments (JPYC, EVM USDC) are allowed separately byNONAGON_EVM_PAY_TO; unset, every EVM payment is refused.
NONAGON LINK payees
The payTo values NONAGON LINK uses (public: they appear in every 402). Put them in the allow-lists:
| Environment | NONAGON_PAY_TO (Solana USDC) | NONAGON_EVM_PAY_TO (JPYC / EVM USDC) |
|---|---|---|
| Production (Solana mainnet; Ethereum / Polygon / Base) | 8yXpNyyPg9iGdMST8BRyz7HEJVbQG81VP6kHBCKXrdH8 | 0x7b689c9b29e5e51700f19d4bb02b382fb418f34d |
| Testing (Solana devnet; Sepolia / Amoy / Base Sepolia) | 6JdW8xNvXrghY7acKXzMn2pJoK88g6nnAVU3YNo1YiF8 | 0xcaeb3ef5dcea1557765323379a292fc6b4011831 |
The current values are also listed at https://nnglink.ai/docs/mcp.
For stricter isolation, install once and reference the binary directly:
npm install -g @nonagon-link/[email protected]{
"mcpServers": {
"nonagon-link": { "command": "nonagon-mcp", "env": { "NONAGON_PRIVATE_KEY": "...", "NONAGON_PAY_TO": "8yXpNyyPg9iGdMST8BRyz7HEJVbQG81VP6kHBCKXrdH8" } }
}
}Environment variables
| Variable | Required | Description |
|---|---|---|
| NONAGON_PRIVATE_KEY | ✅ | Agent's Solana secret key (Base58). Used to sign USDC payments |
| NONAGON_NETWORK | — | CAIP-2 network id. Defaults to Solana mainnet. 402 network must match |
| NONAGON_PAY_TO | For Solana pay_and_call | Comma-separated Solana addresses allowed as 402 payTo (platform wallet). Unset = every Solana USDC payment is refused (EVM payments are governed by NONAGON_EVM_PAY_TO) |
| NONAGON_USDC_MINT | — | Override USDC mint only for unknown NONAGON_NETWORK. Known mainnet/devnet always use the built-in USDC mint |
| MCP_MAX_PAYMENT_USDC_CAP | — | Raise the maxPaymentUsdc (Solana USDC) ceiling (0.1–10, decimal notation, at most 6 decimals). Default 0.100. Does not affect EVM USDC |
| NONAGON_EVM_PRIVATE_KEY | For JPYC / EVM USDC / EVM history | EVM wallet key (0x + 64 hex) used to sign EVM payments (JPYC; EVM USDC when MCP_MAX_PAYMENT_EVM_USDC_CAP is set) and the EIP-712 AgentChallenge that reads the EVM wallet's payment history and spending. Unset = Solana USDC only. Requires NONAGON_NETWORK to be Solana mainnet or devnet (otherwise the server refuses to start). Validated at startup; the value is never logged or returned |
| NONAGON_EVM_PAY_TO | For JPYC / EVM USDC | Comma-separated EVM addresses allowed as the EVM 402 payTo (NONAGON LINK EVM treasury). Unset = every EVM payment is refused (Solana USDC payments are governed by NONAGON_PAY_TO) |
| MCP_MAX_PAYMENT_JPY_CAP | — | Raise the maxPaymentJpy ceiling (100–1000, decimal notation, at most 4 decimals; below 100 the server does not start). Default 100. Ethereum JPYC listings need 300 or more |
| MCP_MAX_PAYMENT_EVM_USDC_CAP | For EVM USDC | The maxPaymentEvmUsdc ceiling and the switch for EVM USDC (range from the pinned USDC prices of the network family — 2–10 today; decimal notation, at most 6 decimals). Unset = EVM USDC is never paid. Requires NONAGON_NETWORK to be Solana mainnet or devnet |
| NONAGON_LINK_BASE_URL | For search_listings / get_listing / get_payment_history / get_spending | NONAGON LINK API base URL (e.g. https://api.nnglink.ai). https only; http allowed for localhost in local development. pay_and_call does not require it |
| MCP_AUTH_TOKEN | HTTP mode only | Bearer token for Streamable HTTP transport (32-byte random, base64url or hex) |
| LOG_LEVEL | — | pino log level. Defaults to info |
Security notes
- Payments are USDC on the configured Solana network, plus the official JPYC (TEST_JPYSC on Sepolia) when an EVM wallet is configured, plus EVM USDC only when
MCP_MAX_PAYMENT_EVM_USDC_CAPis also set. SetNONAGON_PAY_TO(andNONAGON_EVM_PAY_TOfor EVM payments) to the NONAGON LINK wallets orpay_and_callwill refuse the 402. - Use dedicated wallets with small balances. The private keys in
envauthorize real payments. Do not reuse your main wallets. In HTTP mode every client shares the server's wallets. - A signed EVM authorization (JPYC or EVM USDC) can be executed by whoever receives it. EIP-3009
transferWithAuthorizationdoes not restrict who submits it, so the host you call (any HTTPS host) or anyone who sees the authorization can execute it on-chain without NONAGON LINK. The recipient is fixed to yourNONAGON_EVM_PAY_TOallow-list (the NONAGON LINK treasury), so funds can only move there — but in that case no service is delivered and no payment record is created. This is a known limitation; keep the EVM wallet balance small, and whenpaymentStatusisunknownuseauthorizationto check on-chain whether it was executed. - Values made by the host you call (rejection reasons, error messages, receipt claims, response headers) and by providers (listing and OpenAPI text) are returned with control characters and invisible characters removed (bidi controls, zero-width characters, Unicode tag characters, variation selectors and other default-ignorable characters, line/paragraph separators) and cut to a length limit. The API response body itself (
data/details) is returned unchanged. - The signing libraries (
viem,@x402/*including@x402/core,@solana/kit, and the@solana-program/*packages that@x402/svmuses) are declared as exact versions, the same versions the.mcpbbundle ships. This holds for a standalone install (npx/-g). - The private key is never written to logs; log output is redacted and URLs are masked. Access tokens are only ever shown masked.
- Set
NONAGON_LINK_BASE_URLonly to the official NONAGON LINK URL. The agent challenge is unauthenticated, so a malicious base URL could have this server sign a nonce it obtained from the real server and get an agent token for your wallet (read your payment history, post ratings — not pay). This applies to the Solana and the EVM wallet alike. When an EVM key is set and the base URL host is neithernnglink.ai(or a subdomain) norlocalhost/127.0.0.1, the server logs a one-line warning at startup (host only; the key is never printed). - stdio transport is the default and recommended mode. HTTP mode (
--transport http) binds to127.0.0.1only and requiresMCP_AUTH_TOKEN. - The MCP
serverInfo.versionreported over the protocol is independent of this npm package's version.
Documentation
- Setup & verification guide: https://nnglink.ai/docs/mcp
- Agent developer guide: https://nnglink.ai/docs/agent
License
Apache-2.0
