skillZs
★ LIVE SKILL TAGS ★
>>> LIVE SKILLS INDEX <<<
* OPEN SOURCE *
NO LOGIN, NO TRACKING
※ REAL INSTALL DATA ※
← back to all skills
kubesense-ai/kubesense-mcp-skills97 installs

kubesense-mcp

The KubeSense MCP tool layer — connection and auth, the full 38-tool inventory, tool selection, the discovery-first rule, the catalog-label field contract shared by every logs/traces query, WHERE syntax, multi-datasource formula queries, and how to read the TSV/columnar output formats. Read this when a tool returns a field-name or WHERE error.

How do I install this agent skill?

npx skills add https://github.com/kubesense-ai/kubesense-mcp-skills --skill kubesense-mcp
view source ↗

Is this agent skill safe to install?

  • Gen Agent Trust Hubpass

    This skill provides technical documentation and instructions for the KubeSense Model Context Protocol (MCP) layer. It defines tool schemas, query syntax, and authentication procedures for interacting with observability data. No malicious patterns or security risks were identified.

  • Socketpass

    No alerts

  • Snykpass

    Risk: LOW · No issues

What does this agent skill do?

KubeSense MCP

The tool layer every KubeSense query skill sits on. This skill owns the shared contract — field names, WHERE syntax, output formats — so the per-signal skills don't each have to redefine it.

Routing

The user is asking…Read
logs, error messages, grepkubesense-logs
latency, p99, requests, spans, which hop brokekubesense-traces
CPU, memory, disk, PromQLkubesense-metrics
what's running, pod restarts, what changedkubesense-infra
alerts — list, investigate, createkubesense-alerts

Connection

Served by kubeapi at /mcp over Streamable HTTP, mounted outside the /api group. Same credentials as the REST API.

# API key — recommended for agents, does not expire
claude mcp add --scope user --transport http kubesense \
  https://<your-kubesense-host>/mcp \
  --header "x-api-key: <your-api-key>"

# JWT access token — expires
claude mcp add --scope user --transport http kubesense \
  https://<your-kubesense-host>/mcp \
  --header "Authorization: Bearer <access-token>"

Liveness: GET /mcp_health. To confirm who you are authenticated as, call get-current-user — no arguments, cheap, resolved from the request credentials.

RBAC is resolved per tool call against the modules logs, traces, infrastructure (metrics + nodes/pods), and alerts. A permission error names the module. analyze-telemetry resolves every module its sub-queries touch.

Set MCP_LOG_LEVEL=debug server-side to log per-call argument payloads without raising the global log level.

Tools (38)

Discovery — call before querying

ToolReturns
get-trace-or-log-fieldsField catalog for logs or traces in a window
get-available-metricsMetric names
get-metric-labelsLabel names on one metric

Query

ToolReturns
search-logsRaw log rows (default 10)
search-tracesRaw span rows (default 10)
analyze-logsAggregated log series
analyze-tracesAggregated span series
analyze-metricsPromQL result
analyze-telemetryMultiple queries + formulas in one call
get-distributed-traceFull span tree for one trace_id
execute-sqlRows from a raw ClickHouse SELECT over logs or traces
validate-sqlDry-run verdict for a SQL query, plus the SQL that would run
validate-splDry-run verdict for an SPL query, plus the SQL it compiles to
execute-splRows from an SPL pipeline over logs

execute-sql / validate-sql are the escape hatch for what analyze-* cannot express — joins, CTE chains, window functions, arithmetic across aggregates. They take the same catalog labels as everything else, plus a few fields discovery does not list. Refused for scope-restricted roles. See kubesense-sql.

A filter is never the reason to reach for SQL. If the condition fits the where string (the Advanced query language), use search-* / analyze-*: the server compiles it to use the indexes, while SQL runs it as typed — a bare body LIKE '%…%' in SQL scans every log line in the window.

execute-spl / validate-spl are the Logs explorer's piped SPL language, logs only. Validate first: SPL's parser accepts unknown fields AND unknown functions, so a wrong name compiles and only fails once execute-spl has paid for the scan. Note SPL takes STORAGE column names (level, pod_name, cluster) — the inverse of the catalog labels every other tool here requires — and its parser accepts unknown fields and functions, so validating is the only way to find out a query is broken before it is run. See kubesense-spl.

Inventory — see kubesense-infra

