@desktopaccountingapi/quickbooks-desktop-mcp 0.0.0-stage → 0.1.1

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/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+ // Code generated by packages/sdk-generator from packages/mcp/src. DO NOT EDIT.
3
+ // Contract: packages/api-contract/generated/openapi.json (OpenAPI 3.1.0) sha256:1cc3058cecb557ce1cc724d5236d36860df6bec39636e2d427c8a408bf5f2ca2
4
+ // Local (stdio) MCP server for the Desktop Accounting API.
5
+ //
6
+ // npx -y @desktopaccountingapi/quickbooks-desktop-mcp [--read-only] [--resources invoices,customers] [--end-user-id eu_...]
7
+ //
8
+ // Environment: DAAPI_SECRET_KEY (required for API calls), DAAPI_BASE_URL (default
9
+ // https://api.desktopaccountingapi.com), DAAPI_END_USER_ID, DAAPI_MCP_READ_ONLY=true,
10
+ // DAAPI_MCP_RESOURCES, DAAPI_DOCS_URL.
11
+ import { existsSync, readFileSync } from 'node:fs';
12
+ import { McpServer } from './server.js';
13
+ import { serveStdio } from './stdio.js';
14
+ const HELP = `Desktop Accounting API MCP server (stdio)
15
+
16
+ Usage: quickbooks-desktop-mcp [options]
17
+
18
+ Options:
19
+ --read-only Hide and refuse operations that change data. For a limit
20
+ the API enforces, use a read-only secret key.
21
+ --resources <list> Also expose one tool per operation for these resources
22
+ (for example invoices,customers or all).
23
+ --end-user-id <eu_...> Default end user for QuickBooks operations.
24
+ --base-url <url> API origin (default https://api.desktopaccountingapi.com).
25
+ --version Print the version.
26
+ --help Print this help.
27
+
28
+ Environment: DAAPI_SECRET_KEY (secret key), DAAPI_BASE_URL, DAAPI_END_USER_ID,
29
+ DAAPI_MCP_READ_ONLY, DAAPI_MCP_RESOURCES.
30
+ Docs: https://www.desktopaccountingapi.com/docs/guides/mcp/
31
+ `;
32
+ function readJson(candidates) {
33
+ for (const rel of candidates) {
34
+ const url = new URL(rel, import.meta.url);
35
+ if (existsSync(url))
36
+ return JSON.parse(readFileSync(url, 'utf8'));
37
+ }
38
+ throw new Error(`missing ${candidates[0]}`);
39
+ }
40
+ const argv = process.argv.slice(2);
41
+ const opt = (name) => {
42
+ const i = argv.indexOf(`--${name}`);
43
+ return i >= 0 ? argv[i + 1] : argv.find((a) => a.startsWith(`--${name}=`))?.slice(name.length + 3);
44
+ };
45
+ const flag = (name) => argv.includes(`--${name}`);
46
+ const truthy = (v) => !!v && /^(1|true|yes|on)$/i.test(v);
47
+ const pkg = readJson(['../package.json']);
48
+ if (flag('help') || flag('h')) {
49
+ process.stdout.write(HELP);
50
+ process.exit(0);
51
+ }
52
+ if (flag('version')) {
53
+ process.stdout.write(`${pkg.version}\n`);
54
+ process.exit(0);
55
+ }
56
+ const catalog = readJson(['./catalog.json', '../generated/catalog.json']);
57
+ const env = process.env;
58
+ const server = new McpServer({
59
+ catalog,
60
+ version: pkg.version,
61
+ apiKey: env.DAAPI_SECRET_KEY?.trim() || undefined,
62
+ baseUrl: opt('base-url') ?? env.DAAPI_BASE_URL ?? 'https://api.desktopaccountingapi.com',
63
+ endUserId: opt('end-user-id') ?? (env.DAAPI_END_USER_ID || undefined),
64
+ readOnly: flag('read-only') || truthy(env.DAAPI_MCP_READ_ONLY),
65
+ resources: (opt('resources') ?? env.DAAPI_MCP_RESOURCES ?? '').split(',').map((s) => s.trim()).filter(Boolean),
66
+ docsUrl: env.DAAPI_DOCS_URL || undefined,
67
+ userAgent: `desktopaccountingapi-mcp/${pkg.version} (stdio; node ${process.version}; ${process.platform})`,
68
+ });
69
+ if (!env.DAAPI_SECRET_KEY)
70
+ process.stderr.write('desktopaccountingapi-mcp: DAAPI_SECRET_KEY is not set; tools will report the missing key.\n');
71
+ await serveStdio(server);
package/dist/http.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ import type { Catalog } from './catalog.ts';
2
+ export interface HttpOptions {
3
+ catalog: Catalog;
4
+ version: string;
5
+ apiBaseUrl: string;
6
+ fetch?: typeof fetch;
7
+ docsFetch?: typeof fetch;
8
+ docsUrl?: string;
9
+ /** Extra headers for API requests (for example the caller's IP for per-IP limits). */
10
+ apiHeaders?: Record<string, string>;
11
+ /** Where GET from a browser goes (the setup guide). */
12
+ guideUrl?: string;
13
+ }
14
+ export declare function handleMcpRequest(request: Request, o: HttpOptions): Promise<Response>;
package/dist/http.js ADDED
@@ -0,0 +1,80 @@
1
+ // Code generated by packages/sdk-generator from packages/mcp/src. DO NOT EDIT.
2
+ // Contract: packages/api-contract/generated/openapi.json (OpenAPI 3.1.0) sha256:1cc3058cecb557ce1cc724d5236d36860df6bec39636e2d427c8a408bf5f2ca2
3
+ // Streamable HTTP transport (MCP 2025-03-26 and later), stateless: each POST carries one JSON-RPC
4
+ // message (or a batch, for 2025-03-26 clients) and is answered with application/json. No server
5
+ // sessions and no server-initiated stream, so GET and DELETE return 405. Web-standard Request and
6
+ // Response only (Cloudflare Workers, Node 18+).
7
+ //
8
+ // Connection configuration (all optional):
9
+ // Authorization: Bearer sk_... secret key, passed to the API unchanged
10
+ // Daapi-End-User-Id header / ?end_user_id= default end user
11
+ // ?read_only=true hide and refuse writes (a read-only key is the server-enforced control)
12
+ // ?resources=invoices,customers also expose one tool per operation for these resources ("all" for every one)
13
+ import { McpServer, PROTOCOL_VERSIONS } from './server.js';
14
+ const MAX_BODY = 1_000_000;
15
+ const CORS = {
16
+ 'Access-Control-Allow-Origin': '*',
17
+ 'Access-Control-Allow-Methods': 'POST, GET, DELETE, OPTIONS',
18
+ 'Access-Control-Allow-Headers': 'Authorization, Content-Type, Accept, Mcp-Session-Id, Mcp-Protocol-Version, Last-Event-ID, Daapi-End-User-Id',
19
+ 'Access-Control-Expose-Headers': 'Mcp-Session-Id, Mcp-Protocol-Version',
20
+ 'Access-Control-Max-Age': '86400',
21
+ };
22
+ function json(body, status = 200, extra = {}) {
23
+ return new Response(JSON.stringify(body), { status, headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', ...CORS, ...extra } });
24
+ }
25
+ const rpcError = (status, code, message) => json({ jsonrpc: '2.0', id: null, error: { code, message } }, status);
26
+ const truthy = (v) => !!v && /^(1|true|yes|on)$/i.test(v);
27
+ export async function handleMcpRequest(request, o) {
28
+ const url = new URL(request.url);
29
+ if (request.method === 'OPTIONS')
30
+ return new Response(null, { status: 204, headers: CORS });
31
+ if (request.method === 'GET' && !(request.headers.get('Accept') ?? '').includes('text/event-stream') && o.guideUrl) {
32
+ return new Response(null, { status: 302, headers: { Location: o.guideUrl, 'Cache-Control': 'no-store' } });
33
+ }
34
+ if (request.method !== 'POST')
35
+ return json({ jsonrpc: '2.0', id: null, error: { code: -32000, message: 'Method not allowed. This server is stateless: send JSON-RPC messages with POST.' } }, 405, { Allow: 'POST, OPTIONS' });
36
+ const version = request.headers.get('Mcp-Protocol-Version');
37
+ if (version && !PROTOCOL_VERSIONS.includes(version))
38
+ return rpcError(400, -32000, `Unsupported MCP protocol version ${version}. Supported: ${PROTOCOL_VERSIONS.join(', ')}.`);
39
+ const type = request.headers.get('Content-Type') ?? '';
40
+ if (!type.includes('application/json'))
41
+ return rpcError(415, -32000, 'Send Content-Type: application/json.');
42
+ const length = Number(request.headers.get('Content-Length') ?? '0');
43
+ if (length > MAX_BODY)
44
+ return rpcError(413, -32000, 'Request body too large.');
45
+ const raw = await request.text();
46
+ if (raw.length > MAX_BODY)
47
+ return rpcError(413, -32000, 'Request body too large.');
48
+ let body;
49
+ try {
50
+ body = JSON.parse(raw);
51
+ }
52
+ catch {
53
+ return rpcError(400, -32700, 'Parse error');
54
+ }
55
+ const auth = request.headers.get('Authorization') ?? '';
56
+ const apiKey = /^Bearer\s+(\S+)\s*$/i.exec(auth)?.[1];
57
+ const resources = (url.searchParams.get('resources') ?? '').split(',').map((s) => s.trim()).filter(Boolean);
58
+ const server = new McpServer({
59
+ catalog: o.catalog,
60
+ version: o.version,
61
+ apiKey,
62
+ baseUrl: o.apiBaseUrl,
63
+ endUserId: request.headers.get('Daapi-End-User-Id') ?? url.searchParams.get('end_user_id') ?? undefined,
64
+ readOnly: truthy(url.searchParams.get('read_only')),
65
+ resources,
66
+ docsUrl: o.docsUrl,
67
+ fetch: o.fetch,
68
+ docsFetch: o.docsFetch,
69
+ apiHeaders: o.apiHeaders,
70
+ userAgent: `desktopaccountingapi-mcp/${o.version} (hosted)`,
71
+ });
72
+ if (Array.isArray(body)) {
73
+ if (!body.length)
74
+ return rpcError(400, -32600, 'Invalid Request: empty batch');
75
+ const out = (await Promise.all(body.map((m) => server.handle(m)))).filter((r) => r !== null);
76
+ return out.length ? json(out) : new Response(null, { status: 202, headers: CORS });
77
+ }
78
+ const res = await server.handle(body);
79
+ return res ? json(res) : new Response(null, { status: 202, headers: CORS });
80
+ }
@@ -0,0 +1,5 @@
1
+ export { buildCatalog, defsFor, type Catalog, type CatalogEndpoint, type CatalogParam, type JsonSchema } from './catalog.ts';
2
+ export { handleMcpRequest, type HttpOptions } from './http.ts';
3
+ export { isValidSecretKey, maskKey } from './key.ts';
4
+ export { McpServer, PROTOCOL_VERSIONS, type JsonRpcMessage } from './server.ts';
5
+ export { endpointArgsSchema, project, SERVER_NAME, splitDocs, toolName, Tools, type Tool, type ToolOptions, type ToolResult } from './tools.ts';
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ // Code generated by packages/sdk-generator from packages/mcp/src. DO NOT EDIT.
2
+ // Contract: packages/api-contract/generated/openapi.json (OpenAPI 3.1.0) sha256:1cc3058cecb557ce1cc724d5236d36860df6bec39636e2d427c8a408bf5f2ca2
3
+ // Runtime-agnostic MCP server core (no Node-only imports); the tool design is in tools.ts.
4
+ export { buildCatalog, defsFor } from './catalog.js';
5
+ export { handleMcpRequest } from './http.js';
6
+ export { isValidSecretKey, maskKey } from './key.js';
7
+ export { McpServer, PROTOCOL_VERSIONS } from './server.js';
8
+ export { endpointArgsSchema, project, SERVER_NAME, splitDocs, toolName, Tools } from './tools.js';
package/dist/key.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export declare function isValidSecretKey(key: string): boolean;
2
+ /** `sk_live_...` + last 4, safe for messages. */
3
+ export declare function maskKey(key: string): string;
package/dist/key.js ADDED
@@ -0,0 +1,41 @@
1
+ // Code generated by packages/sdk-generator from packages/mcp/src. DO NOT EDIT.
2
+ // Contract: packages/api-contract/generated/openapi.json (OpenAPI 3.1.0) sha256:1cc3058cecb557ce1cc724d5236d36860df6bec39636e2d427c8a408bf5f2ca2
3
+ // Local secret-key check (same rule as the API and SDKs, docs/api-conventions.md section 2):
4
+ // `sk_live_`/`sk_test_` + 40 base62 chars, the last 6 being the base62 CRC32 of the first 34.
5
+ // Rejecting a mistyped key locally keeps it from counting against the API's per-IP
6
+ // failed-authentication limit.
7
+ const BASE62 = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
8
+ let table;
9
+ function crc32(input) {
10
+ if (!table) {
11
+ table = new Uint32Array(256);
12
+ for (let n = 0; n < 256; n++) {
13
+ let c = n;
14
+ for (let k = 0; k < 8; k++)
15
+ c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;
16
+ table[n] = c >>> 0;
17
+ }
18
+ }
19
+ let crc = 0xffffffff;
20
+ for (const byte of new TextEncoder().encode(input))
21
+ crc = table[(crc ^ byte) & 0xff] ^ (crc >>> 8);
22
+ return (crc ^ 0xffffffff) >>> 0;
23
+ }
24
+ function base62(value, width) {
25
+ let out = '';
26
+ let v = value;
27
+ while (v > 0) {
28
+ out = BASE62[v % 62] + out;
29
+ v = Math.floor(v / 62);
30
+ }
31
+ return out.padStart(width, '0');
32
+ }
33
+ export function isValidSecretKey(key) {
34
+ const m = /^sk_(live|test)_([0-9A-Za-z]{40})$/.exec(key);
35
+ return !!m && base62(crc32(m[2].slice(0, 34)), 6) === m[2].slice(34);
36
+ }
37
+ /** `sk_live_...` + last 4, safe for messages. */
38
+ export function maskKey(key) {
39
+ const prefix = key.startsWith('sk_live_') ? 'sk_live_' : key.startsWith('sk_test_') ? 'sk_test_' : '';
40
+ return prefix ? `${prefix}...${key.slice(-4)}` : 'the provided key';
41
+ }
@@ -0,0 +1,24 @@
1
+ import { Tools, type ToolOptions } from './tools.ts';
2
+ /** Newest first. The client's version is used when supported, otherwise the newest. */
3
+ export declare const PROTOCOL_VERSIONS: string[];
4
+ export interface JsonRpcMessage {
5
+ jsonrpc: '2.0';
6
+ id?: string | number | null;
7
+ method?: string;
8
+ params?: Record<string, unknown>;
9
+ result?: unknown;
10
+ error?: {
11
+ code: number;
12
+ message: string;
13
+ data?: unknown;
14
+ };
15
+ }
16
+ export declare class McpServer {
17
+ readonly tools: Tools;
18
+ private readonly version;
19
+ constructor(opts: ToolOptions & {
20
+ version: string;
21
+ });
22
+ /** Handles one message. Returns the response, or null for notifications and responses. */
23
+ handle(msg: unknown): Promise<JsonRpcMessage | null>;
24
+ }
package/dist/server.js ADDED
@@ -0,0 +1,73 @@
1
+ // Code generated by packages/sdk-generator from packages/mcp/src. DO NOT EDIT.
2
+ // Contract: packages/api-contract/generated/openapi.json (OpenAPI 3.1.0) sha256:1cc3058cecb557ce1cc724d5236d36860df6bec39636e2d427c8a408bf5f2ca2
3
+ // Model Context Protocol server core: JSON-RPC 2.0 message handling for the `tools` capability.
4
+ // Transport-independent; stdio.ts and http.ts carry the messages. Implements the lifecycle
5
+ // (initialize with version negotiation, notifications/initialized, ping) plus tools/list and
6
+ // tools/call. Stateless: every HTTP request is answered on its own.
7
+ import { SERVER_NAME, Tools } from './tools.js';
8
+ /** Newest first. The client's version is used when supported, otherwise the newest. */
9
+ export const PROTOCOL_VERSIONS = ['2025-11-25', '2025-06-18', '2025-03-26', '2024-11-05'];
10
+ const INSTRUCTIONS = `Desktop Accounting API: read and write QuickBooks Desktop company files (customers, vendors, invoices, bills, payments, items, accounts, reports and more) through the QuickBooks Web Connector.
11
+
12
+ How to work:
13
+ 1. Call list_end_users to find the end user (eu_...) whose company file to use. Each end user is one QuickBooks company file. Connection status "online" means requests can run now.
14
+ 2. Find the operation with list_api_endpoints (search "invoice", "profit and loss", ...), read its input with get_api_endpoint_schema, then run it with invoke_api_endpoint and end_user_id.
15
+ 3. Lists return one page (default limit). Use filters (for example updatedAfter, customerIds, transactionDateFrom) and the fields argument to keep results small; pass nextCursor as cursor for more.
16
+ 4. Writes change the user's real accounting records. Describe the change and get the user's confirmation before each write. Never repeat a write whose outcome is unknown with a new idempotency key; follow the guidance in the error.
17
+ 5. QuickBooks must be open on the end user's computer. Error results include a userFacingMessage and fixes; relay them instead of guessing.
18
+ 6. For concepts and error codes, use search_docs.`;
19
+ export class McpServer {
20
+ tools;
21
+ version;
22
+ constructor(opts) {
23
+ this.tools = new Tools(opts);
24
+ this.version = opts.version;
25
+ }
26
+ /** Handles one message. Returns the response, or null for notifications and responses. */
27
+ async handle(msg) {
28
+ if (!msg || typeof msg !== 'object' || Array.isArray(msg) || msg.jsonrpc !== '2.0') {
29
+ return { jsonrpc: '2.0', id: null, error: { code: -32600, message: 'Invalid Request' } };
30
+ }
31
+ const m = msg;
32
+ if (m.method === undefined)
33
+ return null; // a response to a server request (none are sent)
34
+ const isNotification = m.id === undefined;
35
+ const reply = (result) => (isNotification ? null : { jsonrpc: '2.0', id: m.id, result });
36
+ const fail = (code, message) => (isNotification ? null : { jsonrpc: '2.0', id: m.id, error: { code, message } });
37
+ const params = (m.params ?? {});
38
+ switch (m.method) {
39
+ case 'initialize': {
40
+ const requested = String(params.protocolVersion ?? '');
41
+ return reply({
42
+ protocolVersion: PROTOCOL_VERSIONS.includes(requested) ? requested : PROTOCOL_VERSIONS[0],
43
+ capabilities: { tools: { listChanged: false } },
44
+ serverInfo: { name: SERVER_NAME, title: 'Desktop Accounting API (QuickBooks Desktop)', version: this.version, websiteUrl: 'https://www.desktopaccountingapi.com/docs/guides/mcp/' },
45
+ instructions: INSTRUCTIONS + (this.tools.opts.readOnly ? '\n\nThis connection is read-only: operations that change data are hidden and refused.' : ''),
46
+ });
47
+ }
48
+ case 'ping':
49
+ return reply({});
50
+ case 'tools/list':
51
+ return reply({ tools: this.tools.list() });
52
+ case 'tools/call': {
53
+ const name = params.name;
54
+ if (typeof name !== 'string')
55
+ return fail(-32602, 'tools/call needs a tool name');
56
+ const args = params.arguments;
57
+ if (args !== undefined && (typeof args !== 'object' || args === null || Array.isArray(args)))
58
+ return fail(-32602, 'arguments must be an object');
59
+ if (!this.tools.list().some((t) => t.name === name))
60
+ return fail(-32602, `Unknown tool: ${name}`);
61
+ return reply(await this.tools.call(name, (args ?? {})));
62
+ }
63
+ case 'resources/list':
64
+ return reply({ resources: [] });
65
+ case 'prompts/list':
66
+ return reply({ prompts: [] });
67
+ default:
68
+ if (m.method.startsWith('notifications/'))
69
+ return null;
70
+ return fail(-32601, `Method not found: ${m.method}`);
71
+ }
72
+ }
73
+ }
@@ -0,0 +1,2 @@
1
+ import type { McpServer } from './server.ts';
2
+ export declare function serveStdio(server: McpServer, input?: NodeJS.ReadableStream, output?: NodeJS.WritableStream): Promise<void>;
package/dist/stdio.js ADDED
@@ -0,0 +1,40 @@
1
+ // Code generated by packages/sdk-generator from packages/mcp/src. DO NOT EDIT.
2
+ // Contract: packages/api-contract/generated/openapi.json (OpenAPI 3.1.0) sha256:1cc3058cecb557ce1cc724d5236d36860df6bec39636e2d427c8a408bf5f2ca2
3
+ // stdio transport: newline-delimited JSON-RPC on stdin/stdout (MCP specification, "stdio").
4
+ // Only protocol messages go to stdout; diagnostics go to stderr. Pure Node.js (no Deno, no
5
+ // POSIX-only features), so it runs the same on Windows, macOS and Linux.
6
+ import { createInterface } from 'node:readline';
7
+ export function serveStdio(server, input = process.stdin, output = process.stdout) {
8
+ const rl = createInterface({ input, crlfDelay: Infinity });
9
+ const write = (msg) => output.write(`${JSON.stringify(msg)}\n`);
10
+ const pending = new Set();
11
+ rl.on('line', (line) => {
12
+ const trimmed = line.trim();
13
+ if (!trimmed)
14
+ return;
15
+ let msg;
16
+ try {
17
+ msg = JSON.parse(trimmed);
18
+ }
19
+ catch {
20
+ write({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Parse error' } });
21
+ return;
22
+ }
23
+ // Requests run concurrently; each response carries its id.
24
+ const work = (async () => {
25
+ if (Array.isArray(msg)) {
26
+ const out = (await Promise.all(msg.map((m) => server.handle(m)))).filter((r) => r !== null);
27
+ if (out.length)
28
+ void write(out);
29
+ }
30
+ else {
31
+ const res = await server.handle(msg);
32
+ if (res)
33
+ void write(res);
34
+ }
35
+ })().catch((err) => void process.stderr.write(`desktopaccountingapi-mcp: ${err instanceof Error ? err.message : String(err)}\n`));
36
+ pending.add(work);
37
+ void work.finally(() => pending.delete(work));
38
+ });
39
+ return new Promise((resolve) => rl.on('close', () => void Promise.all(pending).then(() => resolve())));
40
+ }
@@ -0,0 +1,89 @@
1
+ import { type Catalog, type CatalogEndpoint, type JsonSchema } from './catalog.ts';
2
+ export declare const SERVER_NAME = "desktopaccountingapi-quickbooks-desktop";
3
+ export interface ToolOptions {
4
+ catalog: Catalog;
5
+ /** Secret key (`sk_live_...` or `sk_test_...`). */
6
+ apiKey: string | undefined;
7
+ /** API origin, for example https://api.desktopaccountingapi.com. */
8
+ baseUrl: string;
9
+ /** Default end user for operations that need one; a tool call's `end_user_id` overrides it. */
10
+ endUserId?: string | undefined;
11
+ /** Hide and refuse every operation that changes data. */
12
+ readOnly?: boolean | undefined;
13
+ /** Also expose one tool per operation for these resources (tag or group names, or `all`). */
14
+ resources?: string[] | undefined;
15
+ /** URL of llms-full.txt for search_docs. */
16
+ docsUrl?: string | undefined;
17
+ /** fetch for API requests (the hosted server passes its service binding). */
18
+ fetch?: typeof fetch | undefined;
19
+ /** fetch for the documentation (default: global fetch). */
20
+ docsFetch?: typeof fetch | undefined;
21
+ /** Headers added to every API request (for example the client IP for the hosted server). */
22
+ apiHeaders?: Record<string, string> | undefined;
23
+ /** Largest tool result in characters before lists are cut. */
24
+ maxResultChars?: number | undefined;
25
+ userAgent?: string | undefined;
26
+ }
27
+ export interface Tool {
28
+ name: string;
29
+ title?: string;
30
+ description: string;
31
+ inputSchema: JsonSchema;
32
+ annotations?: {
33
+ title?: string;
34
+ readOnlyHint?: boolean;
35
+ destructiveHint?: boolean;
36
+ idempotentHint?: boolean;
37
+ openWorldHint?: boolean;
38
+ };
39
+ }
40
+ export interface ToolResult {
41
+ content: {
42
+ type: 'text';
43
+ text: string;
44
+ }[];
45
+ isError?: boolean;
46
+ structuredContent?: Record<string, unknown>;
47
+ }
48
+ export declare function toolName(endpoint: string): string;
49
+ /** Flattened arguments for one operation: path and query parameters at the top, the JSON body under `body`. */
50
+ export declare function endpointArgsSchema(catalog: Catalog, e: CatalogEndpoint, withDefs?: boolean): JsonSchema;
51
+ export declare class Tools {
52
+ readonly opts: ToolOptions;
53
+ private readonly byName;
54
+ private readonly perEndpoint;
55
+ private docsCache;
56
+ constructor(opts: ToolOptions);
57
+ list(): Tool[];
58
+ call(name: string, args?: Record<string, unknown>): Promise<ToolResult>;
59
+ private resolve;
60
+ private listEndpoints;
61
+ private endpointSchema;
62
+ private headers;
63
+ private keyProblem;
64
+ private request;
65
+ private listEndUsers;
66
+ invoke(e: CatalogEndpoint, args: Record<string, unknown>, control: {
67
+ end_user_id?: unknown;
68
+ idempotency_key?: unknown;
69
+ fields?: unknown;
70
+ }): Promise<ToolResult>;
71
+ /** Serializes a result within maxResultChars, cutting list pages rather than JSON text. */
72
+ private fit;
73
+ private errorResult;
74
+ private searchDocs;
75
+ private docs;
76
+ }
77
+ interface DocPage {
78
+ title: string;
79
+ url: string;
80
+ text: string;
81
+ }
82
+ /**
83
+ * llms-full.txt: each page starts with `# Title` immediately followed by `Source: <url>`. Only that
84
+ * pair marks a page boundary (a `# ` line inside a code block is never followed by `Source:`).
85
+ */
86
+ export declare function splitDocs(full: string): DocPage[];
87
+ /** Keeps only the given dot paths of an object, or of each item of a list (`data`). */
88
+ export declare function project(value: unknown, paths: string[]): unknown;
89
+ export {};