mcp-db-read-only
Provides read-only SQL access to ClickHouse databases, including schema browsing and running SELECT queries.
Provides read-only search access to Elasticsearch indices, including browsing indices and running Query DSL searches.
Provides read-only SQL access to MariaDB databases, including listing tables, describing schemas, and running read-only queries.
Provides read-only access to MongoDB collections with tools for finding documents, aggregating, counting documents, and retrieving distinct values.
Provides read-only SQL access to MySQL databases, including listing tables, describing schemas, and running read-only queries.
Provides read-only search access to OpenSearch indices, including browsing indices and running Query DSL searches.
Provides read-only SQL access to PostgreSQL databases, including schema browsing and running read-only queries.
Provides read-only access to Redis keys and values, including browsing keys by pattern and running read-only Redis commands.
Provides read-only SQL access to SQLite databases, including table browsing and running read-only queries.
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., "@mcp-db-read-onlyshow me the first 10 rows of the orders table"
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.
mcp-db-read-only
An MCP server that gives an AI assistant read-only access to your databases, whichever kind they are, and lets it switch database, server, credentials and even engine mid-conversation without restarting the client.
Engine | URL scheme | Queried with |
MySQL, MariaDB |
|
|
PostgreSQL (and wire-compatible) |
|
|
SQLite |
|
|
SQL Server, Azure SQL |
|
|
ClickHouse |
|
|
MongoDB |
|
|
Redis (and Valkey, KeyDB) |
|
|
Elasticsearch, OpenSearch |
|
|
The browse tools (list_tables, describe_table, get_table_sample, ...) work on every engine, in that engine's terms: tables, collections, keys or indices.
Runs from npm with npx, or entirely in Docker with nothing installed on your machine.
flowchart LR
A["AI assistant<br/>Claude Desktop / Claude Code"]
B["mcp-db-read-only<br/>one process, whole session"]
C[("PostgreSQL<br/>app")]
D[("MySQL<br/>legacy")]
E[("MongoDB<br/>events")]
F[("Redis<br/>cache")]
G[("anything reached<br/>with connect")]
A <-->|"MCP over stdio"| B
B -.->|"one driver per target"| C
B -.->|"one driver per target"| D
B -.->|"one driver per target"| E
B -.->|"one driver per target"| F
B -.->|"opened at runtime"| GThe server lives for the whole session, so the active connection is just state inside it. Switching selects a different driver rather than reconnecting, and switching back reuses a warm one.
Quick start
npm
DB_URL='postgres://readonly:secret@127.0.0.1:5432/my_database' npx -y @shibbirweb/mcp-db-read-onlyRequires Node 22.13 or newer. There is no container in the way, so 127.0.0.1 means what you expect.
Docker
docker run -i --rm \
--add-host host.docker.internal:host-gateway \
-e DB_URL='postgres://readonly:secret@host.docker.internal:5432/my_database' \
shibbirweb/mcp-db-read-onlyUse host.docker.internal to reach a database on the same machine as Docker. Inside the container, localhost means the container itself.
For SQLite in Docker, mount the file's directory read-only and point at the path inside the container:
docker run -i --rm -v "$PWD/data:/data:ro" -e DB_URL='sqlite:///data/app.db' shibbirweb/mcp-db-read-onlyThe container is the more isolated of the two: the server runs with only what the image and the environment give it. Over npm it runs directly on your machine with your user's access. Both enforce the same read-only guarantees.
Claude Desktop
Add to claude_desktop_config.json:
{
"mcpServers": {
"databases": {
"command": "npx",
"args": ["-y", "@shibbirweb/mcp-db-read-only"],
"env": {
"DB_PROFILES": "{\"app\": \"postgres://readonly@127.0.0.1/app\", \"cache\": \"redis://127.0.0.1:6379/0\"}",
"DB_DEFAULT_PROFILE": "app"
}
}
}
}Or the same server in Docker:
{
"mcpServers": {
"databases": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--add-host", "host.docker.internal:host-gateway",
"-e", "DB_URL=postgres://readonly:secret@host.docker.internal:5432/app",
"shibbirweb/mcp-db-read-only"
]
}
}
}Claude Code
The same shape, in .mcp.json at your project root. Either form above works.
Restart the client once. After that you never need to restart it to change database.
Credentials in these files sit on disk in plain text. Prefer read-only database accounts, and keep the file out of version control. See Security.
Coming from mcp-mysql-read-only
This server reads the old MYSQL_HOST, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_PROFILES and MYSQL_DEFAULT_PROFILE unchanged, so swapping the image or package name is enough. Tool names are the same too; the one change is that connect now takes a URL.
Related MCP server: safe-sql-mcp
Switching connections
Just ask. These map onto the connection tools:
"switch to the staging database" "what collections are in the events database?" "connect to the Redis on 10.0.0.5 and show me the session keys"
Want | Restart? |
Another database on the same server | No |
Another named profile, on any engine | No |
A different server, credentials or engine | No |
A new permanent profile in | Yes, once |
sequenceDiagram
autonumber
actor You
participant A as Assistant
participant S as MCP server
participant P as PostgreSQL
participant M as MongoDB
You->>A: "how many signups yesterday?"
A->>S: run_query(SELECT count(*) ...)
S->>P: read-only transaction
P-->>S: 4821
A-->>You: 4821 signups
You->>A: "and how many of them opened the app?"
A->>S: use_connection(events)
S->>M: connect + ping
Note over S: verified, so the switch is committed
A->>S: count_documents(opens, {...})
S->>M: countDocuments
M-->>S: 3907
A-->>You: 3907 of themA switch that fails verification is never committed, so the previous connection stays active and the session keeps working.
Named profiles
Define several connections up front with DB_PROFILES, a JSON object whose values are URLs, or objects with a separate password:
{
"app": "postgres://readonly@db.internal:5432/app",
"legacy": "mysql://readonly@legacy.internal/shop",
"events": { "url": "mongodb://reader@mongo.internal/events", "password": "p@ss/w#rd" },
"cache": "redis://cache.internal:6379/0",
"logs": "elasticsearch+https://reader@logs.internal:9200",
"reports": "sqlite:///data/reports.db"
}The object form exists because a password inside a URL must be percent-encoded, and one containing @, / or # otherwise splits the URL in the wrong place. A profile that fails to parse is skipped with a warning rather than taking the server down.
Reaching somewhere not in the profiles
The connect tool takes a URL (and optionally a separate password) at runtime and keeps it for the rest of the session under an alias. Nothing is written to disk, and no restart is involved.
URL details
Engine | Notes |
MySQL |
|
PostgreSQL |
|
SQLite |
|
SQL Server | Encrypted by default. |
ClickHouse | The HTTP interface: port 8123, or 8443 with |
MongoDB | Replica sets as |
Redis | The path is the database number: |
Elasticsearch |
|
Tools
Connection
Tool | Purpose |
| Which engine, server and database is active |
| Available profiles and their engines, |
| Databases on the connected server |
| Switch database on the current server |
| Switch to a named profile, optional |
| Open any server from a URL, optional |
Browsing, on every engine
Tool | SQL engines | MongoDB | Redis | Elasticsearch |
| tables and views | collections | keys, by SCAN | indices |
| columns | fields inferred from 100 sampled documents | type, TTL, length | mapping |
| indexes | indexes | n/a | n/a |
| foreign keys (not ClickHouse) | n/a | n/a | n/a |
| up to 50 rows | up to 50 documents | the start of the value | up to 50 hits |
list_tables takes an optional glob pattern, such as user*, which is how you browse a Redis instance with millions of keys.
Querying, per engine family
Tool | Engine | Accepts |
| SQL engines | One read-only statement in the engine's own dialect |
| MongoDB | Filter, projection, sort, limit and skip, as Extended JSON |
| MongoDB | A pipeline, without |
| MongoDB | A filter |
| MongoDB | A field and an optional filter |
| Elasticsearch, OpenSearch | A Query DSL body; |
| Redis | One read-only command and its arguments |
Every tool is advertised all the time, since MCP fixes the tool list at startup while the active engine can change. Calling one against the wrong engine says which tools fit instead.
Every reading tool also accepts an optional database, applied to that call only, leaving the active connection alone.
Configuration
Variable | Default | Purpose |
| none | One connection, registered as the profile |
| none | Password for |
| none | JSON object of named profiles |
| none | Which profile starts active |
|
| Statement timeout, enforced by each server where it can be |
|
| Connection timeout |
| The legacy MySQL-only variables, read unchanged. See above |
None of these are required: with no configuration at all the server still starts, and the tools tell you to call connect.
Starting profile: DB_DEFAULT_PROFILE (or MYSQL_DEFAULT_PROFILE) if it names a real profile, else default, else the first one defined.
Security
Every engine is kept read-only by two independent layers, so a hole in one is not automatically a write. The first layer runs before any connection is used; the second is enforced by the database server itself wherever the engine offers a way, and structurally where it does not.
Engine | Layer one, in this server | Layer two |
MySQL, MariaDB | SQL validator |
|
PostgreSQL | SQL validator, dialect-aware (dollar quotes, | Every statement runs in a |
SQLite | SQL validator | The file is opened read-only by SQLite; extensions disabled |
SQL Server | SQL validator, scanning every statement since T-SQL needs no separators | Every batch runs in a transaction that is always rolled back |
ClickHouse | SQL validator, refusing table functions that reach outside the server | ClickHouse's own |
MongoDB | Operator denylist: | Stage allowlist in the driver, which only ever calls read operations |
Redis | Command allowlist | The server's own |
Elasticsearch | Search body allowlist; index names cannot address an API | The driver can only reach fixed read endpoints |
The SQL validator lexes each dialect exactly as the server will: string literals, quoted identifiers and comments are blanked before any rule looks at the statement, so a keyword or semicolon inside a literal is never mistaken for SQL. Constructs it cannot be certain the server reads the same way, such as nested block comments or MySQL's executable /*! */ comments, are refused rather than guessed at. Only the dialect's read statements may lead (SELECT, WITH, and SHOW, DESCRIBE or EXPLAIN where they exist). Functions that write files, reach other servers or run SQL hidden in a string (INTO OUTFILE, lo_export, dblink, OPENROWSET, ClickHouse's url() and file()) are blocked.
Integration tests prove layer two separately: they send writes straight to each driver, bypassing every validator, and assert the server refused or undid them.
What this is not
This is a guard, not a permission system. It stops an assistant from writing through this server. It does not stop anyone holding the same credentials from writing through any other client.
Point it at read-only accounts. This is the real protection, and on MongoDB and Elasticsearch, whose servers have no read-only session mode, it is the only server-side one:
-- MySQL
CREATE USER 'readonly'@'%' IDENTIFIED BY '...'; GRANT SELECT ON app.* TO 'readonly'@'%';
-- PostgreSQL
CREATE ROLE readonly LOGIN PASSWORD '...'; GRANT pg_read_all_data TO readonly;// MongoDB
db.createUser({ user: "reader", pwd: "...", roles: [{ role: "read", db: "app" }] });# Redis
ACL SETUSER reader on >... ~* +@read -@dangerousOther limits worth knowing:
Results are truncated to 100 rows in the tool output. Add a
LIMIT(or$limit) when reading large tables.A column named exactly like a write keyword must be quoted where the validator scans for them: inside
WITHqueries, and in every SQL Server statement.SQLite queries run in a separate process, so one that exceeds the timeout can be killed outright.
Known behaviour
Parallel tool calls. The active connection is a single piece of process state. If a client issues several tool calls in one batch they are handled concurrently, so a use_database batched alongside a query is not guaranteed to land first. When a read must be pinned to a particular database, pass the per-call database argument instead.
Shutdown. The server exits on SIGINT/SIGTERM, not when stdin closes. Open sockets keep the event loop alive, and stdin reaching EOF only means no further requests were buffered.
Development
Everything runs in Docker, so a clone and Docker are the only requirements:
git clone https://github.com/shibbirweb/mcp-db-read-only.git
cd mcp-db-read-only
./scripts/test-in-docker.sh # every engine
ENGINES="postgres redis" ./scripts/test-in-docker.sh # a subsetThat starts a throwaway container per engine, builds the test image, runs the full suite against them and tears everything down. Your own databases are never touched.
With Node 22.13 or newer installed locally:
npm ci
npm run build
npm run test:unit # no database needed
npm test # integration suites skip any engine they cannot reachThe SQLite and handshake suites need no server and always run. The others read TEST_MYSQL_URL, TEST_POSTGRES_URL, TEST_MSSQL_URL, TEST_CLICKHOUSE_URL, TEST_MONGODB_URL, TEST_REDIS_URL and TEST_ELASTICSEARCH_URL, and create and drop scratch data named mcp_test*, so point them at disposable servers.
Project structure
src/
index.ts Entry point
ApplicationFactory.ts Composition root: the only file that wires things, and the only one naming a driver
types/ Interfaces and type aliases, one file per concern
errors/ Named error classes
domain/ Engine catalog, ConnectionTarget, ConnectionProfile
config/ Reading configuration from the environment
connections/ URL parser, target factory, profile registry, connection manager
drivers/ DatabaseDriver strategy, registry, LRU cache, and sql/ document/ keyvalue/ search/
validation/ sql/ (dialects, skeletonizer, rules), document/, keyvalue/, search/, names/
formatting/ Response, row and JSON rendering
tools/ BaseTool, DatabaseScopedTool, connection/ browse/ sql/ document/ search/ keyvalue/
server/ McpDbServerDeveloper documentation, including why each part is built the way it is, lives in the wiki (source in docs/wiki/).
Contributing
Pull requests target master. CI runs the full suite against every engine, twice (once with MySQL, once with MariaDB), and builds the image for amd64 and arm64. Please keep changes covered by tests, and update docs/wiki/ when behaviour changes.
There is a second copy of this document, README.dockerhub.md, which is published as the Docker Hub description. Docker Hub renders neither mermaid nor relative links, so that copy uses ASCII diagrams and absolute URLs. If you change user-facing behaviour here, change it there too.
Changelog
Release history is in CHANGELOG.md.
Privacy
The server sends nothing anywhere except to the databases you point it at: no telemetry, no analytics, nothing written to disk, nothing kept after it exits. What does leave your machine is whatever your assistant reads, since query results become conversation content. PRIVACY.md sets out both halves.
License
MIT © Md. Shibbir Ahmed
Available Tools
18 toolsaggregateRun Aggregation PipelineARead-onlyIdempotent
Run a read-only MongoDB aggregation pipeline on a collection ($out and $merge are not allowed)
| Name | Required | Description | Default |
|---|---|---|---|
| database | No | Optional database to read from for this call only, without changing the active connection | |
| pipeline | Yes | Pipeline stages as Extended JSON, e.g. [{"$match": {"status": "active"}}, {"$group": {"_id": "$type", "n": {"$sum": 1}}}] | |
| collection | Yes | Collection name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false. The description adds value by explicitly forbidding $out and $merge, which are the two aggregation stages that would violate the read-only contract. This is meaningful behavioral context beyond the annotations. It doesn't mention performance implications or result size limits, but the core safety-relevant behavior 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?
A single sentence that front-loads the core purpose ('read-only MongoDB aggregation pipeline') and immediately states the critical constraint. Every word earns its place; no filler or repetition of schema details.
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 read-only tool with full schema coverage and strong annotations, the description is nearly complete. The main gap is that it doesn't mention what the return value looks like (e.g., array of documents) or any limits on result size, but since there's no output schema and the tool is read-only, these are minor omissions. The $out/$merge exclusion is the most important contextual detail and it's present.
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 schema already documents all three parameters. The description adds the read-only constraint and the $out/$merge exclusion, which helps the agent understand what pipeline stages are acceptable, but it doesn't add parameter-level detail beyond what the schema provides. Baseline 3 is appropriate.
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 states a specific verb ('Run'), a specific resource ('a read-only MongoDB aggregation pipeline on a collection'), and explicitly excludes $out and $merge stages. This clearly distinguishes it from sibling tools like find_documents, run_query, and count_documents.
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 clearly indicates this is for aggregation pipelines, and the read-only constraint plus the $out/$merge exclusion gives implicit guidance on when not to use it. However, it doesn't explicitly name alternative tools for non-aggregation operations or for write operations, so it falls just short of full explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
connectConnect to DatabaseAIdempotent
Connect to a database at runtime with a connection URL (mysql, mariadb, postgres, sqlite, mssql, clickhouse, mongodb, redis, elasticsearch, opensearch). Not persisted to disk, but kept for the rest of the session under an alias
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | Connection URL, e.g. postgres://user@host:5432/db, mongodb://user@host/db, redis://host:6379/0, sqlite:///path/to/file.db. Use host.docker.internal for a database on this machine when running in Docker | |
| alias | No | Name to remember this connection under for use_connection later | |
| password | No | Password, if not in the URL. Avoids percent-encoding special characters |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false, idempotentHint=true, and destructiveHint=false, so the description correctly reflects these (no contradiction). The description adds value by specifying that the connection is session-scoped and not persisted to disk, which is a key behavioral trait beyond the 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 two sentences, front-loading the core purpose and scoping, and then adding a practical note about the alias. Every word earns its place; no fluff.
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?
Given the tool's moderate complexity (3 params, all schema-described, no output schema), the description covers the purpose, usage, and key behavioral nuances. The agent has enough information to invoke it correctly without additional context.
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 coverage is 100%, so the schema already documents all parameters. The description adds context about using the alias with use_connection later, and the password parameter avoids percent-encoding issues, which is not in the schema but is helpful.
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?
States a specific verb ('connect') and a resource ('database'), with a list of supported database types and how the connection is scoped (session-only, under an alias). This clearly distinguishes it from later operations and covers the full scope.
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 clearly sets context: it's a runtime connection that is not persisted, and can be used later via an alias. It doesn't explicitly mention when to prefer this over sibling tools, but given that the siblings are separate actions, a 4 is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
count_documentsCount DocumentsARead-onlyIdempotent
Count documents in a MongoDB collection that match a filter
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No | Query filter as MongoDB Extended JSON, e.g. {"status": "active", "_id": {"$oid": "..."}} | |
| database | No | Optional database to read from for this call only, without changing the active connection | |
| collection | Yes | Collection name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint false, so the safety profile is covered. The description adds the filtering behavior, but it does not mention what the call returns, that an omitted filter counts the whole collection, or any cost/performance caveats. No contradiction with 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?
A single, front-loaded sentence with no filler. Every word contributes to the meaning: what is counted, where, and under what condition.
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 read-only counting operation, the schema covers all parameters and annotations cover side effects. The main gap is that the description does not explicitly state that the result is a numeric count or what happens when filter is omitted, but with no output schema and an obvious count return this is a minor omission.
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%, with each parameter (filter, database, collection) already documented, including a MongoDB Extended JSON example for filter. The description adds no semantic information about parameters that is not already in the schema, so the baseline of 3 applies.
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 uses a specific verb ('Count'), names the exact resource (documents in a MongoDB collection), and adds a filtering condition. This distinguishes it from siblings like find_documents or aggregate, which retrieve or process documents rather than return a count.
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 implies the use case: use this tool when only the number of matching documents is needed. However, it does not explicitly tell the agent when to prefer count_documents over find_documents or aggregate, and it mentions no exclusions or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
current_connectionShow Current ConnectionARead-onlyIdempotent
Show which database server, engine and database the read-only tools are currently pointed at
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only, idempotent, and non-destructive, so the safety profile is covered. The description adds the useful context that the returned state governs the read-only tools, but it does not disclose output shape, failure behavior, or any other operational traits.
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?
A single sentence that front-loads the action and clearly states the scope of the returned information. There is no filler or redundancy.
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 parameterless, read-only introspection tool with rich annotations and no output schema, the description fully tells an agent what to expect: server, engine, and database of the current connection. Nothing else is required to invoke it correctly.
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?
The tool has zero parameters, so the schema leaves nothing undocumented and the description needs no parameter-level detail. Baseline 4 is appropriate for a parameterless tool.
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 uses a specific verb ('Show') with a clear resource: the database server, engine, and database that the read-only tools are currently pointed at. This distinguishes it from sibling tools like list_connections (which lists connections), use_connection, and list_databases, so an agent knows exactly what state it will read.
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 phrase 'currently pointed at' implies this is for inspecting active session context, but it never states when to prefer it over list_connections, list_databases, or use_connection. There is no explicit when-to-use or exclusionary guidance, so the usage context is only inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_tableDescribe TableARead-onlyIdempotent
Show the structure of a table: columns on SQL engines, inferred fields for a MongoDB collection, the mapping of an Elasticsearch index, or the type and TTL of a Redis key
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | Table name (schema.table where the engine has schemas), collection, Redis key, or index | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already disclose a read-only, idempotent, non-destructive operation, and the description adds engine-specific behavioral detail: columns for SQL, inferred fields for MongoDB, mapping for Elasticsearch, and type/TTL for Redis. This goes beyond the structured fields without contradicting them.
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?
A single front-loaded sentence with no filler. The colon-separated list packs four engine-specific behaviors into one compact, readable statement, and every clause earns its place.
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?
With no output schema, the description must explain return values, and it does so for each supported engine. Combined with the schema's parameter descriptions and the safety annotations, it is nearly complete, though it does not state prerequisites such as having an active connection or how errors for missing objects are surfaced.
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 description does not need to add much. It reinforces that the `table` parameter can name a table, collection, index, or key, but it does not add new syntax or format details beyond the schema.
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 uses the verb 'Show' with a specific resource, 'the structure of a table', and enumerates what that means across SQL, MongoDB, Elasticsearch, and Redis. This is not a tautology and clearly identifies a metadata/introspection operation, though it does not explicitly name sibling tools to distinguish itself.
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 no explicit guidance on when to choose this tool over siblings like get_table_sample, get_table_indexes, or list_tables. While the purpose implies schema introspection, there are no when/when-not statements or named alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
distinct_valuesList Distinct ValuesBRead-onlyIdempotent
List the distinct values of a field in a MongoDB collection, optionally within a filter
| Name | Required | Description | Default |
|---|---|---|---|
| field | Yes | Field path, e.g. status or address.city | |
| filter | No | Query filter as MongoDB Extended JSON, e.g. {"status": "active", "_id": {"$oid": "..."}} | |
| database | No | Optional database to read from for this call only, without changing the active connection | |
| collection | Yes | Collection name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds no additional behavioral context such as limits, ordering, missing-field behavior, or return shape, and it does not contradict the 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 front-loaded sentence with minimal waste. It is concise, though 'optionally within a filter' is slightly awkward and the description adds little beyond the title and schema details.
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 read-only operation, the required collection and field plus optional filter and database are documented, and annotations cover safety. The main gap is the lack of output format or edge-case behavior, especially since there is no output schema.
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 parameters including field path format and Extended JSON filter syntax are already documented. The description mainly restates field and filter concepts and adds no new parameter-level meaning beyond what the schema provides.
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 uses a specific verb ('List') and a precise object: distinct values of a field in a MongoDB collection, optionally filtered. It is clear and easily distinguished from siblings like find_documents or count_documents, though it does not explicitly name those alternatives.
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?
There is no guidance about when to use this tool versus find_documents, aggregate, count_documents, or search. The only hint is the semantic meaning of 'distinct values,' which implies a use case but provides no exclusions, prerequisites, or alternative routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_documentsFind DocumentsBRead-onlyIdempotent
Find documents in a MongoDB collection with a filter, optional projection and sort
| Name | Required | Description | Default |
|---|---|---|---|
| skip | No | Documents to skip, for paging | |
| sort | No | Sort order, e.g. {"createdAt": -1} | |
| limit | No | Maximum documents to return (1-100, default 20) | |
| filter | No | Query filter as MongoDB Extended JSON, e.g. {"status": "active", "_id": {"$oid": "..."}} | |
| database | No | Optional database to read from for this call only, without changing the active connection | |
| collection | Yes | Collection name | |
| projection | No | Fields to include or exclude, e.g. {"name": 1, "_id": 0} |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is clear and the description does not contradict it. The description adds no behavioral context beyond the schema's filter/projection/sort fields, such as defaults, paging behavior, or output shape, but with strong annotations that gap is acceptable.
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?
One compact sentence front-loads the verb and target resource, then lists the major options. There is no filler or repetition, and the size is appropriate for the tool's simplicity.
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?
With seven parameters fully documented in the schema, the description only needs to orient the agent, and it names the three core query features. It does not state the return shape explicitly, but the absence of an output schema is mitigated by the action literally being 'find documents.'
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% and each parameter already has a clear description and example (filter as Extended JSON, sort/projection syntax, limit/skip paging). The tool description only restates filter/projection/sort without adding new parameter semantics, so it lands at 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?
States a specific action ('Find documents') on a MongoDB collection and names the main query capabilities (filter, projection, sort), so the core purpose is unambiguous. It does not explicitly contrast with sibling aggregation/counting/search tools, but the verb and resource are specific enough to identify the intended operation.
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 says what the tool does but gives no guidance about when to choose find_documents over aggregate, count_documents, distinct_values, or search. There are no use-case conditions, exclusions, or alternative routing, so an agent must infer appropriateness from the name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_foreign_keysGet Foreign KeysARead-onlyIdempotent
Show foreign key relationships for a table on MySQL, PostgreSQL, SQLite or SQL Server
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | Table name | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds the cross-database scope and indicates the output is relationship information, but does not mention return shape, ordering, or behavior for missing tables—acceptable but not rich.
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?
A single, front-loaded sentence that states the action, target, and scope without wasted words. It is efficiently structured and easy to parse.
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 read-only tool with strong annotations and a fully documented schema, the description is largely sufficient. It could be slightly more complete by noting that a connection must be active or that a database must be selected when not using the optional parameter, but these are minor omissions.
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 schema already documents both 'table' and 'database' parameters fully. The description adds no meaning beyond the schema, leaving the baseline of 3 appropriate.
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 states a specific verb ('Show'), a clear resource ('foreign key relationships for a table'), and distinguishes itself from siblings like describe_table or get_table_indexes by naming the exact relationship type. It also scopes supported databases, fully clarifying what the tool does.
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 clearly implies this is the right tool when an agent needs foreign key relationships for a table across four major databases. It does not explicitly name alternatives or exclusion criteria, but the sibling context and the focused wording provide sufficient usage context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_table_indexesGet Table IndexesARead-onlyIdempotent
Show indexes on a table or MongoDB collection, or the sorting key and skipping indices of a ClickHouse table
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | Table or collection name | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds valuable behavioral nuance by disclosing that ClickHouse tables return sorting key and skipping indices rather than conventional indexes. This is context beyond the structured metadata.
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 entire description is one sentence that states the core behavior first, then adds the ClickHouse variation. There is no redundant phrasing or 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 simple read-only introspection tool with rich annotations, the description provides enough information to call it correctly: it names the required resource and the subtle ClickHouse behavior. It does not describe the exact return shape, but no output schema is promised and the operation is low-risk.
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%, with both 'table' and 'database' already documented in the input schema. The description does not add parameter-level detail, so the baseline of 3 applies.
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 uses a specific verb ('Show') and resource ('indexes on a table or MongoDB collection'), and further clarifies the ClickHouse-specific behavior ('sorting key and skipping indices'). This clearly differentiates it from related introspection tools like get_foreign_keys or describe_table.
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 clearly implies when to use it: when you need index information for a table, collection, or ClickHouse table. It does not explicitly name alternatives or exclusions, but the operation and resource scope are clear enough for an agent to select it without confusion.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_table_sampleGet Table SampleARead-onlyIdempotent
Get sample rows from a table, documents from a collection, hits from an index, or the first entries of a Redis key
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Number of rows to return (1-50, default 5) | |
| table | Yes | Table, collection, index, or Redis key | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the description has less burden. It adds useful scope context by covering four resource types and notes Redis returns 'first entries,' but it does not clarify whether table samples are random or deterministic or describe the return shape.
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, front-loaded sentence with no filler. It efficiently communicates the core action and all supported resource types in a scannable way.
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 read-only sampler with strong annotations and fully documented parameters, the basics are covered. However, with no output schema and no usage guidance, the description leaves the agent to infer return format and when sampling is preferable to search/find_documents.
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 schema already documents all three parameters. The description only restates the table parameter's permitted resource types and adds nothing meaningful about limit or database behavior beyond what the schema provides.
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 states a specific action ('Get sample rows') and enumerates the exact resource types it applies to: tables, collections, indexes, and Redis keys. The 'sample' qualifier distinguishes it from siblings like run_query, find_documents, and search, even without naming 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 phrase 'sample rows' implies a lightweight data-peeking use case, but there is no explicit statement of when to use this tool instead of alternatives like find_documents, search, or redis_command. Usage context is inferred rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_connectionsList Connection ProfilesARead-onlyIdempotent
List the connection profiles available to switch to, with each one's engine, including any added during this session
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior. The description adds genuinely useful dynamic context: 'including any added during this session,' which is not captured by annotations. No contradiction exists.
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?
A single, tightly worded sentence that front-loads the action and resource, then adds the relevant session-created detail. No filler or repetition.
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 zero-parameter, read-only list tool with no output schema, the description covers what is listed (connection profiles), the distinguishing field (engine), and an important edge case (session-added profiles). No missing information needed to call it correctly.
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?
The tool has zero parameters, so the baseline is 4. The description adds no parameter-specific meaning because there are none to describe, and the schema already indicates an empty parameter set.
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 uses a specific verb ('List') and resource ('connection profiles'), and clarifies scope ('available to switch to') and content ('with each one's engine'). This clearly distinguishes it from siblings like list_databases and current_connection.
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 phrase 'available to switch to' provides clear context that this tool is meant for viewing profiles before using use_connection or connect. It does not explicitly name alternatives or exclusion criteria, but the purpose is unambiguous enough that an agent would not confuse it with list_databases or run_query.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_databasesList DatabasesARead-onlyIdempotent
List databases on the currently connected server (schemas on MySQL, numbered databases on Redis)
| Name | Required | Description | Default |
|---|---|---|---|
| include_system | No | Include system databases such as information_schema, pg templates, or MongoDB admin and local |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, openWorldHint, and destructiveHint=false, so the description doesn't need to repeat those. It adds useful behavioral context by noting state dependence on the current connection and platform-specific naming conventions, which helps an agent interpret results correctly.
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 front-loaded sentence with a parenthetical qualifier that adds important nuance without clutter. Every word earns its place, and there is no redundant restatement of the title or annotations.
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 read-only list tool with one optional, fully documented parameter and rich safety annotations, the description is complete. It identifies the target, the connection context, and the cross-engine behavior; the return shape is implicit from the verb 'List' and the tool type.
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%, and the include_system parameter already has a thorough description in the schema. The tool description doesn't discuss the parameter, but that's acceptable because the schema carries the semantic weight; baseline 3 applies.
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 uses a specific verb ('List') and resource ('databases on the currently connected server'), and adds important cross-engine clarification ('schemas on MySQL, numbered databases on Redis'). This clearly distinguishes it from sibling tools like list_connections and list_tables.
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 phrase 'currently connected server' gives clear context: this is meant to be used after establishing a connection to inspect available databases. It doesn't explicitly name alternatives or exclusions, but the target resource is distinct enough from sibling tools that an agent can select it correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_tablesList TablesARead-onlyIdempotent
List the tables in the active database: collections on MongoDB, keys on Redis, indices on Elasticsearch
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | No | Optional glob filter, * for any characters and ? for one, e.g. user* or logs-2026-* | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, open-world, and non-destructive behavior, so the safety profile is covered. The description adds valuable context by explaining that 'tables' maps to different entities depending on the backend (collections, keys, indices) and that listing happens in the active database, which helps an agent form correct expectations across stores.
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?
A single front-loaded sentence conveys the action, resource, and backend-specific terminology with no filler. Every part of the description contributes meaning.
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, read-only, zero-required-parameter listing tool, the description together with the schema and annotations covers purpose, scope, and per-call overrides. It does not explicitly describe the output shape or behavior when no active database exists, but the phrase 'list the tables' plus the absence of an output schema makes the expected result reasonably inferable.
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%, and the schema already explains pattern as a glob filter and database as a per-call override. The description adds no parameter-level details, so it does not need to compensate; the baseline score of 3 is appropriate.
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 states a specific action and resource: 'List the tables in the active database,' then clarifies the cross-store meaning of 'table' as collections (MongoDB), keys (Redis), and indices (Elasticsearch). This makes the tool's purpose unmistakable and distinguishes it from list_databases or list_connections without requiring agents to open those tools.
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 the scope ('active database') and implies an exploratory listing use case, but it does not state when to prefer this tool over siblings such as describe_table, get_table_indexes, or list_databases, nor when not to use it. The usage context is implied by the name rather than explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
redis_commandRun Read-Only Redis CommandARead-onlyIdempotent
Run one read-only Redis command such as GET, HGETALL, LRANGE, ZRANGE, SCAN, TTL or INFO. Write commands and KEYS are refused
| Name | Required | Description | Default |
|---|---|---|---|
| args | No | Arguments, e.g. ["user:42"] | |
| command | Yes | Command name, e.g. HGETALL | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior, and the description reinforces this while adding a useful guardrail: write commands and KEYS are refused. It does not discuss return/error behavior in detail, but for a read-only command runner the safety-relevant behavior is disclosed.
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?
Two tight sentences: the core action is front-loaded, followed by concrete examples and a crisp exclusion. There is no filler, redundancy, or unnecessary restatement.
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 generic Redis command runner, the allowed-command examples and refusal rule give enough context to select and invoke it correctly, and the schema covers all parameters. It would be slightly stronger with a note about raw return shape or command errors, but the definition is still sufficient without it.
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 command, args, and database are already documented structurally. The description's command examples help set expectations, but it adds little parameter-level meaning beyond what the schema already provides.
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 action and resource: 'Run one read-only Redis command', and lists representative commands like GET, HGETALL, LRANGE, and SCAN. It is immediately distinct from the sibling SQL/query tools, and the refusal of write commands and KEYS further pins down its scope.
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?
It clearly states when to use the tool: for read-only Redis commands. It also explicitly gives a when-not signal by refusing write commands and KEYS. It does not name alternative tools for those cases, so it falls just short of full 5-level guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
run_queryRun Read-Only SQL QueryARead-onlyIdempotent
Execute a read-only SQL query (SELECT, WITH, and the engine's SHOW, DESCRIBE or EXPLAIN) on a MySQL, MariaDB, PostgreSQL, SQLite, SQL Server or ClickHouse connection
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | SQL query to execute, in the active engine's dialect | |
| database | No | Optional database to read from for this call only, without changing the active connection |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and non-destructive behavior. The description adds value beyond annotations by specifying exactly which SQL statement types are allowed and which DB engines are supported, giving the agent a concrete behavioral contract for what the tool accepts. No contradictions found.
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?
One tightly packed sentence with no wasted words. The primary action and scope are front-loaded, followed by allowed statements and engine list. Every phrase earns its place.
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?
With only two parameters, high schema coverage, and annotations covering the safety profile, the description is largely complete. It explains what statements are executed and on which engines. Minor omissions like result format, row limits, or single-statement constraints would be useful but are not critical for a read-only query tool, especially with no output schema defined.
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?
Input schema provides 100% coverage with descriptions for both 'query' and 'database', so the description needs no param-level detail. It adds general context about statement types and engines, which is useful but not required beyond the schema. Baseline 3 is appropriate.
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?
States a specific verb ('Execute'), a resource ('read-only SQL query'), enumerates allowed statement types (SELECT, WITH, SHOW, DESCRIBE, EXPLAIN), and lists supported engines. This clearly distinguishes it from sibling data-exploration tools, none of which execute arbitrary SQL.
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 makes the tool's scope explicit (read-only SQL across listed engines), which implies when to use it: when arbitrary SQL querying is needed over a managed connection. It does not explicitly name alternatives or exclusions, but the read-only constraint and statement list effectively rule out write operations and non-SQL tools like redis_command.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchSearch IndexARead-onlyIdempotent
Search an Elasticsearch or OpenSearch index with a Query DSL body. Use size 0 with track_total_hits true to count, and aggs for aggregations
| Name | Required | Description | Default |
|---|---|---|---|
| body | No | Search body, e.g. {"query": {"match": {"title": "error"}}, "size": 10, "sort": [{"@timestamp": "desc"}]} | |
| index | Yes | Index name, pattern such as logs-*, or comma-separated list |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the description doesn't need to repeat those. It adds useful context about how to perform count and aggregation operations via the body parameter, which is beyond the schema. However, it doesn't disclose potential errors (e.g., invalid DSL) or pagination behavior, but with annotations covering safety, a 3 is appropriate.
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?
Two sentences, front-loaded with the purpose, then concise usage tips. Every word earns its place; no fluff.
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?
Given the tool's complexity (query DSL), the schema fully documents parameters, and annotations cover safety. The description adds critical usage patterns for counting and aggregation that an agent might not infer. Output schema is absent, but return format is likely clear from Elasticsearch conventions. It's nearly complete, missing only error-handling notes.
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 coverage is 100%, and both parameters have descriptions in the schema. The description adds usage tips for the body parameter (size 0, track_total_hits, aggs), which is valuable but not directly explaining the parameters' semantics beyond what the schema says. So baseline 3 is correct, with a slight addition of context.
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?
Description states the verb 'Search' and the resource 'Elasticsearch or OpenSearch index' clearly, with a focus on Query DSL body. It distinguishes from sibling tools by being the generic search tool, though it doesn't explicitly name alternatives for filtering or aggregations (though it mentions aggs). It's clear but could be more specific about what makes it unique among siblings.
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?
Provides clear guidance on when to use size 0 with track_total_hits for counting and aggs for aggregations, which are specific use cases. However, it doesn't explicitly say when not to use this tool versus siblings like find_documents or aggregate, but the 'use aggs for aggregations' implies that for aggregation-specific tasks you might use aggregate instead, so it's implicit but not fully explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
use_connectionSwitch Connection ProfileAIdempotent
Switch to a named connection profile, on any engine. Takes effect immediately, no restart needed
| Name | Required | Description | Default |
|---|---|---|---|
| profile | Yes | Profile name from list_connections | |
| database | No | Optional database to use instead of the profile's own database |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as non-read-only, idempotent, and non-destructive. The description adds useful behavioral context beyond those: the switch takes effect immediately and requires no restart. This is meaningful operational information not present in the schema or 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 extremely compact and front-loaded: it states the action, then the scope, then the key behavioral caveat. Every word earns its place and there is no redundant 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 simple state-switch with one required parameter, the combination of description, schema, and annotations is complete: the source of valid profile names is given, the optional database behavior is documented, and the immediate effect is stated. No output schema exists, so return-value expectations are not a gap.
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%, and both parameters are already clearly documented: profile is a name from list_connections, and database is an optional override. The free-text description adds no additional parameter-level detail, so the baseline 3 is appropriate.
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 uses a specific action-object pair ('Switch to a named connection profile') and adds engine-agnostic scope with 'on any engine.' This clearly distinguishes it from sibling tools like use_database, connect, and the list/current connection tools.
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?
It gives clear context for when the tool is relevant—switching an existing profile—and the 'no restart needed' note gives one practical selection criterion. However, it never explicitly mentions alternatives or says when not to use it, so the guidance is implied rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
use_databaseSwitch DatabaseAIdempotent
Switch the active database on the current server. Takes effect immediately, no restart needed
| Name | Required | Description | Default |
|---|---|---|---|
| database | Yes | Database name to switch to, or the database number on Redis |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as non-read-only, non-destructive, and idempotent. The description adds meaningful behavioral context—'Takes effect immediately, no restart needed'—telling the agent the operation has immediate runtime impact without a server restart. It also clarifies the scope to the current server. No contradiction with 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?
Two short sentences with zero waste: the first states the core action and scope, the second adds a relevant behavioral note. The information is front-loaded and every sentence earns its place.
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 single-parameter utility with annotations covering idempotence and non-destructiveness, the description plus schema give an agent enough to call it correctly. It could mention error behavior or that the switch affects subsequent operations, but 'active database' is sufficiently clear. The minor gap keeps it at 4.
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?
The input schema provides 100% coverage of the single parameter, including the Redis variant ('or the database number on Redis'). The tool description adds no additional parameter-level detail, so the schema carries the semantic weight; the baseline 3 applies.
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 states a precise action: 'Switch the active database on the current server.' It clearly identifies the verb and resource, and 'on the current server' distinguishes it from connection-level operations like use_connection. However, it doesn't explicitly name or contrast with any sibling tool, so it falls just short of a 5.
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 implied usage context: it targets a database on the current server, which hints at when to use this versus use_connection or connect. It offers no explicit when-to-use/when-not-to-use guidance or named alternatives, but the 'current server' scoping and 'takes effect immediately' provide some directional context.
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.
18 tool updates
v0.1.0- First observed
aggregate - First observed
connect - First observed
count_documents - First observed
current_connection - First observed
describe_table - First observed
distinct_values - First observed
find_documents - First observed
get_foreign_keys - First observed
get_table_indexes - First observed
get_table_sample - First observed
list_connections - First observed
list_databases - First observed
list_tables - First observed
redis_command - First observed
run_query - First observed
search - First observed
use_connection - First observed
use_database
TDQS
Scored across 18 tools
Most tools target clearly distinct resources and actions, and engine-specific operations (run_query, find_documents, search, redis_command) are easy to tell apart. The only mild ambiguity is among context-switching tools like use_database, use_connection, and connect, though their descriptions clarify the differences.
Many tools follow a list_/get_/use_ verb_noun pattern, but standalone verbs like connect, aggregate, and search, plus noun-only names like distinct_values and redis_command, break the convention. The names are still readable and all snake_case, but the style is not uniform.
At 18 tools, this is slightly over the typical sweet spot, but the broad multi-engine scope (SQL, MongoDB, Elasticsearch, Redis) justifies the count. Each tool covers a distinct operation or engine, and none feel redundant.
The toolset covers the read-only database workflow end-to-end: connection selection, database/table discovery, schema inspection, sample data, and engine-specific query/aggregation/search/read operations. There are no obvious missing capabilities for a read-only toolset.
Maintenance
Related MCP Connectors
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
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.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceProvides AI assistants with read-only access to inspect database schemas, preview data, and run safe queries across PostgreSQL, MySQL, MongoDB, and SQL Server. It enables AI tools to understand database structures and relationships automatically to generate more accurate code.2 npm7MIT
- FlicenseNot gradedqualityDmaintenanceEnables read-only SQL database access for AI assistants, allowing schema exploration and safe query execution without risk of data modification.-
- FlicenseNot gradedqualityDmaintenanceEnables AI assistants to query SQL databases safely with read-only access, allowing schema discovery and SELECT queries while blocking writes and DDL operations.-
- AlicenseNot gradedqualityBmaintenanceEnables AI assistants to safely query and explore SQL Server and PostgreSQL databases with read-only access, supporting schema discovery, relationship exploration, and query execution.8 npm3MIT