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
pnpm add @paygate/mcp-clientQuick Start
Ethereum (SIWE)
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)
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
new MCPClient(config: MCPClientConfig)MCPClientConfig:
| Field | Type | Required | Description |
|---|---|---|---|
endpoint | string | Yes | Full URL of the gateway MCP endpoint (e.g. https://gateway.example.com/mcp) |
cosmosWalletProvider | CosmosWalletProvider | No | Cosmos wallet for SIWC authentication and signing |
evmWalletProvider | EVMWalletConnector | No | EVM wallet for SIWE authentication |
paymentClient | BaseX402Client | No | x402 payment client for paid tools (execute_rpc) |
domain | string | Yes | Application domain, included in the sign-in message |
chainID | string | Yes | Wallet chain ID used in the auth message |
authMethod | "siwc" | "siwe" | Yes | Wallet sign-in method |
bech32Prefix | string | siwc only | Bech32 address prefix (e.g. "osmo", "cosmos") |
x402ChainID | string | Yes | Chain used for x402 payment settlement |
x402Ecosystem | string | Yes | Payment ecosystem ("cosmos" or "evm") |
pricingPlanID | number | Yes | Pricing 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.
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:
| Scenario | Behavior |
|---|---|
| Public tool | Called directly, no auth needed |
| 401 received | Auto-login triggered (nonce → sign → auth_login), then retried |
Paid tool (execute_rpc) | Routed through paymentClient.fetchWithPayment() with x402 protocol |
// 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:
- Calls
generate_auth_noncetool - Gets wallet address from
cosmosWalletProvider - Builds SIWC message (includes bech32 prefix, chain ID, nonce)
- Signs with
cosmosWalletProvider.signArbitrary()(ADR-036) - Calls
auth_logintool with signature, pubkey, and x402 metadata - Stores the returned JWT
EVM (SIWE) flow:
- Calls
generate_auth_noncetool - Gets wallet address from
evmWalletProvider - Builds EIP-4361 SIWE message
- Signs with
evmWalletProvider.signArbitrary() - Calls
auth_logintool with signature and x402 metadata - Stores the returned JWT
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.
client.setToken("eyJhbGciOiJIUzI1NiJ9...");getWalletAddress(): Promise<string>
Returns the wallet address from the configured provider. Throws if no wallet provider is configured.
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
const wallet = await LocalCosmosWalletProvider.fromMnemonic(mnemonic, prefix);| Parameter | Type | Description |
|---|---|---|
mnemonic | string | BIP-39 mnemonic phrase |
prefix | string | Bech32 address prefix (e.g. "osmo", "cosmos") |
Methods
| Method | Returns | Description |
|---|---|---|
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() | Secp256k1HdWallet | Returns 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 callerTypes Reference
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
errorfield (including402payment errors if no payment client is configured) - The HTTP request returns
401and no wallet provider is configured for auto-login - Both or neither wallet providers are configured
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 | |
|---|---|---|
| Protocol | JSON-RPC 2.0 over HTTP | REST HTTP |
| Auth flow | Via gateway tools (generate_auth_nonce, auth_login) | Via REST endpoints (/auth/nonce, /auth/login) |
| Payment handling | Automatic via paymentClient for execute_rpc | Automatic via registered x402 client on /rpc |
| Tool discovery | listTools() returns all capabilities | Fixed REST endpoints |
| Best for | AI agents, MCP-compatible clients | Custom integrations, web apps |
| Local signing | LocalCosmosWalletProvider included | No bundled providers |