sqlscope-mcp
Provides read-only exploration and analysis of SQLite database files, including schema overviews, table descriptions, foreign-key graphing, safe SELECT queries, query-plan explanations, data-quality checks, full-database search, and generated schema documentation.
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., "@sqlscope-mcpCan you show me the schema and foreign-key relationships in ./shop.db?"
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.
sqlscope-mcp
Let your AI agent explore and understand an SQLite database file, without any way to change it.
sqlscope-mcp is an MCP server for SQLite files. Point it at
an app's .db, a browser profile, a game save or a data export, and the agent can see what is
in there, how the tables relate, whether the data is healthy and why a query is slow.
How it differs from other SQLite MCP servers. Several good read-only SQLite servers exist (mcp-sqlite-insights, sqlite-explorer-fastmcp, mcp-sqlite-explorer, mcp-sql-explorer); going by their READMEs they cover schema listing, sampling, a read-only query and some of them plan output. This one is built around two things they do not advertise:
Read-only is a tested property, not a promise. Five layers (read-only URI,
query_only, an authorizer allow-list, a deadline, a value-size limit) and an attack suite that fires 53 hostile statements and checks the file hash and the folder listing are unchanged afterwards. That includes WAL-mode databases, where a naive read-only open silently creates-waland-shmfiles next to your database.Insight tools, not just a query box. A foreign-key graph that finds unindexed FK columns and orphan rows,
typeof()distributions that expose SQLite's dynamic typing, dangling references withforeign_keysoff, inconsistent date formats, whole-database search, plan findings with index suggestions, and generated markdown docs.
Only the Python standard library's sqlite3 and the mcp SDK are used. No native dependencies.
What it looks like
Real output from a stdio session against a small shop database:
> schema_graph
Foreign keys (3), child -> parent:
order_items (sku) -> products(sku)
order_items (order_id) -> orders(id)
orders (customer_id) -> customers(id) [ON DELETE CASCADE]
Missing indexes on foreign-key columns:
orders(customer_id) has no index. Suggestion: CREATE INDEX "idx_orders_customer_id" ON "orders" ("customer_id");
Orphan check (child rows whose parent is missing; independent of PRAGMA foreign_keys):
orders(customer_id) -> customers: 2 of 302 non-null values have no parent (0.7%); e.g. 99999; 88888
order_items(sku) -> products: 1 of 4 non-null values have no parent (25.0%); e.g. ZZZ
> data_quality table=customers
[WARN] notes: 99% NULL (198 of 200)
[WARN] email looks like a key but is not unique: 1 value(s) repeat (1 extra rows), e.g. 'user5@example.com' x2
[WARN] email: 2 value(s) collide after lower() and trim() (2 extra rows; 1 are exact duplicates)
[WARN] created: date-looking text is inconsistent: 4 different formats: '9999-99-99' x197, '99.99.9999' x1, '99/99/9999' x1, ...
> explain_query "SELECT * FROM orders WHERE customer_id = 5"
Query plan:
- SCAN orders
Findings:
* FULL TABLE SCAN of orders (302 rows): every row is read.
Index suggestions (text only, nothing was created):
* orders is scanned and the query filters on customer_id: CREATE INDEX "idx_orders_customer_id" ON "orders" ("customer_id");
> query "DROP TABLE orders"
Error: Only SELECT / WITH / VALUES queries are allowed (got DROP). This server is read-only by construction.Related MCP server: sql-guard-mcp
Install
You need uv and Python 3.11 or newer.
Claude Code
claude mcp add sqlscope -- uvx sqlscope-mcp --dir "C:\Users\me\databases"Claude Desktop (claude_desktop_config.json)
{
"mcpServers": {
"sqlscope": {
"command": "uvx",
"args": ["sqlscope-mcp", "--dir", "C:\\Users\\me\\databases"]
}
}
}Or with pip: pip install sqlscope-mcp, then run sqlscope-mcp --dir PATH.
--dir is optional but recommended: with it, every tool refuses paths outside that folder
(.., absolute paths and symlinks are resolved first) and relative paths are taken inside it.
Without it, any file the server process can read may be opened.
Tools
Every tool takes path, the database file.
Tool | What it does |
| File size, page size, encoding, journal mode, |
| Columns with type, NOT NULL, default, PK and generated flags; NULL %, distinct, min, max and |
| Foreign-key graph as text or mermaid, load order, cycles, FK columns with no index (with |
| One |
|
|
| Find a string or number in any non-BLOB column of any table, with a match cap and a time budget per table. |
| NULL-heavy and always-NULL columns, NULL vs |
| Markdown documentation of the whole schema as text, with a mermaid ER diagram. Nothing is written to disk. |
Handled on purpose: BLOBs are shown as <BLOB n bytes 0x...> and never dumped; very long text is
cut with its length; FTS5 and other virtual tables are listed and queryable but not scanned;
WITHOUT ROWID, STRICT and generated columns; Turkish, quoted and otherwise odd identifiers;
UTF-16 databases; invalid UTF-8 in text; and WAL databases (a pending -wal is read, nothing is
written or checkpointed).
Files that are not usable produce a specific message instead of a stack trace: zero bytes, not SQLite, probably encrypted (SQLCipher), truncated header, corrupt pages, and a hot rollback journal left by a crashed writer.
Try asking
"Give me an overview of
app.db. What are the biggest tables?""Describe the
orderstable and show me a few rows.""How do the tables in this database relate? Draw it as a mermaid diagram."
"Which foreign keys have no index? Are there any orphan rows?"
"Is there anything wrong with the data in this database?"
"Where does the email
ada@example.comappear in this database?""Why is this query slow?" (it will use
explain_query)"Write schema documentation for this database that I can paste into a README."
Security
What is enforced, and by what:
Threat | Defence |
Any write: | Connection opened with |
| Denied by the authorizer; the attach limit is also set to 0. |
| Denied by the authorizer. The statement gate also rejects it. |
| Denied: only a short list of read-only pragmas is allowed, and only in read form. |
Temp tables, views, triggers |
|
| Denied by function name; extension loading is also never enabled. |
Stacked statements ( | One statement per call; the |
Creating | A WAL file with no pending WAL is opened |
Runaway queries ( | A progress handler interrupts after |
Memory bombs ( |
|
Flooding the model's context | Row cap (default 200, max 5000), about 200 KB output cap, 200-character cell cap, BLOBs never dumped. |
Opening files outside a folder |
|
The attack suite in tests/test_readonly.py runs these against real databases and compares a
SHA-256 of every file in the folder before and after.
What it does not do:
Read-only does not mean private. A database can contain secrets, and every row a tool returns becomes part of your conversation with the model. Do not point it at a file you would not paste.
-shm(the WAL index) can be touched by SQLite itself when a database has a pending WAL that another process is using; the database file and the-walare never modified. The tests compare those two, not-shm.It uses the SQLite library bundled with your Python, so features newer than that library are unavailable.
Encrypted databases are not supported; they are detected and reported.
A single value larger than 64 MiB cannot be read.
Without
--dirthe server can open any file the process can read (it still only reads).
Development
uv sync --extra test
uv run ruff check src tests && uv run mypy --strict src
uv run pytest testsTests build real databases with sqlite3: a shop schema with seeded problems, WAL databases (with
and without a live writer), FTS5 (skipped if the build lacks it), a database with a hot journal,
broken and encrypted-looking files, a 1,000,000-row table for the cap and time checks, the attack
suite, and a stdio test that launches the installed server and talks MCP to it.
Want to know how it works? sqlscope-mcp-the-hard-way builds a minimal version step by step.
License
MIT
Available Tools
8 toolsdata_qualityARead-onlyIdempotent
Look for data problems, using SQL over a sample of each table: columns that are mostly or always NULL (and NULL versus empty-string mixes); columns holding mixed storage types (SQLite does not enforce column types; the typeof() distribution is reported, with examples); key-like columns (id, email, uuid, ...) that contain duplicates, case/space-only duplicates, and rows identical in every non-key column; dangling foreign keys even though SQLite does not enforce them by default; and date-looking text columns whose formats are inconsistent.
table: check just this table (default: all ordinary tables). sample: rows to examine per table (100-200000).
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| table | No | ||
| sample | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/non-destructive, and the description adds real substance beyond them: it discloses that work is done via SQL over a sample rather than a full scan, that SQLite does not enforce types or foreign keys (explaining why these checks matter), and that examples accompany the typeof() distribution. It stops short of stating runtime cost or how sampling affects confidence in the results.
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 core sentence is long but front-loaded and each clause names a distinct check, so nothing is wasted. The parameter notes are compactly formatted as a trailing list, keeping the actionable content first.
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?
An output schema exists, so return-value explanation is unnecessary, and the description covers what is inspected and how scope is narrowed. The remaining omissions are the meaning of 'path' and any indication of cost or result reliability under sampling, which matter for a tool that scans many tables.
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 0%, so the description carries the burden. It does add value for two of three parameters: 'table' semantics (single table vs default all ordinary tables) and 'sample' as rows examined per table with a 100-200000 range not present in the schema. The required 'path' parameter is completely unexplained, which is a notable gap given zero schema coverage.
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 ('look for data problems') and then enumerates the exact audit classes: NULL-heavy columns, mixed storage types via typeof(), key duplication, dangling foreign keys, inconsistent date formats. This is unmistakably a data-quality auditing tool and cannot be confused with siblings like query, describe_table, or find_in_db.
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 enumeration of checks, and the 'table' note establishes the default scope (all ordinary tables). However, it never says when to prefer this over running an ad-hoc query or describe_table, nor any preconditions (e.g., cost on large databases, when sampling is insufficient).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
db_overviewARead-onlyIdempotent
Start here. Summarise an SQLite database file: size, page size, text encoding, journal mode (WAL or not), user_version, counts of tables / views / indexes / triggers, and a row count for every table (from ANALYZE statistics when present, otherwise an exact count that stops at 100,000). Virtual tables (FTS5, rtree) are listed with their module and their internal shadow tables are folded away. Opening is read-only and never modifies the file or creates -wal / -shm files.
path: the .db / .sqlite file (relative paths are resolved inside the --dir folder, if one was set).
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint, but the description goes further by stating the concrete consequence: opening never modifies the file and never creates -wal/-shm side files. It also discloses the row-count strategy (ANALYZE statistics first, otherwise an exact count capped at 100,000) and that virtual-table shadow tables are folded away, which materially changes how an agent should interpret the counts.
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?
Front-loaded with the routing cue, then a dense but purposeful enumeration of reported fields, then a separate labelled clause for the path parameter. Every sentence carries information an agent needs; nothing is repeated from the name or schema.
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?
An output schema exists, so return values need not be described, and the description instead covers what the agent must know to call and interpret it: read-only side-effect guarantees, the 100,000 row-count cap, ANALYZE-based estimates, and virtual/shadow table handling. For a one-parameter inspection tool this is fully sufficient.
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 0% and the single parameter has no schema description, so the description must carry it — and it does, explaining that path is the .db/.sqlite file and that relative paths resolve inside the --dir folder when one was set. That resolution rule is meaning an agent could not get from the bare 'string' type; only accepted extensions are covered, not other path edge cases.
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 an explicit orientation cue ('Start here') and then names a specific verb and resource ('Summarise an SQLite database file'), followed by an enumeration of exactly what is reported (size, page size, encoding, journal mode, user_version, object counts, per-table row counts, virtual tables). An agent can distinguish this from describe_table or schema_graph purely from this text.
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?
'Start here' is a direct when-to-use instruction that positions the tool as the first step before the sibling tools (schema_docs, describe_table, query). It does not, however, explicitly name those alternatives or state exclusions such as 'do not use this to inspect a single table', so the routing guidance is clear but not exhaustive.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describe_tableARead-onlyIdempotent
Describe one table or view in depth: columns with declared type, NOT NULL, default, primary key and generated-column flags; per-column NULL percentage, distinct count, min, max and the storage types actually seen (computed over a sample of up to stats_sample rows); foreign keys in both directions; indexes; CHECK constraints; triggers; the CREATE statement; and sample rows. BLOBs are shown as size plus a hex prefix, long text is truncated with its length.
table: table or view name (case-insensitive; a close-match hint is given if it does not exist). sample_rows: how many example rows to show (0-50). stats_sample: rows to sample for the statistics (100-200000).
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| table | Yes | ||
| sample_rows | No | ||
| stats_sample | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish read-only, idempotent, non-destructive, closed-world behavior, so the description's added value is in the details it does supply: statistics are computed over a sample of up to stats_sample rows, BLOBs render as size plus hex prefix, long text is truncated with its length, and a close-match hint is returned for a nonexistent table. The main unstated behavior is the cost/latency of a large stats_sample and any truncation limits on the CREATE statement or constraint lists.
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 capability list is front-loaded in a single dense sentence followed by clean per-parameter lines, so information is easy to scan and nothing is padding. The lead sentence is a long run-on enumeration that could have been bulleted, but the trade-off buys brevity.
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 introspection tool with an output schema present, the definition is largely sufficient: it tells the agent what categories of metadata come back and how large payloads are abridged. The gaps are the undocumented required `path` argument and the absence of any note about result size or runtime as stats_sample grows.
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 0%, so the description must carry the parameter burden, and it only partially does. It documents table (case-insensitive, with close-match hint), sample_rows (0-50) and stats_sample (100-200000), adding real meaning over bare titles, but the required `path` parameter is never mentioned in the description and has no schema description either, leaving the most fundamental parameter unexplained.
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?
Names a specific verb (describes) and resource (one table or view) and then enumerates exactly what is returned: columns with type/NOT NULL/default/PK/generated flags, per-column stats, FKs in both directions, indexes, CHECK constraints, triggers, CREATE statement and sample rows. The scoping to a single object implicitly separates it from db_overview and schema_graph, so an agent can tell what it gets without opening the schema.
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 rather than stated: an agent can infer this is the deep-dive tool for one table when db_overview/schema_graph are too coarse, and the sample_rows: 0-50 range hints that 0 skips examples. However, no sentence explicitly says when to prefer this over schema_docs, find_in_db or query, and no exclusions or prerequisites (e.g. must the DB be attached at path first?) are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explain_queryARead-onlyIdempotent
Show the execution plan of a SELECT / WITH query without running it (EXPLAIN QUERY PLAN), as an indented tree, followed by plain-language findings: full table scans (with row counts), temporary B-tree sorts for ORDER BY / GROUP BY / DISTINCT, and automatic indexes SQLite has to build on every run. Missing-index suggestions are returned as CREATE INDEX text only; nothing is ever created.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true and destructiveHint=false, but the description adds genuinely new behavioral detail: missing-index suggestions come back as CREATE INDEX text only, nothing is ever created, and automatic indexes are rebuilt on every run. It correctly avoids restating the read-only guarantee.
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?
Purpose and the 'without running it' qualifier are front-loaded, and the parenthetical EXPLAIN QUERY PLAN anchors the operation. The trailing findings list is a single run-on sentence that could be tightened, but every clause conveys substantive information.
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 an output schema present and rich annotations, the description only needs to cover intent and quirks, which it does well. The one notable gap is the undocumented 'path' parameter, which neither the schema nor the description explains.
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 0%, so the description has to carry the parameter burden. It usefully constrains 'sql' to SELECT/WITH statements (a real restriction absent from the schema), but says nothing about 'path', which an agent must guess is the database file to inspect.
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 names the exact operation ('Show the execution plan of a SELECT / WITH query without running it (EXPLAIN QUERY PLAN)') and the output shape (indented tree plus plain-language findings), which cleanly separates it from the sibling 'query' tool that actually executes 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?
It gives clear context for use – inspect a SELECT/WITH plan without executing it – and implicitly positions itself as a pre-flight analysis step versus running the query. It never explicitly names the 'query' sibling or states when-not to use it, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_in_dbARead-onlyIdempotent
Find where a string or number appears anywhere in the database: a substring search over every non-BLOB column of every ordinary table (virtual and shadow tables are skipped). Returns, per table, the matching rows (rowid or primary key), the column and a snippet around the match. Each table has a time budget and a match cap, so a huge database cannot hang the call; tables that ran out of budget are listed.
case_sensitive: default false (SQLite folds ASCII letters only, so Turkish or other non-ASCII letters match case-sensitively). max_matches_per_table: 1-50. seconds_per_table: 0.1-30.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| term | Yes | ||
| case_sensitive | No | ||
| seconds_per_table | No | ||
| max_matches_per_table | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the description focuses on what annotations can't convey: substring matching semantics, BLOB column exclusion, virtual/shadow table skipping, per-table time budget and match cap, and the fact that budget-exhausted tables are reported. That is meaningful behavioral context beyond structured fields. It stops short of describing result ordering or how snippets are truncated.
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?
Front-loaded with the core behavior, then scoping caveats, then the return shape, then a terse per-parameter block. Every sentence contributes facts an agent needs. Minor cost: the parameter lines are stripped list fragments rather than sentences, and the snippet/return detail slightly overlaps the output schema.
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 five-parameter search tool whose annotations already establish safety, this covers matching rules, table scope, resource guards, budget-exhaustion reporting, and parameter bounds. The one real gap is that the required `path` parameter is never described, which matters for an agent constructing the call. Return values are briefly summarized even though an output schema exists, which is acceptable rather than wasteful.
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?
With 0% schema description coverage the description carries the full burden, and it delivers for three of five parameters: `case_sensitive` gets the crucial SQLite ASCII-only folding caveat (non-ASCII letters match case-sensitively), and `max_matches_per_table` and `seconds_per_table` get explicit bounds (1-50, 0.1-30). `term` is implicitly defined as the string or number being searched, but `path` is never explained, leaving one required parameter undocumented anywhere.
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 and resource ('Find where a string or number appears anywhere in the database') and immediately narrows the scope: substring search over every non-BLOB column of every ordinary table, skipping virtual and shadow tables. That precision distinguishes it from the sibling `query` tool, which does arbitrary SQL, without needing to name it.
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 'appears anywhere in the database' implies the use case (you don't know which table/column holds a value), and the explicit skip of virtual/shadow tables implies a limit. But it never states when to prefer `query` or `describe_table` instead, nor any exclusions or prerequisites. Usage is inferable rather than directed.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryARead-onlyIdempotent
Run one read-only SELECT / WITH / VALUES statement. Anything that would write (INSERT, UPDATE, DELETE, CREATE, DROP, ATTACH, VACUUM, PRAGMA assignments, load_extension) is refused. Results stop at max_rows rows and about 200 KB, and the query is interrupted after timeout_seconds. BLOB cells show size plus a hex prefix, and text longer than 200 characters is truncated with its length. Prefer aggregates (COUNT, GROUP BY) over pulling raw rows.
format: markdown (default), csv or json. max_rows: 1-5000. timeout_seconds: 0.1-60.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| path | Yes | ||
| format | No | markdown | |
| max_rows | No | ||
| timeout_seconds | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint, and the description goes well beyond them: it lists refused statement types (including PRAGMA assignments and load_extension), the row and ~200 KB result caps, the timeout interruption behavior, BLOB rendering as size plus hex prefix, and text truncation with length. These are exactly the runtime behaviors an agent must anticipate to avoid misreading results or issuing rejected SQL.
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?
Front-loaded with the action and the hard constraint, followed by output-shaping behavior and a compact parameter block; every sentence carries information an agent needs, with no restatement of the name or redundant framing.
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?
An output schema exists and the description still usefully explains result truncation and cell rendering, so return-value behavior is well covered. The remaining gap is the undocumented required `path` argument and no hint about how to page past the max_rows cap.
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 0%, so the description carries the full burden, and it does document format options with the markdown default, max_rows (1-5000) and timeout_seconds (0.1-60) ranges. However, the required `path` parameter is never explained in either schema or description — an agent cannot tell whether it is a database file, an alias, or a directory — and the sql parameter is only characterized indirectly through the allowed-statement sentence.
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?
Opens with a specific verb and resource: 'Run one read-only SELECT / WITH / VALUES statement', and enumerates the statement classes that are refused, so an agent knows exactly the operation class covered. It stops short of naming sibling tools (explain_query, find_in_db) that handle adjacent tasks, so the boundary is only inferable from knowing 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?
'Prefer aggregates (COUNT, GROUP BY) over pulling raw rows' gives concrete positive guidance on how to use it well, and the read-only refusal list effectively defines when the tool will not work. There is no explicit routing statement such as 'use explain_query to inspect a plan' or 'use find_in_db to locate an entity', leaving sibling selection to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schema_docsARead-onlyIdempotent
Generate markdown documentation of the whole schema as text: an entity-relationship diagram (mermaid) when foreign keys exist, then every table with its columns, types, defaults, key and reference notes, indexes, CHECK constraints and triggers, followed by views and trigger definitions. Nothing is written to disk; paste the result where you want it.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false; the description adds genuinely new behavioral context by stating nothing is written to disk and that the mermaid diagram only appears when foreign keys exist. It also discloses the output ordering, which matters for a large documentation blob. It doesn't hint at cost or output size on large schemas, keeping it short of a 5.
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 purpose is front-loaded in the first clause, and the long enumeration of included sections earns its place by telling the agent what the returned blob will contain. The 'paste the result where you want it' tail is a slightly colloquial but useful clarification that it is not persisted.
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 an output schema present, return values need no explanation, and the description covers content and side-effect behavior well for a one-parameter tool. The remaining hole is the meaning and expected format of 'path', which is the only thing an agent must supply and is left entirely undocumented.
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 0% and the single required 'path' parameter is never mentioned in the description, so an agent gets no confirmation of whether it is a database file path, a connection string, or a sub-schema selector. The phrase 'whole schema' gives only the faintest hint about what the value scopes.
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 concrete verb and resource: 'Generate markdown documentation of the whole schema as text', then enumerates exactly what the output contains (mermaid ERD, columns, types, keys, indexes, CHECK constraints, triggers, views). The 'whole schema' scope implicitly separates it from describe_table and schema_graph, but no sibling is named, so an agent must infer the boundary rather than being told.
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 only implied by 'Nothing is written to disk; paste the result where you want it', which signals a human-facing doc workflow. There is no explicit 'use this when you need X instead of schema_graph/describe_table' and no stated prerequisites or size/cost caveats for dumping an entire schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schema_graphARead-onlyIdempotent
Show how tables relate through foreign keys: every child -> parent edge, tables with no relationships, a parents-first load order and circular references. Also reports foreign-key columns that have no index (with a CREATE INDEX suggestion as text) and checks for orphan rows (child rows whose parent does not exist) over a sample, even when PRAGMA foreign_keys is off.
format: "text" (default) or "mermaid" (an erDiagram you can paste into a renderer). orphan_sample: child rows to sample per foreign key (100-100000).
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| format | No | text | |
| orphan_sample | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed-world), and the description adds real context beyond that: orphan detection works even when PRAGMA foreign_keys is off, and index suggestions are returned as text only, never executed. The most valuable disclosure is that orphan checking is over a sample, so results are indicative rather than exhaustive.
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 main capability is front-loaded in the first sentence, followed by secondary analyses and then per-parameter glosses — a clean top-down structure. The first sentence is dense and long, but each clause adds a distinct output rather than padding.
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 an output schema present, return values need no explanation, and the description still front-loads the analytical scope and the sampling caveat. What it omits is minor: no note on behavior for databases with zero foreign keys or on cost of larger orphan_sample values.
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 0%, so the description carries the burden and largely does: it defines format's two values (text vs a pasteable mermaid erDiagram) and explains orphan_sample as child rows sampled per foreign key with a 100-100000 range. Only path is left undefined, which is defensible as an obvious database path argument.
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 names a specific verb and resource (map table relationships via foreign keys) and enumerates concrete outputs: child->parent edges, isolated tables, parents-first load order, circular references. It never names a sibling tool to contrast with (describe_table, db_overview, schema_docs), so the differentiation is inferred from the FK-graph content rather than stated.
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 — an agent can deduce this is the tool for understanding relationship topology — but there is no explicit 'use this when' statement, no prerequisites (e.g. that path must point at a database file), and no exclusions against schema_docs or describe_table, which overlap in subject matter.
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.
8 tool updates
v0.1.0- First observed
data_quality - First observed
db_overview - First observed
describe_table - First observed
explain_query - First observed
find_in_db - First observed
query - First observed
schema_docs - First observed
schema_graph
TDQS
Scored across 8 tools
Each tool has a reasonably distinct role: overview, single-table deep dive, whole-schema docs, FK graph, ad-hoc query, plan analysis, cross-DB text search and data-quality checks. The main overlap is between schema_docs and schema_graph, since both can emit a mermaid ER diagram, and data_quality partially overlaps with what an agent could do via query. Descriptions give strong cues (db_overview is explicitly 'start here'), so misselection is unlikely but not impossible.
All eight names use consistent snake_case with no camelCase or casing drift. The only inconsistency is grammatical style: some are verb_noun (describe_table, explain_query, find_in_db) while others are noun_noun (schema_docs, schema_graph, db_overview, data_quality) or a bare verb (query). Readable and predictable overall, just not a single uniform pattern.
Eight tools is a well-scoped set for a read-only SQLite inspection server, and each tool maps to a distinct inspection task. Nothing feels padded or redundant enough to merge, and nothing essential appears to be missing from the count.
Coverage of the read-only introspection domain is strong: schema docs, overview, per-table detail, FK graph, query execution, plan explanation, value search and data-quality auditing. Minor gaps exist, such as no explicit lightweight 'list tables/views/trigger names' operation (db_overview reports counts and describe_table requires a known name) and no schema-diff or index-only listing tool. The deliberately read-only scope means no write/migration operations, which is appropriate rather than a gap.
Maintenance
Related MCP Connectors
Explore, query, and inspect SQLite databases with ease. List tables, preview results, and view det…
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
The all-in-one data stack for agents. Upload files, run SQL, evolve tables, and render charts.
Related MCP Servers
- AlicenseAqualityCmaintenanceEnables AI agents to safely explore and query a SQLite database in read-only mode, allowing them to inspect schema and run analytical SQL queries without risking data modification.3MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to safely query and explore SQLite databases through read-only, guard-protected tools that block writes, sensitive table access, and runaway queries.1MIT
- AlicenseAqualityBmaintenanceEnables AI agents to inspect database schemas and run strictly read-only SQL queries with guardrails against destructive statements, multi-statement chaining, and unbounded scans. Supports SQLite natively and PostgreSQL optionally.4363 PyPIMIT
- AlicenseAqualityCmaintenanceEnables AI agents to explore and query SQLite databases through read-only, sandboxed tools for listing tables, describing schemas, fetching DDL, and running a single capped SELECT statement. Also supports plain-English questions that are converted to SQL and routed through the same sandbox.4MIT