uvx ndi-mcp (or pip install ndi-mcp). The older ndi-sdk[mcp] extra still resolves to that package.
Hosted
Paste this into the agent’s MCP config. Mint the key on the API keys page; do not commit it.<NDI_BASE_URL>/v1/mcp, with no
trailing slash. The server also accepts the key as Authorization: Bearer ndi_sk_....
The hosted server runs in our cloud, so it cannot see your filesystem. upload_document and upload_file refuse a local path there. Pass a public URL, or run the local server.
Local
ndi-mcp login opens the NDI console in your browser. Approve there; the CLI stores the minted key in ~/.ndi/config.toml. Pass --api-key (or set $NDI_API_KEY) to skip the browser.
Cursor — add to .cursor/mcp.json:
opencode.json:
$NDI_API_KEY is read first; otherwise the key saved by ndi-mcp login. Local files go through upload_document, then parse_document / extract_data with the returned upload_id.
Tools
Same catalog on hosted and local. Names map to the Python SDK:
Ask
get_documentation with a topic (parse, extract, auth, workspaces, …) before writing integration code.
To decide between automatic_search, qa, je_testing, qa_file, and query_tables for a question, follow Choose the right tool. deep_search and fact_search are deprecated: use qa or automatic_search instead of deep_search, and automatic_search with mode="fact" instead of fact_search. Both keep working until they are retired.
start_ledger_understanding measures the ingested journal package;
get_ledger_understanding reads the latest report. list_ledger_sources,
select_ledger_sources, and get_ledger_selection confirm a source
selection; pass the returned selection_id to start and get. Without
force, an unchanged package republishes the stored report. A run already
in flight returns 409 ledger_understanding_in_progress.
A failed tool call returns an error result (isError: true) whose text is
<code>: <message>, such as unauthorized: …. A refused request
(invalid_request) adds one - <field>: <message> line per refused field, up
to five, without repeating the values you sent. Some arguments are checked
before any call; for example, evaluate_systemone refuses an unknown question
type with the validation library’s message.
After automatic_search, qa, or je_testing succeeds, poll every grounding
job id with wait_for_job. For automatic_search, those ids are on
result.output when fact search answered (or a stored deep route), and an
agent answer’s are on result.output.answer when present; for qa, on
result.answer when present; for je_testing and the deprecated search
tools, on result.grounding_job_ids. Do not call
ground_items for those evidences.