@ctxprotocol/sdk 0.5.6 → 0.7.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 +103 -17
- package/dist/client/index.cjs +257 -10
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +217 -17
- package/dist/client/index.d.ts +217 -17
- package/dist/client/index.js +257 -11
- package/dist/client/index.js.map +1 -1
- package/dist/index.cjs +295 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +34 -17
- package/dist/index.d.ts +34 -17
- package/dist/index.js +295 -13
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/types.ts","../src/client/resources/discovery.ts","../src/client/resources/tools.ts","../src/client/client.ts","../src/context/index.ts","../src/auth/index.ts","../src/handshake/types.ts"],"names":["importSPKI","jwtVerify"],"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","/**\n * Context types for portfolio and protocol data injection.\n *\n * These types allow MCP tools to receive personalized user context\n * (wallet addresses, positions, balances) for analysis.\n *\n * =============================================================================\n * DECLARING CONTEXT REQUIREMENTS\n * =============================================================================\n *\n * Since the MCP protocol only transmits standard fields (name, description,\n * inputSchema, outputSchema), context requirements MUST be embedded in the\n * inputSchema using the \"x-context-requirements\" JSON Schema extension.\n *\n * @example\n * ```typescript\n * import { CONTEXT_REQUIREMENTS_KEY, type ContextRequirementType } from \"@ctxprotocol/sdk\";\n * import type { HyperliquidContext } from \"@ctxprotocol/sdk\";\n *\n * const tool = {\n * name: \"analyze_my_positions\",\n * inputSchema: {\n * type: \"object\",\n * [CONTEXT_REQUIREMENTS_KEY]: [\"hyperliquid\"] as ContextRequirementType[],\n * properties: {\n * portfolio: { type: \"object\" }\n * },\n * required: [\"portfolio\"]\n * }\n * };\n *\n * // Your handler receives the injected context:\n * function handleAnalyzeMyPositions(args: { portfolio: HyperliquidContext }) {\n * const { perpPositions, accountSummary } = args.portfolio;\n * // ... analyze and return insights\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Wallet context types\nexport * from \"./wallet.js\";\n\n// Protocol-specific context types\nexport * from \"./polymarket.js\";\nexport * from \"./hyperliquid.js\";\n\n// Re-import for composite type\nimport type { WalletContext, ERC20Context } from \"./wallet.js\";\nimport type { PolymarketContext } from \"./polymarket.js\";\nimport type { HyperliquidContext } from \"./hyperliquid.js\";\n\n// ============================================================================\n// CONTEXT REQUIREMENTS\n//\n// MCP tools that need user portfolio data MUST declare this in inputSchema.\n// The MCP protocol only transmits standard fields (name, description,\n// inputSchema, outputSchema). Custom fields get stripped by the MCP SDK.\n// ============================================================================\n\n/**\n * JSON Schema extension key for declaring context requirements.\n *\n * WHY THIS APPROACH?\n * - MCP protocol only transmits: name, description, inputSchema, outputSchema\n * - Custom fields like `requirements` get stripped by MCP SDK during transport\n * - JSON Schema allows custom \"x-\" prefixed extension properties\n * - inputSchema is preserved end-to-end through MCP transport\n *\n * @example\n * ```typescript\n * import { CONTEXT_REQUIREMENTS_KEY } from \"@ctxprotocol/sdk\";\n *\n * const tool = {\n * name: \"analyze_my_positions\",\n * inputSchema: {\n * type: \"object\",\n * [CONTEXT_REQUIREMENTS_KEY]: [\"hyperliquid\"],\n * properties: { portfolio: { type: \"object\" } },\n * required: [\"portfolio\"]\n * }\n * };\n * ```\n */\nexport const CONTEXT_REQUIREMENTS_KEY = \"x-context-requirements\" as const;\n\n/**\n * Context requirement types supported by the Context marketplace.\n * Maps to protocol-specific context builders on the platform.\n *\n * @example\n * ```typescript\n * inputSchema: {\n * type: \"object\",\n * \"x-context-requirements\": [\"hyperliquid\"] as ContextRequirementType[],\n * properties: { portfolio: { type: \"object\" } },\n * required: [\"portfolio\"]\n * }\n * ```\n */\nexport type ContextRequirementType = \"polymarket\" | \"hyperliquid\" | \"wallet\";\n\n/**\n * @deprecated The `requirements` field at tool level gets stripped by MCP SDK.\n * Use `x-context-requirements` inside `inputSchema` instead.\n *\n * @example\n * ```typescript\n * // ❌ OLD (doesn't work - stripped by MCP SDK)\n * { requirements: { context: [\"hyperliquid\"] } }\n *\n * // ✅ NEW (works - preserved through MCP transport)\n * { inputSchema: { \"x-context-requirements\": [\"hyperliquid\"], ... } }\n * ```\n */\nexport interface ToolRequirements {\n /**\n * @deprecated Use `x-context-requirements` in inputSchema instead.\n */\n context?: ContextRequirementType[];\n}\n\n/**\n * Composite context for tools that need multiple data sources.\n *\n * This is the unified structure that can be passed to MCP tools\n * to provide comprehensive user context.\n */\nexport interface UserContext {\n /** Base wallet information */\n wallet?: WalletContext;\n /** ERC20 token holdings */\n erc20?: ERC20Context;\n /** Polymarket positions and orders */\n polymarket?: PolymarketContext;\n /** Hyperliquid perpetual positions and account data */\n hyperliquid?: HyperliquidContext;\n // Future protocols:\n // aave?: AaveContext;\n}\n","import { jwtVerify, importSPKI, type JWTPayload } from \"jose\";\nimport { ContextError } from \"../client/types.js\";\n\n// ============================================================================\n// Express-compatible types (avoid requiring express as a dependency)\n// ============================================================================\n\ninterface ContextRequest {\n headers: {\n authorization?: string;\n [key: string]: string | string[] | undefined;\n };\n body?: {\n method?: string;\n [key: string]: unknown;\n };\n context?: JWTPayload;\n}\n\ninterface ContextResponse {\n status(code: number): ContextResponse;\n json(data: unknown): void;\n}\n\ntype NextFunction = (error?: unknown) => void;\n\n/**\n * Extended Request object with verified Context Protocol JWT payload.\n *\n * After `createContextMiddleware()` runs successfully on a protected method,\n * the `context` property contains the decoded JWT claims.\n */\nexport interface ContextMiddlewareRequest extends ContextRequest {\n /** The verified JWT payload from Context Protocol (available after auth) */\n context?: JWTPayload;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n// The Context Protocol Public Key\n// In a real scenario, this might be fetched from a well-known URL or passed in config.\n// For now, we hardcode the Official Platform Public Key.\n// Official Context Protocol Platform Public Key (RS256)\nconst CONTEXT_PLATFORM_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9YOgdpkmVQ5aoNovjsu\nchJdV54OT7dUdbVXz914a7Px8EwnpDqhsvG7WO8xL8sj2Rn6ueAJBk+04Hy/P/UN\nRJyp23XL5TsGmb4rbfg0ii0MiL2nbVXuqvAe3JSM2BOFZR5bpwIVIaa8aonfamUy\nVXGc7OosF90ThdKjm9cXlVM+kV6IgSWc1502X7M3abQqRcTU/rluVXnky0eiWDQa\nlfOKbr7w0u72dZjiZPwnNDsX6PEEgvfmoautTFYTQgnZjDzq8UimTcv3KF+hJ5Ep\nweipe6amt9lzQzi8WXaFKpOXHQs//WDlUytz/Hl8pvd5craZKzo6Kyrg1Vfan7H3\nTQIDAQAB\n-----END PUBLIC KEY-----`;\n\n/**\n * MCP methods that require authentication.\n * - tools/call: Executes tool logic, may cost money\n * - resources/read: Reads potentially sensitive data\n * - prompts/get: Gets prompt content\n */\nconst PROTECTED_MCP_METHODS = new Set([\n \"tools/call\",\n // Uncomment these if you want to protect resource/prompt access:\n // \"resources/read\",\n // \"prompts/get\",\n]);\n\n/**\n * MCP methods that are always open (no auth required).\n * These are discovery/listing operations that return metadata only.\n */\nconst OPEN_MCP_METHODS = new Set([\n \"initialize\",\n \"tools/list\",\n \"resources/list\",\n \"prompts/list\",\n \"ping\",\n \"notifications/initialized\",\n]);\n\n// ============================================================================\n// Method Classification\n// ============================================================================\n\n/**\n * Determines if a given MCP method requires authentication.\n *\n * Discovery methods (tools/list, resources/list, etc.) are open.\n * Execution methods (tools/call) require authentication.\n *\n * @param method The MCP JSON-RPC method (e.g., \"tools/list\", \"tools/call\")\n * @returns true if the method requires authentication\n *\n * @example\n * ```typescript\n * if (isProtectedMcpMethod(body.method)) {\n * await verifyContextRequest({ authorizationHeader: req.headers.authorization });\n * }\n * ```\n */\nexport function isProtectedMcpMethod(method: string): boolean {\n return PROTECTED_MCP_METHODS.has(method);\n}\n\n/**\n * Determines if a given MCP method is explicitly open (no auth).\n *\n * @param method The MCP JSON-RPC method\n * @returns true if the method is known to be open\n */\nexport function isOpenMcpMethod(method: string): boolean {\n return OPEN_MCP_METHODS.has(method);\n}\n\n// ============================================================================\n// Request Verification\n// ============================================================================\n\nexport interface VerifyRequestOptions {\n /** The full Authorization header string (e.g. \"Bearer eyJ...\") */\n authorizationHeader?: string;\n /** Expected Audience (your tool URL) for stricter validation */\n audience?: string;\n}\n\n/**\n * Verifies that an incoming request originated from the Context Protocol Platform.\n *\n * @param options Contains the Authorization header\n * @returns The decoded payload if valid\n * @throws ContextError if invalid\n */\nexport async function verifyContextRequest(options: VerifyRequestOptions) {\n const { authorizationHeader, audience } = options;\n\n if (!authorizationHeader || !authorizationHeader.startsWith(\"Bearer \")) {\n throw new ContextError(\n \"Missing or invalid Authorization header\",\n \"unauthorized\",\n 401\n );\n }\n\n const token = authorizationHeader.split(\" \")[1];\n\n try {\n const publicKey = await importSPKI(CONTEXT_PLATFORM_PUBLIC_KEY_PEM, \"RS256\");\n\n const { payload } = await jwtVerify(token, publicKey, {\n issuer: \"https://ctxprotocol.com\",\n audience: audience,\n });\n\n return payload;\n } catch (error) {\n throw new ContextError(\n \"Invalid Context Protocol signature\",\n \"unauthorized\",\n 401\n );\n }\n}\n\n// ============================================================================\n// Easy-Mode Middleware\n// ============================================================================\n\nexport interface CreateContextMiddlewareOptions {\n /** Expected Audience (your tool URL) for stricter validation */\n audience?: string;\n}\n\n/**\n * Creates an Express/Connect-compatible middleware that secures your MCP endpoint.\n *\n * This is the \"1 line of code\" solution to secure your MCP server.\n * It automatically:\n * - Allows discovery methods (tools/list, initialize) without authentication\n * - Requires and verifies JWT for execution methods (tools/call)\n * - Attaches the verified payload to `req.context` for downstream use\n *\n * @param options Optional configuration\n * @returns Express-compatible middleware function\n *\n * @example\n * ```typescript\n * import express from \"express\";\n * import { createContextMiddleware } from \"@ctxprotocol/sdk\";\n *\n * const app = express();\n * app.use(express.json());\n *\n * // 1 line to secure your endpoint\n * app.use(\"/mcp\", createContextMiddleware());\n *\n * app.post(\"/mcp\", (req, res) => {\n * // req.context contains verified JWT payload (on protected methods)\n * // Handle MCP request...\n * });\n * ```\n */\nexport function createContextMiddleware(options: CreateContextMiddlewareOptions = {}) {\n return async function contextMiddleware(\n req: ContextRequest,\n res: ContextResponse,\n next: NextFunction\n ): Promise<void> {\n const method = req.body?.method as string | undefined;\n\n // Allow discovery methods without authentication\n // Discovery methods (tools/list, initialize, etc.) are open by design\n if (!method || !isProtectedMcpMethod(method)) {\n return next();\n }\n\n // Protected method - require authentication\n try {\n const payload = await verifyContextRequest({\n authorizationHeader: req.headers.authorization,\n audience: options.audience,\n });\n\n // Attach verified payload to request for downstream handlers\n req.context = payload;\n next();\n } catch (error) {\n const statusCode = error instanceof ContextError ? error.statusCode || 401 : 401;\n res.status(statusCode).json({ error: \"Unauthorized\" });\n }\n };\n}\n\n\n","/**\n * Handshake Types for MCP Tool Developers\n *\n * Use these types when your tool needs to request user interaction\n * before completing an action (signatures, transactions, OAuth).\n *\n * @see https://docs.ctxprotocol.com/guides/handshake-architecture\n *\n * ## Usage Pattern\n *\n * Tools return handshake actions in the `_meta.handshakeAction` field\n * of their MCP response. The Context platform intercepts these and\n * presents the appropriate UI to the user.\n *\n * ## Action Types\n *\n * - `signature_request`: For EIP-712 signatures (Hyperliquid, Polymarket, etc.)\n * - `transaction_proposal`: For direct on-chain transactions (Uniswap, NFT mints)\n * - `auth_required`: For OAuth flows (Discord, Twitter, etc.)\n */\n\n// === Shared Meta Type ===\n\nexport type HandshakeMeta = {\n /** Human-readable description of the action */\n description: string;\n /** Protocol name (e.g., \"Hyperliquid\", \"Polymarket\") */\n protocol?: string;\n /** Action verb (e.g., \"Place Order\", \"Place Bid\") */\n action?: string;\n /** Token symbol if relevant */\n tokenSymbol?: string;\n /** Human-readable token amount */\n tokenAmount?: string;\n /** UI warning level */\n warningLevel?: \"info\" | \"caution\" | \"danger\";\n};\n\n// === Web3: Signature Requests (for proxy wallet platforms) ===\n\nexport type EIP712Domain = {\n /** Domain name (e.g., \"Hyperliquid\", \"ClobAuthDomain\") */\n name: string;\n /** Domain version */\n version: string;\n /** Chain ID (informational - signing is chain-agnostic) */\n chainId: number;\n /** Optional verifying contract address */\n verifyingContract?: `0x${string}`;\n};\n\nexport type EIP712TypeField = {\n name: string;\n type: string;\n};\n\n/**\n * Signature Request\n *\n * Use this for platforms with proxy wallets (Hyperliquid, Polymarket, dYdX).\n *\n * Benefits:\n * - No gas required (user signs a message, not a transaction)\n * - No network switching needed (signing is chain-agnostic)\n * - Works with Privy embedded wallets on any chain\n *\n * @example\n * ```typescript\n * return {\n * structuredContent: {\n * _meta: {\n * handshakeAction: createSignatureRequest({\n * domain: { name: \"Hyperliquid\", version: \"1\", chainId: 42161 },\n * types: { Order: [...] },\n * primaryType: \"Order\",\n * message: { asset: 4, isBuy: true, ... },\n * meta: { description: \"Place Long ETH order\", protocol: \"Hyperliquid\" }\n * })\n * }\n * }\n * };\n * ```\n */\nexport type SignatureRequest = {\n _action: \"signature_request\";\n /** EIP-712 domain separator */\n domain: EIP712Domain;\n /** EIP-712 type definitions */\n types: Record<string, EIP712TypeField[]>;\n /** The primary type being signed */\n primaryType: string;\n /** The message data to sign */\n message: Record<string, unknown>;\n /** UI metadata for the approval card */\n meta?: HandshakeMeta;\n /**\n * Optional: Tool name to call with the signature result.\n * If provided, the platform will call this tool with { signature, originalParams }\n * after the user signs.\n */\n callbackToolName?: string;\n};\n\n// === Web3: Transaction Proposals (for direct on-chain actions) ===\n\nexport type TransactionProposalMeta = HandshakeMeta & {\n /** Estimated gas cost (informational - Context may sponsor) */\n estimatedGas?: string;\n /** Link to contract on block explorer */\n explorerUrl?: string;\n};\n\n/**\n * Transaction Proposal\n *\n * Use this for protocols without proxy wallets (Uniswap, NFT mints, etc.).\n *\n * Note: May require network switching and gas fees.\n *\n * @example\n * ```typescript\n * return {\n * structuredContent: {\n * _meta: {\n * handshakeAction: createTransactionProposal({\n * chainId: 8453,\n * to: \"0x...\",\n * data: \"0x...\",\n * meta: { description: \"Swap 100 USDC for ETH\", protocol: \"Uniswap\" }\n * })\n * }\n * }\n * };\n * ```\n */\nexport type TransactionProposal = {\n _action: \"transaction_proposal\";\n /** EVM chain ID (e.g., 137 for Polygon, 8453 for Base) */\n chainId: number;\n /** Target contract address */\n to: `0x${string}`;\n /** Encoded calldata */\n data: `0x${string}`;\n /** Wei to send (as string, default \"0\") */\n value?: string;\n /** UI metadata for the approval card */\n meta?: TransactionProposalMeta;\n};\n\n// === Web2: OAuth Requests ===\n\nexport type AuthRequiredMeta = {\n /** Human-friendly service name */\n displayName?: string;\n /** Permissions being requested */\n scopes?: string[];\n /** Description of what access is needed */\n description?: string;\n /** Tool's icon URL */\n iconUrl?: string;\n /** How long authorization lasts */\n expiresIn?: string;\n};\n\n/**\n * Auth Required\n *\n * Use this when your tool needs the user to authenticate with an external service.\n *\n * @example\n * ```typescript\n * if (!hasUserToken(contextDid)) {\n * return {\n * structuredContent: {\n * _meta: {\n * handshakeAction: createAuthRequired({\n * provider: \"discord\",\n * authUrl: \"https://your-server.com/oauth/discord\",\n * meta: { displayName: \"Discord Bot\", scopes: [\"send_messages\"] }\n * })\n * }\n * }\n * };\n * }\n * ```\n */\nexport type AuthRequired = {\n _action: \"auth_required\";\n /** Service identifier (e.g., \"discord\", \"slack\") */\n provider: string;\n /** Your OAuth initiation endpoint (MUST be HTTPS) */\n authUrl: string;\n /** UI metadata for the auth card */\n meta?: AuthRequiredMeta;\n};\n\n// === Union Type ===\n\nexport type HandshakeAction =\n | SignatureRequest\n | TransactionProposal\n | AuthRequired;\n\n// === Type Guards ===\n\nexport function isHandshakeAction(value: unknown): value is HandshakeAction {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"_action\" in value &&\n ((value as { _action: string })._action === \"signature_request\" ||\n (value as { _action: string })._action === \"transaction_proposal\" ||\n (value as { _action: string })._action === \"auth_required\")\n );\n}\n\nexport function isSignatureRequest(value: unknown): value is SignatureRequest {\n return isHandshakeAction(value) && value._action === \"signature_request\";\n}\n\nexport function isTransactionProposal(\n value: unknown\n): value is TransactionProposal {\n return isHandshakeAction(value) && value._action === \"transaction_proposal\";\n}\n\nexport function isAuthRequired(value: unknown): value is AuthRequired {\n return isHandshakeAction(value) && value._action === \"auth_required\";\n}\n\n// === Helper Functions for Tool Developers ===\n\n/**\n * Create a signature request response.\n * Return this from your tool when you need the user to sign EIP-712 typed data.\n *\n * Use this for platforms with proxy wallets (Hyperliquid, Polymarket, dYdX).\n * Benefits: No gas required, no network switching needed.\n */\nexport function createSignatureRequest(\n params: Omit<SignatureRequest, \"_action\">\n): SignatureRequest {\n return {\n _action: \"signature_request\",\n ...params,\n };\n}\n\n/**\n * Create a transaction proposal response.\n * Return this from your tool when you need the user to sign a direct on-chain transaction.\n *\n * Use this for protocols that don't use proxy wallets (Uniswap, NFT mints, etc.).\n * Note: May require network switching and gas.\n */\nexport function createTransactionProposal(\n params: Omit<TransactionProposal, \"_action\">\n): TransactionProposal {\n return {\n _action: \"transaction_proposal\",\n ...params,\n };\n}\n\n/**\n * Create an auth required response.\n * Return this from your tool when you need the user to authenticate via OAuth.\n */\nexport function createAuthRequired(\n params: Omit<AuthRequired, \"_action\">\n): AuthRequired {\n return {\n _action: \"auth_required\",\n ...params,\n };\n}\n\n// === MCP Response Helper ===\n\n/**\n * Wrap a handshake action in the proper MCP response format.\n *\n * MCP tools should return handshake actions in `_meta.handshakeAction` to prevent\n * the MCP SDK from stripping unknown fields.\n *\n * @example\n * ```typescript\n * // In your tool handler:\n * return wrapHandshakeResponse(createSignatureRequest({\n * domain: { name: \"Hyperliquid\", version: \"1\", chainId: 42161 },\n * types: { Order: [...] },\n * primaryType: \"Order\",\n * message: orderData,\n * meta: { description: \"Place order\", protocol: \"Hyperliquid\" }\n * }));\n * ```\n */\nexport function wrapHandshakeResponse(action: HandshakeAction): {\n content: Array<{ type: \"text\"; text: string }>;\n structuredContent: {\n _meta: { handshakeAction: HandshakeAction };\n status: string;\n message: string;\n };\n} {\n const actionType = action._action.replace(\"_\", \" \");\n return {\n content: [\n {\n type: \"text\",\n text: `Handshake required: ${actionType}. Please approve in the Context app.`,\n },\n ],\n structuredContent: {\n _meta: {\n handshakeAction: action,\n },\n status: \"handshake_required\",\n message: action.meta?.description ?? `${actionType} required`,\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/types.ts","../src/client/resources/discovery.ts","../src/client/resources/tools.ts","../src/client/resources/query.ts","../src/client/client.ts","../src/context/index.ts","../src/auth/index.ts","../src/handshake/types.ts"],"names":["importSPKI","jwtVerify"],"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 /** Tool type - currently always \"mcp\" */\n kind?: string;\n\n /**\n * Available MCP tool methods\n * Use items from this array as `toolName` when executing\n */\n mcpTools?: McpTool[];\n\n // Trust metrics (Level 2 - Reputation Ledger)\n /** Total number of queries processed */\n totalQueries?: number;\n\n /** Success rate percentage (0-100) */\n successRate?: string;\n\n /** Uptime percentage (0-100) */\n uptimePercent?: string;\n\n /** Total USDC staked by the developer */\n totalStaked?: string;\n\n /** Whether the tool has \"Proven\" status (100+ queries, >95% success, >98% uptime) */\n isProven?: boolean;\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// Query types (pay-per-response / agentic mode)\n// ---------------------------------------------------------------------------\n\n/**\n * Options for the agentic query endpoint (pay-per-response).\n *\n * Unlike `execute()` which calls a single tool once, `query()` sends a\n * natural-language question and lets the server handle tool discovery,\n * multi-tool orchestration, self-healing retries, and AI synthesis.\n * One flat fee covers up to 100 MCP skill calls per tool.\n */\nexport interface QueryOptions {\n /** The natural-language question to answer */\n query: string;\n\n /**\n * Optional tool IDs to use. When omitted the server discovers tools\n * automatically (Auto Mode). When provided, only these tools are used\n * (Manual Mode).\n */\n tools?: string[];\n}\n\n/**\n * Information about a tool that was used during a query response\n */\nexport interface QueryToolUsage {\n /** Tool ID */\n id: string;\n\n /** Tool name */\n name: string;\n\n /** Number of MCP skill calls made for this tool */\n skillCalls: number;\n}\n\n/**\n * Cost breakdown for a query response.\n * All values are strings representing USD amounts.\n */\nexport interface QueryCost {\n /** AI model inference cost */\n modelCostUsd: string;\n\n /** Sum of all tool fees */\n toolCostUsd: string;\n\n /** Total cost (model + tools) */\n totalCostUsd: string;\n}\n\n/**\n * The resolved result of a pay-per-response query\n */\nexport interface QueryResult {\n /** The AI-synthesized response text */\n response: string;\n\n /** Tools that were used to answer the query */\n toolsUsed: QueryToolUsage[];\n\n /** Cost breakdown */\n cost: QueryCost;\n\n /** Total duration in milliseconds */\n durationMs: number;\n}\n\n/**\n * Successful response from the /api/v1/query endpoint\n */\nexport interface QueryApiSuccessResponse {\n success: true;\n response: string;\n toolsUsed: QueryToolUsage[];\n cost: QueryCost;\n durationMs: number;\n}\n\n/**\n * Raw API response from the query endpoint\n */\nexport type QueryApiResponse = QueryApiSuccessResponse | ExecuteApiErrorResponse;\n\n// ---------------------------------------------------------------------------\n// Query stream event types\n// ---------------------------------------------------------------------------\n\n/** Emitted when a tool starts or changes execution status */\nexport interface QueryStreamToolStatusEvent {\n type: \"tool-status\";\n tool: { id: string; name: string };\n status: string;\n}\n\n/** Emitted for each chunk of the AI response text */\nexport interface QueryStreamTextDeltaEvent {\n type: \"text-delta\";\n delta: string;\n}\n\n/** Emitted when the full response is complete */\nexport interface QueryStreamDoneEvent {\n type: \"done\";\n result: QueryResult;\n}\n\n/**\n * Union of all events emitted during a streaming query\n */\nexport type QueryStreamEvent =\n | QueryStreamToolStatusEvent\n | QueryStreamTextDeltaEvent\n | QueryStreamDoneEvent;\n\n// ---------------------------------------------------------------------------\n// Error types\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 | \"query_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 Object.setPrototypeOf(this, ContextError.prototype);\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 spending cap not set\n * @throws {ContextError} With code `payment_failed` if payment settlement 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 undefined, // Don't hardcode - this was a 200 OK with error body\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 {\n QueryOptions,\n QueryApiResponse,\n QueryResult,\n QueryStreamEvent,\n} from \"../types.js\";\nimport { ContextError } from \"../types.js\";\nimport type { ContextClient } from \"../client.js\";\n\n/**\n * Query resource for pay-per-response agentic queries.\n *\n * Unlike `tools.execute()` which calls a single tool once (pay-per-request),\n * the Query resource sends a natural-language question and lets the server\n * handle tool discovery, multi-tool orchestration, self-healing retries,\n * completeness checks, and AI synthesis — all for one flat fee.\n *\n * This is the \"prepared meal\" vs \"raw ingredients\" distinction:\n * - `tools.execute()` = raw data, full control, predictable cost\n * - `query.run()` / `query.stream()` = curated intelligence, one payment\n */\nexport class Query {\n constructor(private client: ContextClient) {}\n\n /**\n * Run an agentic query and wait for the full response.\n *\n * The server discovers relevant tools (or uses the ones you specify),\n * executes the full agentic pipeline (up to 100 MCP calls per tool),\n * and returns an AI-synthesized answer. Payment is settled after\n * successful execution via deferred settlement.\n *\n * @param options - Query options or a plain string question\n * @returns The complete query result with response text, tools used, and cost\n *\n * @throws {ContextError} With code `no_wallet` if wallet not set up\n * @throws {ContextError} With code `insufficient_allowance` if spending cap not set\n * @throws {ContextError} With code `payment_failed` if payment settlement fails\n * @throws {ContextError} With code `execution_failed` if the agentic pipeline fails\n *\n * @example\n * ```typescript\n * // Simple question — server discovers tools automatically\n * const answer = await client.query.run(\"What are the top whale movements on Base?\");\n * console.log(answer.response); // AI-synthesized answer\n * console.log(answer.toolsUsed); // Which tools were used\n * console.log(answer.cost); // Cost breakdown\n *\n * // With specific tools (Manual Mode)\n * const answer = await client.query.run({\n * query: \"Analyze whale activity\",\n * tools: [\"tool-uuid-1\", \"tool-uuid-2\"],\n * });\n * ```\n */\n async run(options: QueryOptions | string): Promise<QueryResult> {\n const opts = typeof options === \"string\" ? { query: options } : options;\n\n const response = await this.client._fetch<QueryApiResponse>(\n \"/api/v1/query\",\n {\n method: \"POST\",\n body: JSON.stringify({\n query: opts.query,\n tools: opts.tools,\n stream: false,\n }),\n }\n );\n\n // Handle error response\n if (\"error\" in response) {\n throw new ContextError(\n response.error,\n response.code,\n undefined,\n response.helpUrl\n );\n }\n\n // Handle success response\n if (response.success) {\n return {\n response: response.response,\n toolsUsed: response.toolsUsed,\n cost: response.cost,\n durationMs: response.durationMs,\n };\n }\n\n throw new ContextError(\"Unexpected response format from query API\");\n }\n\n /**\n * Run an agentic query with streaming. Returns an async iterable that\n * yields events as the server processes the query in real-time.\n *\n * Event types:\n * - `tool-status` — A tool started executing or changed status\n * - `text-delta` — A chunk of the AI response text\n * - `done` — The full response is complete (includes final `QueryResult`)\n *\n * @param options - Query options or a plain string question\n * @returns An async iterable of stream events\n *\n * @example\n * ```typescript\n * for await (const event of client.query.stream(\"What are the top whale movements?\")) {\n * switch (event.type) {\n * case \"tool-status\":\n * console.log(`Tool ${event.tool.name}: ${event.status}`);\n * break;\n * case \"text-delta\":\n * process.stdout.write(event.delta);\n * break;\n * case \"done\":\n * console.log(\"\\nCost:\", event.result.cost.totalCostUsd);\n * break;\n * }\n * }\n * ```\n */\n async *stream(\n options: QueryOptions | string\n ): AsyncGenerator<QueryStreamEvent> {\n const opts = typeof options === \"string\" ? { query: options } : options;\n\n const response = await this.client._fetchRaw(\"/api/v1/query\", {\n method: \"POST\",\n body: JSON.stringify({\n query: opts.query,\n tools: opts.tools,\n stream: true,\n }),\n });\n\n const body = response.body;\n if (!body) {\n throw new ContextError(\"No response body for streaming query\");\n }\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (trimmed.startsWith(\"data: \")) {\n const data = trimmed.slice(6);\n if (data === \"[DONE]\") return;\n try {\n yield JSON.parse(data) as QueryStreamEvent;\n } catch {\n // Skip malformed SSE events\n }\n }\n }\n }\n\n // Process any remaining buffer\n if (buffer.trim().startsWith(\"data: \")) {\n const data = buffer.trim().slice(6);\n if (data !== \"[DONE]\") {\n try {\n yield JSON.parse(data) as QueryStreamEvent;\n } catch {\n // Skip malformed SSE events\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\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\";\nimport { Query } from \"./resources/query.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 * // Pay-per-request: Execute a specific tool\n * const result = await client.tools.execute({\n * toolId: \"tool-uuid\",\n * toolName: \"get_gas_prices\",\n * args: { chainId: 1 }\n * });\n *\n * // Pay-per-response: Ask a question, get a curated answer\n * const answer = await client.query.run(\"What are the top whale movements on Base?\");\n * console.log(answer.response);\n * ```\n */\nexport class ContextClient {\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private _closed = false;\n\n /**\n * Discovery resource for searching tools\n */\n public readonly discovery: Discovery;\n\n /**\n * Tools resource for executing tools (pay-per-request)\n */\n public readonly tools: Tools;\n\n /**\n * Query resource for agentic queries (pay-per-response).\n *\n * Unlike `tools.execute()` which calls a single tool once, `query` sends\n * a natural-language question and lets the server handle tool discovery,\n * multi-tool orchestration, self-healing, and AI synthesis — one flat fee.\n */\n public readonly query: Query;\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 this.query = new Query(this);\n }\n\n /**\n * Close the client and clean up resources.\n * After calling close(), any in-flight requests may be aborted.\n */\n close(): void {\n this._closed = true;\n }\n\n /**\n * Internal method for making authenticated HTTP requests\n * Includes timeout (30s) and retry with exponential backoff for transient errors\n *\n * @internal\n */\n async _fetch<T>(endpoint: string, options: RequestInit = {}): Promise<T> {\n if (this._closed) {\n throw new ContextError(\"Client has been closed\");\n }\n\n const url = `${this.baseUrl}${endpoint}`;\n const maxRetries = 3;\n const timeoutMs = 30_000;\n\n let lastError: Error | undefined;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`,\n ...options.headers,\n },\n });\n\n clearTimeout(timeout);\n\n if (!response.ok) {\n // Retry on 5xx server errors\n if (response.status >= 500 && attempt < maxRetries) {\n const delay = Math.min(1000 * 2 ** attempt, 10_000);\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\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 } catch (error) {\n clearTimeout(timeout);\n\n if (error instanceof ContextError) {\n throw error;\n }\n\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Retry on network errors and timeouts\n const isRetryable =\n lastError.name === \"AbortError\" ||\n lastError.message.includes(\"fetch failed\") ||\n lastError.message.includes(\"ECONNRESET\") ||\n lastError.message.includes(\"ETIMEDOUT\");\n\n if (isRetryable && attempt < maxRetries) {\n const delay = Math.min(1000 * 2 ** attempt, 10_000);\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n if (lastError.name === \"AbortError\") {\n throw new ContextError(\n `Request timed out after ${timeoutMs / 1000}s`,\n undefined,\n 408\n );\n }\n\n throw new ContextError(\n lastError.message,\n undefined,\n undefined\n );\n }\n }\n\n throw lastError ?? new ContextError(\"Request failed after retries\");\n }\n\n /**\n * Internal method for making authenticated HTTP requests that returns\n * the raw Response object. Used for streaming endpoints (SSE).\n *\n * @internal\n */\n async _fetchRaw(endpoint: string, options: RequestInit = {}): Promise<Response> {\n if (this._closed) {\n throw new ContextError(\"Client has been closed\");\n }\n\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;\n }\n}\n","/**\n * Context types for portfolio and protocol data injection.\n *\n * These types allow MCP tools to receive personalized user context\n * (wallet addresses, positions, balances) for analysis.\n *\n * =============================================================================\n * DECLARING CONTEXT REQUIREMENTS\n * =============================================================================\n *\n * Context requirements are declared via `_meta.contextRequirements` at the tool level.\n * This is the primary mechanism that the Context Platform reads.\n *\n * Previously, `x-context-requirements` in inputSchema was recommended, but the MCP SDK\n * may strip extension properties during transport. Use `_meta` instead.\n *\n * @example\n * ```typescript\n * import { CONTEXT_REQUIREMENTS_KEY, type ContextRequirementType } from \"@ctxprotocol/sdk\";\n * import type { HyperliquidContext } from \"@ctxprotocol/sdk\";\n *\n * const tool = {\n * name: \"analyze_my_positions\",\n * _meta: {\n * contextRequirements: [\"hyperliquid\"] as ContextRequirementType[],\n * },\n * inputSchema: {\n * type: \"object\",\n * properties: {\n * portfolio: { type: \"object\" }\n * },\n * required: [\"portfolio\"]\n * }\n * };\n *\n * // Your handler receives the injected context:\n * function handleAnalyzeMyPositions(args: { portfolio: HyperliquidContext }) {\n * const { perpPositions, accountSummary } = args.portfolio;\n * // ... analyze and return insights\n * }\n * ```\n *\n * @packageDocumentation\n */\n\n// Wallet context types\nexport * from \"./wallet.js\";\n\n// Protocol-specific context types\nexport * from \"./polymarket.js\";\nexport * from \"./hyperliquid.js\";\n\n// Re-import for composite type\nimport type { WalletContext, ERC20Context } from \"./wallet.js\";\nimport type { PolymarketContext } from \"./polymarket.js\";\nimport type { HyperliquidContext } from \"./hyperliquid.js\";\n\n// ============================================================================\n// CONTEXT REQUIREMENTS\n//\n// MCP tools that need user portfolio data MUST declare this in inputSchema.\n// The MCP protocol only transmits standard fields (name, description,\n// inputSchema, outputSchema). Custom fields get stripped by the MCP SDK.\n// ============================================================================\n\n/**\n * @deprecated Use `_meta.contextRequirements` instead (see META_CONTEXT_REQUIREMENTS_KEY).\n *\n * This key was designed for embedding requirements in inputSchema,\n * but the MCP SDK may strip `x-` prefixed extension properties during transport.\n * The `_meta.contextRequirements` approach is what the Context Platform reads.\n */\nexport const CONTEXT_REQUIREMENTS_KEY = \"x-context-requirements\" as const;\n\n/**\n * The key used inside `_meta` to declare context requirements.\n * This is the PRIMARY mechanism — the Context Platform reads `_meta.contextRequirements`.\n *\n * @example\n * ```typescript\n * const tool = {\n * name: \"analyze_my_positions\",\n * _meta: {\n * [META_CONTEXT_REQUIREMENTS_KEY]: [\"hyperliquid\"] as ContextRequirementType[],\n * },\n * inputSchema: {\n * type: \"object\",\n * properties: { portfolio: { type: \"object\" } },\n * required: [\"portfolio\"]\n * }\n * };\n * ```\n */\nexport const META_CONTEXT_REQUIREMENTS_KEY = \"contextRequirements\" as const;\n\n/**\n * Context requirement types supported by the Context marketplace.\n * Maps to protocol-specific context builders on the platform.\n *\n * @example\n * ```typescript\n * inputSchema: {\n * type: \"object\",\n * \"x-context-requirements\": [\"hyperliquid\"] as ContextRequirementType[],\n * properties: { portfolio: { type: \"object\" } },\n * required: [\"portfolio\"]\n * }\n * ```\n */\nexport type ContextRequirementType = \"polymarket\" | \"hyperliquid\" | \"wallet\";\n\n/**\n * @deprecated The `requirements` field at tool level gets stripped by MCP SDK.\n * Use `x-context-requirements` inside `inputSchema` instead.\n *\n * @example\n * ```typescript\n * // ❌ OLD (doesn't work - stripped by MCP SDK)\n * { requirements: { context: [\"hyperliquid\"] } }\n *\n * // ✅ NEW (works - preserved through MCP transport)\n * { inputSchema: { \"x-context-requirements\": [\"hyperliquid\"], ... } }\n * ```\n */\nexport interface ToolRequirements {\n /**\n * @deprecated Use `x-context-requirements` in inputSchema instead.\n */\n context?: ContextRequirementType[];\n}\n\n/**\n * Composite context for tools that need multiple data sources.\n *\n * This is the unified structure that can be passed to MCP tools\n * to provide comprehensive user context.\n */\nexport interface UserContext {\n /** Base wallet information */\n wallet?: WalletContext;\n /** ERC20 token holdings */\n erc20?: ERC20Context;\n /** Polymarket positions and orders */\n polymarket?: PolymarketContext;\n /** Hyperliquid perpetual positions and account data */\n hyperliquid?: HyperliquidContext;\n // Future protocols:\n // aave?: AaveContext;\n}\n","import { jwtVerify, importSPKI, type JWTPayload } from \"jose\";\nimport { ContextError } from \"../client/types.js\";\n\n// ============================================================================\n// Express-compatible types (avoid requiring express as a dependency)\n// ============================================================================\n\ninterface ContextRequest {\n headers: {\n authorization?: string;\n [key: string]: string | string[] | undefined;\n };\n body?: {\n method?: string;\n [key: string]: unknown;\n };\n context?: JWTPayload;\n}\n\ninterface ContextResponse {\n status(code: number): ContextResponse;\n json(data: unknown): void;\n}\n\ntype NextFunction = (error?: unknown) => void;\n\n/**\n * Extended Request object with verified Context Protocol JWT payload.\n *\n * After `createContextMiddleware()` runs successfully on a protected method,\n * the `context` property contains the decoded JWT claims.\n */\nexport interface ContextMiddlewareRequest extends ContextRequest {\n /** The verified JWT payload from Context Protocol (available after auth) */\n context?: JWTPayload;\n}\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\n// The Context Protocol Public Key\n// In a real scenario, this might be fetched from a well-known URL or passed in config.\n// For now, we hardcode the Official Platform Public Key.\n// Official Context Protocol Platform Public Key (RS256)\nconst CONTEXT_PLATFORM_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAs9YOgdpkmVQ5aoNovjsu\nchJdV54OT7dUdbVXz914a7Px8EwnpDqhsvG7WO8xL8sj2Rn6ueAJBk+04Hy/P/UN\nRJyp23XL5TsGmb4rbfg0ii0MiL2nbVXuqvAe3JSM2BOFZR5bpwIVIaa8aonfamUy\nVXGc7OosF90ThdKjm9cXlVM+kV6IgSWc1502X7M3abQqRcTU/rluVXnky0eiWDQa\nlfOKbr7w0u72dZjiZPwnNDsX6PEEgvfmoautTFYTQgnZjDzq8UimTcv3KF+hJ5Ep\nweipe6amt9lzQzi8WXaFKpOXHQs//WDlUytz/Hl8pvd5craZKzo6Kyrg1Vfan7H3\nTQIDAQAB\n-----END PUBLIC KEY-----`;\n\n// ============================================================================\n// JWKS Key Fetching (with hardcoded fallback)\n// ============================================================================\n\nconst JWKS_URL = \"https://ctxprotocol.com/.well-known/jwks.json\";\nconst KEY_CACHE_TTL_MS = 3_600_000; // 1 hour\n\nlet cachedPublicKey: Awaited<ReturnType<typeof importSPKI>> | null = null;\nlet cacheTimestamp = 0;\n\n/**\n * Get the platform public key, trying JWKS endpoint first with hardcoded fallback.\n * Caches the result for 1 hour.\n */\nasync function getPlatformPublicKey(): Promise<Awaited<ReturnType<typeof importSPKI>>> {\n const now = Date.now();\n\n // Return cached key if still valid\n if (cachedPublicKey && now - cacheTimestamp < KEY_CACHE_TTL_MS) {\n return cachedPublicKey;\n }\n\n // Try JWKS endpoint first\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 5000);\n\n const response = await fetch(JWKS_URL, { signal: controller.signal });\n clearTimeout(timeout);\n\n if (response.ok) {\n const jwks = await response.json() as { keys?: Array<{ x5c?: string[]; kty?: string; n?: string; e?: string }> };\n if (jwks.keys && jwks.keys.length > 0) {\n const key = jwks.keys[0];\n // If the JWKS contains x5c (X.509 cert chain), extract the public key\n if (key.x5c && key.x5c.length > 0) {\n const pem = `-----BEGIN CERTIFICATE-----\\n${key.x5c[0]}\\n-----END CERTIFICATE-----`;\n const { importX509 } = await import(\"jose\");\n cachedPublicKey = await importX509(pem, \"RS256\");\n cacheTimestamp = now;\n return cachedPublicKey;\n }\n }\n }\n } catch {\n // JWKS fetch failed - fall back to hardcoded key\n }\n\n // Fallback: use hardcoded key\n cachedPublicKey = await importSPKI(CONTEXT_PLATFORM_PUBLIC_KEY_PEM, \"RS256\");\n cacheTimestamp = now;\n return cachedPublicKey;\n}\n\n/**\n * MCP methods that require authentication.\n * - tools/call: Executes tool logic, may cost money\n * - resources/read: Reads potentially sensitive data\n * - prompts/get: Gets prompt content\n */\nconst PROTECTED_MCP_METHODS = new Set([\n \"tools/call\",\n // Uncomment these if you want to protect resource/prompt access:\n // \"resources/read\",\n // \"prompts/get\",\n]);\n\n/**\n * MCP methods that are always open (no auth required).\n * These are discovery/listing operations that return metadata only.\n */\nconst OPEN_MCP_METHODS = new Set([\n \"initialize\",\n \"tools/list\",\n \"resources/list\",\n \"prompts/list\",\n \"ping\",\n \"notifications/initialized\",\n]);\n\n// ============================================================================\n// Method Classification\n// ============================================================================\n\n/**\n * Determines if a given MCP method requires authentication.\n *\n * Discovery methods (tools/list, resources/list, etc.) are open.\n * Execution methods (tools/call) require authentication.\n *\n * @param method The MCP JSON-RPC method (e.g., \"tools/list\", \"tools/call\")\n * @returns true if the method requires authentication\n *\n * @example\n * ```typescript\n * if (isProtectedMcpMethod(body.method)) {\n * await verifyContextRequest({ authorizationHeader: req.headers.authorization });\n * }\n * ```\n */\nexport function isProtectedMcpMethod(method: string): boolean {\n return PROTECTED_MCP_METHODS.has(method);\n}\n\n/**\n * Determines if a given MCP method is explicitly open (no auth).\n *\n * @param method The MCP JSON-RPC method\n * @returns true if the method is known to be open\n */\nexport function isOpenMcpMethod(method: string): boolean {\n return OPEN_MCP_METHODS.has(method);\n}\n\n// ============================================================================\n// Request Verification\n// ============================================================================\n\nexport interface VerifyRequestOptions {\n /** The full Authorization header string (e.g. \"Bearer eyJ...\") */\n authorizationHeader?: string;\n /** Expected Audience (your tool URL) for stricter validation */\n audience?: string;\n}\n\n/**\n * Verifies that an incoming request originated from the Context Protocol Platform.\n *\n * @param options Contains the Authorization header\n * @returns The decoded payload if valid\n * @throws ContextError if invalid\n */\nexport async function verifyContextRequest(options: VerifyRequestOptions) {\n const { authorizationHeader, audience } = options;\n\n if (!authorizationHeader || !authorizationHeader.startsWith(\"Bearer \")) {\n throw new ContextError(\n \"Missing or invalid Authorization header\",\n \"unauthorized\",\n 401\n );\n }\n\n const token = authorizationHeader.split(\" \")[1];\n\n try {\n const publicKey = await getPlatformPublicKey();\n\n const { payload } = await jwtVerify(token, publicKey, {\n issuer: \"https://ctxprotocol.com\",\n audience: audience,\n });\n\n return payload;\n } catch (error) {\n throw new ContextError(\n \"Invalid Context Protocol signature\",\n \"unauthorized\",\n 401\n );\n }\n}\n\n// ============================================================================\n// Easy-Mode Middleware\n// ============================================================================\n\nexport interface CreateContextMiddlewareOptions {\n /** Expected Audience (your tool URL) for stricter validation */\n audience?: string;\n}\n\n/**\n * Creates an Express/Connect-compatible middleware that secures your MCP endpoint.\n *\n * This is the \"1 line of code\" solution to secure your MCP server.\n * It automatically:\n * - Allows discovery methods (tools/list, initialize) without authentication\n * - Requires and verifies JWT for execution methods (tools/call)\n * - Attaches the verified payload to `req.context` for downstream use\n *\n * @param options Optional configuration\n * @returns Express-compatible middleware function\n *\n * @example\n * ```typescript\n * import express from \"express\";\n * import { createContextMiddleware } from \"@ctxprotocol/sdk\";\n *\n * const app = express();\n * app.use(express.json());\n *\n * // 1 line to secure your endpoint\n * app.use(\"/mcp\", createContextMiddleware());\n *\n * app.post(\"/mcp\", (req, res) => {\n * // req.context contains verified JWT payload (on protected methods)\n * // Handle MCP request...\n * });\n * ```\n */\nexport function createContextMiddleware(options: CreateContextMiddlewareOptions = {}) {\n return async function contextMiddleware(\n req: ContextRequest,\n res: ContextResponse,\n next: NextFunction\n ): Promise<void> {\n const method = req.body?.method as string | undefined;\n\n // Allow discovery methods without authentication\n // Discovery methods (tools/list, initialize, etc.) are open by design\n if (!method || !isProtectedMcpMethod(method)) {\n return next();\n }\n\n // Protected method - require authentication\n try {\n const payload = await verifyContextRequest({\n authorizationHeader: req.headers.authorization,\n audience: options.audience,\n });\n\n // Attach verified payload to request for downstream handlers\n req.context = payload;\n next();\n } catch (error) {\n const statusCode = error instanceof ContextError ? error.statusCode || 401 : 401;\n res.status(statusCode).json({ error: \"Unauthorized\" });\n }\n };\n}\n\n\n","/**\n * Handshake Types for MCP Tool Developers\n *\n * Use these types when your tool needs to request user interaction\n * before completing an action (signatures, transactions, OAuth).\n *\n * @see https://docs.ctxprotocol.com/guides/handshake-architecture\n *\n * ## Usage Pattern\n *\n * Tools return handshake actions in the `_meta.handshakeAction` field\n * of their MCP response. The Context platform intercepts these and\n * presents the appropriate UI to the user.\n *\n * ## Action Types\n *\n * - `signature_request`: For EIP-712 signatures (Hyperliquid, Polymarket, etc.)\n * - `transaction_proposal`: For direct on-chain transactions (Uniswap, NFT mints)\n * - `auth_required`: For OAuth flows (Discord, Twitter, etc.)\n */\n\n// === Shared Meta Type ===\n\nexport type HandshakeMeta = {\n /** Human-readable description of the action */\n description: string;\n /** Protocol name (e.g., \"Hyperliquid\", \"Polymarket\") */\n protocol?: string;\n /** Action verb (e.g., \"Place Order\", \"Place Bid\") */\n action?: string;\n /** Token symbol if relevant */\n tokenSymbol?: string;\n /** Human-readable token amount */\n tokenAmount?: string;\n /** UI warning level */\n warningLevel?: \"info\" | \"caution\" | \"danger\";\n /** Custom title for the signature card (marketplace-friendly, overrides action-based title) */\n title?: string;\n /** Custom subtitle for the signature card (overrides tool name display) */\n subtitle?: string;\n};\n\n// === Web3: Signature Requests (for proxy wallet platforms) ===\n\nexport type EIP712Domain = {\n /** Domain name (e.g., \"Hyperliquid\", \"ClobAuthDomain\") */\n name: string;\n /** Domain version */\n version: string;\n /** Chain ID (informational - signing is chain-agnostic) */\n chainId: number;\n /** Optional verifying contract address */\n verifyingContract?: `0x${string}`;\n};\n\nexport type EIP712TypeField = {\n name: string;\n type: string;\n};\n\n/**\n * Signature Request\n *\n * Use this for platforms with proxy wallets (Hyperliquid, Polymarket, dYdX).\n *\n * Benefits:\n * - No gas required (user signs a message, not a transaction)\n * - No network switching needed (signing is chain-agnostic)\n * - Works with Privy embedded wallets on any chain\n *\n * @example\n * ```typescript\n * return {\n * structuredContent: {\n * _meta: {\n * handshakeAction: createSignatureRequest({\n * domain: { name: \"Hyperliquid\", version: \"1\", chainId: 42161 },\n * types: { Order: [...] },\n * primaryType: \"Order\",\n * message: { asset: 4, isBuy: true, ... },\n * meta: { description: \"Place Long ETH order\", protocol: \"Hyperliquid\" }\n * })\n * }\n * }\n * };\n * ```\n */\nexport type SignatureRequest = {\n _action: \"signature_request\";\n /** EIP-712 domain separator */\n domain: EIP712Domain;\n /** EIP-712 type definitions */\n types: Record<string, EIP712TypeField[]>;\n /** The primary type being signed */\n primaryType: string;\n /** The message data to sign */\n message: Record<string, unknown>;\n /** UI metadata for the approval card */\n meta?: HandshakeMeta;\n /**\n * Optional: Tool name to call with the signature result.\n * If provided, the platform will call this tool with { signature, originalParams }\n * after the user signs.\n */\n callbackToolName?: string;\n};\n\n// === Web3: Transaction Proposals (for direct on-chain actions) ===\n\nexport type TransactionProposalMeta = HandshakeMeta & {\n /** Estimated gas cost (informational - Context may sponsor) */\n estimatedGas?: string;\n /** Link to contract on block explorer */\n explorerUrl?: string;\n};\n\n/**\n * Transaction Proposal\n *\n * Use this for protocols without proxy wallets (Uniswap, NFT mints, etc.).\n *\n * Note: May require network switching and gas fees.\n *\n * @example\n * ```typescript\n * return {\n * structuredContent: {\n * _meta: {\n * handshakeAction: createTransactionProposal({\n * chainId: 8453,\n * to: \"0x...\",\n * data: \"0x...\",\n * meta: { description: \"Swap 100 USDC for ETH\", protocol: \"Uniswap\" }\n * })\n * }\n * }\n * };\n * ```\n */\nexport type TransactionProposal = {\n _action: \"transaction_proposal\";\n /** EVM chain ID (e.g., 137 for Polygon, 8453 for Base) */\n chainId: number;\n /** Target contract address */\n to: `0x${string}`;\n /** Encoded calldata */\n data: `0x${string}`;\n /** Wei to send (as string, default \"0\") */\n value?: string;\n /** UI metadata for the approval card */\n meta?: TransactionProposalMeta;\n};\n\n// === Web2: OAuth Requests ===\n\nexport type AuthRequiredMeta = {\n /** Human-friendly service name */\n displayName?: string;\n /** Permissions being requested */\n scopes?: string[];\n /** Description of what access is needed */\n description?: string;\n /** Tool's icon URL */\n iconUrl?: string;\n /** How long authorization lasts */\n expiresIn?: string;\n};\n\n/**\n * Auth Required\n *\n * Use this when your tool needs the user to authenticate with an external service.\n *\n * @example\n * ```typescript\n * if (!hasUserToken(contextDid)) {\n * return {\n * structuredContent: {\n * _meta: {\n * handshakeAction: createAuthRequired({\n * provider: \"discord\",\n * authUrl: \"https://your-server.com/oauth/discord\",\n * meta: { displayName: \"Discord Bot\", scopes: [\"send_messages\"] }\n * })\n * }\n * }\n * };\n * }\n * ```\n */\nexport type AuthRequired = {\n _action: \"auth_required\";\n /** Service identifier (e.g., \"discord\", \"slack\") */\n provider: string;\n /** Your OAuth initiation endpoint (MUST be HTTPS) */\n authUrl: string;\n /** UI metadata for the auth card */\n meta?: AuthRequiredMeta;\n};\n\n// === Union Type ===\n\nexport type HandshakeAction =\n | SignatureRequest\n | TransactionProposal\n | AuthRequired;\n\n// === Type Guards ===\n\nexport function isHandshakeAction(value: unknown): value is HandshakeAction {\n return (\n typeof value === \"object\" &&\n value !== null &&\n \"_action\" in value &&\n ((value as { _action: string })._action === \"signature_request\" ||\n (value as { _action: string })._action === \"transaction_proposal\" ||\n (value as { _action: string })._action === \"auth_required\")\n );\n}\n\nexport function isSignatureRequest(value: unknown): value is SignatureRequest {\n return isHandshakeAction(value) && value._action === \"signature_request\";\n}\n\nexport function isTransactionProposal(\n value: unknown\n): value is TransactionProposal {\n return isHandshakeAction(value) && value._action === \"transaction_proposal\";\n}\n\nexport function isAuthRequired(value: unknown): value is AuthRequired {\n return isHandshakeAction(value) && value._action === \"auth_required\";\n}\n\n// === Helper Functions for Tool Developers ===\n\n/**\n * Create a signature request response.\n * Return this from your tool when you need the user to sign EIP-712 typed data.\n *\n * Use this for platforms with proxy wallets (Hyperliquid, Polymarket, dYdX).\n * Benefits: No gas required, no network switching needed.\n */\nexport function createSignatureRequest(\n params: Omit<SignatureRequest, \"_action\">\n): SignatureRequest {\n return {\n _action: \"signature_request\",\n ...params,\n };\n}\n\n/**\n * Create a transaction proposal response.\n * Return this from your tool when you need the user to sign a direct on-chain transaction.\n *\n * Use this for protocols that don't use proxy wallets (Uniswap, NFT mints, etc.).\n * Note: May require network switching and gas.\n */\nexport function createTransactionProposal(\n params: Omit<TransactionProposal, \"_action\">\n): TransactionProposal {\n return {\n _action: \"transaction_proposal\",\n ...params,\n };\n}\n\n/**\n * Create an auth required response.\n * Return this from your tool when you need the user to authenticate via OAuth.\n */\nexport function createAuthRequired(\n params: Omit<AuthRequired, \"_action\">\n): AuthRequired {\n return {\n _action: \"auth_required\",\n ...params,\n };\n}\n\n// === MCP Response Helper ===\n\n/**\n * Wrap a handshake action in the proper MCP response format.\n *\n * MCP tools should return handshake actions in `_meta.handshakeAction` to prevent\n * the MCP SDK from stripping unknown fields.\n *\n * @example\n * ```typescript\n * // In your tool handler:\n * return wrapHandshakeResponse(createSignatureRequest({\n * domain: { name: \"Hyperliquid\", version: \"1\", chainId: 42161 },\n * types: { Order: [...] },\n * primaryType: \"Order\",\n * message: orderData,\n * meta: { description: \"Place order\", protocol: \"Hyperliquid\" }\n * }));\n * ```\n */\nexport function wrapHandshakeResponse(action: HandshakeAction): {\n content: Array<{ type: \"text\"; text: string }>;\n structuredContent: {\n _meta: { handshakeAction: HandshakeAction };\n status: string;\n message: string;\n };\n} {\n const actionType = action._action.replace(\"_\", \" \");\n return {\n content: [\n {\n type: \"text\",\n text: `Handshake required: ${actionType}. Please approve in the Context app.`,\n },\n ],\n structuredContent: {\n _meta: {\n handshakeAction: action,\n },\n status: \"handshake_required\",\n message: action.meta?.description ?? `${actionType} required`,\n },\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextClient, ContextClientOptions, ContextError, ContextErrorCode, Discovery, ExecuteApiErrorResponse, ExecuteApiResponse, ExecuteApiSuccessResponse, ExecuteOptions, ExecutionResult, McpTool, SearchOptions, SearchResponse, Tool, Tools } from './client/index.cjs';
|
|
1
|
+
export { ContextClient, ContextClientOptions, ContextError, ContextErrorCode, Discovery, ExecuteApiErrorResponse, ExecuteApiResponse, ExecuteApiSuccessResponse, ExecuteOptions, ExecutionResult, McpTool, Query, QueryApiResponse, QueryApiSuccessResponse, QueryCost, QueryOptions, QueryResult, QueryStreamDoneEvent, QueryStreamEvent, QueryStreamTextDeltaEvent, QueryStreamToolStatusEvent, QueryToolUsage, SearchOptions, SearchResponse, Tool, Tools } from './client/index.cjs';
|
|
2
2
|
import { JWTPayload } from 'jose';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -90,8 +90,14 @@ interface PolymarketOrder {
|
|
|
90
90
|
* This is what gets passed to MCP tools for personalized analysis.
|
|
91
91
|
*/
|
|
92
92
|
interface PolymarketContext {
|
|
93
|
-
/** The wallet address this context is for */
|
|
93
|
+
/** The wallet address this context is for (may be comma-separated if multiple) */
|
|
94
94
|
walletAddress: string;
|
|
95
|
+
/**
|
|
96
|
+
* The active wallet address for signing (the one with Polymarket activity).
|
|
97
|
+
* When multiple wallets are linked, this is the wallet that should be used
|
|
98
|
+
* for placing orders. Determined by activity detection on the client.
|
|
99
|
+
*/
|
|
100
|
+
activeWalletAddress?: string;
|
|
95
101
|
/** All open positions */
|
|
96
102
|
positions: PolymarketPosition[];
|
|
97
103
|
/** All open orders */
|
|
@@ -228,9 +234,11 @@ interface HyperliquidContext {
|
|
|
228
234
|
* DECLARING CONTEXT REQUIREMENTS
|
|
229
235
|
* =============================================================================
|
|
230
236
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
237
|
+
* Context requirements are declared via `_meta.contextRequirements` at the tool level.
|
|
238
|
+
* This is the primary mechanism that the Context Platform reads.
|
|
239
|
+
*
|
|
240
|
+
* Previously, `x-context-requirements` in inputSchema was recommended, but the MCP SDK
|
|
241
|
+
* may strip extension properties during transport. Use `_meta` instead.
|
|
234
242
|
*
|
|
235
243
|
* @example
|
|
236
244
|
* ```typescript
|
|
@@ -239,9 +247,11 @@ interface HyperliquidContext {
|
|
|
239
247
|
*
|
|
240
248
|
* const tool = {
|
|
241
249
|
* name: "analyze_my_positions",
|
|
250
|
+
* _meta: {
|
|
251
|
+
* contextRequirements: ["hyperliquid"] as ContextRequirementType[],
|
|
252
|
+
* },
|
|
242
253
|
* inputSchema: {
|
|
243
254
|
* type: "object",
|
|
244
|
-
* [CONTEXT_REQUIREMENTS_KEY]: ["hyperliquid"] as ContextRequirementType[],
|
|
245
255
|
* properties: {
|
|
246
256
|
* portfolio: { type: "object" }
|
|
247
257
|
* },
|
|
@@ -260,30 +270,33 @@ interface HyperliquidContext {
|
|
|
260
270
|
*/
|
|
261
271
|
|
|
262
272
|
/**
|
|
263
|
-
*
|
|
273
|
+
* @deprecated Use `_meta.contextRequirements` instead (see META_CONTEXT_REQUIREMENTS_KEY).
|
|
264
274
|
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
|
|
269
|
-
|
|
275
|
+
* This key was designed for embedding requirements in inputSchema,
|
|
276
|
+
* but the MCP SDK may strip `x-` prefixed extension properties during transport.
|
|
277
|
+
* The `_meta.contextRequirements` approach is what the Context Platform reads.
|
|
278
|
+
*/
|
|
279
|
+
declare const CONTEXT_REQUIREMENTS_KEY: "x-context-requirements";
|
|
280
|
+
/**
|
|
281
|
+
* The key used inside `_meta` to declare context requirements.
|
|
282
|
+
* This is the PRIMARY mechanism — the Context Platform reads `_meta.contextRequirements`.
|
|
270
283
|
*
|
|
271
284
|
* @example
|
|
272
285
|
* ```typescript
|
|
273
|
-
* import { CONTEXT_REQUIREMENTS_KEY } from "@ctxprotocol/sdk";
|
|
274
|
-
*
|
|
275
286
|
* const tool = {
|
|
276
287
|
* name: "analyze_my_positions",
|
|
288
|
+
* _meta: {
|
|
289
|
+
* [META_CONTEXT_REQUIREMENTS_KEY]: ["hyperliquid"] as ContextRequirementType[],
|
|
290
|
+
* },
|
|
277
291
|
* inputSchema: {
|
|
278
292
|
* type: "object",
|
|
279
|
-
* [CONTEXT_REQUIREMENTS_KEY]: ["hyperliquid"],
|
|
280
293
|
* properties: { portfolio: { type: "object" } },
|
|
281
294
|
* required: ["portfolio"]
|
|
282
295
|
* }
|
|
283
296
|
* };
|
|
284
297
|
* ```
|
|
285
298
|
*/
|
|
286
|
-
declare const
|
|
299
|
+
declare const META_CONTEXT_REQUIREMENTS_KEY: "contextRequirements";
|
|
287
300
|
/**
|
|
288
301
|
* Context requirement types supported by the Context marketplace.
|
|
289
302
|
* Maps to protocol-specific context builders on the platform.
|
|
@@ -467,6 +480,10 @@ type HandshakeMeta = {
|
|
|
467
480
|
tokenAmount?: string;
|
|
468
481
|
/** UI warning level */
|
|
469
482
|
warningLevel?: "info" | "caution" | "danger";
|
|
483
|
+
/** Custom title for the signature card (marketplace-friendly, overrides action-based title) */
|
|
484
|
+
title?: string;
|
|
485
|
+
/** Custom subtitle for the signature card (overrides tool name display) */
|
|
486
|
+
subtitle?: string;
|
|
470
487
|
};
|
|
471
488
|
type EIP712Domain = {
|
|
472
489
|
/** Domain name (e.g., "Hyperliquid", "ClobAuthDomain") */
|
|
@@ -671,4 +688,4 @@ declare function wrapHandshakeResponse(action: HandshakeAction): {
|
|
|
671
688
|
};
|
|
672
689
|
};
|
|
673
690
|
|
|
674
|
-
export { type AuthRequired, type AuthRequiredMeta, CONTEXT_REQUIREMENTS_KEY, type ContextMiddlewareRequest, type ContextRequirementType, type CreateContextMiddlewareOptions, type EIP712Domain, type EIP712TypeField, type ERC20Context, type ERC20TokenBalance, type HandshakeAction, type HandshakeMeta, type HyperliquidAccountSummary, type HyperliquidContext, type HyperliquidOrder, type HyperliquidPerpPosition, type HyperliquidSpotBalance, type PolymarketContext, type PolymarketOrder, type PolymarketPosition, type SignatureRequest, type ToolRequirements, type TransactionProposal, type TransactionProposalMeta, type UserContext, type VerifyRequestOptions, type WalletContext, createAuthRequired, createContextMiddleware, createSignatureRequest, createTransactionProposal, isAuthRequired, isHandshakeAction, isOpenMcpMethod, isProtectedMcpMethod, isSignatureRequest, isTransactionProposal, verifyContextRequest, wrapHandshakeResponse };
|
|
691
|
+
export { type AuthRequired, type AuthRequiredMeta, CONTEXT_REQUIREMENTS_KEY, type ContextMiddlewareRequest, type ContextRequirementType, type CreateContextMiddlewareOptions, type EIP712Domain, type EIP712TypeField, type ERC20Context, type ERC20TokenBalance, type HandshakeAction, type HandshakeMeta, type HyperliquidAccountSummary, type HyperliquidContext, type HyperliquidOrder, type HyperliquidPerpPosition, type HyperliquidSpotBalance, META_CONTEXT_REQUIREMENTS_KEY, type PolymarketContext, type PolymarketOrder, type PolymarketPosition, type SignatureRequest, type ToolRequirements, type TransactionProposal, type TransactionProposalMeta, type UserContext, type VerifyRequestOptions, type WalletContext, createAuthRequired, createContextMiddleware, createSignatureRequest, createTransactionProposal, isAuthRequired, isHandshakeAction, isOpenMcpMethod, isProtectedMcpMethod, isSignatureRequest, isTransactionProposal, verifyContextRequest, wrapHandshakeResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { ContextClient, ContextClientOptions, ContextError, ContextErrorCode, Discovery, ExecuteApiErrorResponse, ExecuteApiResponse, ExecuteApiSuccessResponse, ExecuteOptions, ExecutionResult, McpTool, SearchOptions, SearchResponse, Tool, Tools } from './client/index.js';
|
|
1
|
+
export { ContextClient, ContextClientOptions, ContextError, ContextErrorCode, Discovery, ExecuteApiErrorResponse, ExecuteApiResponse, ExecuteApiSuccessResponse, ExecuteOptions, ExecutionResult, McpTool, Query, QueryApiResponse, QueryApiSuccessResponse, QueryCost, QueryOptions, QueryResult, QueryStreamDoneEvent, QueryStreamEvent, QueryStreamTextDeltaEvent, QueryStreamToolStatusEvent, QueryToolUsage, SearchOptions, SearchResponse, Tool, Tools } from './client/index.js';
|
|
2
2
|
import { JWTPayload } from 'jose';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -90,8 +90,14 @@ interface PolymarketOrder {
|
|
|
90
90
|
* This is what gets passed to MCP tools for personalized analysis.
|
|
91
91
|
*/
|
|
92
92
|
interface PolymarketContext {
|
|
93
|
-
/** The wallet address this context is for */
|
|
93
|
+
/** The wallet address this context is for (may be comma-separated if multiple) */
|
|
94
94
|
walletAddress: string;
|
|
95
|
+
/**
|
|
96
|
+
* The active wallet address for signing (the one with Polymarket activity).
|
|
97
|
+
* When multiple wallets are linked, this is the wallet that should be used
|
|
98
|
+
* for placing orders. Determined by activity detection on the client.
|
|
99
|
+
*/
|
|
100
|
+
activeWalletAddress?: string;
|
|
95
101
|
/** All open positions */
|
|
96
102
|
positions: PolymarketPosition[];
|
|
97
103
|
/** All open orders */
|
|
@@ -228,9 +234,11 @@ interface HyperliquidContext {
|
|
|
228
234
|
* DECLARING CONTEXT REQUIREMENTS
|
|
229
235
|
* =============================================================================
|
|
230
236
|
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
237
|
+
* Context requirements are declared via `_meta.contextRequirements` at the tool level.
|
|
238
|
+
* This is the primary mechanism that the Context Platform reads.
|
|
239
|
+
*
|
|
240
|
+
* Previously, `x-context-requirements` in inputSchema was recommended, but the MCP SDK
|
|
241
|
+
* may strip extension properties during transport. Use `_meta` instead.
|
|
234
242
|
*
|
|
235
243
|
* @example
|
|
236
244
|
* ```typescript
|
|
@@ -239,9 +247,11 @@ interface HyperliquidContext {
|
|
|
239
247
|
*
|
|
240
248
|
* const tool = {
|
|
241
249
|
* name: "analyze_my_positions",
|
|
250
|
+
* _meta: {
|
|
251
|
+
* contextRequirements: ["hyperliquid"] as ContextRequirementType[],
|
|
252
|
+
* },
|
|
242
253
|
* inputSchema: {
|
|
243
254
|
* type: "object",
|
|
244
|
-
* [CONTEXT_REQUIREMENTS_KEY]: ["hyperliquid"] as ContextRequirementType[],
|
|
245
255
|
* properties: {
|
|
246
256
|
* portfolio: { type: "object" }
|
|
247
257
|
* },
|
|
@@ -260,30 +270,33 @@ interface HyperliquidContext {
|
|
|
260
270
|
*/
|
|
261
271
|
|
|
262
272
|
/**
|
|
263
|
-
*
|
|
273
|
+
* @deprecated Use `_meta.contextRequirements` instead (see META_CONTEXT_REQUIREMENTS_KEY).
|
|
264
274
|
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
|
|
269
|
-
|
|
275
|
+
* This key was designed for embedding requirements in inputSchema,
|
|
276
|
+
* but the MCP SDK may strip `x-` prefixed extension properties during transport.
|
|
277
|
+
* The `_meta.contextRequirements` approach is what the Context Platform reads.
|
|
278
|
+
*/
|
|
279
|
+
declare const CONTEXT_REQUIREMENTS_KEY: "x-context-requirements";
|
|
280
|
+
/**
|
|
281
|
+
* The key used inside `_meta` to declare context requirements.
|
|
282
|
+
* This is the PRIMARY mechanism — the Context Platform reads `_meta.contextRequirements`.
|
|
270
283
|
*
|
|
271
284
|
* @example
|
|
272
285
|
* ```typescript
|
|
273
|
-
* import { CONTEXT_REQUIREMENTS_KEY } from "@ctxprotocol/sdk";
|
|
274
|
-
*
|
|
275
286
|
* const tool = {
|
|
276
287
|
* name: "analyze_my_positions",
|
|
288
|
+
* _meta: {
|
|
289
|
+
* [META_CONTEXT_REQUIREMENTS_KEY]: ["hyperliquid"] as ContextRequirementType[],
|
|
290
|
+
* },
|
|
277
291
|
* inputSchema: {
|
|
278
292
|
* type: "object",
|
|
279
|
-
* [CONTEXT_REQUIREMENTS_KEY]: ["hyperliquid"],
|
|
280
293
|
* properties: { portfolio: { type: "object" } },
|
|
281
294
|
* required: ["portfolio"]
|
|
282
295
|
* }
|
|
283
296
|
* };
|
|
284
297
|
* ```
|
|
285
298
|
*/
|
|
286
|
-
declare const
|
|
299
|
+
declare const META_CONTEXT_REQUIREMENTS_KEY: "contextRequirements";
|
|
287
300
|
/**
|
|
288
301
|
* Context requirement types supported by the Context marketplace.
|
|
289
302
|
* Maps to protocol-specific context builders on the platform.
|
|
@@ -467,6 +480,10 @@ type HandshakeMeta = {
|
|
|
467
480
|
tokenAmount?: string;
|
|
468
481
|
/** UI warning level */
|
|
469
482
|
warningLevel?: "info" | "caution" | "danger";
|
|
483
|
+
/** Custom title for the signature card (marketplace-friendly, overrides action-based title) */
|
|
484
|
+
title?: string;
|
|
485
|
+
/** Custom subtitle for the signature card (overrides tool name display) */
|
|
486
|
+
subtitle?: string;
|
|
470
487
|
};
|
|
471
488
|
type EIP712Domain = {
|
|
472
489
|
/** Domain name (e.g., "Hyperliquid", "ClobAuthDomain") */
|
|
@@ -671,4 +688,4 @@ declare function wrapHandshakeResponse(action: HandshakeAction): {
|
|
|
671
688
|
};
|
|
672
689
|
};
|
|
673
690
|
|
|
674
|
-
export { type AuthRequired, type AuthRequiredMeta, CONTEXT_REQUIREMENTS_KEY, type ContextMiddlewareRequest, type ContextRequirementType, type CreateContextMiddlewareOptions, type EIP712Domain, type EIP712TypeField, type ERC20Context, type ERC20TokenBalance, type HandshakeAction, type HandshakeMeta, type HyperliquidAccountSummary, type HyperliquidContext, type HyperliquidOrder, type HyperliquidPerpPosition, type HyperliquidSpotBalance, type PolymarketContext, type PolymarketOrder, type PolymarketPosition, type SignatureRequest, type ToolRequirements, type TransactionProposal, type TransactionProposalMeta, type UserContext, type VerifyRequestOptions, type WalletContext, createAuthRequired, createContextMiddleware, createSignatureRequest, createTransactionProposal, isAuthRequired, isHandshakeAction, isOpenMcpMethod, isProtectedMcpMethod, isSignatureRequest, isTransactionProposal, verifyContextRequest, wrapHandshakeResponse };
|
|
691
|
+
export { type AuthRequired, type AuthRequiredMeta, CONTEXT_REQUIREMENTS_KEY, type ContextMiddlewareRequest, type ContextRequirementType, type CreateContextMiddlewareOptions, type EIP712Domain, type EIP712TypeField, type ERC20Context, type ERC20TokenBalance, type HandshakeAction, type HandshakeMeta, type HyperliquidAccountSummary, type HyperliquidContext, type HyperliquidOrder, type HyperliquidPerpPosition, type HyperliquidSpotBalance, META_CONTEXT_REQUIREMENTS_KEY, type PolymarketContext, type PolymarketOrder, type PolymarketPosition, type SignatureRequest, type ToolRequirements, type TransactionProposal, type TransactionProposalMeta, type UserContext, type VerifyRequestOptions, type WalletContext, createAuthRequired, createContextMiddleware, createSignatureRequest, createTransactionProposal, isAuthRequired, isHandshakeAction, isOpenMcpMethod, isProtectedMcpMethod, isSignatureRequest, isTransactionProposal, verifyContextRequest, wrapHandshakeResponse };
|