list-clusters · list-nodes · get-node-detail · list-pods · get-pod-detail · list-workloads · get-workload-detail · list-issues · get-infra-issues · get-recent-changes

Alerts — see kubesense-alerts

list-alerts (external Alertmanager) · list-active-alerts (native store, firing) · list-alert-rules (rule definitions) · get-alert-details · get-alert-history · list-notification-channels · find-investigation-for-alert

Identity

get-current-user — returns username, name, email, role, auth_type. Note username and email are frequently different; ownership fields such as list-alert-rules' created_by match on username.

Validation — checks a document, stores nothing

validate-alert-json · validate-dashboard-json

Both take a document (a JSON object, or a string containing one) and report every schema problem at once as path / rule / message, where path is a JSON Pointer to the value to fix. Read-only and free to call repeatedly. Run whatever you assembled by hand through the matching one before creating it or handing it over.

Write — mutates state

create-alert · create-dashboard

Both carry write annotations and expect user approval. State exactly what you are about to create before calling. Each validates against the same schema as the tool above and refuses with the same findings, so validating first turns a refusal into a fix.

Discovery-First Rule

Never guess a name. Not a field, metric, cluster, or label.

logs / traces:  get-trace-or-log-fields  →  search-* / analyze-*
metrics:        get-available-metrics     →  get-metric-labels  →  analyze-metrics
clusters:       list-clusters             →  anything with a "clusters" filter

Two reasons this matters more than usual here:

  1. Field names are rejected with an error naming the correct label — good, but only if you read it rather than retrying.
  2. A wrong cluster name or metric name is not an error — it returns an empty result indistinguishable from "the value is zero".

Pass the same time window to get-trace-or-log-fields that you will use for the query: attribute keys are window-scoped and differ across windows.

The Field-Name Contract

Logs/traces inputs — where, required_fields, group_by_fields, fields, sort_by — accept catalog labels only. Storage column names are rejected:

field "pod_name" is a storage column; use the catalog label "instance" instead
  (call get-trace-or-log-fields to see all labels)

unknown field "service" for signal=logs; call get-trace-or-log-fields to discover
  valid fields (attributes carry an @ prefix)
ConceptLogsTraces
severity / outcometype (ERROR — UPPER)status (error — lower)
podinstanceinstance
containercontainercontainer
nodenodenode_name
service identitynot available — use workloadservice
workloadworkloadworkload
HTTP method—method
HTTP status—status_code
endpoint—resource
span role—role
protocol—protocol
message textbodynot available
latency—duration

The full per-signal tables, including hidden-but-accepted fields and every storage mapping, are in references/field-catalog.md.

[!WARNING] The two signals disagree on node/node_name and on severity name and casing, and service exists only on traces. Carrying a field name from one signal to the other is the most common failure.

Read enum casing from the enum_values column of discovery output, never the example column — the example generator silently returns blanks for several enum fields (logs type; traces method, protocol, status_code).

WHERE Syntax

type = ERROR AND namespace = production
status = error AND role = server
namespace IN (production, staging)
NOT (env_type = dev)
body ILIKE "%timeout%"
duration > 500
@user.id = abc-123

Operators the parser accepts: = != < > <= >= LIKE ILIKE SUBSTR_ILIKE IN — combined with AND / OR / NOT and parentheses.

[!WARNING] Discovery's operators column over-advertises. HAS_TOKEN, HAS_ALL, HAS_ANY, LIKE_AND, ILIKE_LOG, IS_IP_ADDRESS, EXIST appear in the legend but have no WHERE-string syntax. body HAS_TOKEN oom is a parse error. exist(@field) is broken on both signals (it emits a value-bearing EXIST the validator rejects) — there is no working existence check.

Quoting. Bare values may contain only letters, digits, _, ., -. Anything with a slash, colon, %, or space must be double-quoted:

resource = "/api/v1/checkout"           ✓
timestamp > "2026-07-30T10:00:00Z"      ✓
resource = /api/v1/checkout             ✗ parse error

NOT IN is not a leaf operator. Write NOT (namespace IN (kube-system, default)).

Attributes carry @ in WHERE — but only on logs. On traces, @attr filters are rejected as unknown fields (a server-side defect; the tool descriptions claim otherwise). Trace attributes still work in group_by_fields / fields / required_fields / sort_by via {"field": "db.system", "is_attribute": true} — no @ there, for either signal.

