Nonagon Link MCP Server — Setup and Verification Guide

Setup and verification guide for the Nonagon Link MCP server


Quick start — connect by copy & paste (recommended)

With the npm package @nonagon-link/mcp you can connect without cloning the repository. Just add the following to your project's .claude/settings.json (or claude_desktop_config.json for Claude Desktop):

{
  "mcpServers": {
    "nonagon-link": {
      "command": "npx",
      "args": ["-y", "--ignore-scripts", "@nonagon-link/mcp@0.2.1"],
      "env": {
        "NONAGON_PRIVATE_KEY": "<Base58 secret key of your payment wallet>",
        "NONAGON_LINK_BASE_URL": "https://api.nnglink.ai"
      }
    }
  }
}

In Claude Code you can also add it with a single command:

claude mcp add nonagon-link -e NONAGON_PRIVATE_KEY=<Base58 secret key> -e NONAGON_LINK_BASE_URL=https://api.nnglink.ai -- npx -y --ignore-scripts @nonagon-link/mcp@0.2.1

⚠️ Security note: always pin an exact version (e.g. @nonagon-link/mcp@0.2.1). Because your private key is passed via env, running an unpinned latest version amplifies supply-chain risk. --ignore-scripts prevents dependency install scripts from running. Use a dedicated wallet with a small balance for payments.

1. Overview

Nonagon Link MCP is a Model Context Protocol (MCP) server that lets AI agents such as Claude / GPT-4 call paid APIs with USDC via Nonagon Link's x402 payment infrastructure. Search (search_listings) → capped purchase (pay_and_call) → token management (get_active_tokens) → payment history and spending (get_payment_history / get_spending) can all be completed through MCP alone.

Available Tools

Tool nameFunction
pay_and_callPay the specified paid API and fetch data (maxPaymentUsdc cap required). Returns paymentInfo with amount, tx signature and timestamp
search_listingsKeyword search over public listings, returning what you need to buy (proxyUrl, price, parameter schema)
get_active_tokensSummary of currently valid masked tokens and remaining validity. May be empty because inline payments issue no access token
get_payment_historyPayment history for this server's wallet (latest N, filterable by status). Includes inline payments
get_spendingCumulative spending for this server's wallet by period (day / week / month / all), with a per-currency breakdown

Transport Modes

ModeUse caseAuthentication
stdioDirect connection from Claude Code / Claude DesktopNone (local process)
HTTP streamConnection from a local HTTP client on the same machineMCP_AUTH_TOKEN (Bearer)

2. Prerequisites

  • Node.js >= 20.0.0
  • npm (monorepo dependencies installed)
  • A Solana wallet (private key) for payments — this wallet's USDC is used to pay API usage fees, and its SOL is used for transaction fees. The agent (MCP server) signs payments with this wallet's private key.

Creating a Solana Wallet for Payments

In production, use a wallet holding real USDC on mainnet. If you do not have a payment wallet yet, follow these steps (the example below is for devnet testing; for production, prepare mainnet USDC and keep NONAGON_NETWORK at its mainnet value):

# Generate a keypair with the Solana CLI
solana-keygen new --outfile ~/.config/solana/devnet.json --no-bip39-passphrase

# Check the public key
solana-keygen pubkey ~/.config/solana/devnet.json

# Get the private key in Base58 (used in the MCP configuration)
node -e "
const fs = require('fs');
const bs58 = require('bs58');
const keyData = JSON.parse(fs.readFileSync(process.env.HOME + '/.config/solana/devnet.json'));
console.log('Public key:', require('@solana/web3.js').Keypair.fromSecretKey(Uint8Array.from(keyData)).publicKey.toBase58());
console.log('Private key (Base58):', bs58.default.encode(Uint8Array.from(keyData)));
"

# Airdrop devnet SOL (for tx fees)
solana airdrop 2 --url devnet

If the Solana CLI is not installed, use brew install solana or see https://docs.solana.com/cli/install-solana-cli-tools.


3. Environment Variables

Required

Variable nameDescriptionExample
NONAGON_PRIVATE_KEYPrivate key (Base58) of the Solana wallet used for payments. USDC / SOL are paid from this wallet5Jh... (64-88 characters)

Optional

