Sign in

MCP server

View as Markdown

Ocost is also a Model Context Protocol server: Claude Desktop, Claude Code, Cursor and other assistants search your documents, read them as ocost.document.v1, ask for your figures and send files, with your API key; claude.ai and ChatGPT connect as the person who allows them.

Address and key

Text
https://api.ocost.io/public/mcp
Authorization: Bearer ocost_sk_<id>_<secret>
  • Transport: Streamable HTTP, stateless; every request stands alone. https://app.ocost.io/public/mcp is the same server.
  • Key: an API key from Settings › API, in every request's Authorization header. Without a valid one: 401 with WWW-Authenticate: Bearer. Revoking works at once. Your Ocost sign-in is not a key.
  • One key per assistant, with only the scopes it needs, so you see its last use and can revoke it alone.
  • Apps that add servers only through OAuth (the connectors of claude.ai and ChatGPT on the web) need no key: Connect claude.ai or ChatGPT.

Tools

The files' tools are the API's routes; the others are the tools Ocost's own chat answers with, the same ones, under the same rights.

ToolScopeDoes
search_documentssearch:readWhat documents say, as a table: one row per document with its page and passage. match: exact (every document holding the text as written, never a look-alike), keywords, meaning, hybrid (the default; by the words when meaning is unavailable, notes: keywords_only). Arguments: query; optionally document_id, kinds, family, company_id, project_id, site_id, issued_since, issued_until, due_since, due_until, gross_min, gross_max, direction (incoming, outgoing), status (open, paid), category (an ECLASS code), limit.
find_categoryfigures:readWords in any of Ocost's languages ("Lebensmittel", "cleaning") to ECLASS codes, the best first: code, level, name, segment; for query_figures' class or search_documents' category. Argument: words.
searchsearch:readFor ChatGPT's deep research and company knowledge: query → results of id, title, url (the document's page in Ocost).
fetchsearch:readA search result whole: id → id, title, text (its pages, up to four), url, metadata.
read_documentdocuments:readOne document's pages as its file says them, up to four pages and 12,000 characters. Arguments: document_id, optionally pages.
get_documentdocuments:readLike GET /public/v1/documents/{document_id}: a document as ocost.document.v1. Argument: document_id.
find_documentsdocuments:readDocuments newest first, optionally of one kind, family or company_id, with number, company, direction, date, gross and status.
find_contractsdocuments:readContracts with their side, party, term, notice, recurring amounts; optionally one company_id's.
find_companydocuments:readSuppliers and customers whose name contains name, with their ids.
find_projectdocuments:readProjects whose name contains name, with their ids.
company_documentsdocuments:readA company's documents both ways. Argument: company_id.
invoice_detaildocuments:readOne invoice as its page shows it: amounts, due date, discount, its order and trail. Argument: invoice_id.
open_decisionsdocuments:readThe open decisions of the person who connected (OAuth only): a key made in Settings has no person.
get_filedocuments:readLike GET /public/v1/files/{file_id}: status, reason, documents. Argument: file_id.
list_filesdocuments:readLike GET /public/v1/files, oldest change first. Arguments: status, updated_since, cursor, limit.
company_profilefigures:readA company's year: bought and sold, terms both ways, what is open, how long each side took to pay. Argument: company_id.
project_overviewfigures:readA project's plan against spent and committed, by supplier and month, and its documents. Argument: project_id.
query_figuresfigures:readAdds up records for a chart, a comparison or a count, as a table: a source, a measure, one or two group_by (ECLASS classes at every level, cost types), filters, a year, compare (previous period or year), top_n, matching (the documents a search finds). Its description lists every source and field.
top_companiesfigures:readThe top suppliers or customers by net over a period in plain words ("2025", "Q3 2025", "last year"; the last 12 months by default), in an ECLASS category too: rank, company, net, gross, share, documents, the rest and a total row.
spend_over_timefigures:readNet by month, quarter or year over a period, every bucket (zeros too), by company or category as a column each; the last row the totals.
largest_documentsfigures:readThe largest documents by gross over a period, a list: rank, number, company, issued, net, gross; every invoice to pay unless a kind is asked.
payables_duefigures:readWhat to pay when to keep Skonto, as a table: unpaid supplier invoices due in a window (this_week, next_7_days, next_14_days, next_30_days, this_month) or from since to until, each with its due day, Skonto deadline and saving. Nothing is overdue while no bank account is connected.
vat_previewfigures:readA USt-Voranmeldung preview for a period (2026-10, 2026-Q4) by Kennzahl (81, 86, 66, 61, 46/67, 89/93, …), each with its invoices (kz). A preview for the tax adviser, never a filing.
check_invoicedocuments:read§ 14 UStG fields and the e-invoice check of one or many supplier invoices (document_ids, company_id, issued dates): what is missing and what costs the input VAT deduction.
find_anomaliesfigures:readDuplicate invoices, a supplier's bank account changed, a price above its order's, from since to until (the last 90 days), each with its documents. For a person to check, never acted on.
supplier_profilefigures:readA supplier in one call (company_id): spend by month and class, terms and Skonto, how fast you pay, open items, the price history of its top items, its documents and contracts.
export_tableexports:writeA table as Excel (xlsx) or CSV: send back a table's query (tool and args, unchanged) and a title; Ocost asks it again for all rows (up to 50 000) and answers a signed link, valid 30 minutes, as text and as a resource_link.
make_datev_exportexports:writeThe DATEV export (EXTF Buchungsstapel, an overview and the receipts as one ZIP) of starts_on to ends_on, days of one fiscal year, with a signed link. Only through the owner's or the accountant's own connection.
send_filedocuments:writeLike POST /public/v1/files. Arguments: filename, content_base64 (the bytes in base64), optionally external_ref.
  • Answers are JSON, as text and as structuredContent, each tool with its outputSchema; every tool but send_file, export_table and make_datev_export (which make a file) is marked read-only. Lists and tables say total (total_rows) and truncated: narrow the question, or page through files with list_files' cursor.
  • Tables and charts: the lists and query_figures come with an interactive table or chart (MCP Apps, ui://ocost/table and ui://ocost/chart) in apps that show them, such as claude.ai and ChatGPT; every other app reads the same JSON. Their links open the record in Ocost and nothing else.
  • What a document says comes inside <document-text source="…">…</document-text>, each line marked ¦ : words written by others, to read as data, never as instructions; quote them without the marks.
  • The API's limits apply: calls a minute per scope (Limits and errors), 25 MB per file before base64, the same formats, resent bytes read and counted once, each document read counted against your plan.
  • Refusals (missing scope, not found, too many calls) come as the tool's error: the problem's JSON with status and type, or the reason in words. Another business's id is not found.
  • No tool deletes, approves or orders, since an assistant may misread. Use DELETE /public/v1/files/{file_id} or Ocost.
  • No URLs: send_file takes bytes, never a link. It answers the file only; whether it was new and the documents left are in POST /public/v1/files and Settings › Plan.
  • Requests are capped at 4 MB, except for keys with documents:write, which may send a file's base64. Past it: 413.
  • Every call is recorded (the tool, its arguments cut short, how many records it answered, how it ended; never a document's words): the owner and the accountant see a key's last calls in Settings › API.

Scopes and who the tools act as

ScopeAllows
search:readsearch_documents, search, fetch
documents:readreading documents, files, contracts, companies, projects, invoices, decisions
figures:readcompany_profile, project_overview, query_figures, top_companies, spend_over_time, largest_documents, find_category, payables_due, vat_preview, find_anomalies, supplier_profile
exports:writeexport_table, make_datev_export
documents:writesend_file
  • A key made in Settings acts as the business: every document outside the Trash, no people's papers (pay, health), no person's own decisions. Only the owner makes one with figures:read.
  • A connection made through OAuth (claude.ai, ChatGPT) acts as the person who allowed it: their roles, what they see in Ocost's chat and nothing more. An accountant's connection reads no CFO figures. A person who leaves, or is no longer the owner or the accountant, ends their connections at their next call.
  • HR papers stay in Ocost: no key or connection ever reads people's papers (pay, health, sick notes), whoever allowed it; they are read in Ocost itself.

Claude Code

Shell
claude mcp add --transport http ocost https://api.ocost.io/public/mcp \
  --header "Authorization: Bearer $OCOST_KEY"

claude mcp list then shows ocost connected. To share it in a repository, put it in .mcp.json with the key from each developer's environment, never in the file:

JSON
{
  "mcpServers": {
    "ocost": {
      "type": "http",
      "url": "https://api.ocost.io/public/mcp",
      "headers": { "Authorization": "Bearer ${OCOST_KEY}" }
    }
  }
}

Claude Desktop

Add Ocost to claude_desktop_config.json (Settings › Developer › Edit Config). mcp-remote forwards the requests with the header and needs Node.js.

JSON
{
  "mcpServers": {
    "ocost": {
      "command": "npx",
      "args": [
        "-y",
        "mcp-remote@0.15.2",
        "https://api.ocost.io/public/mcp",
        "--header",
        "Authorization:${OCOST_AUTH}"
      ],
      "env": { "OCOST_AUTH": "Bearer ocost_sk_…" }
    }
  }
}

Restart Claude Desktop; the tools are under the tools button. Keep Authorization:${OCOST_AUTH} free of spaces: some clients split arguments there.

Cursor

In ~/.cursor/mcp.json, or .cursor/mcp.json in a project:

JSON
{
  "mcpServers": {
    "ocost": {
      "url": "https://api.ocost.io/public/mcp",
      "headers": { "Authorization": "Bearer ${env:OCOST_KEY}" }
    }
  }
}

Connect claude.ai or ChatGPT

Apps that add MCP servers only through OAuth, such as the connectors of claude.ai and ChatGPT on the web, need no key: you sign in to Ocost and allow the access.

  1. Add a connector: in claude.ai under Settings › Connectors › Add custom connector, in ChatGPT as a custom connector in developer mode. Only the URL https://api.ocost.io/public/mcp; leave the client ID and secret empty.
  2. Sign in: the app opens Ocost. Sign in as always. If you belong to several businesses, pick the right one under Another business.
  3. Allow: Ocost shows which app wants access, where it goes back to, and the scopes to tick: search documents, read them, read figures, make exports, send files. The owner and the accountant may allow it, as they may make a key; the app then acts as that person, with their rights.
  • The app gets an API key of its own with the scopes ticked, "<App> (Connector)" in Settings › API, with its last use. Revoke it there and the app is disconnected at once.
  • Ocost's logo shows on the connector; if it still shows a placeholder, connect it again.
  • Its access token holds for an hour, then the app gets a new one with its refresh token. 30 days unused end the connection; connect the app again then.
  • For developers: OAuth 2.1 with PKCE (S256); the metadata at https://api.ocost.io/.well-known/oauth-protected-resource/public/mcp (RFC 9728) and https://app.ocost.io/.well-known/oauth-authorization-server (RFC 8414); Client ID Metadata Documents and Dynamic Client Registration; redirect URIs https only, exactly as registered.

Any MCP client

  • URL: https://api.ocost.io/public/mcp
  • Transport: Streamable HTTP (POST, JSON answers; no SSE stream, no session id)
  • Header: Authorization: Bearer ocost_sk_…

To list the tools:

Shell
curl -sS https://api.ocost.io/public/mcp \
  -H "Authorization: Bearer $OCOST_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "MCP-Protocol-Version: 2025-11-25" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Example: an Odoo developer

An Odoo developer writing the module from Connecting Odoo, with a key holding search:read and documents:read, asks in Claude Code:

Developer: Find the invoice from Büromöbel Schmidt for the office chairs and show me which fields of account.move and its lines each value fills.

Assistant calls find_company (name: "Büromöbel Schmidt"), then search_documents (query: "Bürostuhl", company_id: …, kinds: ["invoice"]), finds invoice BS-7790, calls get_document and answers: seller.vat_id finds the partner_id, number is the ref, issue_date the invoice_date, due_date the invoice_date_due; each of the two lines becomes an invoice_line_ids entry with quantity, price as price_unit and vat_rate finding the purchase tax; totals.gross, 3946.04, checks Odoo's total.

Developer: Any credit notes from them since January?

Assistant calls find_documents (kind: "credit_note", company_id: …): none since January.