@ctxprotocol/sdk 0.1.3 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,6 +16,17 @@ Context Protocol is **npm for AI capabilities**. Just as you install packages to
16
16
  - **⚡️ Agentic Discovery:** Your Agent can search the marketplace at runtime to find tools it didn't know it needed.
17
17
  - **💸 Micro-Billing:** Pay only for what you use (e.g., $0.001/query). No monthly subscriptions for tools you rarely use.
18
18
 
19
+ ## Who Is This SDK For?
20
+
21
+ **This SDK is for AI Agent developers** who want to query the Context marketplace and execute tools.
22
+
23
+ | Role | What You Use |
24
+ |------|--------------|
25
+ | **AI Agent Developer** | `@ctxprotocol/sdk` — Query marketplace, execute tools, handle payments |
26
+ | **Tool Contributor (Data Broker)** | `@modelcontextprotocol/sdk` — Standard MCP server + Context extensions |
27
+
28
+ If you're building an MCP server to contribute tools and earn money, you **don't need this SDK**. See [Building MCP Servers](#building-mcp-servers-tool-contributors) for the simple pattern.
29
+
19
30
  ## Installation
20
31
 
21
32
  ```bash
@@ -340,6 +351,92 @@ try {
340
351
  | `payment_failed` | USDC payment failed | Check balance |
341
352
  | `execution_failed` | Tool error | Feed error to LLM for retry |
342
353
 
354
+ ---
355
+
356
+ ## Building MCP Servers (Tool Contributors)
357
+
358
+ Want to earn money by contributing tools to the Context marketplace? Build a standard MCP server that uses `outputSchema` and `structuredContent` from the [official MCP specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#output-schema):
359
+
360
+ 1. **`outputSchema`** in tool definitions — JSON Schema describing your response
361
+ 2. **`structuredContent`** in responses — Machine-readable data matching the schema
362
+
363
+ > **Note:** These are standard MCP features defined in the [MCP Tools specification](https://modelcontextprotocol.io/specification/2025-11-25/server/tools#output-schema). While optional in vanilla MCP, Context requires them for payment verification, dispute resolution, and AI code generation.
364
+
365
+ ### Why These Matter
366
+
367
+ | Requirement | Purpose |
368
+ |------------|---------|
369
+ | `outputSchema` | AI agents use this to generate type-safe code. Context uses it for dispute resolution. |
370
+ | `structuredContent` | Agents parse this for programmatic access. Text `content` is for humans. |
371
+
372
+ ### Example: Standard MCP Server
373
+
374
+ Build your server with the standard `@modelcontextprotocol/sdk`:
375
+
376
+ ```typescript
377
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
378
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
379
+
380
+ // Define tools with outputSchema (standard MCP feature, required by Context)
381
+ const TOOLS = [{
382
+ name: "get_gas_price",
383
+ description: "Get current gas prices",
384
+ inputSchema: {
385
+ type: "object",
386
+ properties: {
387
+ chainId: { type: "number", description: "EVM chain ID" },
388
+ },
389
+ },
390
+ // 👇 Standard MCP feature (see: modelcontextprotocol.io/specification)
391
+ outputSchema: {
392
+ type: "object",
393
+ properties: {
394
+ gasPrice: { type: "number" },
395
+ unit: { type: "string" },
396
+ },
397
+ required: ["gasPrice", "unit"],
398
+ },
399
+ }];
400
+
401
+ // Standard MCP server setup
402
+ const server = new Server(
403
+ { name: "my-gas-tool", version: "1.0.0" },
404
+ { capabilities: { tools: {} } }
405
+ );
406
+
407
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
408
+ tools: TOOLS, // outputSchema is included automatically
409
+ }));
410
+
411
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
412
+ const data = await fetchGasData(request.params.arguments.chainId);
413
+
414
+ // 👇 Standard MCP feature (see: modelcontextprotocol.io/specification)
415
+ return {
416
+ content: [{ type: "text", text: JSON.stringify(data) }], // Backward compat
417
+ structuredContent: data, // Machine-readable, matches outputSchema
418
+ };
419
+ });
420
+ ```
421
+
422
+ ### Example Servers
423
+
424
+ See complete working examples in `/examples/server/`:
425
+
426
+ - **[blocknative-contributor](./examples/server/blocknative-contributor)** — Gas price API (3 tools)
427
+ - **[hyperliquid-contributor](./examples/server/hyperliquid-contributor)** — DeFi analytics (16 tools)
428
+
429
+ ### Schema Accuracy = Revenue
430
+
431
+ ⚠️ **Important**: Your `outputSchema` is a contract. Context's "Robot Judge" validates that your `structuredContent` matches your declared schema. Schema violations result in automatic refunds to users.
432
+
433
+ ### Server Dependencies
434
+
435
+ ```bash
436
+ pnpm add @modelcontextprotocol/sdk express
437
+ pnpm add -D @types/express
438
+ ```
439
+
343
440
  ## Payment Flow
344
441
 
345
442
  When you execute a tool:
@@ -0,0 +1,194 @@
1
+ 'use strict';
2
+
3
+ // src/client/types.ts
4
+ var ContextError = class extends Error {
5
+ constructor(message, code, statusCode, helpUrl) {
6
+ super(message);
7
+ this.code = code;
8
+ this.statusCode = statusCode;
9
+ this.helpUrl = helpUrl;
10
+ this.name = "ContextError";
11
+ }
12
+ };
13
+
14
+ // src/client/resources/discovery.ts
15
+ var Discovery = class {
16
+ constructor(client) {
17
+ this.client = client;
18
+ }
19
+ /**
20
+ * Search for tools matching a query string
21
+ *
22
+ * @param query - The search query (e.g., "gas prices", "nft metadata")
23
+ * @param limit - Maximum number of results (1-50, default 10)
24
+ * @returns Array of matching tools
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const tools = await client.discovery.search("gas prices");
29
+ * console.log(tools[0].name); // "Gas Price Oracle"
30
+ * console.log(tools[0].mcpTools); // Available methods
31
+ * ```
32
+ */
33
+ async search(query, limit) {
34
+ const params = new URLSearchParams();
35
+ if (query) {
36
+ params.set("q", query);
37
+ }
38
+ if (limit !== void 0) {
39
+ params.set("limit", String(limit));
40
+ }
41
+ const queryString = params.toString();
42
+ const endpoint = `/api/v1/tools/search${queryString ? `?${queryString}` : ""}`;
43
+ const response = await this.client.fetch(endpoint);
44
+ return response.tools;
45
+ }
46
+ /**
47
+ * Get featured/popular tools (empty query search)
48
+ *
49
+ * @param limit - Maximum number of results (1-50, default 10)
50
+ * @returns Array of featured tools
51
+ *
52
+ * @example
53
+ * ```typescript
54
+ * const featured = await client.discovery.getFeatured(5);
55
+ * ```
56
+ */
57
+ async getFeatured(limit) {
58
+ return this.search("", limit);
59
+ }
60
+ };
61
+
62
+ // src/client/resources/tools.ts
63
+ var Tools = class {
64
+ constructor(client) {
65
+ this.client = client;
66
+ }
67
+ /**
68
+ * Execute a tool with the provided arguments
69
+ *
70
+ * @param options - Execution options
71
+ * @param options.toolId - The UUID of the tool (from search results)
72
+ * @param options.toolName - The specific MCP tool method to call (from tool's mcpTools array)
73
+ * @param options.args - Arguments to pass to the tool
74
+ * @returns The execution result with the tool's output data
75
+ *
76
+ * @throws {ContextError} With code `no_wallet` if wallet not set up
77
+ * @throws {ContextError} With code `insufficient_allowance` if Auto Pay not enabled
78
+ * @throws {ContextError} With code `payment_failed` if on-chain payment fails
79
+ * @throws {ContextError} With code `execution_failed` if tool execution fails
80
+ *
81
+ * @example
82
+ * ```typescript
83
+ * // First, search for a tool
84
+ * const tools = await client.discovery.search("gas prices");
85
+ * const tool = tools[0];
86
+ *
87
+ * // Execute a specific method from the tool's mcpTools
88
+ * const result = await client.tools.execute({
89
+ * toolId: tool.id,
90
+ * toolName: tool.mcpTools[0].name, // e.g., "get_gas_prices"
91
+ * args: { chainId: 1 }
92
+ * });
93
+ *
94
+ * console.log(result.result); // The tool's output
95
+ * console.log(result.durationMs); // Execution time
96
+ * ```
97
+ */
98
+ async execute(options) {
99
+ const { toolId, toolName, args } = options;
100
+ const response = await this.client.fetch(
101
+ "/api/v1/tools/execute",
102
+ {
103
+ method: "POST",
104
+ body: JSON.stringify({ toolId, toolName, args })
105
+ }
106
+ );
107
+ if ("error" in response) {
108
+ throw new ContextError(
109
+ response.error,
110
+ response.code,
111
+ 400,
112
+ response.helpUrl
113
+ );
114
+ }
115
+ if (response.success) {
116
+ return {
117
+ result: response.result,
118
+ tool: response.tool,
119
+ durationMs: response.durationMs
120
+ };
121
+ }
122
+ throw new ContextError("Unexpected response format from API");
123
+ }
124
+ };
125
+
126
+ // src/client/client.ts
127
+ var ContextClient = class {
128
+ apiKey;
129
+ baseUrl;
130
+ /**
131
+ * Discovery resource for searching tools
132
+ */
133
+ discovery;
134
+ /**
135
+ * Tools resource for executing tools
136
+ */
137
+ tools;
138
+ /**
139
+ * Creates a new Context Protocol client
140
+ *
141
+ * @param options - Client configuration options
142
+ * @param options.apiKey - Your Context Protocol API key (format: sk_live_...)
143
+ * @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)
144
+ */
145
+ constructor(options) {
146
+ if (!options.apiKey) {
147
+ throw new ContextError("API key is required");
148
+ }
149
+ this.apiKey = options.apiKey;
150
+ this.baseUrl = (options.baseUrl ?? "https://ctxprotocol.com").replace(/\/$/, "");
151
+ this.discovery = new Discovery(this);
152
+ this.tools = new Tools(this);
153
+ }
154
+ /**
155
+ * Internal method for making authenticated HTTP requests
156
+ * All requests include the Authorization header with the API key
157
+ *
158
+ * @internal
159
+ */
160
+ async fetch(endpoint, options = {}) {
161
+ const url = `${this.baseUrl}${endpoint}`;
162
+ const response = await fetch(url, {
163
+ ...options,
164
+ headers: {
165
+ "Content-Type": "application/json",
166
+ Authorization: `Bearer ${this.apiKey}`,
167
+ ...options.headers
168
+ }
169
+ });
170
+ if (!response.ok) {
171
+ let errorMessage = `HTTP ${response.status}: ${response.statusText}`;
172
+ let errorCode;
173
+ let helpUrl;
174
+ try {
175
+ const errorBody = await response.json();
176
+ if (errorBody.error) {
177
+ errorMessage = errorBody.error;
178
+ errorCode = errorBody.code;
179
+ helpUrl = errorBody.helpUrl;
180
+ }
181
+ } catch {
182
+ }
183
+ throw new ContextError(errorMessage, errorCode, response.status, helpUrl);
184
+ }
185
+ return response.json();
186
+ }
187
+ };
188
+
189
+ exports.ContextClient = ContextClient;
190
+ exports.ContextError = ContextError;
191
+ exports.Discovery = Discovery;
192
+ exports.Tools = Tools;
193
+ //# sourceMappingURL=index.cjs.map
194
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/types.ts","../../src/client/resources/discovery.ts","../../src/client/resources/tools.ts","../../src/client/client.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Configuration options for initializing the ContextClient\n */\nexport interface ContextClientOptions {\n /**\n * Your Context Protocol API key\n * @example \"sk_live_abc123...\"\n */\n apiKey: string;\n\n /**\n * Base URL for the Context Protocol API\n * @default \"https://ctxprotocol.com\"\n */\n baseUrl?: string;\n}\n\n/**\n * An individual MCP tool exposed by a tool listing\n */\nexport interface McpTool {\n /** Name of the MCP tool method */\n name: string;\n\n /** Description of what this method does */\n description: string;\n\n /**\n * JSON Schema for the input arguments this tool accepts.\n * Used by LLMs to generate correct arguments.\n */\n inputSchema?: Record<string, unknown>;\n\n /**\n * JSON Schema for the output this tool returns.\n * Used by LLMs to understand the response structure.\n */\n outputSchema?: Record<string, unknown>;\n}\n\n/**\n * Represents a tool available on the Context Protocol marketplace\n */\nexport interface Tool {\n /** Unique identifier for the tool (UUID) */\n id: string;\n\n /** Human-readable name of the tool */\n name: string;\n\n /** Description of what the tool does */\n description: string;\n\n /** Price per execution in USDC */\n price: string;\n\n /** Tool category (e.g., \"defi\", \"nft\") */\n category?: string;\n\n /** Whether the tool is verified by Context Protocol */\n isVerified?: boolean;\n\n /**\n * Available MCP tool methods\n * Use items from this array as `toolName` when executing\n */\n mcpTools?: McpTool[];\n\n /** Creation timestamp */\n createdAt?: string;\n\n /** Last update timestamp */\n updatedAt?: string;\n}\n\n/**\n * Response from the tools search endpoint\n */\nexport interface SearchResponse {\n /** Array of matching tools */\n tools: Tool[];\n\n /** The search query that was used */\n query: string;\n\n /** Total number of results */\n count: number;\n}\n\n/**\n * Options for searching tools\n */\nexport interface SearchOptions {\n /** Search query (semantic search) */\n query?: string;\n\n /** Maximum number of results (1-50, default 10) */\n limit?: number;\n}\n\n/**\n * Options for executing a tool\n */\nexport interface ExecuteOptions {\n /** The UUID of the tool to execute (from search results) */\n toolId: string;\n\n /** The specific MCP tool name to call (from tool's mcpTools array) */\n toolName: string;\n\n /** Arguments to pass to the tool */\n args?: Record<string, unknown>;\n}\n\n/**\n * Successful execution response from the API\n */\nexport interface ExecuteApiSuccessResponse {\n success: true;\n\n /** The result data from the tool execution */\n result: unknown;\n\n /** Information about the executed tool */\n tool: {\n id: string;\n name: string;\n };\n\n /** Execution duration in milliseconds */\n durationMs: number;\n}\n\n/**\n * Error response from the API\n */\nexport interface ExecuteApiErrorResponse {\n /** Human-readable error message */\n error: string;\n\n /** Error code for programmatic handling */\n code?: ContextErrorCode;\n\n /** URL to help resolve the issue */\n helpUrl?: string;\n}\n\n/**\n * Raw API response from the execute endpoint\n */\nexport type ExecuteApiResponse = ExecuteApiSuccessResponse | ExecuteApiErrorResponse;\n\n/**\n * The resolved result returned to the user after SDK processing\n */\nexport interface ExecutionResult<T = unknown> {\n /** The data returned by the tool */\n result: T;\n\n /** Information about the executed tool */\n tool: {\n id: string;\n name: string;\n };\n\n /** Execution duration in milliseconds */\n durationMs: number;\n}\n\n/**\n * Specific error codes returned by the Context Protocol API\n */\nexport type ContextErrorCode =\n | \"unauthorized\"\n | \"no_wallet\"\n | \"insufficient_allowance\"\n | \"payment_failed\"\n | \"execution_failed\";\n\n/**\n * Error thrown by the Context Protocol client\n */\nexport class ContextError extends Error {\n constructor(\n message: string,\n public readonly code?: ContextErrorCode | string,\n public readonly statusCode?: number,\n public readonly helpUrl?: string\n ) {\n super(message);\n this.name = \"ContextError\";\n }\n}\n","import type { Tool, SearchResponse } from \"../types.js\";\nimport type { ContextClient } from \"../client.js\";\n\n/**\n * Discovery resource for searching and finding tools on the Context Protocol marketplace\n */\nexport class Discovery {\n constructor(private client: ContextClient) {}\n\n /**\n * Search for tools matching a query string\n *\n * @param query - The search query (e.g., \"gas prices\", \"nft metadata\")\n * @param limit - Maximum number of results (1-50, default 10)\n * @returns Array of matching tools\n *\n * @example\n * ```typescript\n * const tools = await client.discovery.search(\"gas prices\");\n * console.log(tools[0].name); // \"Gas Price Oracle\"\n * console.log(tools[0].mcpTools); // Available methods\n * ```\n */\n async search(query: string, limit?: number): Promise<Tool[]> {\n const params = new URLSearchParams();\n\n if (query) {\n params.set(\"q\", query);\n }\n\n if (limit !== undefined) {\n params.set(\"limit\", String(limit));\n }\n\n const queryString = params.toString();\n const endpoint = `/api/v1/tools/search${queryString ? `?${queryString}` : \"\"}`;\n\n const response = await this.client.fetch<SearchResponse>(endpoint);\n\n return response.tools;\n }\n\n /**\n * Get featured/popular tools (empty query search)\n *\n * @param limit - Maximum number of results (1-50, default 10)\n * @returns Array of featured tools\n *\n * @example\n * ```typescript\n * const featured = await client.discovery.getFeatured(5);\n * ```\n */\n async getFeatured(limit?: number): Promise<Tool[]> {\n return this.search(\"\", limit);\n }\n}\n","import type {\n ExecuteOptions,\n ExecuteApiResponse,\n ExecutionResult,\n} from \"../types.js\";\nimport { ContextError } from \"../types.js\";\nimport type { ContextClient } from \"../client.js\";\n\n/**\n * Tools resource for executing tools on the Context Protocol marketplace\n */\nexport class Tools {\n constructor(private client: ContextClient) {}\n\n /**\n * Execute a tool with the provided arguments\n *\n * @param options - Execution options\n * @param options.toolId - The UUID of the tool (from search results)\n * @param options.toolName - The specific MCP tool method to call (from tool's mcpTools array)\n * @param options.args - Arguments to pass to the tool\n * @returns The execution result with the tool's output data\n *\n * @throws {ContextError} With code `no_wallet` if wallet not set up\n * @throws {ContextError} With code `insufficient_allowance` if Auto Pay not enabled\n * @throws {ContextError} With code `payment_failed` if on-chain payment fails\n * @throws {ContextError} With code `execution_failed` if tool execution fails\n *\n * @example\n * ```typescript\n * // First, search for a tool\n * const tools = await client.discovery.search(\"gas prices\");\n * const tool = tools[0];\n *\n * // Execute a specific method from the tool's mcpTools\n * const result = await client.tools.execute({\n * toolId: tool.id,\n * toolName: tool.mcpTools[0].name, // e.g., \"get_gas_prices\"\n * args: { chainId: 1 }\n * });\n *\n * console.log(result.result); // The tool's output\n * console.log(result.durationMs); // Execution time\n * ```\n */\n async execute<T = unknown>(options: ExecuteOptions): Promise<ExecutionResult<T>> {\n const { toolId, toolName, args } = options;\n\n const response = await this.client.fetch<ExecuteApiResponse>(\n \"/api/v1/tools/execute\",\n {\n method: \"POST\",\n body: JSON.stringify({ toolId, toolName, args }),\n }\n );\n\n // Handle error response\n if (\"error\" in response) {\n throw new ContextError(\n response.error,\n response.code,\n 400,\n response.helpUrl\n );\n }\n\n // Handle success response\n if (response.success) {\n return {\n result: response.result as T,\n tool: response.tool,\n durationMs: response.durationMs,\n };\n }\n\n // Fallback - shouldn't reach here with valid API responses\n throw new ContextError(\"Unexpected response format from API\");\n }\n}\n","import type { ContextClientOptions } from \"./types.js\";\nimport { ContextError } from \"./types.js\";\nimport { Discovery } from \"./resources/discovery.js\";\nimport { Tools } from \"./resources/tools.js\";\n\n/**\n * The official TypeScript client for the Context Protocol.\n *\n * Use this client to discover and execute AI tools programmatically.\n *\n * @example\n * ```typescript\n * import { ContextClient } from \"@contextprotocol/client\";\n *\n * const client = new ContextClient({\n * apiKey: \"sk_live_...\"\n * });\n *\n * // Discover tools\n * const tools = await client.discovery.search(\"gas prices\");\n *\n * // Execute a tool method\n * const result = await client.tools.execute({\n * toolId: tools[0].id,\n * toolName: tools[0].mcpTools[0].name,\n * args: { chainId: 1 }\n * });\n * ```\n */\nexport class ContextClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n\n /**\n * Discovery resource for searching tools\n */\n public readonly discovery: Discovery;\n\n /**\n * Tools resource for executing tools\n */\n public readonly tools: Tools;\n\n /**\n * Creates a new Context Protocol client\n *\n * @param options - Client configuration options\n * @param options.apiKey - Your Context Protocol API key (format: sk_live_...)\n * @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)\n */\n constructor(options: ContextClientOptions) {\n if (!options.apiKey) {\n throw new ContextError(\"API key is required\");\n }\n\n this.apiKey = options.apiKey;\n this.baseUrl = (options.baseUrl ?? \"https://ctxprotocol.com\").replace(/\\/$/, \"\");\n\n // Initialize resources\n this.discovery = new Discovery(this);\n this.tools = new Tools(this);\n }\n\n /**\n * Internal method for making authenticated HTTP requests\n * All requests include the Authorization header with the API key\n *\n * @internal\n */\n async fetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n const url = `${this.baseUrl}${endpoint}`;\n\n const response = await fetch(url, {\n ...options,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n let errorMessage = `HTTP ${response.status}: ${response.statusText}`;\n let errorCode: string | undefined;\n let helpUrl: string | undefined;\n\n try {\n const errorBody = await response.json();\n if (errorBody.error) {\n errorMessage = errorBody.error;\n errorCode = errorBody.code;\n helpUrl = errorBody.helpUrl;\n }\n } catch {\n // Use default error message if JSON parsing fails\n }\n\n throw new ContextError(errorMessage, errorCode, response.status, helpUrl);\n }\n\n return response.json() as Promise<T>;\n }\n}\n"]}
@@ -0,0 +1,277 @@
1
+ /**
2
+ * Configuration options for initializing the ContextClient
3
+ */
4
+ interface ContextClientOptions {
5
+ /**
6
+ * Your Context Protocol API key
7
+ * @example "sk_live_abc123..."
8
+ */
9
+ apiKey: string;
10
+ /**
11
+ * Base URL for the Context Protocol API
12
+ * @default "https://ctxprotocol.com"
13
+ */
14
+ baseUrl?: string;
15
+ }
16
+ /**
17
+ * An individual MCP tool exposed by a tool listing
18
+ */
19
+ interface McpTool {
20
+ /** Name of the MCP tool method */
21
+ name: string;
22
+ /** Description of what this method does */
23
+ description: string;
24
+ /**
25
+ * JSON Schema for the input arguments this tool accepts.
26
+ * Used by LLMs to generate correct arguments.
27
+ */
28
+ inputSchema?: Record<string, unknown>;
29
+ /**
30
+ * JSON Schema for the output this tool returns.
31
+ * Used by LLMs to understand the response structure.
32
+ */
33
+ outputSchema?: Record<string, unknown>;
34
+ }
35
+ /**
36
+ * Represents a tool available on the Context Protocol marketplace
37
+ */
38
+ interface Tool {
39
+ /** Unique identifier for the tool (UUID) */
40
+ id: string;
41
+ /** Human-readable name of the tool */
42
+ name: string;
43
+ /** Description of what the tool does */
44
+ description: string;
45
+ /** Price per execution in USDC */
46
+ price: string;
47
+ /** Tool category (e.g., "defi", "nft") */
48
+ category?: string;
49
+ /** Whether the tool is verified by Context Protocol */
50
+ isVerified?: boolean;
51
+ /**
52
+ * Available MCP tool methods
53
+ * Use items from this array as `toolName` when executing
54
+ */
55
+ mcpTools?: McpTool[];
56
+ /** Creation timestamp */
57
+ createdAt?: string;
58
+ /** Last update timestamp */
59
+ updatedAt?: string;
60
+ }
61
+ /**
62
+ * Response from the tools search endpoint
63
+ */
64
+ interface SearchResponse {
65
+ /** Array of matching tools */
66
+ tools: Tool[];
67
+ /** The search query that was used */
68
+ query: string;
69
+ /** Total number of results */
70
+ count: number;
71
+ }
72
+ /**
73
+ * Options for searching tools
74
+ */
75
+ interface SearchOptions {
76
+ /** Search query (semantic search) */
77
+ query?: string;
78
+ /** Maximum number of results (1-50, default 10) */
79
+ limit?: number;
80
+ }
81
+ /**
82
+ * Options for executing a tool
83
+ */
84
+ interface ExecuteOptions {
85
+ /** The UUID of the tool to execute (from search results) */
86
+ toolId: string;
87
+ /** The specific MCP tool name to call (from tool's mcpTools array) */
88
+ toolName: string;
89
+ /** Arguments to pass to the tool */
90
+ args?: Record<string, unknown>;
91
+ }
92
+ /**
93
+ * Successful execution response from the API
94
+ */
95
+ interface ExecuteApiSuccessResponse {
96
+ success: true;
97
+ /** The result data from the tool execution */
98
+ result: unknown;
99
+ /** Information about the executed tool */
100
+ tool: {
101
+ id: string;
102
+ name: string;
103
+ };
104
+ /** Execution duration in milliseconds */
105
+ durationMs: number;
106
+ }
107
+ /**
108
+ * Error response from the API
109
+ */
110
+ interface ExecuteApiErrorResponse {
111
+ /** Human-readable error message */
112
+ error: string;
113
+ /** Error code for programmatic handling */
114
+ code?: ContextErrorCode;
115
+ /** URL to help resolve the issue */
116
+ helpUrl?: string;
117
+ }
118
+ /**
119
+ * Raw API response from the execute endpoint
120
+ */
121
+ type ExecuteApiResponse = ExecuteApiSuccessResponse | ExecuteApiErrorResponse;
122
+ /**
123
+ * The resolved result returned to the user after SDK processing
124
+ */
125
+ interface ExecutionResult<T = unknown> {
126
+ /** The data returned by the tool */
127
+ result: T;
128
+ /** Information about the executed tool */
129
+ tool: {
130
+ id: string;
131
+ name: string;
132
+ };
133
+ /** Execution duration in milliseconds */
134
+ durationMs: number;
135
+ }
136
+ /**
137
+ * Specific error codes returned by the Context Protocol API
138
+ */
139
+ type ContextErrorCode = "unauthorized" | "no_wallet" | "insufficient_allowance" | "payment_failed" | "execution_failed";
140
+ /**
141
+ * Error thrown by the Context Protocol client
142
+ */
143
+ declare class ContextError extends Error {
144
+ readonly code?: (ContextErrorCode | string) | undefined;
145
+ readonly statusCode?: number | undefined;
146
+ readonly helpUrl?: string | undefined;
147
+ constructor(message: string, code?: (ContextErrorCode | string) | undefined, statusCode?: number | undefined, helpUrl?: string | undefined);
148
+ }
149
+
150
+ /**
151
+ * Discovery resource for searching and finding tools on the Context Protocol marketplace
152
+ */
153
+ declare class Discovery {
154
+ private client;
155
+ constructor(client: ContextClient);
156
+ /**
157
+ * Search for tools matching a query string
158
+ *
159
+ * @param query - The search query (e.g., "gas prices", "nft metadata")
160
+ * @param limit - Maximum number of results (1-50, default 10)
161
+ * @returns Array of matching tools
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const tools = await client.discovery.search("gas prices");
166
+ * console.log(tools[0].name); // "Gas Price Oracle"
167
+ * console.log(tools[0].mcpTools); // Available methods
168
+ * ```
169
+ */
170
+ search(query: string, limit?: number): Promise<Tool[]>;
171
+ /**
172
+ * Get featured/popular tools (empty query search)
173
+ *
174
+ * @param limit - Maximum number of results (1-50, default 10)
175
+ * @returns Array of featured tools
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const featured = await client.discovery.getFeatured(5);
180
+ * ```
181
+ */
182
+ getFeatured(limit?: number): Promise<Tool[]>;
183
+ }
184
+
185
+ /**
186
+ * Tools resource for executing tools on the Context Protocol marketplace
187
+ */
188
+ declare class Tools {
189
+ private client;
190
+ constructor(client: ContextClient);
191
+ /**
192
+ * Execute a tool with the provided arguments
193
+ *
194
+ * @param options - Execution options
195
+ * @param options.toolId - The UUID of the tool (from search results)
196
+ * @param options.toolName - The specific MCP tool method to call (from tool's mcpTools array)
197
+ * @param options.args - Arguments to pass to the tool
198
+ * @returns The execution result with the tool's output data
199
+ *
200
+ * @throws {ContextError} With code `no_wallet` if wallet not set up
201
+ * @throws {ContextError} With code `insufficient_allowance` if Auto Pay not enabled
202
+ * @throws {ContextError} With code `payment_failed` if on-chain payment fails
203
+ * @throws {ContextError} With code `execution_failed` if tool execution fails
204
+ *
205
+ * @example
206
+ * ```typescript
207
+ * // First, search for a tool
208
+ * const tools = await client.discovery.search("gas prices");
209
+ * const tool = tools[0];
210
+ *
211
+ * // Execute a specific method from the tool's mcpTools
212
+ * const result = await client.tools.execute({
213
+ * toolId: tool.id,
214
+ * toolName: tool.mcpTools[0].name, // e.g., "get_gas_prices"
215
+ * args: { chainId: 1 }
216
+ * });
217
+ *
218
+ * console.log(result.result); // The tool's output
219
+ * console.log(result.durationMs); // Execution time
220
+ * ```
221
+ */
222
+ execute<T = unknown>(options: ExecuteOptions): Promise<ExecutionResult<T>>;
223
+ }
224
+
225
+ /**
226
+ * The official TypeScript client for the Context Protocol.
227
+ *
228
+ * Use this client to discover and execute AI tools programmatically.
229
+ *
230
+ * @example
231
+ * ```typescript
232
+ * import { ContextClient } from "@contextprotocol/client";
233
+ *
234
+ * const client = new ContextClient({
235
+ * apiKey: "sk_live_..."
236
+ * });
237
+ *
238
+ * // Discover tools
239
+ * const tools = await client.discovery.search("gas prices");
240
+ *
241
+ * // Execute a tool method
242
+ * const result = await client.tools.execute({
243
+ * toolId: tools[0].id,
244
+ * toolName: tools[0].mcpTools[0].name,
245
+ * args: { chainId: 1 }
246
+ * });
247
+ * ```
248
+ */
249
+ declare class ContextClient {
250
+ private readonly apiKey;
251
+ private readonly baseUrl;
252
+ /**
253
+ * Discovery resource for searching tools
254
+ */
255
+ readonly discovery: Discovery;
256
+ /**
257
+ * Tools resource for executing tools
258
+ */
259
+ readonly tools: Tools;
260
+ /**
261
+ * Creates a new Context Protocol client
262
+ *
263
+ * @param options - Client configuration options
264
+ * @param options.apiKey - Your Context Protocol API key (format: sk_live_...)
265
+ * @param options.baseUrl - Optional base URL override (defaults to https://ctxprotocol.com)
266
+ */
267
+ constructor(options: ContextClientOptions);
268
+ /**
269
+ * Internal method for making authenticated HTTP requests
270
+ * All requests include the Authorization header with the API key
271
+ *
272
+ * @internal
273
+ */
274
+ fetch<T>(endpoint: string, options?: RequestInit): Promise<T>;
275
+ }
276
+
277
+ export { ContextClient, type ContextClientOptions, ContextError, type ContextErrorCode, Discovery, type ExecuteApiErrorResponse, type ExecuteApiResponse, type ExecuteApiSuccessResponse, type ExecuteOptions, type ExecutionResult, type McpTool, type SearchOptions, type SearchResponse, type Tool, Tools };