@ctxprotocol/sdk 0.1.1 → 0.1.3

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
@@ -1,103 +1,366 @@
1
- # Context SDK
2
- > Server-side helpers for publishing HTTP tools to the Context marketplace.
1
+ # @ctxprotocol/sdk
3
2
 
4
- The Context SDK is a tiny server-side helper for contributors who want to
5
- expose HTTP-based tools to the Context marketplace in a safe, typed, and
6
- consistent way.
3
+ **The Universal Adapter for AI Agents.**
7
4
 
8
- ---
5
+ Connect your AI to the real world without managing API keys, hosting servers, or reading documentation.
6
+
7
+ Context Protocol is **npm for AI capabilities**. Just as you install packages to add functionality to your code, use the Context SDK to give your Agent instant access to thousands of live data sources and actions—from DeFi and Gas Oracles to Weather and Search.
8
+
9
+ [![npm version](https://img.shields.io/npm/v/@ctxprotocol/sdk.svg)](https://www.npmjs.com/package/@ctxprotocol/sdk)
10
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
9
11
 
10
- ## Install
12
+ ## Why use Context?
11
13
 
12
- Using **pnpm**:
14
+ - **🔌 One Interface, Everything:** Stop integrating APIs one by one. Use a single SDK to access any tool in the marketplace.
15
+ - **🧠 Zero-Ops:** We're a gateway to the best MCP tools. Just send the JSON and get the result.
16
+ - **⚡️ Agentic Discovery:** Your Agent can search the marketplace at runtime to find tools it didn't know it needed.
17
+ - **💸 Micro-Billing:** Pay only for what you use (e.g., $0.001/query). No monthly subscriptions for tools you rarely use.
18
+
19
+ ## Installation
13
20
 
14
21
  ```bash
15
- pnpm add @ctxprotocol/sdk zod
22
+ npm install @ctxprotocol/sdk
16
23
  ```
17
24
 
18
- Using **npm**:
25
+ ```bash
26
+ pnpm add @ctxprotocol/sdk
27
+ ```
19
28
 
20
29
  ```bash
21
- npm install @ctxprotocol/sdk zod
30
+ yarn add @ctxprotocol/sdk
31
+ ```
32
+
33
+ ## Prerequisites
34
+
35
+ Before using the API, complete setup at [ctxprotocol.com](https://ctxprotocol.com):
36
+
37
+ 1. **Sign in** — Creates your embedded wallet
38
+ 2. **Enable Auto Pay** — Approve USDC spending for tool payments
39
+ 3. **Fund wallet** — Add USDC for tool execution fees
40
+ 4. **Generate API key** — In Settings page
41
+
42
+ ## Quick Start
43
+
44
+ ```typescript
45
+ import { ContextClient } from "@ctxprotocol/sdk";
46
+
47
+ const client = new ContextClient({
48
+ apiKey: "sk_live_...",
49
+ });
50
+
51
+ // Discover tools
52
+ const tools = await client.discovery.search("gas prices");
53
+
54
+ // Execute a tool
55
+ const result = await client.tools.execute({
56
+ toolId: tools[0].id,
57
+ toolName: tools[0].mcpTools[0].name,
58
+ args: { chainId: 1 },
59
+ });
60
+
61
+ console.log(result.result);
22
62
  ```
23
63
 
24
64
  ---
25
65
 
26
- ## Quick start
27
-
28
- Define a tool with input/output schemas and a handler, then expose it via a
29
- single HTTP endpoint:
30
-
31
- ```ts
32
- import { z } from "zod";
33
- import { defineHttpTool, executeHttpTool } from "@ctxprotocol/sdk";
34
-
35
- const tool = defineHttpTool({
36
- name: "blocknative_gas_base",
37
- inputSchema: z.object({ chainId: z.number().default(8453) }),
38
- outputSchema: z.object({
39
- endpoint: z.string(),
40
- data: z.unknown(),
41
- }),
42
- async handler(input) {
43
- const response = await fetch("https://your-endpoint", {
44
- method: "POST",
45
- body: JSON.stringify(input),
46
- });
47
-
48
- return {
49
- endpoint: "gas_price",
50
- data: await response.json(),
51
- };
52
- },
66
+ ## The Agentic Pattern: How to Build Autonomous Bots
67
+
68
+ The most powerful way to use this SDK is to let your LLM do the driving. Instead of hardcoding tool calls, follow this **Discovery Schema → Execution** loop:
69
+
70
+ ### 1. Discover
71
+
72
+ Let your Agent search for tools based on the user's intent.
73
+
74
+ ```typescript
75
+ const tools = await client.discovery.search(userQuery);
76
+ ```
77
+
78
+ ### 2. Inspect Schemas
79
+
80
+ Feed the discovered tool schemas (`inputSchema`) directly to your LLM's system prompt. This allows the LLM to understand exactly how to format the arguments—just like reading a manual.
81
+
82
+ ```typescript
83
+ const systemPrompt = `
84
+ You have access to the following tools:
85
+
86
+ ${tools.map(t => `
87
+ Tool: ${t.name} (ID: ${t.id})
88
+ Description: ${t.description}
89
+ Price: ${t.price} USDC
90
+
91
+ Methods:
92
+ ${t.mcpTools?.map(m => `
93
+ - ${m.name}: ${m.description}
94
+ Arguments: ${JSON.stringify(m.inputSchema, null, 2)}
95
+ Returns: ${JSON.stringify(m.outputSchema, null, 2)}
96
+ `).join("\n") ?? "No methods available"}
97
+ `).join("\n---\n")}
98
+
99
+ To use a tool, respond with a JSON object: { "toolId": "...", "toolName": "...", "args": {...} }
100
+ `;
101
+ ```
102
+
103
+ ### 3. Execute
104
+
105
+ When the LLM generates the arguments, pass them directly to the SDK.
106
+
107
+ ```typescript
108
+ // The LLM generates this object based on the schema you provided
109
+ const llmDecision = await myLLM.generate(userMessage, systemPrompt);
110
+
111
+ const result = await client.tools.execute({
112
+ toolId: llmDecision.toolId,
113
+ toolName: llmDecision.toolName,
114
+ args: llmDecision.args,
53
115
  });
54
116
 
55
- export async function handler(req: Request) {
56
- const body = await req.json();
57
- const result = await executeHttpTool(tool, body.input, {
58
- headers: Object.fromEntries(req.headers.entries()),
59
- });
117
+ // Feed the result back to your LLM for synthesis
118
+ const finalAnswer = await myLLM.generate(
119
+ `The tool returned: ${JSON.stringify(result.result)}. Summarize this for the user.`
120
+ );
121
+ ```
122
+
123
+ ### Handling Data (Outputs)
124
+
125
+ Context Tools return raw, structured JSON data (via `structuredContent`). This allows your Agent to programmatically filter, sort, or analyze results before showing them to the user.
126
+
127
+ > **Note:** For large datasets (like CSVs or PDF analysis), the API may return a reference URL to keep your context window clean.
128
+
129
+ ### Full Agentic Loop Example
130
+
131
+ ```typescript
132
+ import { ContextClient, ContextError } from "@ctxprotocol/sdk";
133
+
134
+ const client = new ContextClient({ apiKey: process.env.CONTEXT_API_KEY! });
135
+
136
+ async function agentLoop(userQuery: string) {
137
+ // 1. Discover relevant tools
138
+ const tools = await client.discovery.search(userQuery);
139
+
140
+ if (tools.length === 0) {
141
+ return "I couldn't find any tools to help with that.";
142
+ }
143
+
144
+ // 2. Build the system prompt with schemas
145
+ const toolDescriptions = tools.slice(0, 5).map(t => ({
146
+ id: t.id,
147
+ name: t.name,
148
+ description: t.description,
149
+ methods: t.mcpTools?.map(m => ({
150
+ name: m.name,
151
+ description: m.description,
152
+ inputSchema: m.inputSchema,
153
+ })),
154
+ }));
155
+
156
+ const systemPrompt = `You are an AI assistant with access to real-time tools.
157
+
158
+ Available tools:
159
+ ${JSON.stringify(toolDescriptions, null, 2)}
160
+
161
+ If you need to use a tool, respond ONLY with JSON:
162
+ { "toolId": "...", "toolName": "...", "args": {...} }
163
+
164
+ If you can answer without a tool, just respond normally.`;
60
165
 
61
- return Response.json(result);
166
+ // 3. Ask the LLM what to do
167
+ const llmResponse = await myLLM.chat(userQuery, systemPrompt);
168
+
169
+ // 4. Check if LLM wants to use a tool
170
+ try {
171
+ const toolCall = JSON.parse(llmResponse);
172
+
173
+ if (toolCall.toolId && toolCall.toolName) {
174
+ // 5. Execute the tool
175
+ const result = await client.tools.execute({
176
+ toolId: toolCall.toolId,
177
+ toolName: toolCall.toolName,
178
+ args: toolCall.args || {},
179
+ });
180
+
181
+ // 6. Let LLM synthesize the result
182
+ return await myLLM.chat(
183
+ `Tool "${toolCall.toolName}" returned: ${JSON.stringify(result.result)}
184
+
185
+ Please provide a helpful response to the user's original question: "${userQuery}"`
186
+ );
187
+ }
188
+ } catch {
189
+ // LLM responded with text, not JSON - return as-is
190
+ return llmResponse;
191
+ }
62
192
  }
63
193
  ```
64
194
 
65
- See `examples/blocknative-contributor/` for a full Express server that wraps
66
- the Blocknative Gas Platform.
67
-
68
195
  ---
69
196
 
70
- ## Scripts
197
+ ## Configuration
71
198
 
72
- From the repo root:
199
+ ### Client Options
200
+
201
+ | Option | Type | Required | Default | Description |
202
+ | --------- | -------- | -------- | ------------------------ | ------------------------------ |
203
+ | `apiKey` | `string` | Yes | — | Your Context Protocol API key |
204
+ | `baseUrl` | `string` | No | `https://ctxprotocol.com`| API base URL (for development) |
205
+
206
+ ```typescript
207
+ // Production
208
+ const client = new ContextClient({
209
+ apiKey: process.env.CONTEXT_API_KEY!,
210
+ });
73
211
 
74
- - **Build** – bundle to `dist/`:
212
+ // Local development
213
+ const client = new ContextClient({
214
+ apiKey: "sk_test_...",
215
+ baseUrl: "http://localhost:3000",
216
+ });
217
+ ```
75
218
 
76
- ```bash
77
- pnpm run build
78
- ```
219
+ ## API Reference
79
220
 
80
- - **Lint** – Biome checks:
221
+ ### Discovery
81
222
 
82
- ```bash
83
- pnpm run lint
84
- ```
223
+ #### `client.discovery.search(query, limit?)`
85
224
 
86
- - **Test** Vitest (add tests as needed):
225
+ Search for tools matching a query string.
87
226
 
88
- ```bash
89
- pnpm run test
90
- ```
227
+ ```typescript
228
+ const tools = await client.discovery.search("ethereum gas", 10);
229
+ ```
91
230
 
92
- ---
231
+ #### `client.discovery.getFeatured(limit?)`
93
232
 
94
- ## Publishing (for maintainers)
233
+ Get featured/popular tools.
95
234
 
96
- Install dependencies, build once to ensure everything compiles, then publish:
235
+ ```typescript
236
+ const featured = await client.discovery.getFeatured(5);
237
+ ```
97
238
 
98
- ```bash
99
- pnpm install
100
- pnpm run build
101
- pnpm publish --access public
239
+ ### Tools
240
+
241
+ #### `client.tools.execute(options)`
242
+
243
+ Execute a tool method.
244
+
245
+ ```typescript
246
+ const result = await client.tools.execute({
247
+ toolId: "uuid-of-tool",
248
+ toolName: "get_gas_prices",
249
+ args: { chainId: 1 },
250
+ });
251
+ ```
252
+
253
+ ## Types
254
+
255
+ ```typescript
256
+ import type {
257
+ ContextClientOptions,
258
+ Tool,
259
+ McpTool,
260
+ ExecuteOptions,
261
+ ExecutionResult,
262
+ ContextErrorCode,
263
+ } from "@ctxprotocol/sdk";
264
+ ```
265
+
266
+ ### Tool
267
+
268
+ ```typescript
269
+ interface Tool {
270
+ id: string;
271
+ name: string;
272
+ description: string;
273
+ price: string;
274
+ category?: string;
275
+ isVerified?: boolean;
276
+ mcpTools?: McpTool[];
277
+ }
102
278
  ```
103
279
 
280
+ ### McpTool
281
+
282
+ ```typescript
283
+ interface McpTool {
284
+ name: string;
285
+ description: string;
286
+ inputSchema?: Record<string, unknown>; // JSON Schema for arguments
287
+ outputSchema?: Record<string, unknown>; // JSON Schema for response
288
+ }
289
+ ```
290
+
291
+ ### ExecutionResult
292
+
293
+ ```typescript
294
+ interface ExecutionResult<T = unknown> {
295
+ result: T;
296
+ tool: { id: string; name: string };
297
+ durationMs: number;
298
+ }
299
+ ```
300
+
301
+ ## Error Handling
302
+
303
+ The SDK throws `ContextError` with specific error codes. In an agentic context, you can feed errors back to your LLM so it can self-correct.
304
+
305
+ ```typescript
306
+ import { ContextError } from "@ctxprotocol/sdk";
307
+
308
+ try {
309
+ const result = await client.tools.execute({ ... });
310
+ } catch (error) {
311
+ if (error instanceof ContextError) {
312
+ switch (error.code) {
313
+ case "no_wallet":
314
+ // User needs to set up wallet
315
+ console.log("Setup required:", error.helpUrl);
316
+ break;
317
+ case "insufficient_allowance":
318
+ // User needs to enable Auto Pay
319
+ console.log("Enable Auto Pay:", error.helpUrl);
320
+ break;
321
+ case "payment_failed":
322
+ // Insufficient USDC balance
323
+ break;
324
+ case "execution_failed":
325
+ // Tool execution error - feed back to LLM to retry with different args
326
+ const retryPrompt = `The tool failed with: ${error.message}. Try different arguments.`;
327
+ break;
328
+ }
329
+ }
330
+ }
331
+ ```
332
+
333
+ ### Error Codes
334
+
335
+ | Code | Description | Agentic Handling |
336
+ | ------------------------ | ---------------------------------------- | ----------------------------------- |
337
+ | `unauthorized` | Invalid API key | Check configuration |
338
+ | `no_wallet` | Wallet not set up | Direct user to `helpUrl` |
339
+ | `insufficient_allowance` | Auto Pay not enabled | Direct user to `helpUrl` |
340
+ | `payment_failed` | USDC payment failed | Check balance |
341
+ | `execution_failed` | Tool error | Feed error to LLM for retry |
342
+
343
+ ## Payment Flow
344
+
345
+ When you execute a tool:
346
+
347
+ 1. Your pre-approved USDC allowance is used
348
+ 2. **90%** goes to the tool developer
349
+ 3. **10%** goes to the protocol
350
+ 4. Tool executes and returns results
351
+
352
+ ## Links
353
+
354
+ - [Context Protocol](https://ctxprotocol.com) — Main website
355
+ - [GitHub](https://github.com/ctxprotocol/context) — Main project
356
+ - [SDK Repository](https://github.com/ctxprotocol/sdk) — This SDK
357
+ - [NPM Package](https://www.npmjs.com/package/@ctxprotocol/sdk)
358
+
359
+ ## Requirements
360
+
361
+ - Node.js 18+ (for native `fetch`)
362
+ - TypeScript 5+ (recommended)
363
+
364
+ ## License
365
+
366
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,194 @@
1
+ 'use strict';
2
+
3
+ // src/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/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/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.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/types.ts","../src/resources/discovery.ts","../src/resources/tools.ts","../src/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"]}