Skip to main content
Looking for Python? Check out the Python SDK Reference.

Installation

npm install @ctxprotocol/sdk

Requirements

  • Node.js 18+ (for native fetch)
  • TypeScript 5+ (recommended)

Prerequisites

Before using the API, complete setup at ctxprotocol.com:
1

Sign in

Creates your embedded wallet
2

Enable Auto Pay

Approve USDC spending for tool payments
3

Fund wallet

Add USDC for tool execution fees
4

Generate API key

In Settings page

Quick Start

import { ContextClient } from "@ctxprotocol/sdk";

const client = new ContextClient({
  apiKey: "sk_live_...",
});

// Discover tools
const tools = await client.discovery.search("gas prices");

// Execute a tool
const result = await client.tools.execute({
  toolId: tools[0].id,
  toolName: tools[0].mcpTools[0].name,
  args: { chainId: 1 },
});

console.log(result.result);

Configuration

Client Options

OptionTypeRequiredDefaultDescription
apiKeystringYesYour Context Protocol API key
baseUrlstringNohttps://ctxprotocol.comAPI base URL (for development)
// Production
const client = new ContextClient({
  apiKey: process.env.CONTEXT_API_KEY!,
});

// Local development
const client = new ContextClient({
  apiKey: "sk_test_...",
  baseUrl: "http://localhost:3000",
});

API Reference

Discovery

client.discovery.search(query, limit?)

Search for tools matching a query string. Parameters:
ParameterTypeRequiredDescription
querystringYesSearch query
limitnumberNoMaximum results to return
Returns: Promise<Tool[]>
const tools = await client.discovery.search("ethereum gas", 10);

client.discovery.getFeatured(limit?)

Get featured/popular tools. Parameters:
ParameterTypeRequiredDescription
limitnumberNoMaximum results to return
Returns: Promise<Tool[]>
const featured = await client.discovery.getFeatured(5);

Tools

client.tools.execute(options)

Execute a tool method. Parameters:
OptionTypeRequiredDescription
toolIdstringYesUUID of the tool
toolNamestringYesName of the method to call
argsobjectNoArguments matching the tool’s inputSchema
Returns: Promise<ExecutionResult>
const result = await client.tools.execute({
  toolId: "uuid-of-tool",
  toolName: "get_gas_prices",
  args: { chainId: 1 },
});

Types

Import Types

import {
  // Auth utilities for tool contributors
  verifyContextRequest,
  isProtectedMcpMethod,
  isOpenMcpMethod,
} from "@ctxprotocol/sdk";

import type {
  // Client types
  ContextClientOptions,
  Tool,
  McpTool,
  ExecuteOptions,
  ExecutionResult,
  ContextErrorCode,
  // Auth types (for MCP server contributors)
  VerifyRequestOptions,
  // Context types (for MCP server contributors receiving injected data)
  ContextRequirementType,
  HyperliquidContext,
  PolymarketContext,
  WalletContext,
  UserContext,
} from "@ctxprotocol/sdk";

Tool

interface Tool {
  id: string;
  name: string;
  description: string;
  price: string;
  category?: string;
  isVerified?: boolean;
  mcpTools?: McpTool[];
}

McpTool

interface McpTool {
  name: string;
  description: string;
  inputSchema?: Record<string, unknown>;  // JSON Schema for arguments
  outputSchema?: Record<string, unknown>; // JSON Schema for response
}

ExecutionResult

interface ExecutionResult<T = unknown> {
  result: T;
  tool: { id: string; name: string };
  durationMs: number;
}

Context Requirement Types

For MCP server contributors building tools that need user context (e.g., wallet data, portfolio positions):
Why Context Injection Matters:
  • No Auth Required: Public blockchain/user data is fetched by the platform, so you don’t need to handle API keys or user login.
  • Security: Your MCP server never handles private keys or sensitive credentials.
  • Simplicity: You receive structured, type-safe data directly in your tool arguments.
import type { ContextRequirementType } from "@ctxprotocol/sdk";

/** Context types supported by the marketplace */
type ContextRequirementType = "polymarket" | "hyperliquid" | "wallet";

