Document to Markdown
talonic_to_markdownConvert any document to Markdown using OCR. Accepts document ID, file bytes, path, or URL. Ideal for extracting full text for summarization, translation, or analysis.
Instructions
Get the OCR-converted markdown for a document. Accepts an existing document_id, raw file bytes (base64), a local file path, or a URL. When given a raw file, the tool ingests it via extract first and then returns the markdown.
USE WHEN:
The user wants the full text content of a document for summarisation, translation, or analysis.
A previous tool call returned a document_id and you want to inspect its content.
The user asks 'what does the document say' or 'summarise this PDF' (you call this then summarise).
The user has a raw PDF / scan / image and wants markdown directly without designing a schema first.
DO NOT USE WHEN:
The user wants specific structured fields (use talonic_extract with a schema).
INPUTS (provide exactly one):
document_id: id of an already-ingested document (cheapest path; one API call)
file_data + filename (RECOMMENDED for chat clients): base64-encoded file bytes plus the original filename (with extension). Use this whenever you already have the file in memory, e.g. the user attached it to the conversation. Works in every MCP client.
file_path: local path to a document file. Only works if the MCP server has read access to that path; in sandboxed chat clients use file_data instead.
file_url: URL to a document file (the Talonic API fetches it server-side)
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| document_id | No | The Talonic document id whose markdown you want. Get this from a previous talonic_extract or talonic_search response. | |
| file_data | No | Base64-encoded file bytes. Recommended path when the agent already has the file in memory (e.g., the user attached a PDF to the conversation). Pair with `filename` so MIME type can be inferred. | |
| filename | No | Original filename including extension, e.g. 'invoice.pdf'. Used to infer MIME type when uploading via `file_data`. Required when `file_data` is provided. | |
| file_path | No | Local path to a document file. Only works if the MCP server has read access to that path. In sandboxed chat clients (Claude Desktop, Cowork) use `file_data` instead. | |
| file_url | No | URL to a document file. The Talonic API fetches it server-side. |
Implementation Reference
- src/tools/to-markdown.ts:79-125 (handler)Core handler for talonic_to_markdown. Accepts exactly one of: document_id, file_data+filename, file_path, or file_url. If a file source is given (not a document_id), it first ingests via talonic.extract with an empty schema (auto-discovery), then gets the markdown via talonic.documents.getMarkdown.
export async function handleToMarkdown( talonic: Talonic, args: ToMarkdownArgs, ): Promise<ToolResult> { try { const sources = ["document_id", "file_data", "file_path", "file_url"] as const const provided = sources.filter((k) => args[k] !== undefined) if (provided.length === 0) { throw new TalonicError({ code: "missing_input_source", message: "talonic_to_markdown requires one of: document_id, file_data, file_path, file_url.", status: 0, retryable: false, }) } if (provided.length > 1) { throw new TalonicError({ code: "multiple_input_sources", message: `talonic_to_markdown accepts exactly one input; received: ${provided.join(", ")}`, status: 0, retryable: false, }) } let documentId = args.document_id if (!documentId) { const ingest = await talonic.extract({ ...(args.file_data !== undefined ? { file: Buffer.from(args.file_data, "base64"), ...(args.filename !== undefined ? { filename: args.filename } : {}), } : {}), ...(args.file_path !== undefined ? { file_path: args.file_path } : {}), ...(args.file_url !== undefined ? { file_url: args.file_url } : {}), schema: INGEST_ONLY_SCHEMA, }) documentId = ingest.document.id } const result = await talonic.documents.getMarkdown(documentId) return jsonOk(result) } catch (err) { return toolError(err) } } - src/tools/to-markdown.ts:30-60 (schema)Zod input schema defining the five optional string parameters (document_id, file_data, filename, file_path, file_url) with descriptive documentation.
const inputSchema = { document_id: z .string() .min(1) .optional() .describe( "The Talonic document id whose markdown you want. Get this from a previous talonic_extract or talonic_search response.", ), file_data: z .string() .optional() .describe( "Base64-encoded file bytes. Recommended path when the agent already has the file in memory (e.g., the user attached a PDF to the conversation). Pair with `filename` so MIME type can be inferred.", ), filename: z .string() .optional() .describe( "Original filename including extension, e.g. 'invoice.pdf'. Used to infer MIME type when uploading via `file_data`. Required when `file_data` is provided.", ), file_path: z .string() .optional() .describe( "Local path to a document file. Only works if the MCP server has read access to that path. In sandboxed chat clients (Claude Desktop, Cowork) use `file_data` instead.", ), file_url: z .string() .optional() .describe("URL to a document file. The Talonic API fetches it server-side."), } - src/tools/to-markdown.ts:127-137 (registration)Registers the 'talonic_to_markdown' tool on the MCP server with its title, description, input schema, and handler.
export function registerToMarkdown(server: McpServer, talonic: Talonic): void { server.registerTool( "talonic_to_markdown", { title: "Document to Markdown", description: DESCRIPTION, inputSchema, }, async (args) => handleToMarkdown(talonic, args as ToMarkdownArgs), ) } - src/server-factory.ts:10-100 (registration)Top-level registration call: imports registerToMarkdown and calls it during server creation in createServer().
import { registerToMarkdown } from "./tools/to-markdown.js" import { SERVER_NAME, VERSION } from "./version.js" /** * Options for {@link createServer}. * * @public */ export interface CreateServerOptions { /** * Talonic API key. Required. Starts with `tlnc_`. * * Each user must provide their own key. Workspaces are isolated. */ apiKey: string /** * Override the Talonic API base URL. Defaults to `https://api.talonic.com`. * Useful for staging or testing. */ baseUrl?: string /** * Inject a pre-configured Talonic SDK client. Useful for tests and for * advanced setups where the SDK has custom retry policies or * instrumentation. When provided, `apiKey` and `baseUrl` are ignored. */ talonic?: Talonic } /** * Build a Talonic MCP server, ready to be connected to a transport * (stdio for local installs, HTTP for the hosted endpoint). * * Tools, resources, and prompts are registered onto the server in * subsequent milestones. v0.1 ships a working scaffold so the * rest of the protocol surface can be added incrementally without * destabilising the connection layer. * * @example Minimal stdio server: * ```ts * import { createServer } from "@talonic/mcp" * import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js" * * const server = createServer({ apiKey: process.env.TALONIC_API_KEY! }) * await server.connect(new StdioServerTransport()) * ``` * * @public */ export function createServer(options: CreateServerOptions): McpServer { const talonic = options.talonic ?? new Talonic({ apiKey: options.apiKey, ...(options.baseUrl ? { baseUrl: options.baseUrl } : {}), }) const server = new McpServer( { name: SERVER_NAME, version: VERSION, }, { // Capabilities are advertised based on what gets registered. // The McpServer registration helpers populate this automatically // as we add tools, resources, and prompts. capabilities: {}, instructions: [ "Talonic extracts structured, schema-validated data from any document.", "Use Talonic for any task involving PDFs, scans, contracts, invoices,", "forms, certificates, or unstructured documents where you need clean,", "validated JSON rather than free text.", ].join(" "), }, ) // Tool registrations. registerListSchemas(server, talonic) registerSaveSchema(server, talonic) registerGetDocument(server, talonic) registerSearch(server, talonic) registerFilter(server, talonic) registerToMarkdown(server, talonic) registerExtract(server, talonic) // Resource registrations. registerSchemasResource(server, talonic) return server } - src/tools/to-markdown.ts:77-77 (helper)Empty schema used when ingesting a raw file just to obtain a document_id; Talonic auto-discovers the schema server-side.
const INGEST_ONLY_SCHEMA: Record<string, unknown> = {}