Skip to content

MCP Client SDK — @paygate/mcp-client

The @paygate/mcp-client package is a TypeScript client for the x402 RPC Gateway's /mcp endpoint. It speaks JSON-RPC 2.0, handles wallet-based authentication automatically, and routes paid tool calls through the x402 payment protocol — making it the ideal integration point for AI agents and autonomous programs.


Installation

bash
pnpm add @paygate/mcp-client

Quick Start

Ethereum (SIWE)

ts
import { MCPClient } from "@paygate/mcp-client";
import { EthereumX402Client, InjectedWalletConnector } from "@paygate/client-ethereum";

const wallet = new InjectedWalletConnector();

const paymentClient = new EthereumX402Client({
  walletConnector: wallet,
  chainId: 1,
});

const client = new MCPClient({
  endpoint: "https://gateway.example.com/mcp",
  evmWalletProvider: wallet,
  paymentClient,
  domain: "https://gateway.example.com",
  chainID: "1",
  authMethod: "siwe",
  x402ChainID: "84532",
  x402Ecosystem: "evm",
  pricingPlanID: 1,
});

// List available tools
const tools = await client.listTools();

// Execute a paid RPC call — auth and payment handled automatically
const result = await client.callTool("execute_rpc", {
  ecosystem: "evm",
  chain_id: "1",
  resource: "/",
  method: "POST",
  transport: "rpc",
  payload: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "eth_blockNumber",
    params: [],
  }),
});

Cosmos (SIWC)

ts
import { MCPClient, LocalCosmosWalletProvider } from "@paygate/mcp-client";
import { CosmosX402Client } from "@paygate/client-cosmos";

const wallet = await LocalCosmosWalletProvider.fromMnemonic(
  "your mnemonic here",
  "osmo"
);

const paymentClient = new CosmosX402Client({
  walletProvider: wallet,
  rpcEndpoint: "https://rpc.osmosis.zone",
  chainId: "osmosis-1",
});

const client = new MCPClient({
  endpoint: "https://gateway.example.com/mcp",
  cosmosWalletProvider: wallet,
  paymentClient,
  domain: "https://gateway.example.com",
  chainID: "osmosis-1",
  authMethod: "siwc",
  bech32Prefix: "osmo",
  x402ChainID: "osmosis-1",
  x402Ecosystem: "cosmos",
  pricingPlanID: 2,
});

const result = await client.callTool("execute_rpc", {
  ecosystem: "cosmos",
  chain_id: "osmosis-1",
  resource: "/cosmos/bank/v1beta1/balances/osmo1abc...",
  method: "GET",
  transport: "rest",
  payload: "",
});

MCPClient

Constructor

ts
new MCPClient(config: MCPClientConfig)

MCPClientConfig:

