Skip to main content
Glama
m-tahoon1612

mcp-sql-lite

by m-tahoon1612

mcp-sql-lite

A small stdio server that gives an agent three read-only data tools: list_tables, describe_table and run_select. It speaks a subset of the Model Context Protocol (JSON-RPC 2.0, one message per line on stdin/stdout), which is what most agent hosts and IDE assistants expect from a local tool server these days.

I wrote it to understand what an MCP server actually has to do before wiring one up to a real warehouse. Turns out: not much. A handshake, a tool list with JSON schemas, and a tools/call that returns text. The interesting part is deciding what the model is allowed to run.

There's no real database. On startup it loads a fake shop schema (customers, products, orders, ~20 rows) into an in-memory sqlite db.

Run it

python -m mcp_sql_lite              # waits for json-rpc on stdin
python examples/client.py           # spawns the server, lists tools, runs a query
python examples/client.py "SELECT country, count(*) FROM customers GROUP BY 1"

By hand:

$ python -m mcp_sql_lite
{"jsonrpc":"2.0","id":1,"method":"tools/list"}
{"jsonrpc": "2.0", "id": 1, "result": {"tools": [...]}}
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"run_select","arguments":{"sql":"select count(*) from orders"}}}
{"jsonrpc": "2.0", "id": 2, "result": {"content": [{"type": "text", "text": "{\"columns\": ...

To use it from an MCP host, point the host's server config at python -m mcp_sql_lite with this repo as the working directory (or pip install -e . and use the mcp-sql-lite command).

Related MCP server: shop-database-mcp

Tools

tool

args

returns

list_tables

-

table names + row counts

describe_table

table

columns, types, short notes, 3 sample rows

run_select

sql

columns, rows, row_count

Tool failures (unknown table, rejected query, sqlite error) come back as a normal result with isError: true so the model sees the message and can retry. Protocol problems (unknown method, bad JSON) are JSON-RPC errors.

The SELECT gate

safety.py strips comments and string literals, then:

  • first keyword must be SELECT or WITH

  • no second statement after a ;

  • no write/DDL/admin keywords anywhere (DELETE, ATTACH, PRAGMA, ...)

  • LIMIT over 200 is rejected, missing LIMIT gets LIMIT 50 appended

Limitations

  • Keyword checks, not a parser. It's conservative (a column called update_ts is fine, but a bare word like replace in an identifier gets rejected) and I wouldn't trust it as the only guard on real data. Use a read-only DB user too.

  • Only the tools part of MCP: no resources, prompts, sampling, batching or the HTTP transport. Protocol version is hardcoded.

  • Sample data only. Swapping in a real connection means replacing build_db() and SCHEMA.

  • Single-threaded, one request at a time.

Tests

python -m unittest

MIT licensed.

Available Tools

3 tools
describe_tableB

Columns, types and notes for one table, plus 3 sample rows.

NameRequiredDescriptionDefault
tableYes

TDQS

B3/5.0
Behavior3/5

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

With no annotations, the description carries the full burden, but it does disclose real behavior: the response includes column notes and a fixed 3-row sample, which signals cost/content on large tables. It omits read-only confirmation, behavior for missing tables, and whether sampling is truncated or randomized.

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

Conciseness4/5

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

A single front-loaded sentence with zero filler. It is arguably over-terse for a tool that must compensate for an undocumented parameter, but nothing is wasted.

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

Completeness3/5

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

For a simple one-parameter read tool with no output schema, disclosing the returned fields and the 3-row sample meaningfully substitutes for the missing output schema. The identifier format and error/edge-case behavior remain unaddressed.

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

Parameters2/5

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

Schema coverage is 0%, so the description must define the single 'table' parameter, and it only says 'one table'. It does not clarify whether this is a bare name, a schema-qualified name, or an identifier.

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

Purpose4/5

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

Names the exact content returned (columns, types, notes) scoped to 'one table', which implicitly separates it from list_tables (many tables) and run_select (arbitrary query). The verb is nominal rather than imperative, but the resource and scope are unambiguous.

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

Usage Guidelines2/5

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

No statement of when to prefer this over list_tables or run_select, and no prerequisites. An agent must infer that this is the exploratory step before composing a query.

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

list_tablesA

List tables in the database with row counts.

NameRequiredDescriptionDefault

No parameters

TDQS

A3.7/5.0
Behavior3/5

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

With no annotations, the description carries the full burden; it does disclose that row counts are returned, which hints at extra cost versus a bare name list. It does not state that the operation is read-only, whether views/schemas are included, or whether counts are exact or estimated.

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

Conciseness5/5

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

A single sentence with zero waste, front-loading the verb and resource and appending the one useful return detail.

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

Completeness4/5

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

For a trivial zero-parameter read tool with no output schema, the description covers what is listed and what comes back (row counts). Minor gaps remain around schema scope and object types (views, system tables), but nothing blocks correct invocation.

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

Parameters4/5

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

The tool takes zero parameters, so the baseline is 4; there is nothing for the description to disambiguate. The empty schema is consistent with the description's unqualified 'the database' scope, though that scope itself is unstated.

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

Purpose4/5

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

States a specific verb and resource (list tables) plus the notable payload detail (row counts), which distinguishes it from describe_table's per-table detail. It does not explicitly name siblings, so differentiation is inferable 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.

Usage Guidelines3/5

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

Usage is only implied: listing tables is naturally a discovery step before describe_table or run_select, but the description never says when to pick this over those siblings or any exclusions. An agent can infer the workflow but receives no explicit routing guidance.

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

run_selectA

Run a read-only SELECT. A LIMIT is added if missing (max 200 rows).

NameRequiredDescriptionDefault
sqlYes

TDQS

A3.8/5.0
Behavior4/5

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

With no annotations provided, the description carries the full burden and does disclose two non-obvious behaviors: the operation is read-only enforced, and a LIMIT is auto-injected with a 200-row cap when missing — which materially affects result completeness. It stops short of covering error behavior, statement-count limits, or timeouts.

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

Conciseness5/5

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

Two short sentences with zero filler, and the most decision-relevant fact (read-only, auto-LIMIT 200) is front-loaded where an agent will see it first.

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

Completeness4/5

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

For a single-parameter query tool with no annotations, the description covers the essential call-time facts: what it does, the read-only restriction, and the row cap. It could go slightly further on result shape (no output schema exists to document it) and failure modes, but the gaps are minor.

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

Parameters3/5

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

Schema coverage is 0% and the single 'sql' parameter is undocumented in the schema, so the description must compensate. It does add meaning by constraining the input to a SELECT-only statement, but says nothing about dialect, multi-statement support, or placeholder/binding syntax.

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

Purpose4/5

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

States a specific verb+resource pair ('Run a read-only SELECT'), which is clearly distinct from the sibling tools list_tables and describe_table since those deal with metadata rather than executing queries. It doesn't explicitly name those siblings as alternatives, but the purpose is unambiguous.

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

Usage Guidelines3/5

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

The read-only constraint implies when this tool applies (querying data rather than inspecting schema), but there is no explicit when-to-use vs. when-not guidance, no mention of whether write/DDL statements are rejected, and no routing language pointing to list_tables or describe_table for discovery.

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

Tool Schema Changelog

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

  1. 3 tool updatesv0.1.0
    • First observeddescribe_table
    • First observedlist_tables
    • First observedrun_select

TDQS

A3.7/5.0

Scored across 3 tools

Disambiguation5/5

Each tool targets a distinct stage of the workflow: listing tables, inspecting one table's schema, and executing a query. There is no overlap between discovery, inspection, and execution, so misselection is unlikely.

Naming Consistency5/5

All three names follow a consistent snake_case verb_noun pattern (list_tables, describe_table, run_select). The vocabulary is predictable and readable.

Tool Count4/5

Three tools is on the lean side, but each maps to a necessary step in a read-only SQL workflow and none is redundant. It is well-scoped for a 'lite' server, though a slightly richer surface would not feel bloated.

Completeness4/5

The list → describe → select lifecycle covers the core read-only use case, and the LIMIT safeguard prevents runaway results. Minor gaps exist (no EXPLAIN/query-plan inspection, no database/schema enumeration for multi-schema databases), but agents can work around these with SELECT queries.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides AI agents read-only analytical access to a SQLite database over stdio, with tools for listing tables, describing schemas, and running paginated SQL queries.
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables read-only exploration and analysis of an included SQLite shop database through tools for listing tables, describing schemas, and running SQL queries.
    -
  • F
    license
    A
    quality
    C
    maintenance
    Enables an AI agent to inspect and analyze a local SQLite shop database through read-only, single-query SELECT operations, with schema inspection and paginated querying.
    2
    -