MCP server
Give AI assistants read-only access to Nistor through the Model Context Protocol.
The MCP server lets an AI assistant query Nistor through the Model Context Protocol. It
is a client of the backend's REST API that only reads: every tool sends GET requests and nothing else, so an assistant
can search the graph and read lineage, incidents, runs and rules, but never change them.
The package nistor-mcp has two commands, which serve the same tools:
| Command | Transport | Use it for |
|---|---|---|
nistor-mcp |
stdio: one JSON-RPC 2.0 message per line on stdin and stdout | An assistant on your machine, which starts the server itself |
nistor-mcp-remote |
MCP Streamable HTTP | A shared endpoint that assistants reach over the network (see Remote gateway) |
Install#
From a clone of the repository, make dev installs nistor-mcp into .venv, with the extra the gateway needs:
git clone https://gitlab.com/nistor-io/nistor.git
cd nistor
make dev
.venv/bin/nistor-mcp --list-tools
--list-tools prints the tool catalogue as JSON and exits. It needs no backend and no network.
Once released, the package is on PyPI as nistor-mcp, and nistor-mcp[remote] adds what the gateway needs. Until then,
install from a clone. The package needs Python 3.10 or later.
Run it#
An MCP client starts nistor-mcp itself and talks to it over stdin and stdout. Run it by hand only to check that it
starts:
NISTOR_MCP_BASE_URL=https://nistor.example.com NISTOR_MCP_TOKEN=<token> .venv/bin/nistor-mcp
It prints nistor-mcp <version> ready (backend: https://nistor.example.com/api/v1) on stderr and waits for messages.
Everything it logs goes to stderr, because stdout carries the protocol.
The server answers initialize, ping, tools/list and tools/call. When a tool cannot reach the backend, or the
backend refuses the call, the error comes back as the tool's result, marked isError. A missing required argument is a
JSON-RPC error (-32602).
Configure#
The server reads its settings from the environment when it starts:
| Variable | Default | Meaning |
|---|---|---|
NISTOR_MCP_BASE_URL |
http://localhost:8000 |
The backend's URL, without the API prefix. |
NISTOR_MCP_API_PREFIX |
/api/v1 |
The API prefix. |
NISTOR_MCP_TOKEN |
none | The token sent with every request. It is never logged. |
NISTOR_MCP_AUTH_HEADER |
Authorization |
The header that carries the token. |
NISTOR_MCP_AUTH_SCHEME |
Bearer |
The word before the token. Set it to an empty value to send the token alone. |
NISTOR_MCP_TIMEOUT |
30 |
The timeout of one request, in seconds. |
NISTOR_MCP_EMBEDDED_UI_ENABLED |
true |
Add an HTML view to the results of three tools (see Tools). Only 1, true, yes and on count as true. |
NISTOR_MCP_FRONTEND_BASE_URL |
none | The web shell's URL, which makes the "open in Nistor" links of those views absolute. |
NISTOR_MCP_BACKEND_AUDIENCE |
none | For the remote gateway only (see Remote gateway). |
Add it to a client#
Most MCP clients that start a local server read a block like this one:
{
"mcpServers": {
"nistor": {
"command": "nistor-mcp",
"env": {
"NISTOR_MCP_BASE_URL": "https://nistor.example.com",
"NISTOR_MCP_TOKEN": "<token>"
}
}
}
}
If the client cannot find nistor-mcp on its PATH, give the full path to .venv/bin/nistor-mcp in your clone.
The stdio server sends the token in a single header, so it works against a backend that accepts that token directly, such as the Quickstart stack. In the reference Google Cloud deployment (Install on GCP), only the web shell's proxy and Nistor's own service accounts may call the backend's Cloud Run service. Connect assistants to such a deployment through the remote gateway.
Agent tokens#
An agent token is a credential that Nistor issues for one assistant. It does not carry the identity of the person who
registered it. Every agent token acts as one fixed identity that may only read (GET, HEAD and OPTIONS requests) and
holds the permissions listed in the backend setting MCP_AGENT_PERMISSION_CODES: by default graph:view,
catalog:view, finops:view and dataquality:view. You can add other *:view codes to that setting, as a JSON list.
The backend needs two settings before it accepts agent tokens:
AGENT_GOVERNANCE_ENABLED=true. While it is off, the backend refuses every agent token.- A signing key in
AGENT_MCP_TOKEN_SIGNING_KEY: at least 32 characters of random data, for example fromopenssl rand -base64 48. The backend refuses a short or predictable key. In a local environment (ENVIRONMENT=local), it falls back toEXTENSION_TOKEN_SIGNING_KEY.
With the reference Terraform root, enable_agent_governance = true sets the first, creates the secret
agent-mcp-token-signing-key-<env> and passes it to the backend as the second. Add a version holding the random value to
that secret yourself: Terraform never sees it.
To register an assistant, call the API as a person who holds agents:manage:
curl -X POST "$NISTOR_API_URL/api/v1/agent-governance/agents" \
-H "Authorization: Bearer $NISTOR_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "acme-assistant"}'
The response carries the token in token, once: Nistor keeps only its identifier and first characters. A token lasts
AGENT_MCP_TOKEN_TTL_DAYS days (90 by default). POST /api/v1/agent-governance/agents/{id}/rotate-token issues a new
one, and POST /api/v1/agent-governance/agents/{id}/revoke revokes the agent for good. Listing agents needs
agents:view.
A registration also stores allowed tools, a rate limit and a daily budget for the agent. The AI module of Nistor Enterprise enforces them, and its console has a page to register agents. Without that module, these settings have no effect, and you register agents through the API.
Tools#
Results are shaped for a model's context window. A node loses its DDL, schema, column lineage and query text, and long lists are cut (100 nodes per lineage direction, 50 affected nodes, 50 runs), with counts or a marker that say so.
Several tools read the routes of an Enterprise module (Nistor Enterprise). The stdio server lists every tool; without the module, such a tool returns an error from the backend. The remote gateway hides the tools of a capability that an administrator has switched off.
| Tool | What it returns | Needs |
|---|---|---|
nistor_search |
Full-text search over nodes, incidents and rules, and, with the Catalog module, columns, assets and glossary terms. Use it to find the ids the other tools take. | Open source |
nistor_get_node |
One node. | Open source |
nistor_get_lineage |
The upstream and downstream nodes of a node, or its direct neighbours only. | Open source |
nistor_impact_analysis |
What a failure of a node affects downstream: nodes, rules, data-quality checks, scheduled actions and cost at risk. | Open source. The checks come from the Data quality module, the cost from the FinOps module. |
nistor_list_incidents |
Incidents, newest first, by status, severity, type and environment. | Open source |
nistor_get_incident |
One incident. | Open source |
nistor_cost_summary |
Nodes ranked by cost over a number of days (30 by default). | Open source. Without the FinOps module the nodes carry no cost. |
nistor_finops_costs |
BigQuery spend over a date range, by project, writer, log type or node. | FinOps module (capability finops) |
nistor_cost_anomalies |
Detected cost spikes. | FinOps module (finops) |
nistor_cost_to_produce |
A node's cost, including its share of the cost of its upstream nodes. | FinOps module (finops) |
nistor_list_runs |
Recent runs, newest first, by state, action, trigger and time. | Open source |
nistor_get_run |
One run. | Open source |
nistor_run_stats |
Counts of running, completed and failed runs. | Open source |
nistor_list_on_hold |
The actions the scheduler is holding, and why. | Open source, capability scheduler |
nistor_lookup_term |
The glossary definition of a business term. | Catalog module. Without it, there are no matches. |
nistor_get_catalog_asset |
A node's catalog entry: description, owner, tags, certification and columns. | Catalog module (catalog) |
nistor_get_catalog_columns |
One column: description, flags, type and the columns that hold the same field. | Catalog module (catalog) |
nistor_recommend_dq_rules |
The data-quality monitors the Advisor proposes for a node. | Advisor module (advisor) |
nistor_list_dq_checks |
The data-quality checks on a node, with their latest result. | Data quality module (data_quality) |
nistor_get_dq_check |
One check: its configuration and its last 10 runs. | Data quality module (data_quality) |
nistor_dq_check_history |
One check's measured value over its recent runs. | Data quality module (data_quality) |
nistor_list_rules |
The scheduling rules that target a node. | Open source, capability scheduler |
nistor_get_rule |
One scheduling rule. | Open source, capability scheduler |
nistor_node_health |
A node's health: trust verdict, freshness, data-quality summary, run reliability, open incidents and neighbours. | Open source |
nistor_node_usage |
Who reads and writes a node, over a number of days (30 by default). | Open source |
nistor_node_activity |
A node's runs, data-quality runs, incidents and writes over a number of days (14 by default, 90 at most). | Open source. The data-quality runs need the Data quality module. |
nistor_get_lineage, nistor_dq_check_history and nistor_node_activity also return a self-contained HTML view (a
ui://nistor/… resource) for clients that display one. NISTOR_MCP_EMBEDDED_UI_ENABLED=false turns it off.
Permissions#
With a person's token, a tool sees what that person may see. The open-source tools need only a signed-in user.
With an agent token, a tool sees what the agent identity may see (see Agent tokens). That identity does
not hold advisor:view, which the Advisor's routes require, so nistor_recommend_dq_rules fails with an agent token
unless you add that code to MCP_AGENT_PERMISSION_CODES.
Remote gateway#
nistor-mcp-remote serves the same tools over MCP Streamable HTTP, at https://<gateway-host>/mcp/ (/mcp redirects
there). An assistant connects to it with an agent token and runs nothing on its own machine. The gateway also answers
/healthz and /health/live (liveness), /health/ready and /health/installed.
The gateway reads the caller's Authorization: Bearer <token> header and calls the backend in one of two ways:
- With
NISTOR_MCP_BACKEND_AUDIENCEset (to the backend's URL), it calls the backend with a Google identity token of its own service account, and forwards the caller's token inX-Nistor-Agent-Token. The backend accepts that header only from the account named in itsMCP_GATEWAY_SERVICE_ACCOUNTsetting, only whileAGENT_GOVERNANCE_ENABLEDis on, and only for read requests. It then treats the call as the agent's. - Without it, the gateway forwards the caller's token in
Authorization, as the stdio server would.
To run it yourself, start .venv/bin/nistor-mcp-remote with NISTOR_MCP_BASE_URL set. It listens on PORT (8080 by
default) on every interface. In the runtime image, nistor serve mcp starts the same app.
On Google Cloud, the reference Terraform root (deployments/gcp) deploys it when you ask for it:
| Input | Effect |
|---|---|
enable_mcp = true |
Creates the Cloud Run service <prefix>-mcp-<env>, which runs nistor serve mcp with NISTOR_MCP_BASE_URL and NISTOR_MCP_BACKEND_AUDIENCE set to the backend's URL. Its ingress is public and anyone may invoke it: the agent token is the access control. The output mcp_uri is its URL. Off by default. |
role_service_accounts.mcp |
The gateway's own service account, required with enable_mcp. The root makes it the backend's MCP_GATEWAY_SERVICE_ACCOUNT and a trusted caller. The account also needs roles/run.invoker on the backend's service, which the root does not grant. |
enable_agent_governance = true |
Turns agent tokens on, with their signing key (see Agent tokens). |
A client that connects to a remote MCP server with a fixed header takes a block like the one below. Clients name these keys differently: check your client's documentation.
{
"mcpServers": {
"nistor": {
"url": "https://<gateway-host>/mcp/",
"headers": { "Authorization": "Bearer <token>" }
}
}
}
Read next#
- Lineage and impact, for what
nistor_get_lineageandnistor_impact_analysiscompute. - Configuration, for the backend's settings.