Variable nameDefaultDescription
NONAGON_NETWORKsolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpSolana network (CAIP-2). Defaults to mainnet (production, real USDC). For devnet testing, specify solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
NONAGON_LINK_BASE_URL(unset)Required when using the search_listings tool. Base URL of the Nonagon Link API (e.g. https://api.nnglink.ai). If unset, the search tool returns an error
MCP_AUTH_TOKEN(unset)Required only in HTTP stream mode (not needed in stdio mode, the default for Claude Desktop/Code). A Bearer authentication token generated by the operator to protect the local HTTP endpoint. Generate a random secret of at least 32 bytes with openssl rand -base64 32 or similar (at least 43 base64url characters or 64 hex characters)
LOG_LEVELinfoLog level

4. How to Verify Operation

Method A: Run from source (for contributors)

Use this only when you have cloned the repository and want to run the development source directly. For normal usage, follow the "Quick start" section at the top of this page (npm package @nonagon-link/mcp).

1. Create the MCP configuration file

Add to your project's .claude/settings.json:

{
  "mcpServers": {
    "nonagon-link": {
      "command": "npx",
      "args": ["tsx", "apps/nonagon_link/src/mcp/server.ts"],
      "cwd": "/path/to/nonagon_link",
      "env": {
        "NONAGON_PRIVATE_KEY": "<private key (Base58) of the Solana wallet used for payments>",
        "NONAGON_NETWORK": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
        "NONAGON_LINK_BASE_URL": "https://api.nnglink.ai",
        "LOG_LEVEL": "debug"
      }
    }
  }
}

2. Check in Claude Code

> /mcp

If the server with the configuration key name (nonagon-link) is shown as connected, it worked.

3. Test a tool call

Ask Claude something like:

Use the get_active_tokens tool to fetch a summary of the currently valid masked tokens

get_active_tokens returns maskedToken, proxyUrl, expiresAt, and remainingMinutes; it never returns raw token values.

Example of a successful response:

{
  "tokens": [
    {
      "maskedToken": "agt_abcd...mnop",
      "proxyUrl": "https://api.nnglink.ai/api/proxy/weather-api/current",
      "expiresAt": "2026-05-11T12:00:00Z",
      "remainingMinutes": 45
    }
  ]
}

Method B: MCP Inspector (GUI)

Use the official MCP GUI debugging tool.

# Run from the project root
NONAGON_PRIVATE_KEY=<private-key> \
npx @modelcontextprotocol/inspector npx tsx apps/nonagon_link/src/mcp/server.ts

A browser window opens, where you can check the following:

  • Tools tab: pay_and_call / search_listings / get_active_tokens / get_payment_history / get_spending are displayed
  • Tool execution: you can enter arguments and invoke tools directly
  • Schema check: verify that each tool's input schema is correct

Method C: HTTP stream mode

HTTP stream binds only to 127.0.0.1, so it is for local clients on the same machine. It cannot be exposed as a public endpoint over the network.

In HTTP stream mode, setting MCP_AUTH_TOKEN is required. Send Authorization: Bearer <MCP_AUTH_TOKEN> with every request.

Use a CSPRNG-generated secret of at least 32 bytes for MCP_AUTH_TOKEN. The configured value is expected to be at least 43 base64url characters or 64 hex characters.

# Terminal 1: start the server
NONAGON_PRIVATE_KEY=<private-key> \
NONAGON_NETWORK=solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp \
MCP_AUTH_TOKEN=<32-byte-random-base64url-token> \
npx tsx apps/nonagon_link/src/mcp/server.ts --transport http --port 3002
# Terminal 2: health check with curl (MCP initialize)
curl -X POST http://localhost:3002/ \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <32-byte-random-base64url-token>" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": { "name": "test", "version": "1.0" }
    }
  }'

Example of a successful response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-03-26",
    "capabilities": { "tools": {} },
    "serverInfo": { "name": "nonagon_link", "version": "1.0.0" }
  }
}

5. pay_and_call Example

Prerequisites

  • A Solana wallet holding USDC for payments (production = real USDC on mainnet / testing = fake USDC on devnet). You need USDC on the same network as your NONAGON_NETWORK setting
  • An API Provider registered on Nonagon Link must exist

Calling from Claude Code

Use the pay_and_call tool to call the following API:
- URL: https://api.nnglink.ai/api/proxy/weather-api/current
- Method: POST
- Body: { "city": "Tokyo" }
- Payment cap: 0.05 USDC   # maxPaymentUsdc (required, greater than 0 up to a maximum of 10)

Response Structure

{
  "success": true,
  "data": { ... },
  "paymentInfo": {
    "amountUsdc": "0.01",
    "txSignature": "5xKt..."
  }
}

If paymentInfo is null, the response was returned without an additional payment, either because the API is free or because a reusable token was used.

On Error

{
  "success": false,
  "error": "PAYMENT_REQUIRED",
  "details": "Insufficient USDC balance"
}

6. Security

SSRF Protection

The proxyUrl of pay_and_call is automatically validated as follows:

  • Private IPs rejected (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
  • Loopback rejected (127.0.0.0/8, ::1)
  • Link-local rejected (169.254.0.0/16)
  • DNS rebinding prevention (pinnedFetch couples DNS resolution and connection)
  • Only HTTPS URLs allowed
  • Exposing HTTP stream to anything other than 127.0.0.1 is prohibited

Log Redaction

  • URL query parameters/paths are masked (https://api.example.com/***)
  • Access tokens are masked (agt_abcd...mnop)
  • Private keys are never written to logs

HTTP Stream Mode Authentication

  • Bearer token authentication via MCP_AUTH_TOKEN
  • Binds only to 127.0.0.1 (local clients on the same machine only; remote exposure prohibited)
  • Per-session TokenStore isolates multiple clients

7. Troubleshooting

The MCP server does not start

MCP env validation failed:
  - NONAGON_PRIVATE_KEY: Base58 Solana private key format

→ Set the NONAGON_PRIVATE_KEY environment variable.

Unsupported MCP env keys: <legacy-key>. Use only live runtime env vars.

→ Legacy env vars are not supported. Use only NONAGON_PRIVATE_KEY, NONAGON_NETWORK, NONAGON_LINK_BASE_URL, MCP_AUTH_TOKEN, and LOG_LEVEL.

pay_and_call returns SSRF blocked

{ "success": false, "error": "URL_PRIVATE_IP" }

→ Private IPs / localhost cannot be called. Specify a public HTTPS URL.

get_active_tokens returns an empty array

→ There are no tokens yet because you have not called an API with pay_and_call. This is normal behavior.

The MCP server does not appear in Claude Code

  1. Check that the path in .claude/settings.json is correct
  2. Check that cwd points to the project root
  3. Run npx tsx apps/nonagon_link/src/mcp/server.ts directly and check for errors

HTTP stream mode returns 401

→ Check that the Authorization: Bearer <MCP_AUTH_TOKEN> header is correct.

当サイトでは、利用状況の把握と改善のためにアクセス解析 (Google アナリティクス) を使用します。「同意する」を選ぶと、閲覧ページ等の計測情報が Google LLC(米国)へ送信されます。詳細: プライバシーポリシー / 利用者情報の外部送信について