Skip to main content
Glama
Edrient17

elasticsearch-investigation-mcp

by Edrient17

Elasticsearch Investigation MCP

Elasticsearch에 쌓인 로그를 n8n AI Agent가 인용할 수 있는 증거로 바꿔 주는 읽기 전용 MCP 서버입니다. Agent가 호스트·시간 범위·조건을 결정하고, 이 서버는 조회와 파싱, 집계를 결정론적으로 수행합니다.

Zabbix Investigation MCP와 짝을 이룹니다. 메트릭이 "언제 이상해졌는가"를 말한다면 로그는 "무엇이 실패했는가"를 말합니다. 두 서버가 같은 호스트 이름을 쓰기 때문에 한 조사 안에서 나란히 놓일 수 있습니다.

원본이 파싱되어 있지 않다는 전제

이 서버가 읽는 인덱스에는 로그 레벨·서비스·메시지가 필드로 분리되어 있지 않습니다. 수집기가 원문 한 줄을 message에 통째로 넣습니다. 따라서

  • 레벨은 필터가 아니라 파싱 결과입니다. Elasticsearch로는 "그 단어가 들어간 줄"까지만 좁히고, 그중 진짜 그 레벨인 줄은 이 서버가 앞부분을 해석해서 가려냅니다. 본문에 ERROR를 인용한 INFO 줄은 INFO로 셉니다.

  • 응답은 얼마나 이해했는지를 함께 보고합니다. data_quality.formatsunlevelled_lines가 그것입니다. 파싱률을 숨긴 채 정밀해 보이는 숫자만 주면 신뢰할 수 없는 근거가 됩니다.

인식하는 형식은 Spring Boot, 날짜 시각 LEVEL 본문, syslog 세 가지이고, 어느 쪽도 아니면 unrecognised로 표시한 뒤 레벨 단어만 찾아봅니다.

Related MCP server: Elastic MCP Server

제공 도구

summarize_logs — 먼저 부르는 도구

한 호스트가 어떤 구간에 남긴 로그 전체가 무엇을 말하는지 요약합니다. 줄 자체는 반환하지 않습니다. 바쁜 호스트는 시간당 수천 줄을 쓰기 때문에, 이 도구는 "어느 분, 어느 메시지를 봐야 하는가"까지만 알려 줍니다.

  • by_level, by_service — 레벨/서비스별 건수

  • volume_over_time — 구간을 10개 구획으로 나눈 분포. Elasticsearch가 전체 문서를 대상으로 센 값이라 아래의 표본이 잘려도 정확합니다. 80배 급증 같은 것은 여기서 보입니다.

  • repeated_messages — 변하는 부분(숫자·IP·16진수·따옴표 문자열·스택 프레임)을 치환해 같은 모양끼리 묶은 목록. 문제 레벨이 위로 옵니다.

  • analysed, analysed_window, data_quality.sampled_fraction — 파싱 통계가 실제로 어디까지를 설명하는지. 한 시간을 물었는데 표본이 앞 17분이었다면 그 사실이 응답에 있어야 합니다.

search_logs — 요약이 지목한 줄을 읽는 도구

level·contains·services로 좁혀서 실제 줄을 가져옵니다. 최신순입니다. 긴 메시지는 잘라내고 잘랐다고 표시합니다.

반환되는 message는 원문 전체가 아니라 파싱된 본문입니다. Spring 접두부 118자(타임스탬프·레벨·pid·서비스·스레드·로거)는 이미 각각의 필드로 따로 돌려주므로, 그것까지 문자 예산에 넣으면 스택 트레이스가 시작되기도 전에 잘립니다.

쓰기 도구, 인덱스 변경, 클러스터 설정 도구는 제공하지 않습니다.

환경 변수

Copy-Item .env.example .env

