UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

104 lines • 4.54 kB
/** * mockMcpClient — in-memory MCP client for development and tests. * * const slack = mockMcpClient({ * tools: [ * { * name: 'send_message', * description: 'Post a message to a channel', * inputSchema: { type: 'object' }, * handler: async ({ text }) => `Posted: ${text}`, * }, * ], * }); * * const agent = Agent.create({ provider: mock({ reply: 'ok' }) }) * .tools(await slack.tools()) * .build(); * * Pattern: Adapter (GoF) — produces an `McpClient` with the same shape * as `mcpClient(opts)` but driven by an in-memory tool table * instead of the MCP SDK + transport. Drop-in for development: * start with `mockMcpClient`, swap to `mcpClient` once the * real server is ready. * * Why public: `mcpClient`'s `_client` injection is `@internal` because * the SDK shape isn't a stable public surface. `mockMcpClient` exposes * a curated tool-handler shape that's tied to OUR Tool contract instead * — stable, documented, and the right level of abstraction for * mock-first development. */ import type { McpClient, McpClientOptions, McpCallToolResult } from './types.js'; /** A scripted tool exposed by the mock MCP server. */ export interface MockMcpTool { /** Tool name as the LLM sees it. */ readonly name: string; /** Description surfaced to the LLM via the tool schema. */ readonly description?: string; /** * JSON-schema-like input schema. Passed through to the agent's tool * registry verbatim — same as a real MCP server's `listTools()`. */ readonly inputSchema: Readonly<Record<string, unknown>>; /** * MCP's extensibility bag, exactly as a real server would send it (9.71.0). * * agentfootprint's tool DECLARATIONS — `argumentsFrom`, `resultKind`, * `owner`, `resultClass`, `resultCeiling` — ride under the `agentfootprint` * key here, and this mock reads them through the SAME defensive reader * `mcpClient` uses. So a rail armed by a remotely-declared tool can be * developed and tested before the real server exists, and so can the * unhappy path: put a malformed declaration in and watch the field get * dropped, the warning name the rule, and the tool register anyway. * * ```ts * mockMcpClient({ * name: 'fleet-mcp', * tools: [{ * name: 'backup_status', * inputSchema: { type: 'object', properties: { machine: { type: 'string' } } }, * _meta: { agentfootprint: { argumentsFrom: ['fleet_report'] } }, * }], * }); * ``` * * Omitted → the registered `Tool` carries no declarations, exactly as * before this existed. */ readonly _meta?: Readonly<Record<string, unknown>>; /** * Async handler that runs when the agent calls this tool. Receives * the args the LLM produced; returns a string or an MCP result envelope. * Strings retain the existing behavior in text mode; envelopes use the * same result decoder as the real client. * * Defaults to `async () => '[mock result]'` when omitted — useful * when the consumer cares about wiring not behavior. */ readonly handler?: (args: Record<string, unknown>, /** * The request's `_meta` bag, exactly as the real client would send it — * `{ agentfootprint: { time } }` on a call handed `ctx.time` (the time * layer), absent otherwise. A handler that ignores it behaves as before. */ request: { readonly _meta?: Readonly<Record<string, unknown>>; }) => Promise<string | McpCallToolResult>; } export interface MockMcpClientOptions { /** Logical server name. Surfaces in observability + error messages. */ readonly name?: string; /** Tools exposed by the mock server. */ readonly tools: readonly MockMcpTool[]; /** Same result decoding as mcpClient. A string handler becomes one text * block; return McpCallToolResult to exercise structuredContent or isError. */ readonly resultMode?: McpClientOptions['resultMode']; } /** * Build an in-memory `McpClient`. Useful when you want to develop * against MCP semantics without spawning subprocesses, hitting the * network, or installing `@modelcontextprotocol/sdk`. Same `McpClient` * shape as `mcpClient(opts)` — code that consumes one accepts the other. */ export declare function mockMcpClient(options: MockMcpClientOptions): McpClient; //# sourceMappingURL=mockMcpClient.d.ts.map