duration is millisecond-in, nanosecond-out — see kubesense-traces.

Choosing a Tool

QuestionTool
"show me recent errors"search-logs
"how many errors in the last hour"analyze-logs, row_count
"p99 latency for checkout"analyze-traces, p99 over duration
"why did this request fail"get-distributed-trace
"CPU usage"get-available-metrics → analyze-metrics
"error rate as a percentage"analyze-telemetry with a formula
"what's running / what's broken / what changed"inventory tools — one call for what would otherwise be several queries

Aggregate with analyze-*, don't paginate search-*. Reading raw rows to compute a count is slower, costs far more tokens, and — because paged scans are ordered hour-bucket-first across clusters — is not even guaranteed complete.

query_type on every analyze-*: range = time series (trends), instant = one value per series (totals, current state, top-N).

Time ranges are RFC3339 (2026-07-30T10:00:00Z). Start narrow (15–30 min) and widen. Discovery tools default to the last hour; inventory tools too.

Multi-Datasource Queries and Formulas

analyze-telemetry runs several queries in one call and composes them. This is the only way to get a ratio, error rate, or percentage.

{
  "from_time": "2026-07-30T10:00:00Z",
  "to_time": "2026-07-30T11:00:00Z",
  "query_type": "instant",
  "queries": {
    "A": { "selectedMode": "traces", "value_operation": "row_count" },
    "B": { "selectedMode": "traces", "where": "status = error", "value_operation": "row_count" },
    "C": { "query_type": "formula", "expression": "(B/A)*100" }
  }
}

Queries are keyed by single-letter labels. Formula entries use "query_type": "formula" with an expression referencing other labels. See references/multi-query.md for cross-signal examples.

Reading the Output

Three shapes, all designed to save tokens:

TSV (search-*, all inventory and alert list tools) — a # key=value metadata line, then a header row, then one row per record. Empty cell = field absent. A ## name line starts a labelled sub-table (e.g. ## services, ## silences).

Columnar JSON (all analyze-*) — results keyed by query label:

  • range: one shared timestamps array (Unix seconds, emitted once), and each series carries a bare values array aligned positionally — values[i] is the value at timestamps[i], null = no data in that bucket.
  • instant: no timestamps; each series carries a single scalar value.
  • total_series / truncated report how many non-zero series existed before the top-N cap.

Record with sub-tables (get-*-detail) — field<TAB>value lines for scalars, ## name TSV blocks for nested arrays, compact JSON for maps. Empty fields omitted.

Timestamps are always RFC3339 UTC at millisecond precision — exactly the format from_time/to_time accept, so a cell can be copied straight back as a cursor.

Pagination

search-logs / search-traces have no page or offset. You page by narrowing to_time; the window is half-open so the cursor row isn't repeated.

Take the minimum timestamp from the page (timestamp for logs, start_timestamp for traces) and pass it verbatim as the next to_time. Copy the millisecond precision exactly.

Inventory and alert tools do paginate conventionally, with page/page_size (default 50) or limit/offset.

See the per-signal skills for the ordering caveats that make exhaustive raw scans unreliable — and prefer aggregation whenever the answer is a number.

Rules

  1. Discover before querying — fields, metrics, clusters. Never guess.
  2. Pass the same window to get-trace-or-log-fields that you'll query.
  3. Catalog labels only. On a field error, read the suggested label; don't retry the same name.
  4. Never carry a field name across signals (node vs node_name; type vs status; service is traces-only).
  5. Enum casing from enum_values, not example.
  6. WHERE operators: = != < > <= >= LIKE ILIKE SUBSTR_ILIKE IN only. Quote values with /, :, %, or spaces. NOT (x IN (...)), never x NOT IN (...).
  7. value_operation is row_count — never count.
  8. analyze-* for numbers, search-* only to read records.
  9. analyze-telemetry + formula for ratios and percentages.
  10. An empty result is not zero — verify names and widen the window before reporting a value.
  11. create-alert mutates state: say what you're creating, and call list-notification-channels first or it will notify nobody.

Add the canonical catalog link to the repository README so users can inspect current installs and available audits. The publishing guide covers the complete discovery path.

<a href="https://skillzs.dev/skills/kubesense-ai/kubesense-mcp-skills/kubesense-mcp">View kubesense-mcp on skillZs</a>