Skip to main content
Glama
thiagorchaves

AWS OpenSearch MCP Server

README.md
# AWS OpenSearch MCP, read-only

MCP em Python para investigar domínios do **Amazon OpenSearch Service** usando profiles AWS locais, incluindo SSO. O servidor foi desenhado para operação segura em CI, QA, produção e telemetry, sem ferramentas de escrita.

## O que ele entrega

- Profiles permitidos: `ci`, `qa`, `prod` e `telemetry`.
- Regiões permitidas por configuração.
- Descoberta de domínios AWS-managed com `boto3`.
- Targets customizados/self-managed, incluindo OpenSearch atrás de Nginx ou proxy.
- Autenticação no data plane com AWS Signature Version 4, Basic, header de ambiente ou nenhuma autenticação somente para targets explícitos.
- Consultas limitadas por tamanho, timeout e quantidade de documentos.
- Redação de campos com aparência de segredo ou credencial.
- Diagnósticos específicos para shards, flood stage, mappings e timestamps antigos.
- Nenhum endpoint genérico de request e nenhuma ferramenta de escrita.

## Tools disponíveis

| Tool | Objetivo |
|---|---|
| `list_aws_profiles` | Mostra profiles permitidos, disponibilidade local e regiões |
| `list_domains` | Lista domínios por profile e região |
| `get_domain_config` | Lê configuração AWS do domínio |
| `get_cluster_health` | Saúde green/yellow/red |
| `get_cluster_stats` | Estatísticas gerais do cluster |
| `list_indices` | Índices, tamanho, documentos e shards |
| `get_index_details` | Settings, mappings, aliases e stats |
| `search_index` | Query DSL read-only com limites |
| `get_latest_documents` | Documentos mais recentes por timestamp |
| `get_field_mapping` | Tipo e conflito de mapping de um campo |
| `get_field_count` | Uso de `index.mapping.total_fields.limit` |
| `get_shard_allocation` | Distribuição e estado dos shards |
| `explain_unassigned_shard` | Motivo de shard não alocado |
| `get_disk_allocation` | Disco por nó |
| `get_cluster_settings` | Settings transient, persistent e default |
| `get_indexing_stats` | Indexação, busca, merges, refresh e segmentos |
| `get_pending_tasks` | Tarefas pendentes no cluster manager |
| `get_ingest_pipelines` | Pipelines de ingestão |
| `diagnose_cluster` | Diagnóstico consolidado de saúde, disco e flood stage |
| `diagnose_timestamp` | Min/max, mapping e amostras para dados antigos |

## Pré-requisitos

- Python 3.10 ou superior.
- `uv` recomendado.
- Profiles AWS já configurados em `~/.aws/config` e `~/.aws/credentials`.
- Rota de rede até o endpoint. Para domínio VPC-only, a máquina precisa estar na VPN, VPC ou em um túnel apropriado.

## Instalação

```bash
git clone https://github.com/thiagorchaves/aws-opensearch-mcp-server.git
cd aws-opensearch-mcp-server
cp config.example.yaml config.yaml
uv sync --extra dev
```

Valide os profiles utilizados:

```bash
aws sts get-caller-identity --profile telemetry
aws opensearch list-domain-names --profile telemetry --region us-east-1
```

Quando o profile usa AWS SSO:

```bash
aws sso login --profile telemetry
```

## Rodar manualmente

```bash
AWS_OPENSEARCH_MCP_CONFIG="$PWD/config.yaml" \
AWS_SDK_LOAD_CONFIG=1 \
uv run aws-opensearch-mcp
```

O transporte padrão é `stdio`, portanto o processo aparentemente fica sem imprimir respostas no terminal. Isso é esperado: ele aguarda um cliente MCP.

## Targets customizados, self-managed e Nginx

As tools que recebem `domain` também aceitam o nome de um target em `profiles.settings.<profile>.opensearch_targets`. Quando o nome corresponde a um target configurado, o servidor conecta diretamente em `endpoint_url` e **não chama `DescribeDomain`**. Caso contrário, o fluxo AWS-managed permanece inalterado: `DescribeDomain` resolve e valida o domínio antes da conexão.

```yaml
profiles:
  settings:
    telemetry:
      # Mantido por compatibilidade: valida o domínio AWS e usa o proxy no data plane.
      endpoint_overrides:
        logs-production: https://nginx.internal.example

      # Não chama DescribeDomain; use `nginx-logs` no parâmetro domain.
      opensearch_targets:
        nginx-logs:
          endpoint_url: https://nginx.internal.example
          auth_mode: sigv4
          signing_region: us-east-1       # padrão: região informada à tool
          signing_service: es             # padrão: es
          signing_host: search-logs.us-east-1.es.amazonaws.com
          tls_verify: true                # padrão: true

        self-managed-basic:
          endpoint_url: https://opensearch.internal.example
          auth_mode: basic
          username_env: OPENSEARCH_READONLY_USERNAME
          password_env: OPENSEARCH_READONLY_PASSWORD

        self-managed-header:
          endpoint_url: https://opensearch.internal.example
          auth_mode: header
          header_name: Authorization
          header_value_env: OPENSEARCH_READONLY_AUTHORIZATION
```

`endpoint_url` deve usar `https://` por padrão; `http://` só é permitido com `allow_insecure_http: true` no próprio target. URLs com `..` no path, query string ou fragment são rejeitadas. O servidor rejeita campos não suportados no target, portanto senhas e tokens literais em YAML não são aceitos: `basic` e `header` leem seus valores exclusivamente das variáveis de ambiente indicadas.

