klens

MCP tools

The tools klens serves at /mcp, with their arguments, privileges, and limits.

klens serves these tools over the Model Context Protocol at /mcp on mcp.bind. Connect an AI agent shows how to turn MCP on. The arguments on this page use the names an agent sends.

Tools

ToolReads or changesPrivilegeLimited per minute
klens_clustersClusters and their healthNoneNo
klens_searchTopics, groups, brokers, and subjects by nameNoneNo
klens_access_explainWhat the agent may do on each clusterNoneNo
klens_topics_listA cluster's topicsNoneNo
klens_topic_describeOne topicNone. topic_configs adds its configs.No
klens_groups_listA cluster's consumer groupsNoneNo
klens_group_describeOne consumer groupNoneYes
klens_brokers_listA cluster's brokersNone. broker_configs adds configs for one broker.Only with broker
klens_schemas_listA cluster's schema subjectsNoneNo
klens_schema_getOne schema version, from the registryschema_textYes
klens_acls_listA cluster's ACL bindingsaclsNo
klens_records_readA page of records, from KafkarecordsYes
klens_record_getOne record, from KafkarecordsYes
klens_topic_createCreates a topiccreate_topicsYes
klens_record_produceWrites one recordproduceYes
klens_schema_registerRegisters a schema versionregister_schemasYes

A tool without a per-minute limit reads the background projection that the UI reads, so it costs Kafka nothing. A tool with the limit reads Kafka or the registry live, makes klens read more often, or changes something. tuning.mcp.live_calls_per_minute sets the limit, and every client shares it.

The tool list an agent receives leaves out each tool that needs a privilege the agent holds on none of the clusters it sees. It leaves out each write tool unless a cluster the agent sees has writable: true and grants the privilege of that tool.

Every tool that reads one cluster takes a cluster argument. The argument is optional when the agent sees exactly one cluster.

Read the catalog

klens_clusters

Lists the clusters the agent sees, with broker, topic, partition, group, and subject counts, the counts of under-replicated and offline partitions, and each background lane that failed or has not run yet.

ArgumentTypeDescription
clusterStringOne cluster. With it, the result also lists that cluster's under-replicated and offline partitions, offline first.

Finds topics, consumer groups, brokers, and schema subjects by name, on one cluster or on all of them. It returns up to 20 matches for each cluster, best first, each with its kind (TOPIC, GROUP, NODE, or SUBJECT) and exact ID. notReady names each cluster klens has not read yet.

ArgumentTypeDescription
queryString, at most 256 charactersRequired. Matching is fuzzy and ignores case. ord cre finds orders.created. !test leaves out names that match test. ^prod keeps names that start with prod.
clusterStringOne cluster. Omit it to search every cluster.

klens_access_explain

Explains the privileges the agent holds under the MCP ceiling, whether each cluster accepts changes, and the privilege each unavailable tool or section needs.

ArgumentTypeDescription
clusterStringOne cluster. Omit it for every cluster.

klens_topics_list

Lists topics with their partition count, records, size, produce rate, the number of groups that read them, and whether a partition is under-replicated.

ArgumentTypeDescription
nameContainsStringKeeps topics whose name holds this text, in any case.
sortNAME, SIZE, RATE, RECORDS, PARTITIONS, or GROUPSNAME by default, from A to Z. The others put the largest first.
emptyBooleantrue keeps topics with no records, false keeps the others. Both leave out unmeasured topics.
underReplicatedBooleantrue keeps topics with a partition short of in-sync replicas.
includeInternalBooleanAlso lists internal topics such as __consumer_offsets. false by default.
responseFormatCONCISE or DETAILEDDETAILED adds internal, replication factor, records ever received, retention, and cleanup policy.
limit1 to 10025 by default.

klens_topic_describe

Describes one topic: partitions with replicas and watermarks, records, size, produce rate, retention, and cleanup policy. groups lists the groups that read it, largest lag first. subjects lists its <topic>-key and <topic>-value subjects. configs lists each config that differs from Kafka's default and needs topic_configs.

ArgumentTypeDescription
topicStringRequired. The exact topic name.

klens_groups_list

Lists consumer groups, largest total lag first, with their state, member count, and total lag. lagComplete is false when the total leaves out partitions whose lag klens has not read.