필수 설정:

  • ES_URL: Elasticsearch 주소 (예: http://elasticsearch.example.com:9200)

  • ES_API_KEY: 로그 인덱스에 read, view_index_metadata만 가진 API Key. Base64 인코딩된 id:secret 형태 그대로 넣습니다.

  • ES_MCP_AUTH_TOKEN: MCP 클라이언트가 사용할 Bearer Token

[Convert]::ToHexString(
  [Security.Cryptography.RandomNumberGenerator]::GetBytes(32)
).ToLower()

필드 이름

  • ES_HOST_FIELD (기본 host.name) — Zabbix가 부르는 이름과 같은 값이 들어 있어야 합니다. 다르면 로그가 옆에 놓일 메트릭을 찾지 못합니다.

  • ES_TIMESTAMP_FIELD (기본 @timestamp)

  • ES_MESSAGE_FIELD (기본 message)

  • ES_SERVICE_FIELD (기본 service.name)

조회 정책

  • ES_ALLOWED_INDEX_PATTERNS (기본값 없음 = API Key가 허용하는 전부). API Key도 범위를 정하지만 키는 한 번 크게 발급되므로, 이 목록은 키를 다시 발급하지 않고 배포 단위로 좁힐 수 있는 경계입니다. *만 와일드카드로 동작하고 .은 문자 그대로 취급합니다.

  • INVESTIGATION_MAX_WINDOW_HOURS (기본 26) — 한 번의 호출이 덮을 수 있는 구간. 보존 기간이 무제한이면 이 값이 유일한 제동 장치입니다. 호스트 한 대가 이미 시간당 약 4천 줄을 씁니다. 26은 하루치 조회에 시간대 차이만큼의 여유를 더한 값입니다.

  • INVESTIGATION_MAX_FETCH_DOCUMENTS (기본 10000) — 답 하나를 만들려고 Elasticsearch에서 끌어오는 문서 수. 응답 크기가 아니라 작업량의 상한입니다.

  • INVESTIGATION_MAX_RETURNED_LINES (기본 100), INVESTIGATION_MAX_MESSAGE_CHARS (기본 600), INVESTIGATION_MAX_SHAPES (기본 25) — 모델이 실제로 값을 치르는 부분.

  • INVESTIGATION_MAX_FUTURE_HOURS (기본 2) — 미래 구간은 아무것도 반환하지 않는데, 그것이 "조용했다"로 읽히면 안 되므로 오류로 처리합니다.

Docker 실행

docker compose up -d --build
docker compose ps
Invoke-RestMethod http://127.0.0.1:3001/healthz

기본 엔드포인트:

  • MCP: http://<host>:3001/mcp

  • 상태 확인: http://<host>:3001/healthz

Authorization: Bearer <ES_MCP_AUTH_TOKEN>

Zabbix Investigation MCP와 같은 머신에 올릴 수 있습니다. compose project 이름과 게시 포트가 다르므로 서로 간섭하지 않습니다 (MCP_PUBLISHED_PORT=3001). 컨테이너 내부 포트는 양쪽 모두 3000입니다.

네트워크 노출 제한

컨테이너 포트가 게시되는 호스트 인터페이스는 MCP_BIND_ADDRESS가 정합니다.

MCP_BIND_ADDRESS=10.0.0.10   # 이 머신의 사설 IP

값을 지정하지 않으면 127.0.0.1로 게시되므로, 설정을 빠뜨려도 공인 인터페이스에 열리지 않습니다.

MCP_HOST와 혼동하지 않아야 합니다. MCP_HOST는 프로세스 자체의 바인드 주소이고 docker compose에서는 컨테이너 내부 기준 0.0.0.0으로 고정됩니다. 호스트 노출을 실제로 통제하는 값은 MCP_BIND_ADDRESS입니다.

Docker는 자신의 forwarding 규칙을 ufw보다 앞에 삽입하므로, 0.0.0.0으로 게시한 포트는 호스트 방화벽으로 막히지 않습니다. 방화벽에 의존하지 말고 바인드 주소를 지정하십시오.

적용 결과는 실행 전에 확인할 수 있습니다.

docker compose config

MCP_ALLOWED_HOSTS는 소스 IP가 아니라 요청의 Host 헤더를 검사합니다. DNS rebinding 방어용이며 네트워크 접근 제어를 대신하지 않습니다.

로컬 개발

요구 사항은 Node.js 20 이상입니다.

npm ci
npm run typecheck
npm test
npm run build
npm run dev

Elasticsearch가 사설망에 있으면 터널을 열고 붙습니다.

ssh -N -L 19200:<elasticsearch-host>:9200 <jump-host>

저장소 구조

.
├── src/
│   ├── log-parse.ts     원문 한 줄에서 레벨·서비스·본문을 읽어내는 곳
│   ├── policies.ts      구간·인덱스·건수 상한
│   ├── es-client.ts     Elasticsearch REST 호출
│   ├── es-service.ts    두 도구의 실제 동작
│   └── register-tools.ts
├── tests/
├── Dockerfile
├── docker-compose.yml
├── package.json
└── .env.example

클라이언트의 ES_MCP_URL은 이 서버의 /mcp 주소를 가리켜야 하며, n8n HTTP Bearer Auth credential에는 동일한 ES_MCP_AUTH_TOKEN을 입력합니다.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    -
    quality
    A
    maintenance
    A read-only MCP server that exposes Quickwit log search and aggregations to LLM clients, enabling natural language log investigation.
    Apache 2.0
  • A
    license
    -
    quality
    D
    maintenance
    Read-only MCP server for exploring and searching OpenSearch clusters, enabling log analysis, index exploration, and query execution.
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    A read-only MCP server that enables AI assistants to search, aggregate, and explore OpenSearch log data through 12 tools for connectivity, index discovery, search, and aggregations.
    17
    MIT

View all related MCP servers

Related MCP Connectors

  • Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.

  • Search your AI chat history (ChatGPT, Claude, Codex) from any MCP client. Remote, private, read-only

  • AI Reasoning Cache & Consensus Layer with 11 MCP tools via Streamable HTTP.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Edrient17/elasticsearch-investigation-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server