@havesomecode/kibana-mcp-server 1.3.0 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -490
- package/dist/src/bin/kibana-mcp-server.d.ts +2 -0
- package/dist/src/bin/kibana-mcp-server.js +2 -53
- package/dist/src/bin/run_cli.d.ts +4 -0
- package/dist/src/bin/run_cli.js +49 -0
- package/dist/src/commands/context.d.ts +18 -0
- package/dist/src/commands/serve.d.ts +4 -0
- package/dist/src/commands/serve.js +30 -6
- package/dist/src/commands/setup.d.ts +3 -0
- package/dist/src/commands/setup.js +2 -2
- package/dist/src/config/config_file.d.ts +59 -0
- package/dist/src/config/config_file.js +76 -0
- package/dist/src/config/environment.d.ts +100 -0
- package/dist/src/{config.js → config/environment.js} +26 -24
- package/dist/src/config/startup.d.ts +31 -0
- package/dist/src/config/startup.js +86 -0
- package/dist/src/kibana/client.d.ts +28 -0
- package/dist/src/kibana/schema_catalog.d.ts +11 -0
- package/dist/src/{schema_catalog.js → kibana/schema_catalog.js} +33 -11
- package/dist/src/kibana/source_catalog.d.ts +10 -0
- package/dist/src/mcp_entry.d.ts +2 -0
- package/dist/src/mcp_entry.js +1 -1
- package/dist/src/profiles/context.d.ts +4 -0
- package/dist/src/profiles/context.js +15 -0
- package/dist/src/profiles/names.d.ts +10 -0
- package/dist/src/profiles/names.js +35 -0
- package/dist/src/profiles/paths.d.ts +9 -0
- package/dist/src/profiles/runtime.d.ts +43 -0
- package/dist/src/profiles/runtime.js +150 -0
- package/dist/src/profiles/secret_store.d.ts +20 -0
- package/dist/src/profiles/state_lock.d.ts +13 -0
- package/dist/src/{state_lock.js → profiles/state_lock.js} +14 -5
- package/dist/src/profiles/store.d.ts +34 -0
- package/dist/src/{profile_store.js → profiles/store.js} +7 -5
- package/dist/src/query/compiler.d.ts +9 -0
- package/dist/src/query/cursor.d.ts +8 -0
- package/dist/src/query/normalize.d.ts +2 -0
- package/dist/src/server.d.ts +29 -0
- package/dist/src/server.js +40 -50
- package/dist/src/setup/bootstrap.d.ts +50 -0
- package/dist/src/{bootstrap.js → setup/bootstrap.js} +10 -36
- package/dist/src/setup/client_registration.d.ts +38 -0
- package/dist/src/setup/setup_flow.d.ts +26 -0
- package/dist/src/{setup_flow.js → setup/setup_flow.js} +6 -6
- package/dist/src/stores/catalog_store.d.ts +38 -0
- package/dist/src/stores/catalog_store.js +22 -0
- package/dist/src/stores/file.d.ts +5 -0
- package/dist/src/stores/file.js +48 -0
- package/dist/src/stores/ioredis.d.ts +21 -0
- package/dist/src/stores/ioredis.js +33 -0
- package/dist/src/stores/mongodb.d.ts +42 -0
- package/dist/src/stores/mongodb.js +57 -0
- package/dist/src/stores/postgres.d.ts +24 -0
- package/dist/src/stores/postgres.js +65 -0
- package/dist/src/stores/redis.d.ts +24 -0
- package/dist/src/stores/redis.js +31 -0
- package/dist/src/stores/shared.d.ts +25 -0
- package/dist/src/stores/shared.js +88 -0
- package/dist/src/stores/sqlite.d.ts +26 -0
- package/dist/src/stores/sqlite.js +63 -0
- package/dist/src/tools/configure.d.ts +59 -0
- package/dist/src/tools/configure.js +1 -1
- package/dist/src/tools/configure_index.d.ts +35 -0
- package/dist/src/tools/configure_index.js +75 -66
- package/dist/src/tools/describe_fields.d.ts +29 -0
- package/dist/src/tools/discover.d.ts +27 -0
- package/dist/src/tools/filter.d.ts +180 -0
- package/dist/src/tools/query.d.ts +181 -0
- package/dist/src/transports/http.d.ts +15 -0
- package/dist/src/transports/http.js +291 -0
- package/dist/src/transports/stdio.d.ts +1 -0
- package/dist/src/transports/stdio.js +46 -0
- package/dist/src/types.d.ts +254 -0
- package/dist/src/utils/cli_io.d.ts +11 -0
- package/dist/src/utils/cli_prompts.d.ts +9 -0
- package/dist/src/utils/cli_ui.d.ts +6 -0
- package/dist/src/utils/fs.d.ts +3 -0
- package/dist/src/utils/fs.js +30 -0
- package/package.json +58 -1
- package/skills/kibana-log-investigation/SKILL.md +36 -5
- package/dist/src/mcp_runtime.js +0 -23
- /package/dist/src/{kibana_client.js → kibana/client.js} +0 -0
- /package/dist/src/{source_catalog.js → kibana/source_catalog.js} +0 -0
- /package/dist/src/{profile_paths.js → profiles/paths.js} +0 -0
- /package/dist/src/{secret_store.js → profiles/secret_store.js} +0 -0
- /package/dist/src/{client_registration.js → setup/client_registration.js} +0 -0
package/README.md
CHANGED
|
@@ -2,76 +2,43 @@
|
|
|
2
2
|
|
|
3
3
|
Read-only MCP server for agent-driven log investigation against Kibana-backed search endpoints protected with basic auth.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It gives an agent what a Kibana UI cannot: a short list of logical sources it can trust, the fields it may filter on, and typed results.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
- `
|
|
12
|
-
- `
|
|
13
|
-
- `filter` runs an exact-field filter when the field name is already known
|
|
7
|
+
**Documentation: https://havesomecode.github.io/kibana-mcp-server/**
|
|
8
|
+
|
|
9
|
+
## What it provides
|
|
10
|
+
|
|
11
|
+
- `discover` lists the logical sources configured for the caller
|
|
12
|
+
- `describe_fields` exposes the effective fields of a source, including which ones support exact matching
|
|
14
13
|
- `query` searches one or more sources over an absolute time window in `hits`, `count`, `histogram`, `terms`, `stats`, or `grouped_top_hits` mode
|
|
14
|
+
- `filter` runs an exact-field filter when the field name is already known
|
|
15
|
+
- `configure_index` validates and persists exactly one index or pattern after the user explicitly names it
|
|
15
16
|
|
|
16
|
-
|
|
17
|
+
The server never writes to Elasticsearch or Kibana, and never guesses an index.
|
|
17
18
|
|
|
18
19
|
## Requirements
|
|
19
20
|
|
|
20
21
|
- Node.js 22+
|
|
21
22
|
- A Kibana-compatible read endpoint reachable with basic auth
|
|
22
|
-
- One or more Elasticsearch index patterns
|
|
23
|
-
|
|
24
|
-
## Project Status
|
|
25
|
-
|
|
26
|
-
This repo is live for external adoption and AI-agent use.
|
|
27
|
-
|
|
28
|
-
- Homepage: `https://havesomecode.github.io/kibana-mcp-server/`
|
|
29
|
-
- Published package: `npx -y @havesomecode/kibana-mcp-server`
|
|
30
|
-
- Agent skill: `npx skills add Havesomecode/kibana-mcp-server --skill kibana-log-investigation`
|
|
31
|
-
- Repo-local Codex plugin install remains a first-class path for cloned checkouts
|
|
32
|
-
|
|
33
|
-
- Guaranteed: prompt-free package bootstrap and Codex registration (see `INSTALL.md`)
|
|
34
|
-
- Supported: guided machine setup through `npm run setup` for hand-authored catalogs
|
|
35
|
-
- Available: published package install via `npx -y @havesomecode/kibana-mcp-server`
|
|
36
|
-
- Active: semantic-release automation for tags, npm publish, and GitHub Releases
|
|
37
|
-
- Support posture and compatibility details live in `docs/project/support-policy.md`
|
|
38
|
-
- Contributing and security reporting live in `CONTRIBUTING.md` and `SECURITY.md`
|
|
39
|
-
|
|
40
|
-
## Support and Releases
|
|
41
|
-
|
|
42
|
-
- Distribution strategy: `docs/project/distribution-strategy.md`
|
|
43
|
-
- Compatibility matrix: `docs/project/compatibility-matrix.md`
|
|
44
|
-
- Release checklist: `docs/project/release-checklist.md`
|
|
45
|
-
- npm publishing setup: `docs/project/npm-publishing.md`
|
|
46
|
-
- GitHub Releases are the canonical release notes and version record
|
|
47
|
-
- The `version` field in `package.json` inside git is not the release source of truth
|
|
48
|
-
|
|
49
|
-
## Installation
|
|
23
|
+
- One or more Elasticsearch index patterns
|
|
50
24
|
|
|
51
|
-
|
|
25
|
+
## Quick start
|
|
52
26
|
|
|
53
|
-
Pre-provision the connection values in the environment:
|
|
27
|
+
Pre-provision the connection values in the environment, then bootstrap:
|
|
54
28
|
|
|
55
29
|
```bash
|
|
56
30
|
export KIBANA_BASE_URL='https://kibana.example.com'
|
|
57
31
|
export KIBANA_USERNAME='elastic'
|
|
58
32
|
export KIBANA_PASSWORD='use-a-secret-provider'
|
|
59
33
|
|
|
60
|
-
npx -y @havesomecode/kibana-mcp-server bootstrap
|
|
61
|
-
--client codex
|
|
34
|
+
npx -y @havesomecode/kibana-mcp-server bootstrap --client codex
|
|
62
35
|
```
|
|
63
36
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
After bootstrap, call `discover`. When no source is configured, the agent must ask the user which exact Kibana index or index pattern to use. Only after the user answers may the agent call `configure_index` with that value. That tool validates only the approved index and persists it without accepting credentials.
|
|
67
|
-
|
|
68
|
-
Bootstrap reruns preserve sources that were configured through this explicit flow. It refuses to replace a hand-authored or modified catalog unless `--replace` is supplied explicitly; `--replace` creates an empty managed catalog.
|
|
37
|
+
Bootstrap verifies only the Kibana connection, creates an empty managed catalog, stores the credentials securely and registers the server. It does not list, scan, infer, or configure indexes: the agent asks which exact index or pattern to use, then calls `configure_index`.
|
|
69
38
|
|
|
70
39
|
Never pass passwords as command-line arguments. Use `KIBANA_PASSWORD`, `--password-env NAME`, or `--password-stdin`.
|
|
71
40
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
The repository contains a standard Agent Skill discoverable by the `skills` CLI and skills.sh:
|
|
41
|
+
Install the agent skill that teaches the investigation workflow:
|
|
75
42
|
|
|
76
43
|
```bash
|
|
77
44
|
npx skills add Havesomecode/kibana-mcp-server \
|
|
@@ -81,464 +48,61 @@ npx skills add Havesomecode/kibana-mcp-server \
|
|
|
81
48
|
--yes
|
|
82
49
|
```
|
|
83
50
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
## Use In Codex
|
|
87
|
-
|
|
88
|
-
The prompt-free package bootstrap above is the primary Codex path. The repo-scoped plugin remains available for contributors working from a cloned checkout.
|
|
89
|
-
|
|
90
|
-
### Quick path
|
|
91
|
-
|
|
92
|
-
1. Clone the repository.
|
|
93
|
-
2. Make sure Node.js 22+ is available.
|
|
94
|
-
- if it is missing, ask Codex to use the plugin skill `ensure-node-runtime`
|
|
95
|
-
- the repo pins Node major `22` in `.node-version`
|
|
96
|
-
3. From the repo root, run:
|
|
97
|
-
|
|
98
|
-
```bash
|
|
99
|
-
npm install
|
|
100
|
-
npm run build
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
4. Open the cloned repo in Codex.
|
|
104
|
-
5. Open the plugin directory in Codex and install `Kibana Log Investigation` from the repo marketplace.
|
|
105
|
-
- if the current model cannot complete that install itself, do the Codex UI click manually and let the agent continue with configuration afterward
|
|
106
|
-
6. Restart Codex if the new MCP server does not appear immediately.
|
|
107
|
-
7. Run `node dist/src/bin/kibana-mcp-server.js bootstrap --client none` to verify the connection and save an empty profile. The repo plugin already supplies the client registration.
|
|
108
|
-
8. In a fresh thread, call `discover`, ask the user for the exact index or pattern, then call `configure_index` only after they answer.
|
|
109
|
-
|
|
110
|
-
Repo-scoped plugin files:
|
|
111
|
-
|
|
112
|
-
- `.agents/plugins/marketplace.json`
|
|
113
|
-
- `plugins/kibana-log-investigation/.codex-plugin/plugin.json`
|
|
114
|
-
- `plugins/kibana-log-investigation/.mcp.json`
|
|
115
|
-
|
|
116
|
-
### Minimal handoff prompt
|
|
117
|
-
|
|
118
|
-
If you are handing only the repo link to another Codex agent, this usually works:
|
|
119
|
-
|
|
120
|
-
```text
|
|
121
|
-
Install the `kibana-log-investigation` skill from Havesomecode/kibana-mcp-server, then run its connection-only bootstrap with the provisioned KIBANA_BASE_URL, KIBANA_USERNAME, and KIBANA_PASSWORD values. Do not edit Codex config files, import the example catalog, or inspect indexes. After install, ask me which exact index or pattern to configure before calling configure_index.
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Configuration
|
|
125
|
-
|
|
126
|
-
The preferred path is deterministic connection-only bootstrap:
|
|
127
|
-
|
|
128
|
-
- `npx -y @havesomecode/kibana-mcp-server bootstrap --client codex`
|
|
129
|
-
- verifies `/api/status` without touching an index endpoint
|
|
130
|
-
- creates an empty managed source catalog on first install
|
|
131
|
-
- rejects conflicting MCP registrations instead of overwriting them
|
|
132
|
-
- saves non-secret profile metadata and credentials for later threads
|
|
133
|
-
- exposes `configure_index` for one user-approved index or pattern at a time
|
|
134
|
-
|
|
135
|
-
Guided setup remains available for hand-authored source catalogs:
|
|
136
|
-
|
|
137
|
-
- `npm run setup` or `node dist/src/bin/kibana-mcp-server.js setup`
|
|
138
|
-
- saves non-secret profile metadata in the user’s machine-level app config directory
|
|
139
|
-
- saves credentials in the platform credential store
|
|
140
|
-
- macOS Keychain
|
|
141
|
-
- Windows Credential Manager
|
|
142
|
-
- Linux Secret Service when available
|
|
143
|
-
- imports the selected source catalog into machine-local state so later threads do not depend on the repo checkout
|
|
144
|
-
- requires an explicit catalog path; type `example` to opt into the bundled example deliberately
|
|
145
|
-
|
|
146
|
-
The server also supports two advanced compatibility paths:
|
|
147
|
-
|
|
148
|
-
- bootstrap at process start through environment variables plus a JSON source catalog
|
|
149
|
-
- runtime from your MCP client through the `configure` tool
|
|
150
|
-
|
|
151
|
-
When `configure` is called, the source catalog is still persisted to disk so restarts do not wipe the logical source setup.
|
|
152
|
-
|
|
153
|
-
### Machine profiles
|
|
154
|
-
|
|
155
|
-
After guided setup, the default saved profile loads automatically on startup.
|
|
156
|
-
|
|
157
|
-
If you saved more than one environment, select a non-default profile with:
|
|
158
|
-
|
|
159
|
-
- `KIBANA_PROFILE=<PROFILE_NAME>`
|
|
160
|
-
|
|
161
|
-
Example:
|
|
162
|
-
|
|
163
|
-
```bash
|
|
164
|
-
KIBANA_PROFILE=staging npm run dev
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
### Bootstrap configuration
|
|
168
|
-
|
|
169
|
-
The server can still read connection details from environment variables and source definitions from a JSON file.
|
|
170
|
-
|
|
171
|
-
Environment variables:
|
|
172
|
-
|
|
173
|
-
- `KIBANA_BASE_URL`
|
|
174
|
-
- `KIBANA_USERNAME`
|
|
175
|
-
- `KIBANA_PASSWORD`
|
|
176
|
-
- `KIBANA_PROFILE` optional, selects a saved non-default machine profile
|
|
177
|
-
- `KIBANA_TIMEOUT_MS` optional, default `10000`
|
|
178
|
-
- `KIBANA_SOURCE_CATALOG_PATH` optional, default `config/sources.runtime.json`
|
|
179
|
-
|
|
180
|
-
`KIBANA_TIMEOUT_MS` bounds each Kibana HTTP request end to end: it includes waiting for a request slot, connecting, and reading the response body. The server allows at most eight concurrent Kibana requests and 32 queued requests per configured client; excess work fails immediately with `KIBANA_OVERLOADED`. Cancelled MCP tool calls abort their queued or in-flight backend work.
|
|
181
|
-
|
|
182
|
-
Backend failures use stable diagnostic codes such as `KIBANA_TIMEOUT`, `KIBANA_CANCELLED`, `KIBANA_OVERLOADED`, `KIBANA_AUTHENTICATION`, `KIBANA_DNS`, `KIBANA_TLS`, `KIBANA_CONNECTION`, and `KIBANA_RESPONSE`. Failed backend tool results also expose the diagnostic fields in `_meta.kibana_request_error`.
|
|
183
|
-
|
|
184
|
-
`KIBANA_BASE_URL` is the Kibana base prefix that the server joins with each configured backend or schema path.
|
|
185
|
-
|
|
186
|
-
Use:
|
|
187
|
-
|
|
188
|
-
- `https://kibana.example.com`
|
|
189
|
-
- `https://gateway.example.com/logs` when Kibana is reverse-proxied under `/logs`
|
|
190
|
-
|
|
191
|
-
Do not use:
|
|
192
|
-
|
|
193
|
-
- `https://kibana.example.com/internal/search/es`
|
|
194
|
-
- `https://gateway.example.com/logs/internal/search/es`
|
|
195
|
-
|
|
196
|
-
The source definition already carries endpoint paths such as `/internal/search/es`, so including a full API path in `KIBANA_BASE_URL` usually produces a bad combined URL and a `404`.
|
|
197
|
-
|
|
198
|
-
For the env-bootstrap path, start from `config/sources.example.json` and copy it to `config/sources.json`.
|
|
199
|
-
If no explicit `KIBANA_SOURCE_CATALOG_PATH` is set, env bootstrap will try `config/sources.runtime.json` first and then fall back to `config/sources.json`.
|
|
200
|
-
|
|
201
|
-
### Multiple environments
|
|
202
|
-
|
|
203
|
-
The recommended path is to save multiple machine profiles during setup.
|
|
204
|
-
|
|
205
|
-
Then:
|
|
206
|
-
|
|
207
|
-
- the default profile loads automatically
|
|
208
|
-
- extra MCP entries can select another saved environment with `KIBANA_PROFILE`
|
|
209
|
-
- you do not need to redefine `KIBANA_BASE_URL`, credentials, or source-catalog paths per thread
|
|
210
|
-
|
|
211
|
-
Example:
|
|
212
|
-
|
|
213
|
-
```bash
|
|
214
|
-
KIBANA_PROFILE=staging npm run dev
|
|
215
|
-
KIBANA_PROFILE=prod npm run dev
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
If you still prefer env-bootstrap entries, keep these distinct per environment:
|
|
219
|
-
|
|
220
|
-
- `KIBANA_BASE_URL`
|
|
221
|
-
- `KIBANA_USERNAME`
|
|
222
|
-
- `KIBANA_PASSWORD`
|
|
223
|
-
- `KIBANA_SOURCE_CATALOG_PATH`
|
|
224
|
-
|
|
225
|
-
Using separate source-catalog paths matters because the `configure` tool persists sources to disk, and one shared runtime file would cause the environments to overwrite each other.
|
|
226
|
-
|
|
227
|
-
Each source definition should provide:
|
|
228
|
-
|
|
229
|
-
- stable `id`
|
|
230
|
-
- human-readable `name`
|
|
231
|
-
- `timeField`
|
|
232
|
-
- `tags` and optional `description`
|
|
233
|
-
- `fieldHints` so agents can form exact-match filters
|
|
234
|
-
- `defaultTextFields` for free-text search
|
|
235
|
-
- `evidenceFields` to elevate likely report-worthy fields
|
|
236
|
-
- `backend` describing how the source is queried
|
|
237
|
-
- optional `schema` describing how field introspection is performed for `describe_fields` and other schema-dependent features
|
|
51
|
+
`INSTALL.md` is the deterministic install and handoff guide for agents.
|
|
238
52
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
- `kibana_internal_search_es`
|
|
242
|
-
- POSTs to a Kibana endpoint like `/internal/search/es`
|
|
243
|
-
- wraps the query body inside `{ "params": { "index": ..., "body": ... } }`
|
|
244
|
-
- adds `kbn-xsrf`
|
|
245
|
-
- `elasticsearch_search`
|
|
246
|
-
- POSTs the compiled Elasticsearch body directly to the configured path
|
|
247
|
-
|
|
248
|
-
Supported schema backend kinds:
|
|
249
|
-
|
|
250
|
-
- `kibana_data_views_fields`
|
|
251
|
-
- tries Kibana wildcard field-metadata endpoints, preferring `/internal/data_views/_fields_for_wildcard`
|
|
252
|
-
- adds `pattern=...` from `schema.index` or `backend.index`
|
|
253
|
-
- if all known field-metadata endpoints return `404`, falls back to sampling fields through the configured search backend
|
|
254
|
-
- `kibana_index_patterns_fields`
|
|
255
|
-
- tries the legacy wildcard field-metadata endpoint `/api/index_patterns/_fields_for_wildcard` and related fallbacks
|
|
256
|
-
- adds `pattern=...` from `schema.index` or `backend.index`
|
|
257
|
-
- if all known field-metadata endpoints return `404`, falls back to sampling fields through the configured search backend
|
|
258
|
-
- `elasticsearch_field_caps`
|
|
259
|
-
- GETs an Elasticsearch field capabilities endpoint such as `/<index-pattern>/_field_caps?fields=*`
|
|
260
|
-
- uses `schema.path` when provided or derives the default from `schema.index`
|
|
261
|
-
|
|
262
|
-
Deployment note:
|
|
263
|
-
|
|
264
|
-
- some Kibana deployments expose search transport but not field-metadata endpoints
|
|
265
|
-
- when direct schema endpoints such as `/api/data_views/fields_for_wildcard`, `/api/index_patterns/_fields_for_wildcard`, or `/<index>/_field_caps` return `404`, the server falls back to sampling fields through the configured search backend
|
|
266
|
-
- this fallback is heuristic rather than authoritative, but it is often sufficient to recover `.keyword` promotion and object-path discovery in search-only environments
|
|
267
|
-
|
|
268
|
-
Example source shape for an application log stream:
|
|
269
|
-
|
|
270
|
-
```json
|
|
271
|
-
{
|
|
272
|
-
"id": "app_logs",
|
|
273
|
-
"name": "Application Logs",
|
|
274
|
-
"timeField": "@timestamp",
|
|
275
|
-
"backend": {
|
|
276
|
-
"kind": "kibana_internal_search_es",
|
|
277
|
-
"path": "/internal/search/es",
|
|
278
|
-
"index": "app-logs-*"
|
|
279
|
-
},
|
|
280
|
-
"schema": {
|
|
281
|
-
"kind": "kibana_data_views_fields",
|
|
282
|
-
"index": "app-logs-*"
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
```
|
|
53
|
+
## Run it as a shared service
|
|
286
54
|
|
|
287
|
-
|
|
55
|
+
By default the server speaks stdio and serves one configuration. Over HTTP, one process serves every caller of your gateway, each with their own source catalog:
|
|
288
56
|
|
|
289
|
-
|
|
57
|
+
```ts
|
|
58
|
+
// kibana.mcp.config.ts
|
|
59
|
+
import { defineKibanaMcpConfig } from "@havesomecode/kibana-mcp-server/config";
|
|
60
|
+
import store from "@havesomecode/kibana-mcp-server/stores/postgres";
|
|
290
61
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
KIBANA_PASSWORD
|
|
295
|
-
|
|
296
|
-
|
|
62
|
+
export default defineKibanaMcpConfig({
|
|
63
|
+
url: process.env.KIBANA_URL,
|
|
64
|
+
user: process.env.KIBANA_USER,
|
|
65
|
+
password: process.env.KIBANA_PASSWORD,
|
|
66
|
+
store,
|
|
67
|
+
storeOptions: { url: process.env.DATABASE_URL },
|
|
68
|
+
http: { port: 3000, profileHeader: "x-kibana-profile", authToken: process.env.MCP_TOKEN },
|
|
69
|
+
});
|
|
297
70
|
```
|
|
298
71
|
|
|
299
|
-
Or, after guided setup:
|
|
300
|
-
|
|
301
72
|
```bash
|
|
302
|
-
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
## Tool Shapes
|
|
306
|
-
|
|
307
|
-
### `configure_index`
|
|
308
|
-
|
|
309
|
-
Use this tool only after the user explicitly names the exact index or index pattern to configure. It accepts no credentials and never lists or scans for candidate indexes.
|
|
310
|
-
|
|
311
|
-
Input:
|
|
312
|
-
|
|
313
|
-
```json
|
|
314
|
-
{
|
|
315
|
-
"index": "app-logs-*",
|
|
316
|
-
"source_name": "Application logs"
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
The tool inspects fields and runs one bounded validation search only for that index. It then persists the generated source in the managed catalog. Optional `source_id`, `time_field`, and `replace` fields support explicit collision or schema handling.
|
|
321
|
-
|
|
322
|
-
### `configure`
|
|
323
|
-
|
|
324
|
-
Input:
|
|
325
|
-
|
|
326
|
-
```json
|
|
327
|
-
{
|
|
328
|
-
"kibana": {
|
|
329
|
-
"baseUrl": "https://kibana.example.com",
|
|
330
|
-
"username": "elastic",
|
|
331
|
-
"password": "secret",
|
|
332
|
-
"timeoutMs": 10000
|
|
333
|
-
},
|
|
334
|
-
"sources": [
|
|
335
|
-
{
|
|
336
|
-
"id": "app_logs",
|
|
337
|
-
"name": "Application Logs",
|
|
338
|
-
"tags": ["app", "logs", "production"],
|
|
339
|
-
"timeField": "@timestamp",
|
|
340
|
-
"backend": {
|
|
341
|
-
"kind": "kibana_internal_search_es",
|
|
342
|
-
"path": "/internal/search/es",
|
|
343
|
-
"index": ["app-logs-*"]
|
|
344
|
-
},
|
|
345
|
-
"schema": {
|
|
346
|
-
"kind": "kibana_data_views_fields",
|
|
347
|
-
"index": ["app-logs-*"]
|
|
348
|
-
},
|
|
349
|
-
"fieldHints": [
|
|
350
|
-
{
|
|
351
|
-
"name": "traceId",
|
|
352
|
-
"aliases": ["trace_id"]
|
|
353
|
-
}
|
|
354
|
-
],
|
|
355
|
-
"defaultTextFields": ["message"],
|
|
356
|
-
"evidenceFields": ["traceId"]
|
|
357
|
-
}
|
|
358
|
-
]
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
If you do not bootstrap via env vars and do not have a saved default profile, call `configure` before `discover` or `query`.
|
|
363
|
-
Calling `configure` also persists the provided sources to the runtime source-catalog file so later restarts can reload them automatically.
|
|
364
|
-
If you want `describe_fields`, exact-field auto-resolution in `query`, or nested-filter validation, configure `schema` for each relevant source.
|
|
365
|
-
In deployments where schema endpoints are routed indirectly or return `404`, prefer `schema.kind = "kibana_data_views_fields"` with `schema.index` set and omit `schema.path`.
|
|
366
|
-
|
|
367
|
-
### `discover`
|
|
368
|
-
|
|
369
|
-
Input:
|
|
370
|
-
|
|
371
|
-
```json
|
|
372
|
-
{
|
|
373
|
-
"query": "application",
|
|
374
|
-
"limit": 10
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
Output includes:
|
|
379
|
-
|
|
380
|
-
- source id
|
|
381
|
-
- source name
|
|
382
|
-
- time field
|
|
383
|
-
- tags
|
|
384
|
-
- configured field hints
|
|
385
|
-
|
|
386
|
-
### `describe_fields`
|
|
387
|
-
|
|
388
|
-
Use `describe_fields` when the agent needs to know whether a field is safe for exact term matching, grouping, or sorting.
|
|
389
|
-
If the source does not configure a schema backend, `describe_fields` fails clearly instead of guessing.
|
|
390
|
-
When direct schema endpoints are unavailable, the server will infer fields from sample hits via the configured search backend.
|
|
391
|
-
|
|
392
|
-
Input:
|
|
393
|
-
|
|
394
|
-
```json
|
|
395
|
-
{
|
|
396
|
-
"source_id": "workflow_metrics",
|
|
397
|
-
"query": "event",
|
|
398
|
-
"limit": 50
|
|
399
|
-
}
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
Output includes:
|
|
403
|
-
|
|
404
|
-
- field name
|
|
405
|
-
- field type
|
|
406
|
-
- `searchable`
|
|
407
|
-
- `aggregatable`
|
|
408
|
-
- available subfields
|
|
409
|
-
- `preferred_exact_field` when a safer exact-match variant exists, such as `.keyword`
|
|
410
|
-
|
|
411
|
-
### `query`
|
|
412
|
-
|
|
413
|
-
Input:
|
|
414
|
-
|
|
415
|
-
```json
|
|
416
|
-
{
|
|
417
|
-
"source_ids": ["app_logs", "workflow_metrics"],
|
|
418
|
-
"start_time": "2026-04-02T12:00:00Z",
|
|
419
|
-
"end_time": "2026-04-02T12:15:00Z",
|
|
420
|
-
"text": "SERVICE_RELOAD",
|
|
421
|
-
"filters": [
|
|
422
|
-
{ "field": "region", "value": "us-east-1" },
|
|
423
|
-
{ "field": "traceId", "value": "trace-12345" }
|
|
424
|
-
],
|
|
425
|
-
"nested_filters": [
|
|
426
|
-
{
|
|
427
|
-
"path": "steps",
|
|
428
|
-
"field": "name",
|
|
429
|
-
"value": "CACHE_REFRESH"
|
|
430
|
-
}
|
|
431
|
-
],
|
|
432
|
-
"extract_nested": true,
|
|
433
|
-
"mode": "hits",
|
|
434
|
-
"sort_by": "total_duration_ms",
|
|
435
|
-
"sort": "desc",
|
|
436
|
-
"limit": 50
|
|
437
|
-
}
|
|
438
|
-
```
|
|
439
|
-
|
|
440
|
-
Supported modes:
|
|
441
|
-
|
|
442
|
-
- `hits`
|
|
443
|
-
- `count`
|
|
444
|
-
- `histogram`
|
|
445
|
-
- requires `histogram_interval`
|
|
446
|
-
- `terms`
|
|
447
|
-
- requires `group_by`
|
|
448
|
-
- `stats`
|
|
449
|
-
- requires `stats_field`
|
|
450
|
-
- can also take `group_by`
|
|
451
|
-
- `grouped_top_hits`
|
|
452
|
-
- requires `group_by`
|
|
453
|
-
- requires `sort_by`
|
|
454
|
-
- accepts `top_hits_size`
|
|
455
|
-
|
|
456
|
-
Every response includes a `query_echo` section so the investigating agent can explain which sources, bounds, filters, and mode were actually used.
|
|
457
|
-
For `hits` mode, you can also pass `sort_by` to sort on a chosen field. In `query`, exact filters and grouped bucket fields use field-hint alias resolution plus schema-aware exact-field preference when metadata is available. When the server rewrites a logical field such as `event` to a safer exact field such as `event.keyword`, the response includes an advisory. If schema metadata is unavailable, the query proceeds with the requested field and returns a `schema_unavailable` advisory instead of silently pretending exact-safe resolution happened.
|
|
458
|
-
|
|
459
|
-
For very large single-source hit sets, `query` also supports cursor pagination:
|
|
460
|
-
|
|
461
|
-
```json
|
|
462
|
-
{
|
|
463
|
-
"source_ids": ["workflow_metrics"],
|
|
464
|
-
"start_time": "2026-04-02T12:00:00Z",
|
|
465
|
-
"end_time": "2026-04-02T12:15:00Z",
|
|
466
|
-
"mode": "hits",
|
|
467
|
-
"limit": 100,
|
|
468
|
-
"cursor": "REPLACE_ME_NEXT_CURSOR"
|
|
469
|
-
}
|
|
73
|
+
kibana-mcp-server serve --http --config ./kibana.mcp.config.ts
|
|
470
74
|
```
|
|
471
75
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
Nested filtering also depends on schema metadata. If a source does not expose a working `schema` backend, nested requests fail early with a clear configuration error instead of reaching Kibana and failing with a backend 404.
|
|
475
|
-
|
|
476
|
-
Example `stats` query:
|
|
76
|
+
Catalogs can live in files, Redis, PostgreSQL, MongoDB, SQLite, or a store you write. The HTTP transport trusts the profile header as sent: only a gateway that has authenticated the caller should reach it.
|
|
477
77
|
|
|
478
|
-
|
|
479
|
-
{
|
|
480
|
-
"source_ids": ["workflow_metrics"],
|
|
481
|
-
"start_time": "2026-04-02T12:00:00Z",
|
|
482
|
-
"end_time": "2026-04-02T12:15:00Z",
|
|
483
|
-
"mode": "stats",
|
|
484
|
-
"stats_field": "total_duration_ms",
|
|
485
|
-
"group_by": "trace_id",
|
|
486
|
-
"limit": 25
|
|
487
|
-
}
|
|
488
|
-
```
|
|
489
|
-
|
|
490
|
-
Example `grouped_top_hits` query:
|
|
491
|
-
|
|
492
|
-
```json
|
|
493
|
-
{
|
|
494
|
-
"source_ids": ["workflow_metrics"],
|
|
495
|
-
"start_time": "2026-04-02T12:00:00Z",
|
|
496
|
-
"end_time": "2026-04-02T12:15:00Z",
|
|
497
|
-
"mode": "grouped_top_hits",
|
|
498
|
-
"group_by": "trace_id",
|
|
499
|
-
"sort_by": "total_duration_ms",
|
|
500
|
-
"top_hits_size": 1,
|
|
501
|
-
"limit": 25
|
|
502
|
-
}
|
|
503
|
-
```
|
|
78
|
+
## Documentation
|
|
504
79
|
|
|
505
|
-
|
|
80
|
+
| Topic | Link |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| Getting started | https://havesomecode.github.io/kibana-mcp-server/guide/getting-started |
|
|
83
|
+
| Investigating with an agent | https://havesomecode.github.io/kibana-mcp-server/guide/investigating |
|
|
84
|
+
| HTTP transport and security model | https://havesomecode.github.io/kibana-mcp-server/deployment/http |
|
|
85
|
+
| Catalog stores | https://havesomecode.github.io/kibana-mcp-server/deployment/catalog-stores |
|
|
86
|
+
| Integration examples (gateway, Ts.ED, Docker) | https://havesomecode.github.io/kibana-mcp-server/integrations/ |
|
|
87
|
+
| Tool, CLI and configuration reference | https://havesomecode.github.io/kibana-mcp-server/reference/cli |
|
|
506
88
|
|
|
507
|
-
|
|
89
|
+
The documentation sources live in `website/`.
|
|
508
90
|
|
|
509
|
-
|
|
91
|
+
## Project status
|
|
510
92
|
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
"value": "WORKFLOW_RELOAD_STATS",
|
|
518
|
-
"nested_filters": [
|
|
519
|
-
{
|
|
520
|
-
"path": "steps",
|
|
521
|
-
"field": "steps.name.keyword",
|
|
522
|
-
"value": "CACHE_REFRESH"
|
|
523
|
-
}
|
|
524
|
-
],
|
|
525
|
-
"extract_nested": true,
|
|
526
|
-
"mode": "hits",
|
|
527
|
-
"sort_by": "total_duration_ms",
|
|
528
|
-
"limit": 50
|
|
529
|
-
}
|
|
530
|
-
```
|
|
531
|
-
|
|
532
|
-
`filter` returns the same structured output envelope as `query`, but it does not apply field-hint alias rewrites.
|
|
533
|
-
If schema metadata is available and you pass a logical text field such as `event`, the server may still promote it to a preferred exact field such as `event.keyword` for exact term matching. If you pass an exact backend field like `event.keyword`, it is used as-is.
|
|
534
|
-
`sort_by` is supported for `hits` and `grouped_top_hits`.
|
|
93
|
+
- Published package: `npx -y @havesomecode/kibana-mcp-server`
|
|
94
|
+
- Agent skill: `npx skills add Havesomecode/kibana-mcp-server --skill kibana-log-investigation`
|
|
95
|
+
- Repo-local Codex plugin install remains a first-class path for cloned checkouts
|
|
96
|
+
- GitHub Releases are the canonical release notes and version record; the `version` field in `package.json` inside git is not the release source of truth
|
|
97
|
+
- Support posture, compatibility matrix, distribution strategy and release checklist live in `docs/project/`
|
|
98
|
+
- Contributing and security reporting live in `CONTRIBUTING.md` and `SECURITY.md`
|
|
535
99
|
|
|
536
100
|
## Development
|
|
537
101
|
|
|
538
102
|
```bash
|
|
539
|
-
npm
|
|
540
|
-
npm run format:check
|
|
541
|
-
npm run check:types
|
|
542
|
-
npm test
|
|
103
|
+
npm install
|
|
543
104
|
npm run verify
|
|
105
|
+
npm run docs:dev
|
|
544
106
|
```
|
|
107
|
+
|
|
108
|
+
This project is independent and not affiliated with or endorsed by Elastic. Kibana and Elasticsearch are trademarks of Elasticsearch B.V.
|
|
@@ -1,54 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import registerServeCommand from "../commands/serve.js";
|
|
5
|
-
import registerSetupCommands from "../commands/setup.js";
|
|
6
|
-
import { startMcpServer } from "../mcp_runtime.js";
|
|
7
|
-
import { createCliIo } from "../utils/cli_io.js";
|
|
8
|
-
import { createCliUi } from "../utils/cli_ui.js";
|
|
9
|
-
export async function runCli(argv = process.argv.slice(2), overrides = {}, dependencies = {}) {
|
|
10
|
-
const io = createCliIo(overrides);
|
|
11
|
-
let exitCode = 0;
|
|
12
|
-
const context = {
|
|
13
|
-
argv,
|
|
14
|
-
io,
|
|
15
|
-
ui: createCliUi(io),
|
|
16
|
-
dependencies,
|
|
17
|
-
setExitCode: (code) => {
|
|
18
|
-
exitCode = code;
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
const program = new Command()
|
|
22
|
-
.name("kibana-mcp-server")
|
|
23
|
-
.description("Kibana Log Investigation")
|
|
24
|
-
.showHelpAfterError()
|
|
25
|
-
.exitOverride()
|
|
26
|
-
.configureOutput({
|
|
27
|
-
writeOut: (message) => io.stdout(message.trimEnd()),
|
|
28
|
-
writeErr: (message) => io.stderr(message.trimEnd()),
|
|
29
|
-
})
|
|
30
|
-
.action(async () => {
|
|
31
|
-
try {
|
|
32
|
-
await (dependencies.startMcpServerFn ?? startMcpServer)(io.env);
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
context.ui.error(error instanceof Error ? error.message : String(error));
|
|
36
|
-
exitCode = 1;
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
registerSetupCommands(program, context);
|
|
40
|
-
registerServeCommand(program, context);
|
|
41
|
-
try {
|
|
42
|
-
await program.parseAsync(["node", "kibana-mcp-server", ...argv], { from: "node" });
|
|
43
|
-
}
|
|
44
|
-
catch (error) {
|
|
45
|
-
if (error instanceof CommanderError)
|
|
46
|
-
return error.exitCode;
|
|
47
|
-
io.stderr(error instanceof Error ? error.message : String(error));
|
|
48
|
-
return 1;
|
|
49
|
-
}
|
|
50
|
-
return exitCode;
|
|
51
|
-
}
|
|
52
|
-
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
53
|
-
process.exitCode = await runCli();
|
|
54
|
-
}
|
|
2
|
+
import { runCli } from "./run_cli.js";
|
|
3
|
+
process.exitCode = await runCli(process.argv);
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { CliCommandContext } from "../commands/context.js";
|
|
2
|
+
import { type CliIo } from "../utils/cli_io.js";
|
|
3
|
+
export type CliDependencies = CliCommandContext["dependencies"];
|
|
4
|
+
export declare function runCli(argv: string[], overrides?: Partial<CliIo>, dependencies?: CliDependencies): Promise<number>;
|