FieldTypeRequiredDescription
endpointstringYesFull URL of the gateway MCP endpoint (e.g. https://gateway.example.com/mcp)
cosmosWalletProviderCosmosWalletProviderNoCosmos wallet for SIWC authentication and signing
evmWalletProviderEVMWalletConnectorNoEVM wallet for SIWE authentication
paymentClientBaseX402ClientNox402 payment client for paid tools (execute_rpc)
domainstringYesApplication domain, included in the sign-in message
chainIDstringYesWallet chain ID used in the auth message
authMethod"siwc" | "siwe"YesWallet sign-in method
bech32Prefixstringsiwc onlyBech32 address prefix (e.g. "osmo", "cosmos")
x402ChainIDstringYesChain used for x402 payment settlement
x402EcosystemstringYesPayment ecosystem ("cosmos" or "evm")
pricingPlanIDnumberYesPricing plan ID the session is bound to

Wallet Provider Constraint

Exactly one of cosmosWalletProvider or evmWalletProvider must be provided — not both. Providing both will cause an error when calling authenticated or paid tools.


Methods

listTools(): Promise<JSONRPCResponse>

Sends a tools/list JSON-RPC request to the gateway and returns all available tools with their names, descriptions, and input schemas.

ts
const response = await client.listTools();
console.log(response.result.tools);

No authentication required.


callTool(name: string, args?: Record<string, any>): Promise<MCPToolResult>

Invokes a gateway tool by name with optional arguments. Handles the full tool invocation lifecycle automatically:

ScenarioBehavior
Public toolCalled directly, no auth needed
401 receivedAuto-login triggered (nonce → sign → auth_login), then retried
Paid tool (execute_rpc)Routed through paymentClient.fetchWithPayment() with x402 protocol
ts
// Public tool — no auth needed
const health = await client.callTool("health_check");

// Authenticated tool — auto-login if no token
const credits = await client.callTool("check_credit_balance", {
  wallet: "0xAbc...",
});

// Paid tool — x402 payment handled automatically
const rpcResult = await client.callTool("execute_rpc", {
  ecosystem: "evm",
  chain_id: "1",
  resource: "/",
  method: "POST",
  transport: "rpc",
  payload: '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}',
});

Paid Tool Note

execute_rpc is the only paid tool. paymentClient must be configured for it to work. If the gateway returns a 402, the payment is made on-chain automatically and the call is retried in the same invocation.


login(x402ChainID: string, x402Ecosystem: string, pricingPlanID: number): Promise<void>

Explicitly triggers the wallet authentication flow. Normally you do not need to call this — callTool handles 401 responses automatically. Use this to pre-authenticate before making calls.

Cosmos (SIWC) flow:

  1. Calls generate_auth_nonce tool
  2. Gets wallet address from cosmosWalletProvider
  3. Builds SIWC message (includes bech32 prefix, chain ID, nonce)
  4. Signs with cosmosWalletProvider.signArbitrary() (ADR-036)
  5. Calls auth_login tool with signature, pubkey, and x402 metadata
  6. Stores the returned JWT

EVM (SIWE) flow:

  1. Calls generate_auth_nonce tool
  2. Gets wallet address from evmWalletProvider
  3. Builds EIP-4361 SIWE message
  4. Signs with evmWalletProvider.signArbitrary()
  5. Calls auth_login tool with signature and x402 metadata
  6. Stores the returned JWT
ts
await client.login("84532", "evm", 1);

setToken(token: string): void

Injects a pre-existing JWT into the client. Use this to restore a session without re-authenticating.

ts
client.setToken("eyJhbGciOiJIUzI1NiJ9...");

getWalletAddress(): Promise<string>

Returns the wallet address from the configured provider. Throws if no wallet provider is configured.

ts
const address = await client.getWalletAddress();

LocalCosmosWalletProvider

A bundled Cosmos wallet implementation backed by a Secp256k1HdWallet (mnemonic-based). Suitable for server-side agents and scripts.

Static Factory

ts
const wallet = await LocalCosmosWalletProvider.fromMnemonic(mnemonic, prefix);
ParameterTypeDescription
mnemonicstringBIP-39 mnemonic phrase
prefixstringBech32 address prefix (e.g. "osmo", "cosmos")

Methods

MethodReturnsDescription
getAccounts()Promise<readonly { address: string; pubkey: Uint8Array }[]>Returns accounts with their public keys
signArbitrary(message)Promise<{ signature: string; pubkey: string }>Signs a message using ADR-036; returns base64-encoded signature and pubkey
getOfflineSigner()Secp256k1HdWalletReturns the underlying signer

ADR-036 Signing

signArbitrary uses the Cosmos ADR-036 spec (sign/MsgSignData with empty chain ID and zero account sequence). This is the signing format required by the gateway's SIWC authentication.


Internal Flow Diagram

callTool("execute_rpc", args)

  ├─ no token → login()
  │    ├─ callTool("generate_auth_nonce")
  │    ├─ wallet.signArbitrary(message)
  │    └─ callTool("auth_login", { ... })

  ├─ paid tool detected
  │    └─ paymentClient.fetchWithPayment(endpoint, request)
  │         ├─ POST /mcp  →  402 response
  │         ├─ on-chain transfer to payTo address
  │         └─ POST /mcp with X-PAYMENT header  →  200 response

  └─ result returned to caller

Types Reference

ts
interface MCPClientConfig {
  endpoint: string;
  cosmosWalletProvider?: CosmosWalletProvider;
  evmWalletProvider?: EVMWalletConnector;
  paymentClient?: BaseX402Client;
  domain: string;
  chainID: string;
  authMethod: "siwc" | "siwe";
  bech32Prefix?: string;
  x402ChainID: string;
  x402Ecosystem: string;
  pricingPlanID: number;
}

interface JSONRPCRequest {
  jsonrpc: "2.0";
  id: number;
  method: string;
  params?: any;
}

interface JSONRPCError {
  code: number;
  message: string;
}

interface JSONRPCResponse<T = any> {
  jsonrpc: "2.0";
  id: number;
  result?: T;
  error?: JSONRPCError;
}

interface MCPToolResult {
  [key: string]: any;
}

interface CosmosWalletProvider {
  getAccounts(): Promise<readonly { address: string; pubkey: Uint8Array }[]>;
  signArbitrary(message: string): Promise<{ signature: string; pubkey: Uint8Array }>;
}

Error Handling

callTool throws when:

  • The JSON-RPC response contains an error field (including 402 payment errors if no payment client is configured)
  • The HTTP request returns 401 and no wallet provider is configured for auto-login
  • Both or neither wallet providers are configured
ts
try {
  await client.callTool("execute_rpc", args);
} catch (err: any) {
  // err.message contains the JSON-RPC error message
  // For 402: includes payment requirements in error.data
  console.error(err.message);
}

vs. REST Client SDK

@paygate/mcp-client@paygate/client-x402-rpc
ProtocolJSON-RPC 2.0 over HTTPREST HTTP
Auth flowVia gateway tools (generate_auth_nonce, auth_login)Via REST endpoints (/auth/nonce, /auth/login)
Payment handlingAutomatic via paymentClient for execute_rpcAutomatic via registered x402 client on /rpc
Tool discoverylistTools() returns all capabilitiesFixed REST endpoints
Best forAI agents, MCP-compatible clientsCustom integrations, web apps
Local signingLocalCosmosWalletProvider includedNo bundled providers

Built on open standards — JSON-RPC 2.0, HTTP 402, SIWx.