@devrobotlabs/visionapi-mcp
Official# @devrobotlabs/visionapi-mcp
MCP server for the [Vision API](https://visionapi.io). Point Claude Code, Claude Desktop, Cursor
or any other MCP host at a folder of scans and ask for the invoices — no integration to write,
no API key in generated code, no contract paraphrased from memory.
```
You: pull the totals out of every invoice in ~/inbox and put them in a CSV
Claude: [vision_analyze × 7]
Done — 7 invoices, 14 credits. Three had no PO number; I left those cells empty.
```
## Install
Nothing to install. Add it to your host's config and it runs via `npx`.
**Claude Code** — `claude mcp add visionapi --env VISION_API_KEY=sk_live_... -- npx -y @devrobotlabs/visionapi-mcp ~/inbox`
**Claude Desktop** — `claude_desktop_config.json`:
```jsonc
{
"mcpServers": {
"visionapi": {
"command": "npx",
"args": ["-y", "@devrobotlabs/visionapi-mcp", "/Users/me/inbox"],
"env": { "VISION_API_KEY": "sk_live_..." }
}
}
}
```
**Cursor** — `.cursor/mcp.json`, same shape:
```jsonc
{
"mcpServers": {
"visionapi": {
"command": "npx",
"args": ["-y", "@devrobotlabs/visionapi-mcp", "."],
"env": { "VISION_API_KEY": "sk_live_..." }
}
}
}
```
**VS Code** — `.vscode/mcp.json`:
```jsonc
{
"servers": {
"visionapi": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@devrobotlabs/visionapi-mcp", "${workspaceFolder}"],
"env": { "VISION_API_KEY": "sk_live_..." }
}
}
}
```
Get a key at [app.visionapi.io/dashboard/keys](https://app.visionapi.io/dashboard/keys). New
accounts get 50 credits, no card.
> The host config blocks live in this README rather than in an `examples/` directory — a
> departure from the nine client libraries, and a deliberate one. A snippet that exists only in
> a README cannot drift from a runnable script nobody runs.
## Which directories it can read
**Every positional argument is a directory the server may read files from.** With none given,
the process working directory is the only root — which is the safe default, because MCP hosts
launch a stdio server with the project directory as its cwd.
This matters more than it may look. The server holds a **live spending credential** and runs
with your filesystem permissions, so it can read anything your shell can. Asking it for the raw
text of `~/Documents/passport.jpg` is a working way to get that document's contents into a
model's context and into whatever transcript your host keeps. The allowlist is what stops a
confused or manipulated agent doing that by accident.
Paths are resolved with `realpath` on **both** sides before being compared, so a symlink inside
an allowed directory cannot point out of it.
`--allow-any-path` turns the allowlist off entirely. It warns on stderr at startup and you
should have a reason.
## Tools
| Tool | What it does | Cost |
| --- | --- | --- |
| `vision_analyze` | Structured fields out of one image or PDF | 1 credit an image, 2 a PDF page |
| `vision_ask` | Up to 5 plain-language questions about one file | 1 credit an image, 1 a PDF page |
| `vision_detect` | What is this file? Ranked presets, no extraction | 1 credit per 5 calls |
| `vision_list_presets` | The preset catalogue | free |
| `vision_get_preset` | Every field one preset returns | free |
| `vision_credits` | Balance and buckets | free |
| `vision_get_task` | Status/result of a queued task | free |
The three that spend credits are annotated `readOnlyHint: false`, so a host that auto-approves
read-only tools will still stop and ask before one of them runs.
The catalogue is also exposed as resources — `visionapi://presets` and
`visionapi://presets/{name}` — for hosts that prefer them. Tools are the primary surface,
because resource support is uneven across hosts.
### Output
Responses are rendered for a model to read, not dumped as JSON. A 37-field invoice preset over
a document that fills twelve of them comes back as a table plus one `Not found in this
document (25): …` line, rather than as twenty-five repetitions of
`{"value":null,"confidence":"low"}` — three to four times smaller, and easier to act on.
Nothing is lost in the process. Every tool takes a `format`:
- **`markdown`** (default) — the rendering above.
- **`compact_json`** — the same information as data, with `_not_found` and `_low_confidence`
arrays. For when the agent will parse rather than read.
- **`json`** — the API response verbatim. What to reach for when writing real HTTP code
against the contract.
Confidence is printed only when it is *not* high, so `(mid)` and `(low)` stand out and the
common case costs nothing to read.
### Long documents
Leave `mode` at `auto`. The API kills a synchronous request at 60 seconds; the server then
re-submits it to the queue and polls, reporting progress to your host as it goes. **You are
charged once**, because the timed-out attempt released its reservation in full.
Pass `mode: "async"` up front for anything over roughly ten pages, and `pages: "1-5"` to sample
a long document cheaply — you are charged for selected pages only.
## Costs and failures
Failures cost nothing. Every non-2xx releases the credit reservation in full, so a failed call
is safe to correct and repeat and there is no cleanup to do. The tool descriptions say so, which
is why an agent using this server behaves sensibly after an error instead of either giving up or
retrying something that cannot work.
Two errors carry advice that is worth knowing yourself:
| Error | What it means |
| --- | --- |
| `insufficient_credits` | Retrying cannot help — the balance does not change on its own. [Top up.](https://app.visionapi.io/dashboard/billing) |
| `too_many_tasks` | Your own async tasks are at the plan's cap. It clears when one of *them* finishes, not on a timer — so sleeping and retrying blocks the very thing you are waiting for. |
## Environment
| Variable | Required | Purpose |
| --- | --- | --- |
| `VISION_API_KEY` | for billable tools | Your key. The catalogue tools work without it. |
| `VISION_API_URL` | no | Override the API base URL. Rarely needed. |
A missing key does not stop the server starting: it warns on stderr, `tools/list` still works,
and the first billable call returns a message naming the fix. A server that refuses to start
tells the user only that something is broken.
## Development
```bash
npm install
npm run typecheck
npm test # 37 offline tests — no key, no network
npx @modelcontextprotocol/inspector node ./dist/cli.js ~/some/dir
```
`npm install --no-save ../node` to test against a local build of the client. **Not
`npm install ../node`** — that rewrites `package.json` to `"file:../node"`, and that manifest is
what gets published.
## Links
- [Documentation](https://docs.visionapi.io)
- [Integration reference for coding agents](https://docs.visionapi.io/agents.md)
- [Preset catalogue](https://visionapi.io/presets)
- [Pricing](https://visionapi.io/pricing)
MIT licensed.
TDQS
Scored across 7 tools
Each tool serves a distinct purpose: catalog discovery, preset details, credit balance, extraction, Q&A, detection, and async task retrieval. Even the overlapping detect/analyze pair is explicitly disambiguated with guidance on when each is appropriate, eliminating selection ambiguity.
All tools follow the vision_<action> pattern, with actions being clear verbs (list, get, analyze, ask, detect, get). The lone exception 'credits' represents a state query but still fits the pattern as a noun-based action. The prefix is consistent and each name clearly signals its function.
Seven tools is well-scoped for a vision API server, covering catalog management, extraction, Q&A, detection, credits, and async task handling. Each tool earns its place with no redundancy or bloat, matching the typical range for a focused service.
The tool set provides full lifecycle coverage: discover presets (list/get), perform operations (analyze/ask/detect), handle async tasks (get_task), and monitor usage (credits). There are no obvious gaps, and any missing features like custom schema management are handled via the dashboard rather than needing tools.