agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
86 lines (85 loc) • 4.24 kB
TypeScript
/**
* mcpClient — connect to an MCP server, expose its tools to your Agent.
*
* const slack = await mcpClient({
* name: 'slack',
* transport: { transport: 'stdio', command: 'npx', args: ['@example/slack-mcp'] },
* });
*
* const tools = await slack.tools(); // → readonly Tool[]
* const agent = Agent.create({ ... }).tools(tools).build();
*
* // ...
*
* await slack.close();
*
* Pattern: Adapter (GoF) — translates MCP `listTools()` / `callTool()`
* into agentfootprint's `Tool` interface (schema + execute).
* Each MCP tool becomes ONE agentfootprint Tool. The agent's
* existing tool-call handler invokes `client.callTool()`
* inside the wrapped `execute`.
*
* Role: Layer-3 integration. Sits next to `defineTool` — same
* shape, different source. Once tools land on the agent,
* the rest of the library doesn't know they came from MCP.
* Since 9.71.0 that is true of DECLARATIONS too: a server's
* `_meta` bag becomes `argumentsFrom` / `resultKind` / `owner`
* / `resultClass` / `resultCeiling` on the registered `Tool`,
* so the integrity checks, the placement mint and the identity
* joins arm for a remote tool exactly as for a local one. The
* reading NEVER throws — see `toolExtras.ts`.
*
* Emits: N/A — wrapped tools emit the standard
* `agentfootprint.stream.tool_start` / `tool_end` events
* when the agent calls them. Add `name: '<mcp-server>'` to
* `McpClientOptions` so observability surfaces can group
* tool calls by server. On a transport this module builds,
* a call the agent dispatched also gets its request's retry
* series as `agentfootprint.tools.request_attempts`, filed by
* the series through the call's own port (`requestLedger.ts`).
*
* Lazy-require pattern: the `@modelcontextprotocol/sdk` peer-dep
* loads only when a consumer actually constructs a client. Tests
* inject `_client` and skip the import path entirely.
*/
import type { Tool } from '../tools/tools.js';
import type { McpClient, McpClientOptions, McpConnectionOptions, McpListedTool } from './types.js';
import { type ClientPort, type PooledClientSeam } from './clientPort.js';
/**
* Connect to an MCP server. Returns an `McpClient` that exposes the
* server's tools as agentfootprint `Tool[]` and a `close()` to tear
* down the transport.
*
* Three ways to get a connection, and they are three because a browser can
* only take the last two:
*
* - `{ transport }` — the library loads the SDK through its Node loader and
* builds everything. The default, and what every Node consumer already
* does.
* - `{ transport, sdk }` — you supply the two SDK modules with static
* imports; the library still builds the transport, so gateway vending,
* `retryOnThrottle`, `headers` and your own `fetch` all keep working.
* - `{ connection }` — you built and connected the client yourself; the
* library only adapts its tools.
*
* @throws when the two arms are mixed, when a `connection` is not one, or when
* `@modelcontextprotocol/sdk` cannot be loaded (the message says which of
* "not installed" and "no Node loader here" actually happened), or when the
* transport fails to connect.
*/
export declare function mcpClient(opts: McpClientOptions | McpConnectionOptions): Promise<McpClient>;
/**
* @internal The MCP client pool's way to open a client (`mcp/pool/`): an
* ordinary `mcpClient` — the same discovery, checks, ledger and retry series —
* plus what only a pool asks for (`clientPort.ts`), and the port back.
*/
export declare function openPooledClient(opts: McpClientOptions, seam: PooledClientSeam): Promise<{
readonly client: McpClient;
readonly port: ClientPort;
}>;
/**
* @internal What a listed MCP tool looks like as a `Tool`, less its `execute`:
* its schema, its provenance and the declarations its `_meta` carries. The ONE
* shape both an `mcpClient` tool and an MCP client pool's bound tool take.
*/
export declare function mcpToolShape(serverName: string, mcp: McpListedTool): Omit<Tool, 'execute'>;