kibana-console-mcp
# kibana-console-mcp
An MCP server and CLI for searching logs in a **Kibana 8.17** deployment, going
through the Dev Tools console proxy (`POST /api/console/proxy`) so it needs only
the Kibana host and Kibana credentials.
Built for a viewer-level role with no Elasticsearch cluster privileges, on a
cluster of 63 data streams and ~35 billion log documents.
| Option | Works on Kibana 8.17? | |
| --- | --- | --- |
| Kibana Agent Builder MCP (`/api/agent_builder/mcp`) | ❌ | Added in Kibana 9.2.0 |
| `elastic/mcp-server-elasticsearch` | ✅ | Needs a reachable Elasticsearch endpoint; deprecated upstream |
| **this server** | ✅ | Only needs Kibana |
## Quick start
```bash
npm install
cp .env.example .env # fill in KIBANA_URL, KIBANA_SPACE, a credential
npm run smoke # checks the live cluster, step by step
```
Then wire it into Claude Code — no `env` block needed, the server reads `.env`:
```bash
claude mcp add kibana -- node /path/to/kibana-console-mcp/src/index.js
```
Full instructions, including how to get a credential when the signed-in user
cannot create an API key: **[docs/SETUP.md](docs/SETUP.md)**.
## Ask it something
Four tools answer most questions in a single request.
```
es_overview { "window": "1h" } what is going on
es_patterns { "window": "1h", "filter": "EXCEPTION" } what is in these logs
es_why { "window": "30m", "baseline": "24h" } why did it spike
es_find { "text": "connection refused" } where is this happening
```
```
38700 action EXCEPTION actionDescription esb.pty.customerBillUpdated additionalInfo postpaidEarn …
15700 appName nlp-openapi-bff appResult Http Exception appResultCode appResultHttpStatus …
800 action EXCEPTION actionDescription SharedRedemptionService.getCampaignByFilters LogTime failed
```
The same thing from a shell:
```bash
node scripts/kq.js overview 1h
node scripts/kq.js patterns 1h EXCEPTION
node scripts/kq.js why 30m 24h
node scripts/kq.js find "connection refused" 1h
```
More, with real output: **[docs/PLAYBOOK.md](docs/PLAYBOOK.md)**.
## Tools
| Tool | Purpose |
| --- | --- |
| `es_overview` | **Start here.** Volume, errors, unusual containers, sample lines — one `_msearch` |
| `es_find` | Phrase → count, namespaces, containers, time shape, samples |
| `es_patterns` | Millions of lines → a dozen message templates with counts |
| `es_why` | What is statistically unusual in a window versus a baseline |
| `es_trace` | Timeline for one correlation id across services |
| `es_search` | Query DSL search with `size`/`from`/`sort`/`source`/`aggs` |
| `es_count` | Count matching documents |
| `es_esql` | ES\|QL query, allowlist-checked, returned as rows or a matrix |
| `es_get_mappings` | Field mappings, falling back to `_field_caps` |
| `es_list_indices` | Index discovery: `_cat/indices`, falling back to `_resolve/index` |
| `kbn_list_data_views` | Index discovery through Kibana, needs no cluster privilege |
| `kbn_find_saved_objects` | Dashboards, visualizations, index patterns, lens objects |
| `kbn_status` | Connectivity, Kibana version, active guardrails |
| `es_request` | Escape hatch for any other Elasticsearch path |
## Safety
Read-only by default, with a glob allowlist enforced on every tool — including
`es_esql` and `es_request`, where the target hides inside a query string — and
MSISDN/secret masking on results *and* errors.
**These logs contain customer PII.** Anything a tool returns enters the model's
context permanently. **[docs/SECURITY.md](docs/SECURITY.md)** covers what is in
them and what cookie authentication costs.
## Speed
Measured against the live cluster. The intuitive answers were mostly wrong:
window width dominates (24h costs 13× 1h), fan-out barely matters (63 streams
cost 1.6× one), filter context makes no difference, and `LIKE "*x*"` times out
at 30 seconds. **[docs/PERFORMANCE.md](docs/PERFORMANCE.md)** has the numbers and
what the server does about them.
## Development
```bash
npm run check # lint + the test suite + stdio selftest. No credentials, no network.
npm run smoke # the only command that touches the live cluster.
```
| | |
| --- | --- |
| [CLAUDE.md](CLAUDE.md) | Conventions and non-negotiables for agents working here (`AGENTS.md` is a symlink to it) |
| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | How it works, and the proxy quirks it absorbs |
| [docs/CLUSTER.md](docs/CLUSTER.md) | This deployment: version, role, data shape, feature availability |
| [docs/TROUBLESHOOTING.md](docs/TROUBLESHOOTING.md) | Error → cause → fix |
| [docs/TOOLS.md](docs/TOOLS.md) | Every tool and parameter, generated from the server |
| [CHANGELOG.md](CHANGELOG.md) | What changed, including every audit finding |
| [TODO.md](TODO.md) | Work that is deliberately unfinished, and why |
TDQS
Scored across 14 tools
Each tool targets a clearly distinct operation: querying (es_search, es_count, es_esql), discovery (es_list_indices, es_get_mappings, kbn_list_data_views), investigation (es_trace, es_find, es_patterns, es_why, es_overview), and administrative access (kbn_status, kbn_find_saved_objects, es_request). Overlapping-looking tools like es_find vs es_search are explicitly differentiated by purpose and guidance in their descriptions.
The set follows a mostly consistent convention: es_ for Elasticsearch operations and kbn_ for Kibana operations, with verb_noun pairs like es_get_mappings, es_list_indices, kbn_find_saved_objects. A few tools use noun/adverb style names (es_patterns, es_why, es_overview), which breaks the verb-led pattern but remains predictable and readable.
14 tools is well-scoped for a Kibana/Elasticsearch investigation console. Each tool covers a distinct capability — from low-level search, to aggregations, to incident-analysis helpers, to saved-object access — without feeling bloated or redundant.
The tool surface is comprehensive for its read-only investigation purpose: it covers index discovery, field mappings, query execution (DSL, count, ES|QL), log pattern analysis, trace following, statistical comparisons, overview generation, saved object lookup, and a general escape hatch for unlisted Elasticsearch APIs. No obvious dead ends remain.