Skip to main content
Glama

Document to Markdown

talonic_to_markdown

Convert 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

TableJSON Schema
NameRequiredDescriptionDefault
document_idNoThe Talonic document id whose markdown you want. Get this from a previous talonic_extract or talonic_search response.
file_dataNoBase64-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.
filenameNoOriginal filename including extension, e.g. 'invoice.pdf'. Used to infer MIME type when uploading via `file_data`. Required when `file_data` is provided.
file_pathNoLocal 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_urlNoURL to a document file. The Talonic API fetches it server-side.

Implementation Reference

  • 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)
      }
    }
  • 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."),
    }
  • 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),
      )
    }
  • 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
    }
  • 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> = {}
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Discloses that raw files are first ingested via extract before returning markdown, and mentions cost implications (cheapest path: document_id). No annotations provided, but description covers behavioral traits adequately.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Well-structured with bullet points and sections; front-loaded purpose; every sentence provides useful information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Coverage is high with 100% schema descriptions and clear mutual exclusivity of parameters. However, no output schema means the return format (markdown string) is not described, a minor gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Adds value beyond schema descriptions by recommending specific parameters for different scenarios (e.g., file_data for chat clients, document_id as cheapest), and explaining constraints (file_path requires read access).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Clearly states it returns OCR-converted markdown for documents, with multiple input methods. Differentiates from sibling talonic_extract (structured fields) and talonic_search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Includes explicit 'USE WHEN' and 'DO NOT USE WHEN' sections, providing scenarios like full text extraction or summarisation, and advising against use for structured fields.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/talonicdev/talonic-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server