openobserve-readonly-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@openobserve-readonly-mcpShow me error logs from the app_logs stream in the last hour"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
openobserve-readonly-mcp
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
POSTis/_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 |
| List streams with type, document count, last event time. Supports substring and type filters. |
| Field names and types for one stream. Use it before writing a query. |
| Run one |
All three are annotated readOnlyHint: true.
Install
Requires Node.js 18.17 or newer.
npx openobserve-readonly-mcpOr install globally:
npm install -g openobserve-readonly-mcpOr from source:
git clone https://github.com/KietDev-JS/openobserve-readonly-mcp.git
cd openobserve-readonly-mcp
npm testConfiguration
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 |
| yes | — | e.g. |
| yes | — |
|
| no |
| OpenObserve organization identifier. |
| no |
| Largest allowed search window, in minutes. |
| no |
| Upstream request timeout. |
| no | — | Log the resolved config (credential redacted) to stderr. |
Generate the Basic value with:
printf 'you@example.com:YOUR_PASSWORD' | base64Client 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 DESCUseful details:
_timestampis microseconds since the epoch. Each returned row also carries an ISO-8601_timefield for readability.The window defaults to the last 15 minutes. Pass
minutes, or an explicitstart/endISO-8601 pair.sizedefaults to 50 and is capped at 200 rows.Keywords inside string literals are fine: searching for the text
'delete'is not mistaken for aDELETEstatement.
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 |
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_DEBUGoutput 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_AUTHthrough your MCP client'senvblock over exporting it into your shell profile.
Development
npm test # 141 tests, no network access required
npm run test:coverage # ~98% line coverageThe suite injects a fake fetch, so it runs fully offline and deterministically.
License
MIT
Available Tools
3 toolso2_list_streamsARead-onlyIdempotent
List OpenObserve streams (read-only) with type, document count and last event time.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Only streams of this type. | |
| limit | No | Max streams to return (default 100). | |
| filter | No | Case-insensitive substring of the stream name. |
TDQS
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.
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.
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.
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.
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.
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_searchARead-onlyIdempotent
Run one read-only SQL SELECT/WITH query against OpenObserve. Quote the stream name: SELECT * FROM "stream" ORDER BY _timestamp DESC. Defaults to the last 15 minutes and returns at most 200 rows. No semicolons or SQL comments outside string literals.
| Name | Required | Description | Default |
|---|---|---|---|
| end | No | ISO-8601 end time (default now). | |
| sql | Yes | One SELECT or WITH statement. | |
| size | No | Rows to return (default 50). | |
| type | No | Stream type (default logs). | |
| start | No | ISO-8601 start time (overrides minutes). | |
| minutes | No | Look back this many minutes from end (default 15). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only, idempotent, and non-destructive behavior. The description goes beyond that by disclosing SQL syntactic restrictions, required stream-name quoting, the default 15-minute lookback, and the 200-row cap. It does not describe error behavior or result shape, but the safety profile is well covered.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences, each earning its place: purpose, syntax example, and key operational constraints. The most important information is front-loaded and there is no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a SQL query tool with complete schema coverage and safety annotations, the description covers everything needed to invoke it correctly: query type, stream quoting, time defaults, row limit, and syntax restrictions. No output schema exists, but the dynamic result shape cannot be meaningfully pre-declared.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds meaningful value with a real SQL example quoting the stream name and by clarifying default time window and row limits that map to the start/minutes/size parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Run one read-only SQL SELECT/WITH query against OpenObserve.' The concrete example and constraints make it unmistakably distinct from sibling tools like o2_list_streams and o2_stream_schema, which focus on metadata rather than query execution.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied by the read-only SQL query purpose and the stated defaults, but the description never explicitly says when to use this tool versus alternatives or when not to use it. No sibling tools are mentioned, so an agent must infer the selection context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
o2_stream_schemaARead-onlyIdempotent
Field names and types of one stream (read-only). Use before writing a query to learn valid column names.
| Name | Required | Description | Default |
|---|---|---|---|
| type | No | Stream type (default logs). | |
| stream | Yes | Exact stream name. |
TDQS
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.
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.
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.
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.
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.
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.
3 tool updates
v1.0.0- First observed
o2_list_streams - First observed
o2_search - First observed
o2_stream_schema
TDQS
Scored across 3 tools
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.
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.
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.
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
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
- mcpOAuthcom.vibgrate
Query your team's drift, vulnerability, and upgrade data from any AI assistant. OAuth 2.1, 51 tools.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables read-only SQL database access for AI assistants, allowing schema exploration and safe query execution without risk of data modification.-
- AlicenseNot gradedqualityBmaintenanceAn 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.5MIT
- AlicenseNot gradedqualityBmaintenanceGives 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
- AlicenseAqualityCmaintenanceEnables 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.6MIT