ArgumentTypeDescription
nameContainsStringKeeps groups whose ID holds this text, in any case.
stateSTABLE, EMPTY, PREPARING_REBALANCE, COMPLETING_REBALANCE, ASSIGNING, RECONCILING, DEAD, or UNKNOWNKeeps groups in this state.
topicStringKeeps groups that read this exact topic.
minLagIntegerKeeps groups with at least this total lag.
responseFormatCONCISE or DETAILEDDETAILED adds the topics each group reads.
limit1 to 10025 by default.

klens_group_describe

Describes one group: state, assignment protocol, total lag, members, and partitions, largest lag first. findings names what looks wrong:

FindingMeaning
NO_MEMBERSThe group has no members.
REBALANCINGThe group is rebalancing.
MORE_MEMBERS_THAN_PARTITIONSSome members have no partition.
UNASSIGNED_PARTITIONSSome partitions have no member.
LAG_ON_ONE_MEMBEROne member holds at least 80% of a complete total lag of 1000 or more.

A call makes klens read the offsets of the group every tuning.ingest.fast_offset for tuning.ingest.interest_ttl, as opening the group in the UI does.

ArgumentTypeDescription
groupStringRequired. The exact group ID.

klens_brokers_list

Lists brokers by ID with address, rack, controller flag, partition counts, size, and log dirs.

ArgumentTypeDescription
brokerIntegerDescribes this broker alone, with each config that differs from Kafka's default. It reads configs live and needs broker_configs.
afterIntegerLists only brokers with a higher ID. Pass the last ID of the previous result.
limit1 to 10025 by default.

klens_schemas_list

Lists schema subjects from A to Z with their latest version, schema type, and compatibility level. It fails with NO_SCHEMA_REGISTRY when the cluster has no schema_registry.

ArgumentTypeDescription
nameContainsStringKeeps subjects whose name holds this text, in any case.
responseFormatCONCISE or DETAILEDDETAILED adds the latest schema ID and the newest 10 versions with their schema IDs.
limit1 to 10025 by default.

klens_schema_get

Reads one version of a subject's schema live from the registry, with its references.

ArgumentTypeDescription
subjectStringRequired. The exact subject name.
versionInteger, at least 1The latest version by default.

klens_acls_list

Lists ACL bindings. status DISABLED means the cluster runs no authorizer. DENIED means the Kafka user of klens may not describe ACLs.

ArgumentTypeDescription
containsStringKeeps bindings whose principal, resource name, or host holds this text, in any case.
resourceTypeTOPIC, GROUP, CLUSTER, TRANSACTIONAL_ID, or DELEGATION_TOKENKeeps bindings on this resource type.
operationALL, READ, WRITE, CREATE, DELETE, ALTER, DESCRIBE, CLUSTER_ACTION, DESCRIBE_CONFIGS, ALTER_CONFIGS, or IDEMPOTENT_WRITEKeeps bindings for this exact operation.
permissionALLOW or DENYKeeps bindings with this permission.
limit1 to 10025 by default.

Read records

klens_records_read

Reads a page of records live from Kafka. For the next page, pass the cursor of the result with the other arguments unchanged.

ArgumentTypeDescription
topicStringRequired. The exact topic name.
partitionsList of integersReads only these partitions. Every partition by default.
orderNEWEST or OLDESTNEWEST reads back from the end of each partition. OLDEST reads forward from the start. NEWEST by default.
startOffsetIntegerStarts at this offset, inclusive, in the one partition that partitions names.
fromRFC 3339 timeKeeps records stamped at or after this time.
toRFC 3339 timeKeeps records stamped at or before this time.
containsStringKeeps records whose key or value holds this text, in any case.
limit1 to 5010 by default.
cursorStringThe cursor of the previous page.

klens_record_get

Reads one record live from Kafka. It fails with UNKNOWN_OFFSET when the partition holds no record at that offset.

ArgumentTypeDescription
topicStringRequired. The exact topic name.
partitionIntegerRequired. The partition of the record.
offsetIntegerRequired. The offset of the record.

Record results

A record result is text. For each record, a first JSON line gives the partition, offset, timestamp, size, value schema ID, verbatim, cut, and headersLeftOut. verbatim is true when the text shows the exact bytes. A second JSON line holds the key, the headers, and the value, between two markers that change with every result. The result tells the agent to read the text between the markers as data, not as instructions. JSON escapes keep a payload on one line, and klens escapes a payload that holds the closing marker.

