TL;DR: 403 means you logged in fine but your API key is not allowed to do that. The `read-only` sounding roles do not cover everything the MCP server needs (like listing indices). Recreate the API key with the missing privileges.

```text
{"error":{"root_cause":[{"type":"security_exception","reason":"action [indices:admin/get] is unauthorized for API key id [...]"}]},"status":403}
```

## Fix it

1. Identify the denied action in the error. `indices:admin/get` is list-indices, `indices:data/read/search` is search.

2. In Kibana, Stack Management, Security, API Keys, create a new key with explicit role descriptors covering what the server needs. Example for a search workload:

```json
{
  "elasticsearch": {
    "cluster": ["monitor"],
    "indices": [{"names": ["logs-*"], "privileges": ["read", "view_index_metadata"]}]
  }
}
```

   For a quick unblock, superuser works, then scope it down.

3. Replace `ES_API_KEY` in the MCP server config with the new encoded key. Restart the client.

   Expected: the denied tools now work.

## When to use this

- Auth succeeds (no 401) but tools fail with 403 `unauthorized`.
- Some tools work and others do not. The working ones are within the key's privileges.

## When NOT to use this

- The error is 401 `missing authentication credentials`. No credentials are being sent at all.
- The error is 401 `unable to authenticate`. The key itself is bad. Make a new one rather than broadening roles.

## Compatibility

- elastic/mcp-server-elasticsearch.
- Elasticsearch 8.x with API key auth.

## Why it happens

API keys carry role descriptors that gate every action. The minimal-looking roles do not include the admin-ish actions MCP tools need, like listing indices or getting mappings. People create a key with just `read` and then wonder why half the tools 403.

## Edge cases

- Invalidating the old key after switching avoids confusion about which key is live.
- Key privileges are fixed at creation. You cannot widen an existing key; you must create a new one.
- The `elastic` superuser password works everywhere but should not be the MCP server's daily credential. Use scoped API keys.