Configuring the Confluent MCP Server
July 27, 2026 · View on GitHub
This is the single reference for configuring mcp-confluent.
It covers the YAML config file (-c config.yaml), the legacy env-var path (-e config.env) that the server still accepts during the transition, and how the two interact via ${VAR} interpolation.
Contents
- Two paths, one configuration
- Quick start (YAML)
- Anatomy of a YAML config
- Multiple connections (and zero connections)
${VAR}interpolation- How env vars and
.envfiles fit into the YAML world - Authentication modes
- HTTP/SSE transport security
- Tool enablement: which block lights up what
- Legacy env-var configuration (deprecated)
- Troubleshooting
Two paths, one configuration
mcp-confluent accepts configuration through either of two entry points, both of which feed the same internal configuration model at startup:
| Path | Invocation | Status |
|---|---|---|
| YAML | -c path/to/config.yaml | Preferred. |
| Env vars (legacy) | -e path/to/config.env or exported in the parent shell | Accepted; deprecated. |
The two paths are mutually exclusive: if you pass -c, the YAML file is the source of truth; otherwise the server reads the legacy environment variables listed in Legacy env-var configuration.
Roadmap. The two paths have full parity today. In a near-future release the env-var-only path will emit a startup warning; a release or two later it will be removed.
If you are starting fresh, begin with YAML.
If you have an existing .env, migrate when convenient — both -c and -e continue to work for now.
Quick start (YAML)
# 1. Drop a starter config.yaml into the current directory.
npx @confluentinc/mcp-confluent --init-config
# 2. Edit ./config.yaml — fill in the blocks you need.
# 3. Start the server.
npx @confluentinc/mcp-confluent --config ./config.yaml
--init-config copies config.example.yaml into ./config.yaml and idempotently appends the filename to a sibling .gitignore so secrets cannot slip into a commit.
It refuses to overwrite an existing config.yaml.
For OAuth-only setups use --init-oauth-config instead; it drops config.oauth.example.yaml at the same destination.
The two flags are mutually exclusive.
Anatomy of a YAML config
A config is a connections: map plus an optional top-level server: block for transport/security/logging settings.
Each connection block is one of two types — OAuth or direct — taken in turn below; a single configuragion may hold several connections and mix their types (see Multiple connections (and zero connections)).
The fully annotated reference is config.example.yaml; per-field comments live there rather than being duplicated here.
Compact examples for common local-Docker setups live in sample_configs/.
OAuth connection (type: oauth)
Confluent Cloud login via PKCE: the browser opens on the first tool call that needs Cloud access, the resulting session is reused for the rest of the process, and there are no API keys to provision. The connection itself carries no service blocks — resource IDs (cluster, env) flow in as tool arguments at call time.
server:
transports: [stdio]
log_level: info
connections:
ccloud-oauth:
type: oauth
description: "Confluent Cloud Production"
Get a starter file via --init-oauth-config.
Not every tool is OAuth-eligible yet — see Authentication modes for the supported list.
Direct connection (type: direct)
Credentials live in the YAML — API key/secret per service block, typically ${VAR}-interpolated from your shell environment.
Each service block under the connection is independently optional: include the ones you need and omit the rest.
The tools that depend on missing blocks disable themselves.
At least one service block must remain.
server:
transports: [stdio]
log_level: info
connections:
staging:
type: direct
description: "Confluent Cloud Staging via API Keys"
kafka: { ... }
schema_registry: { ... }
confluent_cloud: { ... }
flink: { ... }
tableflow: { ... }
telemetry: { ... }
The connection id (staging above) is freeform.
Either connection flavor also accepts an optional description — a free-text label echoed back by the list-configured-connections tool so an agent can tell your connections apart.
A blank or whitespace-only description is treated as no description.
Either connection flavor also accepts an optional read_only flag (default false).
When set to read_only: true, every tool that mutates state is automatically disabled for that connection, leaving only the read-only tools enabled.
A tool's mutation posture comes from its readOnlyHint annotation, so there is nothing to configure per-tool: reads stay available while writes — produce, create/alter/delete, and the like — can never fire against that connection.
This is the recommended posture for handing an agent a staging or production connection while keeping full read/write on a throwaway dev cluster.
The list-configured-connections tool reports each connection's read-onlyness, so an agent can see at a glance which connections are read-only or write-enabled.
Service blocks
| Block | Purpose |
|---|---|
kafka | Bootstrap address + auth for the native Kafka admin/producer/consumer client; REST endpoint + cluster/env IDs for REST-proxy tools. |
schema_registry | Endpoint + auth for Confluent Schema Registry. |
confluent_cloud | Endpoint + auth for the Confluent Cloud control plane (environments, clusters, connectors, billing, catalog). |
flink | Endpoint + auth + IDs for Flink SQL and the Flink catalog. All five of endpoint, auth, environment_id, organization_id, compute_pool_id are required if the block is present. |
tableflow | Auth for Tableflow topic and catalog-integration tools. Pairs with confluent_cloud for environment/cluster lookups. |
telemetry | Endpoint + auth for the Metrics API. Optional override; defaults inherit from confluent_cloud.auth. |
Field-level details, defaults, and which CLI/env-var each field replaces are in config.example.yaml.
The top-level server: block
The top-level server: block sits beside connections: and applies to the whole config, regardless of which connection flavors you defined.
It is entirely optional — omit it to accept the same defaults today's env-var users get.
The fully annotated example is in config.example.yaml; when present, it replaces these env vars:
| Field | Replaces env var |
|---|---|
server.transports | --transport CLI flag |
server.log_level | LOG_LEVEL |
server.do_not_track | DO_NOT_TRACK (env wins as the floor; disables usage analytics and Sentry error reporting; see Telemetry) |
server.http.port | HTTP_PORT |
server.http.host | HTTP_HOST |
server.http.mcp_endpoint | HTTP_MCP_ENDPOINT_PATH |
server.http.sse_endpoint | SSE_MCP_ENDPOINT_PATH |
server.http.sse_message_endpoint | SSE_MCP_MESSAGE_ENDPOINT_PATH |
server.auth.api_key | MCP_API_KEY |
server.auth.allowed_hosts | MCP_ALLOWED_HOSTS |
server.auth.disabled | MCP_AUTH_DISABLED / --disable-auth |
server.transports and the --transport CLI flag are mutually exclusive — declare transports in YAML or on the command line, not both.
Multiple connections (and zero connections)
A single config.yaml may define several named entries under connections: — for example a Confluent Cloud connection alongside a local Apache Kafka broker — and each tool call routes to the connection you address by id.
There is no fixed ceiling on the number of connections.
Ready-to-use two-connection starters pairing a read/write local-Docker connection with a read-only Cloud or Confluent Platform connection — across OAuth, API-key, and CP auth — live in sample_configs/.
One rule constrains the mix: you may pair as many type: direct connections as you like, but at most one may be type: oauth.
The shared Confluent Cloud sign-in owns a single browser session and identity, so a second OAuth connection is rejected at startup with Multiple OAuth connections defined in configuration; only one is supported.
A config may also define no connections at all.
The five connection-independent tools — search-product-docs, get-product-doc-page, explain-disabled-tools, list-configured-connections, and describe-configured-connection — stay enabled regardless, so an empty config still gives you documentation search plus the server-diagnostic tools.
This capability is YAML-only — the legacy env-var path can express only a single connection.
${VAR} interpolation
YAML values support ${VAR} and ${VAR:-default} substitution, so secrets can live in your shell environment (or a -e dotenv) while structure lives in the file:
connections:
production:
type: direct
kafka:
bootstrap_servers: "broker.confluent.cloud:9092"
auth:
type: api_key
key: "${KAFKA_API_KEY}"
secret: "${KAFKA_API_SECRET}"
A missing variable with no :-default is a parse-time error.
Plain literals also work; interpolation is a convenience, not a requirement.
How env vars and .env files fit into the YAML world
Even after the legacy env-var-only configuration path retires, env vars keep doing real work for mcp-confluent. They have three jobs with different lifecycles — keep them straight when you read the rest of this document:
- Interpolation source for
${VAR}in YAML. Long-term supported. This is the recommended way to keep secrets out of version control: structure inconfig.yaml, secrets in your environment (or a dotenv loaded via-e). - Linked-library passthrough. Long-term supported. Several libraries mcp-confluent depends on read environment variables directly — OpenSSL (
SSL_CERT_FILE,NODE_EXTRA_CA_CERTS, ...), cyrus-sasl (SASL_PATH), krb5 (KRB5_CONFIG,KRB5CCNAME, ...), undici (HTTPS_PROXY,NO_PROXY, ...). There is no YAML knob for these; they have to reach the server as env vars. - Sole configuration source on the legacy path. Deprecated; will be removed in a near-future release. This is what happens when you start the server without
-c— everyKAFKA_API_KEY,FLINK_REST_ENDPOINT, etc. listed in Legacy env-var configuration is serving this job today and only this job.
The -e <file> CLI flag loads a dotenv file into the server's environment once, at startup, and the resulting values then feed all three jobs above.
Same flag, three lifecycles:
# Job 1 only: YAML structure, secrets and linked-library vars in the dotenv.
npx @confluentinc/mcp-confluent -c config.yaml -e secrets.env
# Jobs 1 + 2: same as above; linked-library vars in the same dotenv.
npx @confluentinc/mcp-confluent -c config.yaml -e env-with-tls-and-secrets.env
# Job 3 (legacy): no -c, the server reads every known var from the dotenv.
npx @confluentinc/mcp-confluent -e legacy.env
Caveat — dynamic-linker vars.
LD_LIBRARY_PATH,LD_PRELOAD, macOSDYLD_*, and anything else consumed before Node starts cannot be set via-e. Set those in the shell that launches mcp-confluent.
Authentication modes
Two type: values on a connection, with different ergonomics:
type: direct — API keys in YAML
Each service block carries its own auth: { type: api_key, key, secret }.
The keys can live in YAML literals (fine for local dev), or — much more commonly — ${VAR} interpolated from the environment:
connections:
prod:
type: direct
confluent_cloud:
auth:
type: api_key
key: "${CONFLUENT_CLOUD_API_KEY}"
secret: "${CONFLUENT_CLOUD_API_SECRET}"
type: oauth — Confluent Cloud login (PKCE)
The big new feature of this release. The server opens the Confluent Cloud sign-in page in your browser on the first tool call that needs Cloud access; the resulting session is reused for the rest of the process. No API keys to provision.
connections:
ccloud-oauth:
type: oauth
OAuth connections carry no service blocks.
Resource IDs (cluster_id, environment_id, ...) that direct-mode connections pin in YAML instead flow in as tool arguments at call time.
A server may define at most one OAuth connection, alongside any number of type: direct connections — see Multiple connections (and zero connections).
Get a starter file via --init-oauth-config.
OAuth-eligible tools. Not every tool has been migrated to OAuth yet — REST-only categories (Connect, Tableflow, Flink, Metrics, Catalog & Tags) still require type: direct.
The currently-supported list:
| Category | Tools | Notes |
|---|---|---|
| Kafka (native) | list-topics, create-topics, delete-topics, produce-message, consume-messages | Pass cluster_id + environment_id as arguments. Schema Registry serialization works on produce/consume for AVRO, JSON, and PROTOBUF. |
| Kafka REST | get-topic-config, alter-topic-config | Pass clusterId + environmentId as arguments. |
| Schema Registry | list-schemas, create-schema, delete-schema | Pass environment_id; the SR cluster and endpoint are auto-resolved. |
| Organizations, Environments & Clusters | list-organizations, list-environments, read-environment, list-clusters | — |
| Billing | list-billing-costs | — |
HTTP/SSE transport security
HTTP and SSE transports require API-key authentication by default to prevent unauthorized access and DNS rebinding.
Enable them by listing them in server.transports (or via --transport http,sse); auth is on unless you explicitly opt out.
Generating an API key
npx @confluentinc/mcp-confluent --generate-key
Add the result to server.auth.api_key:
server:
transports: [http]
auth:
api_key: "${MCP_API_KEY}"
Clients pass it in the cflt-mcp-api-key header on every request:
curl -H "cflt-mcp-api-key: $MCP_API_KEY" http://localhost:8080/mcp
DNS-rebinding protection
The server validates the Host header against server.auth.allowed_hosts (default: [localhost, 127.0.0.1]):
server:
auth:
allowed_hosts: [localhost, 127.0.0.1, myhost.local]
It also binds to 127.0.0.1 by default — set server.http.host to expose it elsewhere.
Disabling auth (development only)
server:
auth:
disabled: true
Or use --disable-auth on the command line. Never disable auth in production or when the server is network-accessible.
Tool enablement: which block lights up what
Tools auto-enable based on which service blocks are present in the resolved configuration.
Run --list-tools to see the live set for your config, or use the explain-disabled-tools MCP tool to ask the running server why a specific tool is missing.
| Block(s) required | Tools enabled |
|---|---|
| (always on) | search-product-docs, get-product-doc-page, explain-disabled-tools, list-configured-connections, config-help, describe-configured-connection |
kafka with bootstrap_servers or type: oauth | list-topics, create-topics, delete-topics, produce-message, consume-messages |
kafka with rest_endpoint + auth or type: oauth | get-topic-config, alter-topic-config |
schema_registry or type: oauth | list-schemas, create-schema, delete-schema |
flink | create-flink-statement, list-flink-statements, get-flink-statement-results, delete-flink-statements, get-flink-statement-exceptions, check-flink-statement-health, detect-flink-statement-issues, list-flink-catalogs, list-flink-databases, list-flink-tables, describe-flink-table, get-flink-table-info |
flink + telemetry | get-flink-statement-profile |
tableflow | create-tableflow-topic, list-tableflow-topics, read-tableflow-topic, update-tableflow-topic, delete-tableflow-topic, list-tableflow-regions, create-tableflow-catalog-integration, list-tableflow-catalog-integrations, read-tableflow-catalog-integration, update-tableflow-catalog-integration, delete-tableflow-catalog-integration |
confluent_cloud or type: oauth | list-organizations, list-environments, read-environment, list-clusters, list-billing-costs |
confluent_cloud (direct only) | list-connectors, get-connector-config, get-connector-offsets, get-connector-status, get-connector-tasks, get-connector-error-summary, get-connector-error-recommendations, get-connector-logs, delete-connector, pause-connector, resume-connector, restart-connector, update-connector-config |
confluent_cloud + kafka.auth (direct only) | create-connector |
schema_registry with api-key auth (direct only) | search-topics-by-tag, search-topics-by-name, create-topic-tags, delete-tag, remove-tag-from-entity, add-tags-to-topic, list-tags |
telemetry | list-available-metrics, query-metrics |
Legacy env-var configuration (deprecated)
If you are starting fresh, skip this section — use Quick start (YAML) instead.
What "deprecated" means here. Setting credentials and endpoints purely via env vars (job 3 in How env vars and
.envfiles fit into the YAML world) will emit a startup warning in a near-future release and be removed a release or two later. Using env vars to feed${VAR}interpolation in YAML (job 1) and to pass through linked-library settings (job 2) is long-term supported and unaffected.
Run the server without -c and these variables, read either from the parent shell or from a -e <file> dotenv, populate the same internal configuration the YAML path would build.
Show full variable list
| Variable | Description | Default | Required |
|---|---|---|---|
| HTTP_HOST | Host to bind for HTTP transport. Defaults to localhost only for security. | 127.0.0.1 | No |
| HTTP_MCP_ENDPOINT_PATH | HTTP endpoint path for MCP transport (e.g. /mcp). | /mcp | No |
| HTTP_PORT | Port to use for HTTP transport. | 8080 | No |
| LOG_LEVEL | Log level for application logging (trace, debug, info, warn, error, fatal). | info | No |
| MCP_API_KEY | API key for HTTP/SSE authentication. Generate with --generate-key. Required when auth is enabled. | If HTTP/SSE without --disable-auth | |
| MCP_AUTH_DISABLED | Disable authentication for HTTP/SSE transports. Development only. | false | No |
| MCP_ALLOWED_HOSTS | Comma-separated Host header allowlist for DNS rebinding protection. | localhost,127.0.0.1 | No |
| SSE_MCP_ENDPOINT_PATH | SSE endpoint path for establishing SSE connections. | /sse | No |
| SSE_MCP_MESSAGE_ENDPOINT_PATH | SSE endpoint path for receiving messages. | /messages | No |
| BOOTSTRAP_SERVERS | Comma-separated Kafka broker addresses (host1:port1,host2:port2). | For Kafka tools | |
| CONFLUENT_CLOUD_API_KEY | Confluent Cloud control-plane API key. | For CCloud tools | |
| CONFLUENT_CLOUD_API_SECRET | Confluent Cloud control-plane API secret. | For CCloud tools | |
| CONFLUENT_CLOUD_REST_ENDPOINT | Base URL for Confluent Cloud's REST API. | https://api.confluent.cloud | No |
| FLINK_API_KEY | Confluent Cloud Flink API key. | For Flink tools | |
| FLINK_API_SECRET | Confluent Cloud Flink API secret. | For Flink tools | |
| FLINK_CATALOG_NAME | Flink catalog name used as sql.current-catalog. Typically the CCloud environment's display name. | No | |
| FLINK_COMPUTE_POOL_ID | Flink compute pool ID; must start with lfcp-. | For Flink tools | |
| FLINK_DATABASE_NAME | Default Flink database, used as sql.current-database. | No | |
| FLINK_ENV_ID | Flink environment ID; must start with env-. | For Flink tools | |
| FLINK_ORG_ID | Confluent Cloud organization ID. | For Flink tools | |
| FLINK_REST_ENDPOINT | Base URL for Confluent Cloud's Flink REST API. | For Flink tools | |
| KAFKA_API_KEY | Kafka SASL username. | For authenticated Kafka | |
| KAFKA_API_SECRET | Kafka SASL password. | For authenticated Kafka | |
| KAFKA_CLUSTER_ID | Kafka cluster ID within Confluent Cloud. | For Kafka REST tools | |
| KAFKA_ENV_ID | Environment ID for the Kafka cluster; must start with env-. | For Kafka REST tools | |
| KAFKA_REST_ENDPOINT | REST endpoint for Kafka cluster management. | For Kafka REST tools | |
| SCHEMA_REGISTRY_API_KEY | Schema Registry API key. | For Schema Registry tools | |
| SCHEMA_REGISTRY_API_SECRET | Schema Registry API secret. | For Schema Registry tools | |
| SCHEMA_REGISTRY_ENDPOINT | Schema Registry endpoint URL. | For Schema Registry tools | |
| TABLEFLOW_API_KEY | Tableflow API key. | For Tableflow tools | |
| TABLEFLOW_API_SECRET | Tableflow API secret. | For Tableflow tools | |
| TELEMETRY_ENDPOINT | Base URL for the Confluent Cloud Telemetry (Metrics) API. | https://api.telemetry.confluent.cloud | No |
| TELEMETRY_API_KEY | Telemetry API key; falls back to CONFLUENT_CLOUD_API_KEY if unset. See the Metrics API auth docs. | No | |
| TELEMETRY_API_SECRET | Telemetry API secret; falls back to CONFLUENT_CLOUD_API_SECRET if unset. | No | |
| DO_NOT_TRACK | Set to true to opt out of anonymous telemetry and Sentry error reporting. See Telemetry. Wins over server.do_not_track in YAML. | No |
To migrate, run --init-config, then translate each variable you currently set into the matching block from config.example.yaml.
For a side-by-side, every ${VAR:-...} placeholder in config.example.yaml names the env var that field used to come from.
You can keep secrets in your existing .env and reference them via ${VAR} from the YAML — that is job 1 above, and is the recommended migration target.
Troubleshooting
Tools not appearing. The tool's required service block is not present in your resolved config.
Run --list-tools to see the live set, or call the explain-disabled-tools MCP tool from your client — it prints exactly which YAML block or field is missing for each disabled tool.
When you have a specific tool in mind, call config-help with that tool name to get the exact YAML snippet to add, per connection, to unlock it.
${VAR} parse-time error. A ${VAR} reference resolved to no value and had no ${VAR:-default}.
Either export the variable, pass it through -e, or add a default.
Authentication errors on HTTP/SSE. Generate a key with --generate-key, put it in server.auth.api_key, and pass it in the cflt-mcp-api-key header on every request.
Or run with server.auth.disabled: true if and only if you are on localhost-only development.
See HTTP/SSE transport security.
HTTP_PORT / port conflicts. The default is 8080.
Set server.http.port (YAML) or HTTP_PORT (env-var path) to something else.
Tableflow authorization errors. Tableflow tools require IAM roles in your cloud account that allow the Flink runtime to access your storage and catalog. See the Confluent Tableflow quick start.