Skip to main content
Glama
danilin-em

opensearch-dashboard-mcp

by danilin-em
README.md
# opensearch-dashboard-mcp

MCP server that exposes OpenSearch Dashboards to an LLM client over stdio. Read
saved objects, list tenants and index patterns, and query logs like the Discover
app — all through the Dashboards API, so it works even when the raw OpenSearch
REST API isn't exposed.

## Run

```bash
uvx opensearch-dashboard-mcp
```

(After publishing to PyPI. For local dev use `uvx --from . opensearch-dashboard-mcp`.)

## Configure

Environment variables:

| Variable | Default | Purpose |
|---|---|---|
| `OPENSEARCH_DASHBOARDS_URL` | `http://localhost:5601` | Base URL |
| `OPENSEARCH_DASHBOARDS_USERNAME` | — | Basic auth / session-login user |
| `OPENSEARCH_DASHBOARDS_PASSWORD` | — | Basic auth / session-login password |
| `OPENSEARCH_DASHBOARDS_VERIFY_TLS` | `true` | Verify TLS certs |
| `SSH_PROXY_TO` | — | If set (e.g. `user@host`), route all requests through an embedded SSH SOCKS5 tunnel to that host |
| `SSH_PROXY_PORT` | auto | Local port for the tunnel; a free port is picked when unset |

### SSH tunnel

When `SSH_PROXY_TO` is set, the server spawns `ssh -N -D <port> <host>` before
serving and routes HTTP through the resulting `socks5h://` proxy. DNS is resolved
on the remote side, so this reaches targets only visible from a remote network
(e.g. a VPN living inside a container). Requires key-based SSH auth (runs with
`BatchMode=yes`). The tunnel lives exactly as long as the server.

## Use in an MCP client

```json
{
  "mcpServers": {
    "opensearch-dashboards": {
      "command": "uvx",
      "args": ["opensearch-dashboard-mcp"],
      "env": {
        "OPENSEARCH_DASHBOARDS_URL": "http://localhost:5601",
        "OPENSEARCH_DASHBOARDS_USERNAME": "admin",
        "OPENSEARCH_DASHBOARDS_PASSWORD": "admin"
      }
    }
  }
}
```

## Tools

- `ping()` — check connectivity + auth. Hits the security authinfo endpoint;
  on a 401 with credentials set, performs a session login and re-checks.
  Returns `{connected, authenticated, user, tenants}` or the error reason.
- `list_saved_objects(type_="dashboard", per_page=20, tenant=None)` — saved
  objects via `saved_objects/_find`, returned as compact `{id, title, type}`.
  `tenant` selects the multi-tenancy tenant (name, `"__user__"` for the private
  tenant, or `None` for the user default).
- `get_tenants()` — multi-tenancy tenants via the security plugin config API,
  as `{name, description, reserved, hidden}`.
- `get_index_patterns(per_page=50)` — index patterns (saved objects of type
  `index-pattern`), as `{id, title, time_field}`.
- `discover_search(index, query=None, time_from=None, time_to=None, time_field="@timestamp", size=10, fields=None, tenant=None)`
  — fetch documents like the Discover app through the internal search API
  (`/internal/search/opensearch`). `query` is a Lucene query_string; `time_from`/
  `time_to` filter a range (`now-15m`, ISO, …); `fields` trims `_source` to avoid
  flooding context. Returns `{index, total, count, hits}`.

Multi-tenancy note: saved objects are stored per tenant. Discover available tenant
names with `get_tenants`, then pass one as `tenant` to the other tools.

## Develop

```bash
uv sync --group dev
uv run opensearch-dashboard-mcp        # starts on stdio; Ctrl-D to exit
uv run pytest                          # tests (add --cov for the 100% gate)
```

Layout: `config.py` (env → `Settings`), `client.py` (async httpx wrapper),
`tools.py` (tool registrations), `server.py` (entry point + tunnel), `tunnel.py`
(SSH SOCKS5 tunnel). See `CLAUDE.md` for the architecture in depth.

TDQS

A4.2/5.0

Scored across 5 tools

Disambiguation5/5

Each tool targets a distinct resource or action: search, index patterns, tenants, saved objects, and connectivity. No overlap in purpose.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern (e.g., discover_search, get_index_patterns), and 'ping' is a standard imperative verb, fitting the pattern.

Tool Count5/5

5 tools is well-scoped for a dashboard interaction server, covering essential query and listing operations without being overly numerous.

Completeness4/5

Covers core read operations (search, list index patterns, tenants, saved objects) but lacks write operations (create/update/delete) and direct retrieval of saved object details, which are minor gaps for a query-focused tool.

Maintenance

ActivityStale
ResponsivenessUnresponsive