# MCP server The DocAI MCP server gives a coding agent direct access to your knowledge bases. It runs locally over stdio, calls the same public `/v1` API documented in the [API reference](/api), and needs one environment variable. This page is the tool reference. To install the server in Claude Code, Cursor or Codex, see [plugins and commands](/plugins). For the instructions that ship alongside it, and why they are the safety mechanism, see [agent guidance](/skill). Each group of tools below points at the guide for the endpoints it wraps. ## Configuration | Variable | Required | Default | Effect | |---|---|---|---| | `DOCAI_API_KEY` | yes | — | Sent as `x-api-key` on every request | | `DOCAI_BASE_URL` | no | `https://api.providus.ai` | Point at an on-prem deployment; trailing slashes are stripped | | `DOCAI_MCP_ALLOW_DESTRUCTIVE` | no | unset | `true`, `1` or `yes` registers the two permanent-delete tools | A missing key fails at startup rather than on the agent's first tool call: ``` DOCAI_API_KEY is required. Create a key in DocAI Settings and set it. ``` That is deliberate. One clear line on stderr beats a 401 on every tool the model tries. On a healthy start the server writes a single diagnostic line, also to stderr, because stdout is the protocol transport and anything else written there corrupts the stream: ``` [docai-mcp] 20 tools against https://api.providus.ai ``` Twenty, not 22, when `DOCAI_MCP_ALLOW_DESTRUCTIVE` is unset. That count is the quickest way to tell which configuration actually loaded. ## The tools Twenty-two tools. Ten are annotated read-only and cannot change anything. ### Knowledge bases These wrap the endpoints in [knowledge bases and search](/knowledge-bases). | Tool | Parameters | What it does | |---|---|---| | `docai_list_knowledge_bases` | none | Every knowledge base the key can see. Read-only. | | `docai_create_knowledge_base` | `name`, `description` (optional) | Creates one. Names must be unique within the organization. | | `docai_kb_index` | `kb_id` | Every file in a knowledge base with parse status and artifact links, in one call. Read-only. | ### Getting files in | Tool | Parameters | What it does | |---|---|---| | `docai_list_files` | `kb_id` (optional) | Lists files, optionally scoped to one knowledge base. Read-only. | | `docai_upload_file` | `path`, `kb_id`, `folder_id` (optional) | Uploads one local file. `path` must be absolute. Uploading does not parse. | ### Processing The parse tools wrap [parsing](/parsing), the extract tools wrap [extraction](/extraction), and `docai_classify` and `docai_split` wrap [document workflows](/workflows). All of them spend [credits](/quickstart#credits). | Tool | Parameters | What it does | |---|---|---| | `docai_parse_file` | `file_id` | Queues a parse. Returns a job to poll. Costs credits per page. | | `docai_parse_bulk` | `file_ids` (at least one) | Queues parses for many files. Costs credits for every page of every file. | | `docai_extract` | `file_id`, `schema` (object) | Extraction on a parsed file with an inline **JSON Schema**, kept as a durable artifact. This endpoint does not accept `schema_id` — use `docai_extract_run`. | | `docai_extract_run` | `file_id`, `schema_id` (optional), `schema` (optional object), `segment_ids` (optional) | Runs a **saved** schema by id, or DocAI's own `{title, fields}` shape — not JSON Schema. Queues an operation; the result arrives inline when you poll it. | | `docai_extract_bulk` | `file_ids` (at least one), `schema_id` (optional) | Queues extraction across many files. | | `docai_classify` | `file_id`, `classes` (array of strings, at least one) | Classifies a document and its pages, returning the classes and per-page assignments. Without classes every page comes back Unknown and the run still costs a credit, so the API rejects it. | | `docai_suggest_classes` | `file_id`, `guidelines` (optional) | Asks DocAI to propose a class list from the document, instead of inventing class names. Queued; costs 1 credit. | | `docai_split` | `file_id`, `suggest_rules` (optional), `rules` (optional array of objects) | Splits a PDF holding several documents. With `suggest_rules` it proposes rules instead of running. | | `docai_split_download` | `file_id`, `start_page`, `end_page`, `title`, `out_dir` (optional) | Saves one split record as its own PDF and returns the path. The API sends PDF bytes, not JSON. Free. | `docai_split` is the one tool that changes endpoint based on a flag: `suggest_rules` sends `POST /v1/split/rules/suggest`, otherwise `POST /v1/split/runs`. Both are queued work — poll with `docai_operation_status`, not `docai_job_status`. ### Schemas Schemas are covered in [extraction](/extraction). | Tool | Parameters | What it does | |---|---|---| | `docai_generate_schema` | `file_id`, `title` (optional) | Derives a reusable extraction schema from a parsed document. | | `docai_list_schemas` | none | Saved schemas, so one can be reused by id. Read-only. | ### Status | Tool | Parameters | What it does | |---|---|---| | `docai_job_status` | `file_id`, `job_id`, `include_events` (optional) | Parse or extract job status. `include_events` returns the stage-by-stage log. Read-only. | | `docai_operation_status` | `operation_id` | Queued workflow status, such as a split run. `output` stays null until `status` is `completed`. Read-only. | A job needs both ids. `docai_job_status` reads `/v1/files/{file_id}/jobs/{job_id}`, so a job id alone will not do — carry the file id with it. Set `include_events` when a job has failed. Without it you get the terminal status and nothing about which stage produced it. ### Reading out Artifacts and segments are described in [parsing](/parsing). | Tool | Parameters | What it does | |---|---|---| | `docai_read_artifact` | `file_id`, `key` | One artifact from the file's newest parse. Read-only. | | `docai_get_segments` | `file_id` | Segments with page coordinates, for citing an exact place in the source. Read-only. | `key` is an enum, and only these seven values are accepted: ``` result_md result_json grounding_json tables_json workbook_json pages imgs ``` `result_md` is the parsed markdown, `result_json` the extraction output, `grounding_json` the page coordinates. The tool resolves the manifest itself: it lists the file's artifacts, sorts by `created_at` and reads from the newest one, so you never pass a manifest id. If the file has never been parsed it fails with `No parse artifacts for file . Parse it first.` ### Search The search parameters and the response shape are in [knowledge bases and search](/knowledge-bases). | Tool | Parameters | What it does | |---|---|---| | `docai_search` | `kb_id`, `query`, `limit` (optional, 1–100), `file_ids` (optional), `table_only` (optional) | Full-text search over parsed evidence. Read-only. | It calls no model, so it spends no credits, and it returns exact file and segment pointers to cite. `file_ids` narrows the search to specific documents; `table_only` restricts hits to table content. ### Account | Tool | Parameters | What it does | |---|---|---| | `docai_credits` | none | Remaining credits and the monthly quota. Read-only. | ### Deleting | Tool | Parameters | What it does | |---|---|---| | `docai_delete_file` | `file_id` | Soft delete. The row is kept, the file leaves lists and indexes, and it can be restored. | | `docai_permanent_delete_file` | `file_id` | Removes the file, every version, and all parsed artifacts. Gated. Cannot be undone. | | `docai_delete_knowledge_base` | `kb_id` | Removes the knowledge base and everything in it. Gated. Cannot be undone. | ## A worked session Index a folder of contracts, then answer a question with citations. Nine calls, and only one of them spends money. **1. Find the knowledge base.** `docai_list_knowledge_bases` returns names and ids. If none fits, `docai_create_knowledge_base` with `name: "Contracts"`. **2. Check the balance first.** `docai_credits` before anything bulk. The agent should report the balance to you and wait, rather than discovering halfway through a folder that the quota is gone. **3. Upload the files.** `docai_upload_file` once per document — absolute `path` plus `kb_id`. Uploading does not parse; that is the next step. (Bulk folder import and sync are DocAI web-app features, not agent tools.) **4. See what state everything is in.** `docai_kb_index` with `kb_id`. One call returns every file, its parse status and its artifact links — which is also how you collect the file ids for the next step. **5. Parse what is unparsed.** `docai_parse_bulk` with the file ids from the index. This is the call that costs credits, per page, per file. **6. Wait.** Poll `docai_kb_index` to watch parse status move across the whole batch in one request. Drop to `docai_job_status` with `include_events: true` only for a file that failed, where you need the stage that broke. **7. Search rather than read.** `docai_search` with `kb_id` and a query such as `"termination for convenience"`. It costs nothing and comes back with file and segment pointers. **8. Read only the hits.** `docai_read_artifact` with `key: "result_md"` for the one or two files search pointed at. Reading all 34 documents to find one clause would burn context for no gain, and gives a worse answer than the pointers already did. **9. Cite precisely.** `docai_get_segments` for the answering file gives page coordinates, so the answer points at the line it came from rather than at the document. To pull the same field out of every contract instead, replace steps 7–9 with `docai_generate_schema` on one representative file, then `docai_extract_bulk` with the resulting `schema_id` across the set. Check `docai_credits` first — that one spends per file. ## Destructive tools `docai_permanent_delete_file` and `docai_delete_knowledge_base` are **not registered** unless `DOCAI_MCP_ALLOW_DESTRUCTIVE` is set to `true`, `1` or `yes`. They are skipped at registration rather than registered and refusing. An agent cannot call a tool it cannot see, and it cannot argue its way past one that does not exist. `docai_delete_file` is always available. It is a soft delete: the row stays, the file leaves lists and indexes, and it can be restored. The flag has to be present in the environment the **editor** launches the server in, and the server restarted afterwards. Setting it in a shell that the editor did not inherit changes nothing. ## Security **A DocAI API key is organization-root and bypasses RBAC.** It is not scoped to a knowledge base, and there is no read-only key today. Anything holding your key can read and write every knowledge base in your organization, whatever roles and grants you have configured for people. Consequences worth being explicit about: - An editor config file containing a key is production access to the whole organization. Treat it like a deploy credential, and keep it out of version control. - Any agent you connect can reach every knowledge base, not only the one you had in mind for the session. - Revoking the key is the only containment. There is no per-knowledge-base downgrade to fall back on. Scoped keys and a browser login flow are planned. The key itself is never written into a log or an error message. Failures carry the HTTP status, the method and path, the API's stable `code`, and the message — see [error codes](/errors). Error text reaches the model and may end up in a transcript, so nothing else is put in it.