Skip to main content
Glama
CloudCorpRecords

indexsearch

README.md
# indexsearch

indexsearch gives an agent — or you, at a terminal — the five core
Elasticsearch tools: see which indices exist, read an index's field
mappings, run a search in query DSL, run an ES|QL query, and inspect
shard placement. Everything goes through the cluster's own HTTP API;
there is no bundled client library and no second query language to
learn.

Each tool call is first mapped to a plain HTTP request — method, path,
and JSON body — and that mapping is the whole contract:
`GET /_cat/indices?format=json`, `GET /{index}/_mapping`,
`POST /{index}/_search`, `POST /_query`, `GET /_cat/shards`. Transport
is an injectable fetch function, which is what the test suite drives;
no live cluster is needed to verify behaviour, and no result is ever
invented when a cluster is unreachable or answers with an error.

## Install

```bash
npx @reneturcios/indexsearch list-indices
```

Or run the container image:

```bash
docker run -i ghcr.io/cloudcorprecords/indexsearch
```

The container defaults to the MCP server (see below). Pass CLI
arguments to use it as a CLI instead, and pass the cluster settings as
environment variables (`-e ES_URL=...`).

## Configuration

| Variable | Meaning | Default |
| --- | --- | --- |
| `ES_URL` | Cluster base URL | `http://localhost:9200` |
| `INDEXSEARCH_URL` | Fallback cluster base URL when `ES_URL` is unset | — |
| `ES_API_KEY` | API key, sent as `Authorization: ApiKey <key>` | unset (no auth) |

## CLI

```bash
# List indices
indexsearch list-indices

# Read one index's field mappings
indexsearch mappings products

# Search with query DSL (a bare clause, or a full {"query": ...} body)
indexsearch search products '{"match":{"name":"shoes"}}'

# Run an ES|QL query
indexsearch esql 'FROM products | SORT price DESC | LIMIT 5'

# Shard information for every index, or for one
indexsearch shards
indexsearch shards products

# Start the MCP server
indexsearch mcp

indexsearch --version
```

Exit codes: `0` on success, `1` when the request or the cluster
fails (the error names the HTTP status or the unreachable URL),
`2` for usage errors.

Index names are validated before any request is made: names carrying
characters Elasticsearch forbids in index names (whitespace, `/`, `*`,
`?`, `"`, `<`, `>`, `|`, `,`, `#`, `:`, `\`) are rejected locally.

## MCP server

One bin serves both faces. The `mcp` subcommand starts a stdio MCP
server:

```bash
npx -y @reneturcios/indexsearch mcp
```

MCP client configuration:

```json
{
  "mcpServers": {
    "indexsearch": {
      "command": "npx",
      "args": ["-y", "@reneturcios/indexsearch", "mcp"],
      "env": { "ES_URL": "http://localhost:9200" }
    }
  }
}
```

### Tools

| Tool | Required | Optional | HTTP request | What it does |
| --- | --- | --- | --- | --- |
| `list_indices` | — | — | `GET /_cat/indices?format=json` | List all available indices |
| `get_mappings` | `index` | — | `GET /{index}/_mapping` | Get field mappings for an index |
| `search` | `index`, `query` (object) | — | `POST /{index}/_search` with `{ "query": ... }` | Search using query DSL |
| `esql` | `query` (string) | — | `POST /_query` with `{ "query": ... }` | Run an ES|QL query |
| `get_shards` | — | `index` | `GET /_cat/shards[/{index}]?format=json` | Get shard information for all or specific indices |

Replies are returned as the cluster's parsed JSON. A non-JSON reply is
returned under a `raw` key rather than being dropped, and an empty
reply reads as an empty object.

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # node test runner over test/*.test.ts, no network, no live cluster
npm run dev     # run the CLI from source via tsx
```

Request construction, validation, header and body assembly, error
surfacing, and settings resolution are all covered by tests that drive
the core through a fake fetch and assert the exact paths and bodies.

## License

MIT — see `LICENSE`.