// Usage: Declare context requirements in _meta at the tool level (MCP spec)
const TOOLS = [{
  name: "analyze_my_positions",
  description: "Analyze your positions with personalized insights",

  // ⭐ REQUIRED: Context requirements in _meta (MCP spec for arbitrary metadata)
  // The Context platform reads this to inject user data
  _meta: {
    contextRequirements: ["hyperliquid"] as ContextRequirementType[],
  },

  inputSchema: {
    type: "object",
    properties: {
      portfolio: { 
        type: "object",
        description: "Portfolio context (injected by platform)",
      },
    },
    required: ["portfolio"],
  },
  outputSchema: { /* ... */ },
}];
Why _meta at the tool level? The _meta field is part of the MCP specification for arbitrary tool metadata. The Context platform reads _meta.contextRequirements to determine what user data to inject. This is preserved through MCP transport because it’s a standard field.

Injected Context Types

HyperliquidContext

interface HyperliquidContext {
  walletAddress: string;
  perpPositions: HyperliquidPerpPosition[];
  spotBalances: HyperliquidSpotBalance[];
  openOrders: HyperliquidOrder[];
  accountSummary: HyperliquidAccountSummary;
  fetchedAt: string;
}

PolymarketContext

interface PolymarketContext {
  walletAddress: string;
  positions: PolymarketPosition[];
  openOrders: PolymarketOrder[];
  totalValue?: number;
  fetchedAt: string;
}

WalletContext

interface WalletContext {
  address: string;
  chainId: number;
  balances: TokenBalance[];
  fetchedAt: string;
}

Error Handling

The SDK throws ContextError with specific error codes:
import { ContextError } from "@ctxprotocol/sdk";

try {
  const result = await client.tools.execute({ ... });
} catch (error) {
  if (error instanceof ContextError) {
    switch (error.code) {
      case "no_wallet":
        // User needs to set up wallet
        console.log("Setup required:", error.helpUrl);
        break;
      case "insufficient_allowance":
        // User needs to enable Auto Pay
        console.log("Enable Auto Pay:", error.helpUrl);
        break;
      case "payment_failed":
        // Insufficient USDC balance
        break;
      case "execution_failed":
        // Tool execution error
        break;
    }
  }
}

Error Codes

CodeDescriptionHandling
unauthorizedInvalid API keyCheck configuration
no_walletWallet not set upDirect user to helpUrl
insufficient_allowanceAuto Pay not enabledDirect user to helpUrl
payment_failedUSDC payment failedCheck balance
execution_failedTool errorRetry with different args

Securing Your Tool (MCP Contributors)

If you’re building an MCP server, verify incoming requests are legitimate.
Free vs Paid Security Requirements:
Tool TypeSecurity MiddlewareRationale
Free Tools ($0.00)OptionalGreat for distribution and adoption
Paid Tools ($0.01+)MandatoryWe cannot route payments to insecure endpoints

Quick Implementation

import express from "express";
import { createContextMiddleware } from "@ctxprotocol/sdk";

const app = express();
app.use(express.json());

// 1 line of code to secure your endpoint
app.use("/mcp", createContextMiddleware());

app.post("/mcp", (req, res) => {
  // req.context contains verified JWT payload (on protected methods)
  // Handle MCP request...
});

MCP Security Model

Critical for tool contributors: Not all MCP methods require authentication. The middleware selectively protects only execution methods.
MCP MethodAuth RequiredWhy
initialize❌ NoSession setup
tools/list❌ NoDiscovery - agents need to see your schemas
resources/list❌ NoDiscovery
prompts/list❌ NoDiscovery
tools/callYesExecution - costs money, runs your code
What this means in practice:
  • https://your-mcp.com/mcp + initialize → Works without auth
  • https://your-mcp.com/mcp + tools/list → Works without auth
  • https://your-mcp.com/mcp + tools/callRequires Context Protocol JWT
This matches standard API patterns (OpenAPI schemas are public, GraphQL introspection is open).

Manual Verification

For more control, use the lower-level utilities:
import { 
  verifyContextRequest, 
  isProtectedMcpMethod, 
  ContextError 
} from "@ctxprotocol/sdk";

// Check if a method requires auth
if (isProtectedMcpMethod(body.method)) {
  const payload = await verifyContextRequest({
    authorizationHeader: req.headers.authorization,
    audience: "https://your-tool.com/mcp", // optional
  });
  // payload contains verified JWT claims
}

Verification Options

OptionTypeRequiredDescription
authorizationHeaderstringYesFull Authorization header (e.g., "Bearer eyJ...")
audiencestringNoExpected audience claim for stricter validation

Payment Flow

When you execute a tool:
  1. Your pre-approved USDC allowance is used
  2. 90% goes to the tool developer
  3. 10% goes to the protocol
  4. Tool executes and returns results