Skip to main content
MCP (Model Context Protocol) is an open standard for connecting AI agents to external tools and services. Semantic supports MCP as a transport for x402, meaning AI agents can discover, call, and pay for tools through a standard MCP server.

How it works

A normal MCP flow: an agent connects to an MCP server, discovers available tools via listTools(), and calls them via callTool(). With x402, the server can require payment for specific tools. The @x402/mcp package handles the payment flow transparently:
  1. Agent calls a tool via MCP
  2. Server responds with a 402 Payment Required challenge (embedded in the MCP response)
  3. The x402 MCP client automatically signs a payment authorization
  4. Client retries the tool call with the payment header
  5. The facilitator settles on-chain, and the tool returns its result
From the agent’s perspective, it just calls a tool. Payment happens in the background.

Install

npm install @x402/mcp @x402/evm @modelcontextprotocol/sdk

Client setup

Use createx402MCPClient to create an MCP client with built-in x402 payment handling.
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { createx402MCPClient } from "@x402/mcp";
import { WalletAccountEvm } from "@tetherto/wdk-wallet-evm";

// WDK wallet as the payment signer
const account = new WalletAccountEvm(process.env.SEED_PHRASE, {
  provider: "https://rpc.plasma.to",
});

// Create x402-enabled MCP client
const mcpClient = createx402MCPClient({
  name: "my-agent",
  version: "1.0.0",
  schemes: [
    { network: "eip155:9745", client: new ExactEvmScheme(account) },
  ],
  autoPayment: true,
  onPaymentRequested: async (context) => {
    const price = context.paymentRequired.accepts[0];
    console.log(`Payment: ${price.amount} on ${price.network} for ${context.toolName}`);
    return true; // approve
  },
});

// Connect to MCP server
const transport = new SSEClientTransport(new URL("http://localhost:4022/sse"));
await mcpClient.connect(transport);

Discovering and calling tools

Once connected, use standard MCP methods. Payment is handled automatically when a tool requires it.
// Discover available tools
const { tools } = await mcpClient.listTools();

for (const tool of tools) {
  console.log(`${tool.name}: ${tool.description}`);
}

// Call a tool — payment happens automatically if required
const result = await mcpClient.callTool("get-weather", { city: "Dubai" });

console.log(result.content[0]?.text);

// Check if payment was made
if (result.paymentMade) {
  console.log("Settled:", result.paymentResponse.transaction);
}

Payment control

The onPaymentRequested callback gives you control over which payments to approve. Return true to pay, false to reject.
const mcpClient = createx402MCPClient({
  // ...
  autoPayment: false, // require explicit approval
  onPaymentRequested: async (context) => {
    const price = context.paymentRequired.accepts[0];
    const amount = Number(price.amount) / 1e6; // USDT0 has 6 decimals

    // Reject anything over $1
    if (amount > 1.0) {
      console.log(`Rejected: $${amount} is too expensive`);
      return false;
    }

    return true;
  },
});

Using with LLMs

The standard pattern is: connect to MCP, convert tools to your LLM’s format, let the LLM decide when to call tools, execute via MCP.

OpenAI

import OpenAI from "openai";

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

// Convert MCP tools to OpenAI function calling format
const { tools } = await mcpClient.listTools();

const openaiTools: OpenAI.ChatCompletionTool[] = tools.map((tool) => ({
  type: "function",
  function: {
    name: tool.name,
    description: tool.description || "",
    parameters: tool.inputSchema as Record<string, unknown>,
  },
}));

// Let the LLM decide which tools to call
const response = await openai.chat.completions.create({
  model: "gpt-4o",
  messages: [{ role: "user", content: "What's the weather in Dubai?" }],
  tools: openaiTools,
  tool_choice: "auto",
});

// Execute tool calls via MCP (payment handled automatically)
for (const toolCall of response.choices[0].message.tool_calls || []) {
  const args = JSON.parse(toolCall.function.arguments);
  const result = await mcpClient.callTool(toolCall.function.name, args);
  console.log(result.content[0]?.text);
}

Anthropic

import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic();

// Convert MCP tools to Anthropic format
const { tools } = await mcpClient.listTools();

const anthropicTools = tools.map((tool) => ({
  name: tool.name,
  description: tool.description || "",
  input_schema: tool.inputSchema,
}));

const response = await anthropic.messages.create({
  model: "claude-sonnet-4-20250514",
  max_tokens: 1024,
  messages: [{ role: "user", content: "What's the weather in Dubai?" }],
  tools: anthropicTools,
});

// Execute tool calls via MCP
for (const block of response.content) {
  if (block.type === "tool_use") {
    const result = await mcpClient.callTool(block.name, block.input);
    console.log(result.content[0]?.text);
  }
}

Multi-network support

Register multiple chains so the client can pay on whichever network the server requires:
const mcpClient = createx402MCPClient({
  name: "my-agent",
  version: "1.0.0",
  schemes: [
    { network: "eip155:9745", client: new ExactEvmScheme(plasmaAccount) },
    { network: "eip155:988", client: new ExactEvmScheme(stableAccount) },
  ],
  autoPayment: true,
});

Cleanup

Always close the client when done:
await mcpClient.close();

Next steps

Last modified on February 13, 2026