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:
Sign in
Creates your embedded wallet
Enable Auto Pay
Approve USDC spending for tool payments
Fund wallet
Add USDC for tool execution fees
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
| Option | Type | Required | Default | Description |
|---|
apiKey | string | Yes | — | Your Context Protocol API key |
baseUrl | string | No | https://ctxprotocol.com | API 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:
| Parameter | Type | Required | Description |
|---|
query | string | Yes | Search query |
limit | number | No | Maximum results to return |
Returns: Promise<Tool[]>
const tools = await client.discovery.search("ethereum gas", 10);
client.discovery.getFeatured(limit?)
Get featured/popular tools.
Parameters:
| Parameter | Type | Required | Description |
|---|
limit | number | No | Maximum results to return |
Returns: Promise<Tool[]>
const featured = await client.discovery.getFeatured(5);
Execute a tool method.
Parameters:
| Option | Type | Required | Description |
|---|
toolId | string | Yes | UUID of the tool |
toolName | string | Yes | Name of the method to call |
args | object | No | Arguments 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";
interface Tool {
id: string;
name: string;
description: string;
price: string;
category?: string;
isVerified?: boolean;
mcpTools?: 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
| Code | Description | Handling |
|---|
unauthorized | Invalid API key | Check configuration |
no_wallet | Wallet not set up | Direct user to helpUrl |
insufficient_allowance | Auto Pay not enabled | Direct user to helpUrl |
payment_failed | USDC payment failed | Check balance |
execution_failed | Tool error | Retry with different args |
If you’re building an MCP server, verify incoming requests are legitimate.
Free vs Paid Security Requirements:| Tool Type | Security Middleware | Rationale |
|---|
| Free Tools ($0.00) | Optional | Great for distribution and adoption |
| Paid Tools ($0.01+) | Mandatory | We 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 Method | Auth Required | Why |
|---|
initialize | ❌ No | Session setup |
tools/list | ❌ No | Discovery - agents need to see your schemas |
resources/list | ❌ No | Discovery |
prompts/list | ❌ No | Discovery |
tools/call | ✅ Yes | Execution - 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/call → Requires 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
| Option | Type | Required | Description |
|---|
authorizationHeader | string | Yes | Full Authorization header (e.g., "Bearer eyJ...") |
audience | string | No | Expected audience claim for stricter validation |
Payment Flow
When you execute a tool:
- Your pre-approved USDC allowance is used
- 90% goes to the tool developer
- 10% goes to the protocol
- Tool executes and returns results
Links