Skip to main content
Glama
KietDev-JS

openobserve-readonly-mcp

by KietDev-JS

openobserve-readonly-mcp

CI npm Node License: MIT

A read-only MCP server for OpenObserve. It lets an AI assistant list streams, inspect schemas, and run bounded SQL searches over your logs, metrics and traces — without the ability to write anything.

Zero runtime dependencies; it uses only the Node standard library.

Why read-only matters here

Giving a model log search is useful. Giving it an observability API token is a different proposition: the same credential that reads logs can often delete streams, change retention, or edit alerts.

This server narrows that surface in-process:

  • Three endpoints, allowlisted. Every outbound request is matched against an allowlist before it is sent. The only POST is /_search. Anything else — including a request the model constructs itself — is refused locally.

  • SELECT/WITH only. SQL is parsed for structure before it leaves the process: no stacked statements, no comments, no DDL/DML keywords outside string literals.

  • Bounded output. Row counts, string sizes, the time window, and the total response size are all capped, so one careless query cannot flood the context window or the upstream server.

This does not reduce the privileges of the credential you supply. The allowlist constrains this process, not your token. For an actual guarantee, create a read-only OpenObserve user and put that in O2_AUTH. The two layers are complementary: the token bounds what is possible, this server bounds what is attempted.

Related MCP server: OpenObserve MCP Server

Tools

Tool

Purpose

o2_list_streams

List streams with type, document count, last event time. Supports substring and type filters.

o2_stream_schema

Field names and types for one stream. Use it before writing a query.

o2_search

Run one SELECT/WITH query over a bounded time window.

All three are annotated readOnlyHint: true.

Install

Requires Node.js 18.17 or newer.

npx openobserve-readonly-mcp

Or install globally:

npm install -g openobserve-readonly-mcp

Or from source:

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

Configuration

Configuration is environment-only. There is no default host: the server exits with status 2 and an explanatory message rather than guessing where to send your credentials.

Variable

Required

Default

Notes

O2_BASE_URL

yes

e.g. https://openobserve.example.com. A reverse-proxy subpath such as https://host/observe is supported.

O2_AUTH

yes

Basic <base64 of email:password> or Bearer <token>.

O2_ORG

no

default

OpenObserve organization identifier.

O2_MAX_WINDOW_MIN

no

1440

Largest allowed search window, in minutes.

O2_TIMEOUT_MS

no

60000

Upstream request timeout.

O2_DEBUG

no

Log the resolved config (credential redacted) to stderr.

Generate the Basic value with:

printf 'you@example.com:YOUR_PASSWORD' | base64

Client setup

Claude Desktop (claude_desktop_config.json), Claude Code (~/.claude.json):

{
  "mcpServers": {
    "openobserve": {
      "command": "npx",
      "args": ["-y", "openobserve-readonly-mcp"],
      "env": {
        "O2_BASE_URL": "https://openobserve.example.com",
        "O2_AUTH": "Basic BASE64_HERE"
      }
    }
  }
}

opencode (opencode.json):

{
  "mcp": {
    "openobserve": {
      "type": "local",
      "command": ["npx", "-y", "openobserve-readonly-mcp"],
      "enabled": true,
      "environment": {
        "O2_BASE_URL": "https://openobserve.example.com",
        "O2_AUTH": "Basic BASE64_HERE"
      }
    }
  }
}

See docs/SETUP.md for a step-by-step walkthrough, including a connectivity check to run before touching any MCP config.

Querying

Stream names must be double-quoted, and results are ordered by _timestamp descending in practice:

SELECT _timestamp, level, message
FROM "app_logs"
WHERE level = 'ERROR'
ORDER BY _timestamp DESC

Useful details:

  • _timestamp is microseconds since the epoch. Each returned row also carries an ISO-8601 _time field for readability.

  • The window defaults to the last 15 minutes. Pass minutes, or an explicit start/end ISO-8601 pair.

  • size defaults to 50 and is capped at 200 rows.

  • Keywords inside string literals are fine: searching for the text 'delete' is not mistaken for a DELETE statement.

Limits

Limit

Value

Why

Rows per search

200

Keeps a single call from flooding the context window.

Streams per listing

500

Same.

String cell length

500 chars

Clipped at any nesting depth; long stack traces are the usual culprit.

Response size

60 KB

Rows are shed progressively; output is always valid JSON.

Time window

1440 min

Bounds upstream query cost. Raise with O2_MAX_WINDOW_MIN.

When a result is reduced, the response includes a truncated object recording how many rows were returned out of how many matched — the reduction is reported rather than silent.

Security notes

  • The credential is never echoed in error messages or logs; O2_DEBUG output redacts it.

  • Stream names are validated against ^[A-Za-z0-9_][A-Za-z0-9_.-]*$, and any request whose path changes under URL normalization is refused, so traversal attempts cannot escape the allowlisted routes.

  • Prefer passing O2_AUTH through your MCP client's env block over exporting it into your shell profile.

