Skip to main content
Glama
KietDev-JS

o2-readonly

by KietDev-JS

mcp-openobserve-readonly

A read-only MCP server for OpenObserve. It lets an AI assistant list your log streams, inspect their fields and run SELECT queries against them — and nothing else.

One file, no dependencies, stdio transport. Node 18 or newer.

you ──▶ assistant ──▶ o2-readonly (this server) ──▶ OpenObserve HTTP API
                        │
                        └── only 3 endpoints, SELECT-only SQL, capped rows and time window

Why it exists

Handing an assistant a generic HTTP tool and your OpenObserve credential means it can call any endpoint the credential allows, including ones that change things. This server sits in between and refuses everything except three read paths, so an assistant investigating an incident can explore logs freely without you worrying about what else it might reach.

Related MCP server: safe-sql-mcp

Tools

Tool

What it does

o2_list_streams

Lists streams with type, document count and last event time. Filter by name substring or stream type; up to 500 results.

o2_stream_schema

Field names and types for one stream.

o2_search

Runs a single SELECT / WITH query against a stream.

Name

Default

Notes

sql

required

One SELECT or WITH statement. Quote the stream name: SELECT * FROM "my_stream".

minutes

15

How far back to look from end.

start / end

end = now

ISO-8601. start overrides minutes.

size

50

Rows to return, maximum 200.

type

logs

logs, metrics or traces.

// list the streams whose name contains "api"
{ "name": "o2_list_streams", "arguments": { "filter": "api" } }

// errors in the last hour
{ "name": "o2_search", "arguments": {
    "sql": "SELECT _timestamp, level, message FROM \"my_stream\" WHERE level = 'error' ORDER BY _timestamp DESC",
    "minutes": 60, "size": 100 } }

// a specific window, hours grouped
{ "name": "o2_search", "arguments": {
    "sql": "SELECT histogram(_timestamp, '1 hour') AS hr, count(*) AS n FROM \"my_stream\" GROUP BY hr ORDER BY hr",
    "start": "2026-03-26T00:00:00Z", "end": "2026-03-27T00:00:00Z" } }

What it refuses

Enforced inside the process, whatever the credential is allowed to do:

  • Three endpoints onlyGET /api/{org}/streams, GET /api/{org}/streams/{stream}/schema, POST /api/{org}/_search. The only POST is the search itself. Paths that change under URL normalisation are rejected.

  • SELECT / WITH only — one statement, no semicolons, no SQL comments, unbalanced quotes rejected, and a keyword deny-list (insert, update, delete, drop, alter, create, truncate, grant, revoke, merge, copy, attach, detach, exec, execute) outside string literals. The search API can't write anyway; this is a second line of defence.

  • Caps — 200 rows, 500 characters per cell, 60,000 characters of output, and a time window of O2_MAX_WINDOW_MIN minutes (1440 by default). Oversized results are halved until they fit and marked truncated.

  • Stream names must match [A-Za-z0-9_][A-Za-z0-9_.-]*, and the organisation name [A-Za-z0-9_-]+.

It does not weaken the credential itself. These limits live in this process. If someone runs a different client with the same credential, they get whatever that credential allows. For a real guarantee, put a non-admin, read-only OpenObserve user in O2_AUTH — see SETUP.md.

Configuration

Variable

Default

Meaning

O2_AUTH

Required. Basic <base64 of email:password>. On Windows, falls back to the user-level environment variable read from the registry.

O2_BASE_URL

http://localhost:5080

Your OpenObserve base URL.

O2_ORG

default

Organisation name.

O2_MAX_WINDOW_MIN

1440

Largest allowed query window, in minutes.

Quick start

git clone https://github.com/KietDev-JS/mcp-openobserve-readonly.git
cd mcp-openobserve-readonly

# Claude Code
claude mcp add o2-readonly \
  -e O2_BASE_URL="https://openobserve.example.com" \
  -e O2_AUTH="Basic $(printf 'you@example.com:password' | base64)" \
  -- node "$PWD/server.mjs"

claude mcp list   # expect: o2-readonly … ✔ Connected

Full walkthrough, including Claude Desktop and other MCP clients, credential setup and troubleshooting: SETUP.md.

Notes and limits

  • A query window covers at most 24 hours by default. To look further back, query one day at a time with explicit start and end, or raise O2_MAX_WINDOW_MIN.

  • histogram(_timestamp, '1 hour') is the practical way to see the shape of a log volume over time.

  • Timestamps are microseconds. Results add a readable _time field alongside _timestamp.

  • The server speaks MCP protocol versions 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05, and echoes back whichever the client asks for if it recognises it.

License

MIT.

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    A
    maintenance
    Allows AI assistants to list tables, read data, and execute SQL queries through a controlled interface, making database exploration and analysis safer and more structured.
    3
    3,443 PyPI
    1,394
    MIT
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables read-only SQL database access for AI assistants, allowing schema exploration and safe query execution without risk of data modification.
    -
  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables AI assistants to query SQL databases safely with read-only access, allowing schema discovery and SELECT queries while blocking writes and DDL operations.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables an AI assistant to run guarded, read-only SQL queries against a Postgres database with enforced limits and validation.
    MIT