Para `sigv4`, `signing_host` é aplicado como o header HTTP `Host`, que é o valor usado pelo `AWSV4SignerAuth` ao calcular a assinatura, enquanto a conexão TCP/TLS continua apontando para `endpoint_url`. Isso exige que o Nginx/proxy aceite e encaminhe esse Host. Não há canal separado de host de assinatura no `opensearch-py`; se o proxy precisar receber um Host diferente do host assinado, é necessária uma custom connection/proxy que resolva essa tradução.

`auth_mode: none` é permitido exclusivamente em um `opensearch_targets` configurado de forma explícita; domínios AWS-managed e `endpoint_overrides` legados continuam usando SigV4.

## Configuração no Kiro

Use o arquivo de usuário `~/.kiro/settings/mcp.json` ou o arquivo do workspace `.kiro/settings/mcp.json`:

```json
{
  "mcpServers": {
    "aws-opensearch-readonly": {
      "command": "uv",
      "args": [
        "--directory",
        "/home/SEU_USUARIO/Projects/aws-opensearch-mcp-server",
        "run",
        "aws-opensearch-mcp"
      ],
      "env": {
        "AWS_OPENSEARCH_MCP_CONFIG": "/home/SEU_USUARIO/Projects/aws-opensearch-mcp-server/config.yaml",
        "AWS_SDK_LOAD_CONFIG": "1",
        "AWS_OPENSEARCH_MCP_LOG_LEVEL": "INFO"
      },
      "timeout": 120000
    }
  }
}
```

Evite `autoApprove` no primeiro uso. Depois de revisar os parâmetros e resultados, ferramentas puramente informativas, como `get_cluster_health`, podem ser aprovadas conforme a política do time.

## Testes

```bash
uv run pytest -q
uv run ruff check .
```

Para abrir no MCP Inspector:

```bash
uv run mcp dev mcp_server.py
```

## Exemplos de prompts no Kiro

```text
Use o profile telemetry em us-east-1 e liste os domínios OpenSearch disponíveis.
```

```text
No domínio logs-production, rode diagnose_cluster e explique apenas achados warning ou superiores.
```

```text
No índice sentinelone-*, verifique o mapping de @timestamp e diagnostique por que os documentos mais novos parecem ser de janeiro.
```

```text
Liste os 20 maiores índices e verifique quais estão próximos de index.mapping.total_fields.limit.
```

```text
Encontre shards não alocados e execute explain_unassigned_shard para o primeiro deles. Não faça alterações.
```

## Privacidade dos dados

As respostas das tools entram no contexto do cliente de IA. Restrinja `source_fields`, evite consultar documentos com dados pessoais desnecessários e use uma identidade com acesso somente aos índices necessários.

## IAM mínimo

O arquivo `examples/iam-policy.example.json` contém uma base. Ajuste conta, domínio e regiões.

A permissão `es:ESHttpPost` aparece porque APIs read-only como `_search` e `_cluster/allocation/explain` usam POST. O MCP não expõe endpoints arbitrários nem operações de escrita, mas a identidade AWS ainda deve seguir privilégio mínimo e, quando disponível, Fine-Grained Access Control do OpenSearch.

## Proteções implementadas

- Allowlist de profile e região.
- Validação de domínio, índice e campo.
- Bloqueio de path injection.
- Limite de documentos, bytes de query e resposta.
- Timeout em consultas.
- Bloqueio de `script`, `script_fields`, `runtime_mappings`, `rescore` e `stored_fields` nas queries fornecidas pelo modelo.
- Redação recursiva de tokens, senhas, cookies, chaves e segredos.
- Paginação e tamanhos internos de agregações limitados.
- Logs enviados para `stderr`, preservando o protocolo MCP em `stdout`.
- Produção e todos os demais profiles permanecem read-only nesta versão.

## Evolução sugerida

Uma segunda versão pode adicionar ferramentas de escrita estritamente específicas, sempre em pares `preview_*` e `apply_*`, com confirmação explícita e bloqueio por profile. Não adicione uma tool de request HTTP arbitrário, pois ela contornaria todas as proteções deste servidor.

## Referências oficiais

- MCP Python SDK: https://github.com/modelcontextprotocol/python-sdk
- Amazon OpenSearch Service, assinatura SigV4: https://docs.aws.amazon.com/opensearch-service/latest/developerguide/managedomains-signing-service-requests.html
- OpenSearch API: https://docs.opensearch.org/latest/api-reference/
- Kiro MCP configuration: https://kiro.dev/docs/mcp/configuration/

TDQS

B3.4/5.0

Scored across 20 tools

Disambiguation5/5

Each tool targets a distinct aspect of OpenSearch cluster management and diagnosis, such as health, shards, fields, ingest pipelines, and domain configuration. Even tools with overlapping themes (e.g., diagnose_cluster and explain_unassigned_shard) have clearly different scopes, minimizing confusion.

Naming Consistency5/5

All tool names follow a consistent verb-noun pattern using snake_case (e.g., diagnose_cluster, get_cluster_health, list_indices). Verbs like 'get', 'list', 'diagnose', 'explain' are used predictably, making it easy for an agent to infer functionality.

Tool Count5/5

With 20 tools, the set is well-scoped for a dedicated OpenSearch diagnostic server. It covers a wide range of inspection and diagnosis tasks without being overwhelming, and each tool serves a clear purpose.

Completeness4/5

The tool set comprehensively covers read-only diagnostics: cluster health, stats, settings, shard allocation, field mappings, ingest pipelines, and more. Minor gaps exist, such as lack of node-specific details or thread pool stats, but these are acceptable given the read-only and diagnostic focus.

Maintenance

ActivityMaintained
ResponsivenessNo issues