SDK
@repo/sdk — a thin client for accounting-mcp, the MCP-based sibling surface to the REST Public API.
@repo/sdk (package name @repo/sdk) is a small TypeScript client for accounting-mcp — a separate, MCP-protocol surface that exposes the same underlying product domain (invoices, quotes, counterparties, expenses, transactions, reports, Self Assessment, CRM, and more) as self-describing tools, rather than as REST/OpenAPI routes.
A different surface from api.ac-co.ai
Everything else on this site (Authentication, Scopes, the API Reference) documents api.ac-co.ai, the REST gateway over a curated slice of the platform contract. @repo/sdk talks to accounting-mcp instead — a Model Context Protocol server built for LLM hosts (Claude, ChatGPT, MCP Inspector) and this repo's own ac-co CLI. Both surfaces authenticate with the same ac_… API keys, but they are different products with different endpoint sets — don't assume an endpoint documented here also exists as an MCP tool, or vice versa.
What it does
The SDK is a wrapper around the official @modelcontextprotocol/sdk StreamableHTTPClientTransport, plus a raw fetch call to a companion /uploads route (MCP tool calls can't carry binary file bodies). It exposes:
connect(options?: { url?: string; apiKey?: string }): Promise<{
serverUrl: URL;
listTools(): Promise<AccoTool[]>;
call(name: string, args?: Record<string, unknown>): Promise<AccoCallResult>;
upload(bytes: Uint8Array, opts: { name: string; contentType: string }): Promise<UploadResult>;
close(): Promise<void>;
}>listTools()— the full set of available tools (every product API accounting-mcp exposes), each with a JSON Schema describing its arguments. This is what powers theac-coCLI's auto-generated subcommands.call(name, args)— invoke any tool by name with a JSON argument object.upload(bytes, { name, contentType })— POST a file to be ingested and auto-classified (invoices, bank statements, contracts, …).
Install and authenticate
bun add @repo/sdk # workspace package — inside this monorepo onlyAuth is an ac_… API key (the same kind used against the REST Public API), passed as a bearer token on the underlying HTTP transport:
import { connect } from "@repo/sdk";
const client = await connect({ apiKey: process.env.AC_CO_API_KEY });If you omit apiKey, it falls back to the AC_CO_API_KEY environment variable. If you omit url, it falls back to AC_CO_API_URL, then ACCOUNTING_MCP_URL, then ACCOUNTING_MCP_PUBLIC_BASE_URL, then a local development default — set AC_CO_API_URL to accounting-mcp's real endpoint (e.g. https://accounting-mcp.ac-co.ai/mcp) for anything other than local dev.
Example: list and call tools
import { connect } from "@repo/sdk";
const client = await connect({ apiKey: process.env.AC_CO_API_KEY });
const tools = await client.listTools();
console.log(tools.map((t) => t.name));
const result = await client.call("search_invoices", { status: "unpaid" });
console.log(result.structuredContent ?? result.content);
await client.close();Example: upload a document
import { readFile } from "node:fs/promises";
import { connect } from "@repo/sdk";
const client = await connect({ apiKey: process.env.AC_CO_API_KEY });
const bytes = await readFile("./invoice.pdf");
const result = await client.upload(new Uint8Array(bytes), {
name: "invoice.pdf",
contentType: "application/pdf",
});
console.log(result.documentId);See also
The CLI is built directly on this SDK — every tool listTools() returns becomes a CLI subcommand automatically, with zero CLI-side code changes needed when a new tool ships.