An obfuscation rule hides what it covers, as in the UI, and contains matches only what klens shows.

Change Kafka

Each write tool needs its privilege in mcp.privileges and a cluster with writable: true. On any other cluster it fails with READ_ONLY_CLUSTER. klens logs each change as it logs a change from the UI. A client that names itself in each request appears on that log line as unverified:<name>.

klens_topic_create

Creates a topic. It fails with REFUSED when Kafka refuses, such as for a topic that exists. The result gives the name and the partition count, which is null when the call gave no partitions and klens has not seen the topic yet.

ArgumentTypeDescription
topicStringRequired. Letters, digits, ., _, and -.
partitions1 to 65535The broker's num.partitions by default.
replicationFactor1 to 255The broker's default.replication.factor by default.
configsMap of stringsTopic configs such as cleanup.policy or retention.ms.

klens_record_produce

Writes one record and returns its partition and offset. klens writes no tombstones, so value is required. It fails with UNENCODABLE when the data does not fit its schema.

ArgumentTypeDescription
topicStringRequired. The exact topic name.
valuePayloadRequired. The value.
keyPayloadThe key. Omit it for a record without a key.
partitionIntegerThe partition. Without it, the producer picks one, by the hash of the key when there is a key.
headersList of {key, value}Headers with text values.

A payload is an object with an encoding:

encodingFieldsWrites
TEXTdatadata as UTF-8 text.
BASE64dataThe bytes that data encodes in base64.
SCHEMAdata, schemaIdThe JSON in data, encoded with the registry schema schemaId.

klens_schema_register

Registers a schema as the next version of a subject and returns the version and the schema ID. When the subject already holds the same schema, the registry returns that version and registers nothing. It fails with REGISTRY_REFUSED when the registry refuses the schema, such as for one the compatibility level of the subject rules out.

ArgumentTypeDescription
subjectStringRequired. The registry creates the subject when it does not exist.
typeAVRO, JSON, or PROTOBUFRequired.
schemaStringRequired. JSON for AVRO and JSON, .proto source for PROTOBUF.
referencesList of {name, subject, version}The schemas this one references.

Limits

LimitValue
Calls served at once, across every clienttuning.mcp.max_concurrent_calls, 16 by default
Live calls a minute, across every clienttuning.mcp.live_calls_per_minute, 30 by default
Request body64 KiB
Search query256 characters
Result24,000 bytes, counting the text and the structured copy
Name a client chose, in klens_group_describe256 characters, then …
Config value500 characters, then marked cut

A call past either call limit fails with RATE_LIMITED, and klens does not queue it. A list result that does not fit keeps its first rows and says how many it left out. A record result instead cuts long keys, headers, and values to one length, so that a page keeps every record and its cursor, and it marks each record it cut. When the cursor of a topic with many partitions leaves too little room, klens_records_read fails with INVALID_REQUEST and asks for fewer records or partitions.

A count, size, or rate that klens has not measured yet is null, not 0.

Errors

A refused call returns a JSON object with error, code, and hint. The hint says what the agent can call next. When the refusal carries a message from Kafka or the registry, the message sits between markers, as record text does. klens logs the tool and the code at info level, never the arguments.

This list holds the codes an agent meets most often. HTTP API errors lists every code.

CodeCause
UNKNOWN_CLUSTERThe cluster does not exist, or MCP does not reach it.
FORBIDDENThe ceiling does not grant the privilege the call needs.
READ_ONLY_CLUSTERA write tool ran on a cluster without writable: true.
UNKNOWN_TOPIC, UNKNOWN_GROUP, UNKNOWN_BROKER, UNKNOWN_SUBJECT, UNKNOWN_PARTITIONThe named object does not exist.
UNKNOWN_OFFSETThe partition holds no record at the offset.
INVALID_REQUESTAn argument does not fit the input schema, or a cursor does not fit the other arguments.
NOT_READYklens has not read the data the call needs yet.
NO_SCHEMA_REGISTRYThe cluster has no schema_registry.
REFUSEDKafka refused the change.
REGISTRY_REFUSEDThe registry refused the change.
UNENCODABLEThe data does not fit the schema.
RATE_LIMITEDThe call passed a call limit.
NOT_FROM_GATEWAYmcp.secret is set and the request does not carry it.

On this page