nifi-mcp
Provides tools for interacting with the Apache NiFi REST API, enabling management of process groups, processors, connections, queues, controller services, parameters, provenance, and version control in a NiFi instance.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@nifi-mcp show me the process group tree"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
nifi-mcp
An MCP server and a CLI for the Apache NiFi REST API, sharing one async client.
nifi-mcp— exposes NiFi to an LLM agent over stdio (59 tools).nifi— the same capabilities from a terminal, with tables by default and--jsonfor scripting.
Built and verified against NiFi 1.15.3. See SPEC.md for the design decisions.
Install
uv sync
source .venv/bin/activate
nifi doctor # verify connectivity, auth, host header, and versionRelated MCP server: n8n MCP Server
Configuration
Settings resolve in this order: environment → .env → defaults.
Copy .env.example to .env to start. The important ones:
Variable | Default | Meaning |
|
| The NiFi instance |
|
| Host header override — see below |
|
| Gates every mutating MCP tool |
|
| TLS verification (dev server is self-signed) |
Credentials
Credentials come from the environment, and only from the environment:
Variable | Meaning |
| Login identity |
| Login password |
Set them however your environment does it — exported in the shell, in the MCP server's
env block, or in a .env file next to pyproject.toml (gitignored). The process is
handed its secret; it never goes looking for one on disk, so what it authenticates with
does not depend on the directory it was launched from.
export NIFI_USERNAME='7090b632-6bb7-4a11-b6bc-c308a331e559'
export NIFI_PASSWORD='...'
nifi doctorNiFi in single-user mode generates the pair on its first run and logs it once, to
logs/nifi-app.log on the NiFi host:
grep 'Generated \(Username\|Password\)' logs/nifi-app.log... o.a.n.a.s.SingleUserCredentialsGenerator Generated Username [<uuid>]
... o.a.n.a.s.SingleUserCredentialsGenerator Generated Password [<password>]Copy those two values into the variables above. If the line has already been rotated out of the log, set a pair of your own instead:
./bin/nifi.sh set-single-user-credentials <username> <password> # on the NiFi hostThe values are exchanged for a JWT at POST /access/token; the token is cached, its
exp is decoded, and it is refreshed about 60s before expiry (and once more on any
401). The password itself is sent only at login, is held in a SecretStr, and never
appears in logs or repr().
The host header
NiFi validates the Host header against nifi.web.proxy.host. Reaching the instance by
an address that is not in that allowlist — for example from WSL at 172.21.80.1 when NiFi
runs on the Windows host — gets this:
The request contained an invalid host header [172.21.80.1:8443]NIFI_HOST_HEADER rewrites the header without changing where the connection goes. Set it
to an empty value if your NiFi accepts the real host. nifi doctor diagnoses this case.
CLI
nifi doctor # connectivity + auth + version diagnostics
nifi about # version and identity
nifi status # flow health at a glance
nifi bulletins # recent warnings and errors
nifi pg tree # the flow, as a tree
nifi pg list|get|create|delete|start|stop
nifi processor list|get|create|update|start|stop|run-once|terminate|delete
nifi connection list|get|create|delete
nifi queue list|peek|empty
nifi cs list|get|create|enable|disable|delete
nifi param list|get|create|set|delete
nifi types search|show
nifi provenance query|lineage
nifi version status|registries|commit
nifi system diagnostics|counters|clusterGlobal flags: --json (raw JSON), --yes (skip destructive prompts), --dry-run
(show what would happen), --verbose (log HTTP to stderr).
Exit codes: 0 ok, 1 NiFi error, 2 usage error, 3 connection or auth failure.
Example: build and run a flow
GID=$(nifi --json pg create demo | jq -r .id)
GEN=$(nifi --json processor create GenerateFlowFile --pg $GID --name gen \
--period "1 sec" --prop "File Size=64B" | jq -r .id)
LOG=$(nifi --json processor create LogAttribute --pg $GID --name log \
--y 300 --auto-terminate success | jq -r .id)
nifi connection create $GEN $LOG -r success --pg $GID
nifi pg start $GID
nifi connection list $GID # watch the queue
nifi pg stop $GID
nifi --yes pg delete $GIDComponent types accept short names (GenerateFlowFile); they are resolved against the
instance's catalogue. nifi types search kafka finds what is installed.
MCP server
Register with Claude Code:
claude mcp add nifi -- /home/alexsaez/projects/nifi-mcp/.venv/bin/nifi-mcpOr add to your MCP client config directly:
{
"mcpServers": {
"nifi": {
"command": "/home/alexsaez/projects/nifi-mcp/.venv/bin/nifi-mcp",
"env": {
"NIFI_BASE_URL": "https://172.21.80.1:8443",
"NIFI_HOST_HEADER": "localhost:8443",
"NIFI_USERNAME": "7090b632-6bb7-4a11-b6bc-c308a331e559",
"NIFI_PASSWORD": "...",
"NIFI_ALLOW_WRITE": "false"
}
}
}
}Note that env values in this config file are stored in plain text, so it should be
readable only by you. To keep the password out of the file entirely, export
NIFI_USERNAME / NIFI_PASSWORD in the shell that launches the client and reference
them as "${NIFI_PASSWORD}" if your client expands variables, or omit them here and let
the server inherit them.
If the configuration is wrong the server still starts and each tool call returns a
structured error naming the problem. It does not exit, because a process that dies
before the transport is established shows up in the client as nothing more than
"connection closed". nifi doctor diagnoses the same things from a terminal.
Write safety
Two layers, because the caller is a model:
NIFI_ALLOW_WRITE— when false (the default), mutating tools are not registered. The model sees 28 read tools and cannot attempt a write at all. Set it totrueto register all 59.confirm— the 9 destructive tools (deletes,nifi_empty_queue,nifi_terminate_processor,nifi_stop_version_control) takeconfirm. Called without it, they report exactly what would be affected and change nothing.
Tools also carry MCP annotations (read_only_hint, destructive_hint) so clients can
apply their own policy.
The CLI is deliberately not gated by NIFI_ALLOW_WRITE — a human at a terminal is
already the confirmation. Destructive commands prompt instead; --yes skips the prompt.
Development
pytest # 49 unit tests, no server needed
NIFI_INTEGRATION=1 pytest # + 5 live tests against NIFI_BASE_URL
ruff check src tests && mypy src/nifi_mcpIntegration tests build a real flow inside a scratch process group and tear it down afterwards; they never touch anything outside it.
Layout
src/nifi_mcp/
├── config.py settings from environment and .env
├── errors.py typed exceptions with actionable hints
├── client.py async client: auth, host header, revisions, retries
├── compat.py version detection, 1.x/2.x differences
├── summaries.py trim NiFi entities to the useful fields
├── api/ one module per resource family
├── tools/ MCP tool definitions (read_tools / write_tools)
├── server.py MCP entry point
└── cli.py Typer CLINotes on the NiFi API
Three things the client handles so callers don't have to:
Revisions. Every mutating call must echo the revision it read (optimistic locking).
update_with_revisionfetches, merges, and retries once on a409.Async request endpoints. Queue listings, drop requests, provenance queries, and parameter updates are submitted, polled, then deleted. Some of these are
POSTs that only read; those bypass the write gate explicitly.Display strings. NiFi returns
queuedCountas a formatted string ("1,234"). The summaries expose numericcount/bytesalongside the_displayvariants.
Known gaps
NiFi 2.x auth (OIDC/SAML) — the compat layer detects the version, but 2.x is untested.
Version-control writes are implemented but unexercised: no registry is configured on the dev server.
Cluster management, tenants/policies, and templates are out of scope (SPEC.md §11).
Available Tools
28 toolsnifi_aboutARead-onlyIdempotent
Version, build, and identity information for the connected NiFi instance.
Backed by GET /flow/about and /flow/current-user. Use this first to confirm connectivity and learn which NiFi generation you are talking to.
Inputs: no named parameters. Returns: object
nifi_countersBRead-onlyIdempotent
Flow counters and their current values.
Backed by GET /counters.
Inputs: no named parameters. Returns: result
nifi_find_component_typesARead-onlyIdempotent
Search the catalogue of installable component types by name, tag, or description.
Backed by GET /flow/processor-types and /flow/controller-service-types.
kind is "processor", "controller_service", or "both". Use this to find the
correct type before calling nifi_create_processor.
Inputs: kind, limit, query. Returns: result
nifi_flow_statusARead-onlyIdempotent
Aggregate controller status: running/stopped/invalid counts, queued data, bulletins.
Backed by GET /flow/status and /flow/bulletin-board. The fastest way to answer "is anything wrong right now?".
Inputs: no named parameters. Returns: object
nifi_flow_treeARead-onlyIdempotent
Recursive process-group tree with processors and connections.
Backed by GET /flow/process-groups/{id}. depth bounds the recursion; groups
beyond it are listed by id and name only. Start here to understand a flow's shape.
Inputs: depth, pg_id, include_components. Returns: object
nifi_get_connectionCRead-onlyIdempotent
One connection: endpoints, routed relationships, queue depth, prioritizers.
Backed by GET /connections/{id}.
Inputs: connection_id (required), verbose. Returns: object
nifi_get_controller_serviceBRead-onlyIdempotent
One controller service: properties, state, and what references it.
Backed by GET /controller-services/{id}. Sensitive values are masked.
Inputs: service_id (required), verbose. Returns: object
nifi_get_flowfileBRead-onlyIdempotent
Metadata and attributes for one queued flowfile.
Backed by GET /flowfile-queues/{id}/flowfiles/{uuid}.
Inputs: connection_id (required), flowfile_uuid (required). Returns: object
nifi_get_flowfile_contentARead-onlyIdempotent
Content of one queued flowfile, truncated to max_bytes.
Backed by GET /flowfile-queues/{id}/flowfiles/{uuid}/content. Binary content is
returned base64-encoded, indicated by the encoding field.
Inputs: connection_id (required), flowfile_uuid (required), max_bytes. Returns: object
nifi_get_lineageARead-onlyIdempotent
Lineage graph for a flowfile, as nodes and links.
Backed by POST /provenance/lineage, polled to completion. Supply either
flowfile_uuid or event_id.
Inputs: event_id, direction, flowfile_uuid. Returns: object
nifi_get_parameter_contextBRead-onlyIdempotent
One parameter context with its parameters and bound process groups.
Backed by GET /parameter-contexts/{id}.
Inputs: context_id (required). Returns: object
nifi_get_process_groupBRead-onlyIdempotent
A process group's identity, component-state counts, and version-control state.
Backed by GET /process-groups/{id}. Pass "root" for the top-level group.
Inputs: pg_id, verbose. Returns: object
nifi_get_process_group_contentsARead-onlyIdempotent
The direct contents of one process group: children, processors, connections, ports.
Backed by GET /flow/process-groups/{id}. Unlike nifi_flow_tree this does not recurse, so it is the cheaper choice when inspecting a single group.
Inputs: pg_id, verbose. Returns: object
nifi_get_processorARead-onlyIdempotent
One processor in full: properties, scheduling, relationships, validation errors.
Backed by GET /processors/{id}. Sensitive property values are masked.
Inputs: processor_id (required), verbose. Returns: object
nifi_get_property_descriptorARead-onlyIdempotent
Descriptor for one processor property: type, default, and allowable values.
Backed by GET /processors/{id}/descriptors. Use this before setting a property whose valid values you are unsure of.
Inputs: processor_id (required), property_name (required). Returns: object
nifi_get_provenance_eventBRead-onlyIdempotent
One provenance event with its full before/after attribute set.
Backed by GET /provenance-events/{id}.
Inputs: event_id (required). Returns: object
nifi_get_version_infoBRead-onlyIdempotent
Version-control state of a process group: registry, bucket, flow, and version.
Backed by GET /process-groups/{id}.
Inputs: pg_id. Returns: object
nifi_list_bulletinsARead-onlyIdempotent
Recent bulletins — NiFi's warning and error notices.
Backed by GET /flow/bulletin-board. The first place to look when a processor is failing but its configuration looks correct.
Inputs: limit. Returns: result
nifi_list_connectionsARead-onlyIdempotent
Connections in a process group with queue depth and backpressure settings.
Backed by GET /process-groups/{id}/connections. queued.count and
queued.bytes are numeric; the _display variants are formatted strings.
Inputs: pg_id. Returns: result
nifi_list_controller_servicesBRead-onlyIdempotent
Controller services visible to a process group, with state and referencing components.
Backed by GET /flow/process-groups/{id}/controller-services.
Inputs: pg_id, include_ancestors. Returns: result
nifi_list_parameter_contextsARead-onlyIdempotent
All parameter contexts and their parameters. Sensitive values are masked.
Backed by GET /flow/parameter-contexts.
Inputs: no named parameters. Returns: result
nifi_list_processorsBRead-onlyIdempotent
Processors in a process group with run status, validity, and throughput.
Backed by GET /process-groups/{id}/processors.
Inputs: pg_id, include_descendants. Returns: result
nifi_list_registry_clientsBRead-onlyIdempotent
NiFi Registry clients configured on this instance.
Backed by GET /controller/registry-clients.
Inputs: no named parameters. Returns: result
nifi_process_group_statusARead-onlyIdempotent
Throughput and queue statistics for a process group, recursively.
Backed by GET /flow/process-groups/{id}/status.
Inputs: pg_id. Returns: object
nifi_provenance_queryARead-onlyIdempotent
Search provenance events to trace what happened to data.
Backed by POST /provenance, polled to completion. Dates use NiFi's
MM/dd/yyyy HH:mm:ss format. This reads history only.
Inputs: end_date, filename, event_type, start_date, +3 more. Returns: object
nifi_queue_listingBRead-onlyIdempotent
List the flowfiles currently queued on a connection.
Backed by POST /flowfile-queues/{id}/listing-requests, polled to completion. This reads state only; it does not modify the queue.
Inputs: connection_id (required), limit. Returns: object
nifi_searchARead-onlyIdempotent
Search the flow for components by name, id, property value, or comment.
Backed by GET /flow/search-results — the same search the NiFi UI uses.
Inputs: query (required), pg_id. Returns: object
nifi_system_diagnosticsARead-onlyIdempotent
JVM heap, thread counts, repository disk usage, and uptime.
Backed by GET /system-diagnostics. Use when diagnosing performance or memory pressure rather than flow logic.
Inputs: verbose. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 28 tools
Most tools target distinct NiFi resources and the descriptions explicitly differentiate overlapping process-group views (tree vs contents vs status). However several status/diagnostic tools (flow_status, process_group_status, get_process_group) and provenance/lineage tools share enough conceptual ground that misselection is possible for less careful agents.
All tools use a consistent nifi_ prefix and snake_case. The dominant pattern is verb_noun (get_, list_, search_, find_, query_), with a few noun-only deviations (about, counters, flow_status, flow_tree, system_diagnostics) that are still readable.
28 tools exceed the 25-tool threshold for 'too many' per the rubric, especially given the apparent read-only scope. While they cover many subresources, the set could be consolidated or split into focus modes.
The surface is almost entirely read-only: no create/update/delete/start/stop tools for processors, connections, controller services, or process groups. Descriptions even reference nifi_create_processor and setting processor properties, which are absent, indicating significant gaps for flow management.
Maintenance
Related MCP Connectors
Create and manage AI agents that collaborate and solve problems through natural language interacti…
Protocol-native energy infrastructure orchestration for AI data centers. Provides 46 MCP tools across 8 grid protocols (IEC-61850, DNP3, Modbus, OCPP, OpenADR, IEEE 2030.5, IEC 60870-5-104, ICCP) with 5 core API primitives: connect, dispatch, settle, comply, and intel. Enables AI agents to programmatically interact with substations, grid interfaces, and energy assets for real-time workload-grid coordination.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Remote MCP for RunComfy: ComfyUI deployments, hosted models, LoRA training. 31 tools.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables AI agents to create, retrieve, update, and manage n8n workflows through the n8n API. Supports full workflow lifecycle management including activation, deactivation, and deletion operations.3923 npmMIT
- AlicenseBqualityCmaintenanceEnables AI assistants to interact with n8n workflow automation instances through the REST API. Supports workflow management, execution control, tag organization, execution history monitoring, and webhook management.19148 npm5MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to manage n8n workflow automation instances through tools for workflow CRUD operations, execution monitoring, and webhook triggering. It facilitates programmatic interaction with n8n instances via the n8n API with AI-optimized descriptions and error handling.62MIT
- FlicenseNot gradedqualityDmaintenanceEnables LLMs to programmatically control n8n via natural language for automated workflow creation, modification, and execution management.1-