Development

npm test              # 141 tests, no network access required
npm run test:coverage # ~98% line coverage

The suite injects a fake fetch, so it runs fully offline and deterministically.

License

MIT

Available Tools

3 tools
o2_list_streamsA
Read-onlyIdempotent

List OpenObserve streams (read-only) with type, document count and last event time.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoOnly streams of this type.
limitNoMax streams to return (default 100).
filterNoCase-insensitive substring of the stream name.

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the safety profile is covered. The description adds value by specifying the output fields (type, document count, last event time), which is behavioral context beyond what annotations provide. It does not contradict annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that front-loads the primary action (List OpenObserve streams) and follows with key output details. No unnecessary words, and it is immediately scannable.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has no output schema, so the description's mention of the returned fields (type, document count, last event time) is sufficient for an agent to understand what it will receive. Parameter details are fully covered by the schema. It does not mention pagination or defaults beyond the schema, but those are already in the parameter descriptions, making this complete enough for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so all three parameters are well documented in the input schema. The description does not add any additional meaning to the parameters; it only mentions 'type' in the output context, not as a filter. Since the schema covers everything, the description adds no extra semantic value beyond the baseline.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb (list), resource (OpenObserve streams), and specifies that it is read-only and includes type, document count, and last event time. This is specific and distinguishes it from sibling tools like o2_stream_schema (schema retrieval) and o2_search (searching), though it does not explicitly name them.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description conveys a clear use case: listing streams. It does not explicitly compare against alternatives or state when not to use it, but the purpose is unambiguous enough for an agent to infer appropriate usage. It lacks explicit exclusions, but the context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

o2_stream_schemaA
Read-onlyIdempotent

Field names and types of one stream (read-only). Use before writing a query to learn valid column names.

ParametersJSON Schema
NameRequiredDescriptionDefault
typeNoStream type (default logs).
streamYesExact stream name.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, and destructiveHint=false, which cover safety and idempotency. The description adds the contextual behavior of being a pre-query step, which is useful. It does not contradict annotations and adds a small but valuable behavioral nuance about when it should be invoked.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, compact sentence that states the purpose, read-only nature, and usage timing. It is front-loaded with the core function and provides the key usage hint without any fluff. Every word adds value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple schema-retrieval tool with only two parameters, both well-documented in the schema, and annotations covering safety and idempotency, the description is complete. It tells the agent exactly when to use it and what it returns (field names and types), with no output schema needed since the return is self-explanatory.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, meaning both parameters (type and stream) are fully described in the input schema with types, enums, and descriptions. The tool description adds no additional parameter details, so the baseline of 3 is appropriate because the schema carries the full burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns field names and types for a single stream, and explicitly notes it is read-only. It distinguishes itself from siblings by focusing on schema retrieval for one stream, while o2_list_streams lists streams and o2_search searches data. The verb 'learn' and resource 'column names' make the purpose unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives explicit when-to-use guidance: 'Use before writing a query to learn valid column names.' It implies this is a prerequisite step, which is clear and actionable. However, it does not explicitly mention alternatives or when not to use it, though the sibling tools are implicitly differentiated by the tool's specific purpose.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv1.0.0
    • First observedo2_list_streams
    • First observedo2_search
    • First observedo2_stream_schema

TDQS

A4.4/5.0

Scored across 3 tools

Disambiguation5/5

The three tools serve clearly distinct purposes: listing streams, retrieving schema, and running queries. No overlap exists, so an agent can confidently select the right tool.

Naming Consistency4/5

All tools share the 'o2_' prefix, and most follow a verb_noun pattern (list_streams, search). 'stream_schema' is a slight deviation as it's noun_phrase, but it remains predictable and readable.

Tool Count5/5

With only 3 tools, the server is tightly scoped for read-only access to OpenObserve. Each tool is essential and earns its place, making the set easy to navigate.

Completeness5/5

For a read-only server, the surface is complete: discover streams, inspect schemas, and execute queries. These cover the core workflows without missing critical operations.

Related MCP Connectors

Related MCP Servers

  • 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.
    -
  • A
    license
    Not graded
    quality
    B
    maintenance
    An MCP server that enables AI assistants to query and explore your OpenObserve observability data. Provides read-only access to logs, metrics, and traces for analysis and troubleshooting.
    5
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Gives AI agents read-only access to any QuestDB instance, enabling schema discovery, time-series querying, and monitoring of partitions, WAL state, symbols, and ingestion health through MCP.
    Apache 2.0
  • A
    license
    A
    quality
    C
    maintenance
    Enables AI assistants to query Grafana datasources (Prometheus/Loki metrics and SQL databases like ClickHouse/Postgres/MySQL) and search or inspect dashboards through natural language, using read-only access to Grafana's API.
    6
    MIT