jdbc-mcp-server
Provides read-only access to PostgreSQL databases, allowing AI agents to run SQL queries, inspect execution plans, and explore database structure including tables, columns, indexes, foreign keys, views, functions, and sequences.
JDBC MCP Server
A local MCP server for read-only access to PostgreSQL, Oracle, and Microsoft SQL Server databases. It lets AI agents such as Claude Code, Cursor, VS Code Copilot, and others write SQL queries, inspect execution plans, and explore database structure: tables, columns, indexes, foreign keys, views, functions, and sequences.
PostgreSQL, Oracle, and Microsoft SQL Server JDBC drivers are bundled into the fat jar, so no extra driver installation is required.
The server exposes 49 MCP tools and can optionally expose catalog-qualified MCP resources for table and column metadata. Tools may update the local SQLite catalog, but they never write to the inspected PostgreSQL, Oracle, or SQL Server database.
One server process can serve several databases: name them in
connections.json and pass connection to any tool. The tool manifest
stays a single set regardless of how many databases are configured, and pools are opened only for the
databases actually used.
Quickstart
1. Get the jar — download jdbc-mcp-server.jar from the
latest release (JDK 21+ required;
all JDBC drivers are bundled), or build it yourself:
./gradlew bootJar # → build/libs/jdbc-mcp-server.jar2. Describe your databases in ~/.jdbc-mcp-server/connections.json:
{
"connections": {
"myapp": {
"url": "jdbc:postgresql://db.example.com:5432/myapp",
"username": "ai_readonly",
"password": "secret",
"description": "Application database — customers, orders, shipments"
}
}
}Use a read-only database user; five minutes there outweighs every other protection in this server.
3. Register the server with your MCP client — with no database settings in the client config:
{
"command": "java",
"args": ["-jar", "<absolute-path>/jdbc-mcp-server.jar"],
"env": {}
}For Claude Code that is one command:
claude mcp add --scope user jdbc java -jar /path/to/jdbc-mcp-server.jar4. Ask the agent for listConnections. It answers with the databases this server serves; every
other tool takes that name as its first argument:
{"connection": "myapp", "sql": "SELECT count(*) FROM orders"}Full details: Databases and Credentials, Connecting an AI Client, Serving Several Databases from One Server.
Related MCP server: mcp-multi-db
Databases and Credentials
Every database this server serves is described in one JSON file. Nothing about a database — URL, credentials, schema, timeouts, limits — comes from the environment.
The connections file
Default path ~/.jdbc-mcp-server/connections.json (<data-dir>/connections.json), overridden with
JDBC_MCP_CONNECTIONS_FILE. When the file is missing or defines no connection the server still
starts (so an MCP client can list its tools), logs a warning, and listConnections returns an empty
list; every other tool then reports that no connection is available. A file that is present but
malformed is a startup error.
{
"connections": {
"orders": {
"url": "jdbc:postgresql://db.example.com:5432/orders",
"username": "ai_readonly",
"password": "secret",
"defaultSchema": "public",
"description": "Order service — customers, orders, shipments",
"structureSnapshotSchemas": ["public", "nsi"]
},
"billing": {
"url": "jdbc:oracle:thin:@//oracle.example.com:1521/BILLING",
"username": "AI_READONLY",
"password": "${BILLING_DB_PASSWORD}",
"description": "Legacy billing (Oracle)"
}
}
}The object key is the connection name. It is also the name of the connection's local catalog
directory (<data-dir>/<name>/) and appears in MCP resource URIs, so it must match
[A-Za-z0-9._-]+(@[A-Za-z0-9._-]+)?, be at most 64 characters, and not be . or ...
The optional @ is there to name the two axes separately: <service>@<stand>, as in ssj@dev,
nsi@dev, ssj@tst. A dash cannot do that job, because dashes already occur inside service names
(ssj-ws, ssj-ek-export, ais-ui), so ssj-ws-dev is ambiguous to a human and to a model alike.
@ never occurs in a service name and reads as "what, where" the way user@host does. It is
percent-encoded to %40 in resource URIs; nothing else about the name changes — the directory on
disk is the name as written.
url is the only required field; the engine is detected from its prefix (jdbc:postgresql:,
jdbc:oracle:, jdbc:sqlserver:). description is free text returned by listConnections, so an
agent can pick a database by meaning rather than by name — worth filling in.
Any string value may reference an environment variable as ${VAR}. A referenced variable that is
not set fails startup with a message naming the variable and the field; it never becomes an empty
password. Read the next section before reaching for it.
Why credentials live in a file, not in environment variables
The point of this server is that the agent reaches the database only through it: every statement
goes through the read-only guard, every result is capped by maxRows, and nothing but
SELECT / WITH / EXPLAIN gets through.
Credentials in environment variables undermine exactly that. They are set on the server process by
the MCP client, which means they also sit in the client's own configuration — a file agents read and
edit as a matter of routine — and in the environment of whatever shell launched it. An agent that
has seen a URL, a user and a password does not need the tools any more: psql, sqlplus, sqlcmd
or three lines of Python connect straight to the database, with no guard, no row cap and no trace in
this server's log.
So the server accepts no database credentials from the environment at all — there are no JDBC_URL
/ JDBC_USERNAME / JDBC_PASSWORD variables. They live in connections.json, which only the server
reads.
Be clear about what that does and does not buy:
It removes the easy path. Credentials stop being part of the material an agent routinely handles: MCP client configs, shell environment,
envdumps in logs and bug reports.It is not a sandbox. An agent with shell access running as you can read the file;
chmod 600keeps out other users, not a process running as your user.The guarantee that survives everything is a read-only database user. The file narrows the attack surface; the database's own permissions close it.
For the same reason, prefer a literal password in the file over a ${VAR} reference whose variable
would be set in the MCP client's env block — that puts the secret straight back where the agent
looks. ${VAR} earns its place when the value is injected from outside the agent's reach (a systemd
unit, a wrapper script, a secret manager), or when the file itself is shared or committed and the
secret must not be.
Connection fields
Everything except url is optional; a field left out falls back to the built-in default:
Field | Default | Meaning |
| required | JDBC URL; also selects the engine |
| none | Database credentials |
| none | Free text returned by |
| the session schema | Schema used when a metadata tool call omits one |
|
| Per-query timeout; |
|
| Row cap for one response; |
|
| JDBC |
|
|
|
|
| Hikari maximum pool size |
|
| Hikari minimum idle; |
|
| Hikari connection checkout timeout |
|
| Hikari validation timeout |
|
| Idle connections above |
| the default schema | Schemas captured by |
|
| Oracle-only timeout for the bulk column query during |
|
| When |
| none | Extra directories, JSON files or zip archives with QueryUsage records |
| the default schema | Schemas scanned for native usage |
|
| What native usage scanning covers |
|
| Maximum native usage records per index build |
The JDBC_MCP_TOOLS_* group flags stay in the environment — they shape the tool manifest, which is
shared by all connections. See Configuration for the handful of variables the
server itself reads.
URL examples
jdbc:postgresql://db.example.com:5432/myapp
jdbc:postgresql://db.example.com:5432/myapp?currentSchema=public&sslmode=require
jdbc:oracle:thin:@//db.example.com:1521/ORCLPDB1
jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=...)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=...)))
jdbc:sqlserver://db.example.com:1433;databaseName=myapp;encrypt=true;trustServerCertificate=false
jdbc:sqlserver://db.example.com;databaseName=myapp;integratedSecurity=falseWhy This Exists
Scenario: you ask an LLM to "check the database and show how many orders we had by status last month." Without this server, the LLM may:
invent table and column names;
miss the real schema details, such as nullable fields, types, and foreign keys;
accidentally generate a
DELETEorTRUNCATEwhile "reasoning."
With this server, the LLM can:
call
schemaBriefto discover the schema map, orqueryContextto get ready-to-use detailed context: tables, columns, relationships, and constraints;refine the context with
tableContextaround a specific table orfindJoinPathsfor JOIN path discovery;write a query and optionally call
inspectQuery,queryLint, orresolveQueryLineagefor AST, metadata, and view/routine lineage checks;call
validateQuerywith the sameparamsornamedParamsthat will be used for execution, validating syntax without running the query;call
explainQuerywhen a plan is needed;call
executeQueryto fetch data.
Any non-SELECT query is blocked before it reaches the database.
Beyond live schema introspection, the server also keeps a local usage catalog of known SQL
queries used by applications and reports against the inspected database, together with their
business context — parameter meanings, output column descriptions, and where each output is
rendered (Excel cell, dashboard widget, BI Publisher region). This lets the LLM answer questions
like "which production reports already touch this column?" and "what business label does this
field have in the customer card?" against a curated body of evidence instead of guessing from
names alone. The catalog is also the source of the typed three-layer evidence bundle on
relationship edges, so undeclared joins observed in production queries are treated as first-class
hints alongside declared FKs. See Usage Catalog below.
Architecture
+------------+
+---> | database A |
+-------------+ stdio +----------+ | +------------+
| AI agent | <------------> | jdbc-mcp | | +------------+
| (Claude Code| stdin/stdout | server |-+---> | database B |
| Cursor...) | | (Java) | | +------------+
+-------------+ +----------+ |
+---> ...
read-only JDBC
PG / Oracle / SQL ServerThe protocol is stdio only. The client starts the server as a child process. One process serves
any number of named databases, all declared in the
connections file; a connection's pool is opened the first time a tool
call names it.
MCP Resources
When JDBC_MCP_RESOURCES_ENABLED=true, the server exposes — for every configured connection that
already has a local catalog file — a concrete catalog manifest, one concrete resource for every table
or view already persisted in that connection's structure snapshot, and two parameterized resource
templates:
jdbc-mcp://catalog/<catalog>/manifest
jdbc-mcp://catalog/<catalog>/schemas/SSV/tables/CUSTOMERS
jdbc-mcp://catalog/<catalog>/schemas/{schema}/tables/{table}
jdbc-mcp://catalog/<catalog>/schemas/{schema}/tables/{table}/columns/{column}<catalog> is the percent-encoded connection name. It is fixed per connection when the server
starts and is not a
template variable clients can use to switch databases: a read resolves the connection from the URI it
was given. This keeps resource URIs unambiguous both across the connections of one server and across
several registered instances of this jar. The manifest reports database kind,
snapshot version/build time/covered schemas, and the exact templates for its catalog. Table and
column reads reuse MetadataService, so they have the same persistent-snapshot and live-fallback
semantics as describeTable.
Concrete table resources are loaded from the local SQLite snapshots when the MCP server starts — no
database is contacted and no JDBC pool is created for this — so clients with MCP resource-picker
support can offer entries like SSV.CUSTOMERS without querying the live database. Their compact descriptions contain the database comment when present, the primary-key
columns, and outgoing foreign-key mappings; column lists and counts are intentionally omitted. After
running rebuildCatalog in an already-running server, restart or reconnect that MCP server instance
to refresh its concrete resource list.
Column resources include the column definition plus matching PK position, unique constraints, indexes, outgoing/incoming foreign keys, and CHECK constraints. URI path segments preserve case and use UTF-8 percent encoding. Resources are disabled by default; enabling them leaves the MCP tools unchanged.
MCP Tools
The 49 tools are grouped below by purpose.
Every tool takes connection as its first, required argument, naming the database to run
against — including installations that serve exactly one database. listConnections lists the
names. See Serving Several Databases from One Server.
Tool Groups
Tools are organised into groups that can be turned on or off independently with
JDBC_MCP_TOOLS_* flags. All groups are on by default, so the full tool set is available out of
the box. Turning groups off shrinks the tools/list manifest, which matters for small-context
(local) models that would otherwise be flooded with tool schemas before the first call.
Group | Flag | Default | Tools |
Metadata |
| on |
|
Query |
| on |
|
Admin |
| on |
|
Sample |
| on |
|
Query analysis |
| on |
|
Distribution |
| on |
|
Statistics |
| on |
|
Benchmark |
| on |
|
Usage catalog |
| on |
|
Schema context |
| on |
|
Connections |
| on |
|
Each flag accepts true / false. For a small-context local model, turn off the groups you do not
need — for example keep only Metadata + Query by setting the rest to false — to cut the manifest
down to a minimal "explore the schema and run a query" set. The sections below describe each tool
regardless of its group.
Query
Tool | Description |
| Execute a |
| Return the execution plan. PostgreSQL: |
| Compact LLM-oriented plan summary instead of a large raw plan dump: highest-cost nodes, full scans on large tables, estimate errors (planner vs. reality, requires |
| Validate syntax without execution: read-only guard plus driver |
| Parse SQL through JSqlParser without touching the database and return an AST summary: tables, aliases, CTEs, select items, joins, predicates, order by, columns, parameters, features, and parser warnings |
| Parse SQL and combine the AST with metadata, index, and FK checks. Returns advisory warnings such as unknown tables or columns, |
| Resolve direct objects referenced by a query and recursively expand database views/materialized views to underlying physical tables. Function/procedure expansion is best-effort: embedded |
Benchmarking
Tools for measuring the real cost of a query, so the LLM does not have to guess from the plan and can see actual milliseconds and buffer counters.
Tool | Description |
| Run the query |
| Regular |
Metadata
Tool | Description |
| List schemas. System schemas are hidden by default; use |
| List tables and views in a schema. Parameters: |
| Full object description in one call: columns, primary key, unique constraints, indexes, outgoing/incoming FKs, CHECK constraints and allowed values, plus compact trigger metadata |
| Trigger body for one named trigger. Parameters: |
| SQL definition of a view |
| Functions, procedures, and packages in a schema |
| Function or procedure source code. On Oracle, all |
| Sequences in one schema, or across schemas when |
| Case-insensitive substring search across non-system tables, views, routines, sequences, and synonyms |
Schema Context
High-level tools for quick schema orientation and SQL authoring. Instead of manually calling
listTables -> describeTable -> sampleRows for each table, an LLM can get ready-to-use
context in one call: tables, columns, relationships, constraints, and sample rows.
Tool | Description |
| Context around one table: the table itself, FK parents, and optionally child tables and relationship edges. FK traversal uses the requested depth (default 1, max 4). Parameters: |
| Find JOIN paths between two tables through FKs. The graph is traversed in both directions and each edge includes |
| Plain-text full-schema map for SQL authoring: all matching tables/views with column counts, PK, incoming/outgoing relationship counts, key-like columns, central/isolated tables, and capped key FK relationships. Use this first when relevant tables are unknown; follow with |
| Schema relationship graph metrics: nodes with in/out degree and classification, edges, central tables, isolated tables, connected components, and cycle hints. Optionally includes the shortest path between two tables |
| Schema lint audit: missing primary keys, FKs without indexes, FK type mismatches, nullable unique constraints, status/type columns without CHECK constraints, orphan |
| Build compact SQL-authoring context from search terms and/or explicit tables. Finds relevant tables and columns using declared schema names/comments plus usage-catalog semantic evidence when available, includes constraints and allowed values, relationships and JOIN paths between selected tables, and optionally sample rows (up to 3 per table) |
| DOT/Graphviz representation of the schema relationship graph. Nodes are tables with all columns and types ( |
Edge evidence
When includeObserved is left unset, tableContext / findJoinPaths enable
it automatically if the local usage catalog is enabled (see Usage Catalog below). Every
relationship edge then carries a typed three-layer evidence bundle. Each layer is independently
optional and is omitted when there is no signal:
declaredSchema— the relationship is a declared foreign key in the database catalog. Carries the FK name and column lists.observedQuery— the equi-join pair appears in stored application queries. CarriesjoinSupport(number of distinct queries) andqueryUids(up to 5 contributing uids).semanticUsage— terms shared across queries that touch both tables: business domains, business objects, and output labels, plus the co-occurring query count and uid preview. This layer decorates existing edges only — it never proposes new relationships.
{
"relationshipType": "foreignKey",
"fromTable": "ORDERS", "fromColumns": ["CUSTOMER_ID"],
"toTable": "CUSTOMERS", "toColumns": ["ID"],
"evidence": {
"declaredSchema": { "foreignKeyName": "FK_ORDERS_CUSTOMER", "fromColumns": ["CUSTOMER_ID"], "toColumns": ["ID"] },
"observedQuery": { "joinSupport": 18, "queryUids": ["SHOP/InvoiceReport.json#header"] },
"semanticUsage": {
"sharedBusinessDomains": [{ "value": "Customers", "support": 12, "queryUids": [...] }],
"sharedBusinessObjects": [{ "value": "Invoice payer", "support": 4, "queryUids": [...] }],
"sharedOutputLabels": [{ "value": "Payer name", "support": 3, "queryUids": [...] }],
"coOccurringQueryCount": 22,
"coOccurringQueryUids": [...]
}
}
}Equi-join pairs seen only in stored queries (no declared FK) are appended as new edges with
relationshipType: "observed" and undirected: true, between tables already in scope. Composite
(multi-column) FKs receive a declaredSchema layer but no observed-pair match in this iteration.
schemaBrief, schemaGraph, and queryContext only surface declared FK relationships.
Evidence model
The schema-context layer keeps three sources of knowledge separate:
declared_schema- live database introspection: tables, columns, PK/FK, indexes, constraints, comments and statistics.observed_query- the indexed query catalog: which stored application/report queries reference a table or column, and in which SQL context (select,where,join,order_by,having).semantic_usage- adapter-supplied business meaning: query domains/tags/labels, output labels, parameter descriptions, field usages, rendered business objects and confidence.
In tableContext, the existing table fields are the compact declared_schema view. When
includeObserved is enabled and the usage catalog is available, each table also gets an
evidence block:
{
"evidence": {
"observedQuery": {
"queryCount": 12,
"queryUids": ["SHOP/reports/customer-card#main"],
"columns": [
{"column": "STATUS", "queryCount": 5, "contexts": [{"value": "where", "support": 4}]}
]
},
"semanticUsage": {
"businessDomains": [{"value": "Customers", "support": 8}],
"businessTags": [{"value": "customer", "support": 6}],
"queryLabels": [{"value": "Customer card", "support": 3}],
"outputLabels": [{"value": "Customer name", "support": 4}],
"businessObjects": [{"value": "Customer card", "support": 3}]
}
}
}The server treats this as evidence, not as a single canonical business model. Different queries may legitimately attach different business roles to the same physical table or column.
queryContext also uses semantic_usage as a discovery signal. When the user passes natural
language terms, the server searches usage-catalog domains, tags, query labels, output labels and
business objects. Matching tables are returned in semanticMatches and are considered before the
fallback name/comment scan over live schema metadata. This lets terms such as "payer" find a
physical CUSTOMERS table when existing reports expose customers.name as "Payer name".
Usage Catalog
A catalog of known SQL usage against the inspected database, together with optional business context: parameters with descriptions, output columns with their meaning, and where each output is displayed in the consuming artifact (Excel cell in a BI Publisher report, dashboard widget, etc.).
There are two sources. File-backed usage comes from directories / JSON files / zip archives containing canonical QueryUsage JSON records. Database-native usage is derived automatically from the connected schema's views, routines and triggers. At runtime the server parses these records and builds a persistent SQLite index with extracted tables / columns / equi-join pairs as facts. JSON files remain authoritative for file-backed records; native records are refreshed from live metadata.
Why this exists. The metadata tools answer "what tables and columns exist". The usage catalog answers "how are they actually used by applications". With both, an LLM can replace guesses about undeclared joins with evidence-based reasoning ("these two columns are joined in 17 production reports, here are their uids").
Identity. Each query is keyed by (source.kind, source.path, source.unit). Diagnostics and
evidence render this key as:
{source.kind}/{source.path}#{source.unit}The #unit suffix is omitted when there is no unit. Examples:
bi-publisher-report/reports/customers/CustomerCard.xdo#CUST
manual/manual/ad-hoc-2026-05-01
java-dao/src/main/java/com/example/shop/OrderDao.java#findByCustomersource.kind and source.unit must not contain / or #; source.path must not contain #.
For duplicate source keys, the first record wins for that index build.
Where the files live. The default catalog directory is
<data-dir>/<connection>/usage-catalog. Configure usageCatalogPaths on the connection as a list
of additional directories, .json files, or .zip archives. Directories are scanned recursively
for *.json; zip archives are scanned for JSON entries. Set usageCatalogEnabled: false to
disable the catalog. usageCatalogStatus then reports catalogEnabled: false; other public usage
tools return an argument error explaining how to enable it.
Database-native usage. The catalog also indexes supported database objects from the default schema:
views / materialized views as
source.kind="database-view"orsource.kind="database-materialized-view";functions and procedures as
source.kind="database-function"/source.kind="database-procedure"where the engine reports that distinction;triggers as
source.kind="database-trigger".
Views usually contribute fully parsed table, column and join evidence. Routine and trigger bodies
are engine-specific, so the indexer first uses an ANTLR-based procedural pre-extractor to find
embedded SELECT / WITH / INSERT / UPDATE / DELETE / MERGE statements, then feeds those
statements into the existing JSqlParser analysis pipeline. If no embedded statement is found, the
object is still kept as a provenance record. Use usageNativeSchemas on the connection to
scan explicit schemas.
Persistent index. The server never builds the usage index on startup. The first usage-catalog
lookup builds it synchronously from file-backed records and database-native objects into the local
SQLite <catalog>.db. Source files and database objects remain authoritative. Use
invalidateUsageCatalogCache after changing them; it clears the indexed usage rows and the next
lookup rebuilds them.
Local-only writes. The usage catalog never writes to the inspected JDBC database
(PostgreSQL / Oracle / SQL Server). The existing ReadOnlyGuard and connection-level protections
remain in force.
Typed payload. The canonical source, parameters[], outputs[], fieldUsages[] and nested
objects are described by the JSON Schema (field names, types, descriptions, enum values). The same
record types (QueryUsage and friends in usage/format/) are used by file indexing.
The canonical source-agnostic JSON format is documented in
docs/usage-catalog-format.md; its JSON Schema lives at
src/main/resources/schemas/query-usage-record.schema.json, with examples under
examples/usage/. Source-specific adapters should emit this canonical shape rather than being
implemented inside the JDBC MCP server.
Tool | Description |
| Current catalog state ( |
| Drop the runtime index. The next lookup rebuilds it synchronously from configured files and database-native objects |
| Full record selected by |
| Paginated listing with optional filters: |
| All catalog queries that reference a given table. Case-insensitive matching against alias-resolved, uppercased table names. Optional |
| All catalog queries that reference a given column, with the SQL |
| Aggregate observed equi-join pairs across stored queries, grouped by |
| Tags currently used in the catalog, with query counts. Lets the agent reuse a stable vocabulary across ingest calls |
| Same for |
| Source-kinds currently used in the catalog with their query counts. Helps the agent discover valid values for |
Resolution. During indexing, table / column qualifiers are resolved cheaply through the
parser's alias map and uppercased for case-insensitive matching. An explicit schema in the SQL
(SCHEMA.TABLE) is preserved verbatim. Unqualified table references are resolved as part of the
index build against the live JDBC schema: exactly one match fills the schema, multiple matches are
marked ambiguous, and zero matches stay unresolved.
Catalog Administration
Tool | Description |
| Rebuild the persistent structure snapshot and usage index for comma-separated |
This tool writes only to the local catalog. It does not modify the inspected database.
Connections
Tool | Description |
| List the databases this server serves: |
listConnections reads configuration and the local filesystem only — it opens no database
connection, so it still answers when some of the configured databases are down. In an unfamiliar
installation it is the first call worth making.
Persistent Structure Snapshot
Structural metadata (columns, keys, indexes, FKs, views, routines, triggers, sequences) is held in a
persistent structure snapshot stored in the local SQLite <catalog>.db file (the same database
file as the usage catalog, under <data-dir>/<catalog>/). SQLite runs in WAL mode, so Codex,
Claude, and other local agent processes can use the same catalog concurrently. This speeds up repeated calls to
tableContext, findJoinPaths, schemaLint, schemaGraph, queryContext, describeTable,
searchObjects, and the usage-catalog re-resolver. Statistics tools such as tableStats,
indexStats, columnStats, and sampleRows are not cached; their counters are live.
The snapshot is authoritative ("cache forever") — there is no TTL or staleness detection. It is
filled lazily (describeTable persists each table it loads) and can be front-loaded for whole
schemas with the rebuildCatalog tool, which builds the structure snapshot and the usage index
into one distributable <catalog>.db. rebuildCatalog checkpoints the WAL before returning.
Clear the catalog while all server processes are stopped by deleting <catalog>.db and any
adjacent <catalog>.db-wal / <catalog>.db-shm files.
Existing H2 <catalog>.mv.db files are not converted or deleted. On first SQLite startup the
server creates a new <catalog>.db, logs a warning, and leaves the legacy file untouched; run
rebuildCatalog to populate the new catalog.
Configuration:
structureSnapshotSchemas- schemas to front-load on a full rebuild (empty → the default schema).structureSnapshotOracleColumnQueryTimeoutSeconds- Oracle-only timeout for theDBMS_XMLGEN-backed bulk column/default query during a full rebuild (default300;0disables).
Both are per-connection fields in connections.json.
Data Exploration
Tool | Description |
| Return a few rows from a table or view ( |
Selectivity and Distribution
Tool | Description |
| Basic column statistics: |
columnStats only reports extremes. The other tools answer "how selective is this predicate?"
and "how skewed are values in this column?", which is the information an LLM needs to choose an
index or rewrite a JOIN meaningfully.
Tool | Description |
| Top-N most frequent values of a column plus their share. Surfaces skew, for example |
| Percentiles P25 / P50 / P75 / P90 / P95 / P99 plus |
| One scan for null / non-null counts across every table column. Columns are sorted by descending |
| Estimate how many rows a predicate would return without executing the query, using |
| Estimate the output row count of a |
Object Statistics
These tools give the LLM object scale and health signals; without that, optimization advice becomes
guesswork. Data comes from system catalogs (pg_class, pg_stat_*, ALL_TABLES, ALL_INDEXES,
DBA_SEGMENTS) and is aggregated on the Java side.
Tool | Description |
| Table and index sizes in bytes, estimated row count, dead tuples on PostgreSQL, last vacuum/analyze, and seq/idx scan counters. On Oracle, also includes best-effort |
| Per-index size, scan counter, columns, unique/primary flag, and index type. PostgreSQL extras: |
| Indexes with zero scans on PostgreSQL ( |
| Indexes whose column list is a strict prefix of another index on the same table. Unique indexes are not reported because dropping them would remove a constraint. Index type must match |
| Foreign keys on the child side that lack a supporting index, a classic cause of slow |
All tools are read-only; data is not modified.
Error Format
All tools return errors in the same shape: JSON with error and kind fields.
{"error": "Only SELECT / WITH / EXPLAIN statements are allowed", "kind": "rejected"}
| When |
| The database returned a |
| Invalid tool argument |
| The read-only guard blocked the query before it reached the database |
|
|
| Internal driver failure, unhandled failure, or plan parsing failure |
validateQuery uses its own shape, without kind; valid is the discriminator.
{"valid": true, "parameters": 1, "columns": 3}
{"valid": false, "stage": "guard|params|driver", "error": "..."}Read-only Protection
Protection is layered and is designed primarily for accidental DELETE / DROP statements from
an LLM, not for a malicious actor. A malicious actor already has the database URL, username, and
password — which is also why the server
keeps credentials out of the environment,
so that an agent does not casually acquire them.
ReadOnlyGuard in project code. Before sending SQL to the database, the server first parses it with JSqlParser and checks the AST. Only a single
SELECT,WITH, orEXPLAINis allowed. Write CTEs,SELECT INTO, and locking clauses such asFOR UPDATEare forbidden. If JSqlParser cannot parse dialect-specific SQL, the guard falls back to the older lexical check: first meaningful token, multi-statement rejection, comment skipping, and write-keyword detection outside strings and quoted identifiers.connection.setReadOnly(true). Set by Hikari and again by this server on each checkout.PostgreSQL:
default_transaction_read_only=on. Added to the JDBC URL automatically unless you already provided your ownoptions=. Even server-side DDL is rejected.Oracle: JDBC read-only hint. Oracle JDBC treats
setReadOnly(true)mostly as an advisory hint. The client-side guard and a dedicated read-only database user are the primary Oracle protections. OracleEXPLAIN PLANwrites a static plan toPLAN_TABLE; this server scopes those reads with a generatedSTATEMENT_ID.SQL Server: JDBC read-only hint plus SHOWPLAN estimated plans. SQL Server also treats
setReadOnly(true)as a hint. Use a least-privilege login/user for strong enforcement.explainQueryandanalyzePlanuseSHOWPLAN_TEXT/XML, which returns estimated plans without executing the statement.
Maximum Protection: Use a Read-only Database User
If you can spend five minutes, create a dedicated user with read-only permissions. This is the strongest guarantee even if the guard is accidentally disabled.
PostgreSQL:
CREATE ROLE ai_readonly LOGIN PASSWORD 'strong-password';
GRANT CONNECT ON DATABASE mydb TO ai_readonly;
GRANT USAGE ON SCHEMA public TO ai_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO ai_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public
GRANT SELECT ON TABLES TO ai_readonly;Oracle:
CREATE USER ai_readonly IDENTIFIED BY "strong-password";
GRANT CREATE SESSION TO ai_readonly;
GRANT SELECT ANY DICTIONARY TO ai_readonly; -- for metadata
-- For each required table/view:
GRANT SELECT ON app_schema.customers TO ai_readonly;
-- ...or a role collecting all SELECT grants:
-- CREATE ROLE ai_ro_role; GRANT ai_ro_role TO ai_readonly;SQL Server:
CREATE LOGIN ai_readonly WITH PASSWORD = 'strong-password';
CREATE USER ai_readonly FOR LOGIN ai_readonly;
GRANT SELECT ON SCHEMA::dbo TO ai_readonly;
GRANT VIEW DEFINITION TO ai_readonly; -- for object definitions and richer metadata
GRANT SHOWPLAN TO ai_readonly; -- for explainQuery/analyzePlan estimated plansDisabling the Guard
If you need to call, for example, a stored procedure with read-only semantics that the guard does not allow, you can disable client-side validation:
"readonlyGuard": "off"Connection-level protections (setReadOnly and, on PostgreSQL, default_transaction_read_only)
remain enabled. On Oracle and SQL Server, setReadOnly is best-effort; use a read-only database
user for the strongest guarantee.
Stack
Java 21, Spring Boot 4.0, Spring AI MCP 2.0.0-M6 (
stdiotransport)HikariCP through Spring Boot
starter-jdbcPostgreSQL JDBC 42.7.4
Oracle JDBC
ojdbc1123.6.0.24.10Microsoft SQL Server JDBC 12.8.1
SQLite 3.51.3 WAL catalog (
<catalog>.db) holding the usage index and persistent structure snapshotGradle 9.3.1 with version catalog
License
This project is licensed under the Apache License, Version 2.0. See LICENSE.
Runtime and test dependencies are licensed by their respective owners. See
THIRD_PARTY_NOTICES.md, especially if you distribute a built fat jar containing bundled JDBC
drivers.
Build
# Set JDK 21+ explicitly if it is not your default JDK:
export JAVA_HOME="$HOME/.jdks/jdk-21.0.6"
./gradlew buildResult: build/libs/jdbc-mcp-server.jar (includes PostgreSQL, Oracle, and SQL Server drivers).
Integration Tests
Integration tests start real PostgreSQL, Oracle Free, and SQL Server instances through Testcontainers, so Docker is required. They are excluded from the regular build and run separately:
./gradlew integrationTestTo run only the SQL Server Testcontainers suite:
./gradlew integrationTest --tests "*SqlServerIntegration*"The first Oracle Free and SQL Server runs download large images and may take several minutes to start.
Smoke Tests Against a Real Oracle Database
If you have access to an existing Oracle database, you can run read-only smoke tests
(LiveOracleIntegrationTest) directly against it. The tests execute only SELECT queries against
the dictionary (DUAL, ALL_TABLES) and the user schema; there are no
CREATE / INSERT / UPDATE statements.
Username and password are not stored in the repository; they are passed through environment variables. If they are not set, the tests are skipped quietly and do not break the regular build.
export LIVE_ORACLE_URL='jdbc:oracle:thin:@db.example.com:1521:ORCL'
export LIVE_ORACLE_USERNAME='ai_readonly'
export LIVE_ORACLE_PASSWORD='secret'
# optional, defaults to LIVE_ORACLE_USERNAME uppercased:
# export LIVE_ORACLE_SCHEMA='APP_SCHEMA'
./gradlew liveOracleTestWindows (PowerShell):
$env:LIVE_ORACLE_URL = 'jdbc:oracle:thin:@db.example.com:1521:ORCL'
$env:LIVE_ORACLE_USERNAME = 'ai_readonly'
$env:LIVE_ORACLE_PASSWORD = 'secret'
./gradlew liveOracleTest.env is listed in .gitignore; if desired, store variables there and load them before running
tests, for example with direnv, dotenv-cli, or set -a; . ./.env; set +a in bash. Gradle does
not parse .env itself; variables must already be present in the environment when Gradle starts.
Configuration
Databases, credentials and everything that varies per database live in
connections.json — deliberately
not in the environment. The
environment configures only the server process itself:
Variable | Required | Description |
| no | Path of the JSON file describing the named connections this server serves; default |
| no | Root directory for server-local data, default |
| no | Expose the catalog-qualified manifest plus concrete table resources and table/column resource templates; default |
| no | Per-group tool toggles that control which tools appear in |
A connection's own settings — URL, credentials, default schema, timeouts, row caps, pool sizes, the
read-only guard, snapshot and usage options — are fields of its connections.json entry; see
Connection fields.
Running
With connections.json in place:
java -jar jdbc-mcp-server.jar(Use build/libs/jdbc-mcp-server.jar if you built it locally, or the file downloaded from
Releases.)
The server immediately starts listening for MCP over stdin/stdout. Logs are written to stderr. Tool
calls address a database by the name it has in the file: "connection": "myapp".
Docker
The image is published to GHCR with every release. Mount the directory holding connections.json
at /data — it is also where the server keeps its local catalogs and logs:
docker run -i --rm -v ~/.jdbc-mcp-server:/data ghcr.io/igorolv/jdbc-mcp-server:latestThe same command is what an MCP client should launch (-i keeps stdin open for the stdio
transport). JDBC URLs in connections.json must be reachable from inside the container: use the
database host name, not localhost, or add --network host on Linux. To build the image locally:
docker build -t jdbc-mcp-server .Connecting an AI Client
Add this server to the client configuration:
{
"command": "java",
"args": ["-jar", "<absolute-path>/jdbc-mcp-server.jar"],
"env": {}
}There is nothing to put in env: the databases come from
connections.json, and keeping credentials out of the client config
is the point. Add
JDBC_MCP_CONNECTIONS_FILE only if you keep the file somewhere other than the default path.
Where to Configure It
Client | Connection method |
Claude Code |
|
Qwen Code |
|
VS Code |
|
Cursor |
|
Claude Desktop |
|
For Claude Code, omitting --scope user adds the server only to the current project.
Check the connection with claude mcp list. Restart the client after adding the server.
Serving Several Databases from One Server
One server process can serve any number of named databases. The tool manifest stays a single set of
49 tools no matter how many are configured — each tool takes connection as its first argument —
and a database's pool, local catalog and services are created the first time something actually asks
for that connection.
This matters at scale: registering fifteen MCP server instances puts fifteen tool manifests into the agent's context and fifteen JVMs in memory, when the session may end up touching two of the databases.
Each database is one entry in connections.json; adding a database
means adding an entry and restarting the server.
Choosing a connection
There is no default connection: every tool call names the database it means in its first argument.
A missing or unknown name returns an argument error listing the available names. Call
listConnections to see what exists — it reads configuration only, so it works even when some of
the configured databases are down.
A single database
Nothing changes for one database: a connections.json with a single entry, and its name passed as
connection. There is no environment-variable shortcut — one file is the whole configuration.
Isolation
Configuring a connection costs nothing until it is used: no pool, no catalog file, no connection.
Reaching database
Xopens pools forXonly.A database that is down, or an entry whose URL is not a supported JDBC URL, fails the calls made against it and leaves the other connections working.
listConnectionsreports the reason inconfigError.Each connection keeps its own local catalog at
<data-dir>/<name>/<name>.db, so structure snapshots and usage indexes never mix.MCP resources (when
JDBC_MCP_RESOURCES_ENABLED=true) are published for every configured connection that already has a local catalog file; URIs were catalog-qualified already.
The single server process keeps its shared rolling log under
<data-dir>/logs/jdbc-mcp-server.log. Log entries emitted while handling a tool call include its
connection name; process-level entries use connection=server.
One instance per database (the earlier approach)
Registering one server instance per database still works and remains a reasonable choice for one or two databases. The client namespaces tools by server key, at the cost of one tool manifest and one JVM per database:
{
"mcpServers": {
"jdbc-orders": {
"command": "java",
"args": ["-jar", "<absolute-path>/jdbc-mcp-server.jar"],
"env": {"JDBC_MCP_CONNECTIONS_FILE": "<absolute-path>/orders-connections.json"}
},
"jdbc-billing": {
"command": "java",
"args": ["-jar", "<absolute-path>/jdbc-mcp-server.jar"],
"env": {"JDBC_MCP_CONNECTIONS_FILE": "<absolute-path>/billing-connections.json"}
}
}
}Do not give two databases the same connection name, in either setup: their usage index and structure
snapshot would share one <catalog>.db file.
Project Structure
+-- src/main/java/ru/it_spectrum/ai/jdbc/mcp/
| +-- JdbcMcpServerApplication.java - Spring Boot entry point
| +-- config/
| | +-- JdbcProperties.java - connection settings from env
| | +-- JdbcMcpProperties.java - local data directory and catalog name
| | +-- UsageProperties.java - usage-catalog sources and native-object settings
| | +-- StructureSnapshotProperties.java - schemas captured by rebuildCatalog
| | +-- DatabaseKind.java - PG/Oracle/SQL Server autodetection from URL
| | +-- DataSourceConfig.java - Hikari pool builder + connection-level read-only mode
| | +-- ConnectionsConfig.java - global defaults and the connection registry bean
| +-- connection/
| | +-- ConnectionsFile.java - connections.json shape
| | +-- ConnectionsLoader.java - file + env defaults -> connection definitions
| | +-- EnvironmentPlaceholders.java - ${ENV_VAR} substitution
| | +-- ConnectionDefinition.java - one named database and its effective settings
| | +-- ConnectionRegistry.java - configured connections, lazily built, closed on shutdown
| | +-- ConnectionContext.java - the service graph of one connection
| | +-- SpringConnectionContextFactory.java - builds it as a lazy child ApplicationContext
| | +-- ConnectionScopeConfig.java - per-connection DataSource and DatabaseKind beans
| +-- dialect/
| | +-- SqlDialect.java - dialect interface
| | +-- PostgresDialect.java - EXPLAIN, pg_catalog, pg_get_viewdef
| | +-- OracleDialect.java - EXPLAIN PLAN, ALL_VIEWS, ALL_SOURCE, Oracle metadata queries
| | +-- SqlServerDialect.java - SHOWPLAN, sys catalog metadata, SQL Server pagination
| | +-- DialectConfig.java - implementation selection by DatabaseKind
| +-- sql/
| | +-- ReadOnlyGuard.java - JSqlParser AST guard + lexical fallback
| | +-- SqlNotAllowedException.java
| | +-- QueryResult.java - result shape
| | +-- SqlExecutor.java - query execution with limits
| | +-- BenchmarkService.java - benchmark (cold+warm) and timed (+ pg_stat_statements diff)
| +-- metadata/
| | +-- MetadataService.java - DatabaseMetaData + dialect-specific metadata
| | +-- SqliteStructureSnapshotStore.java - persistent SQLite structure snapshot
| | +-- StatsService.java - table/index stats, FK coverage, redundant/unused indexes
| | +-- DistributionService.java - column distribution / histogram / null ratio / selectivity / join cardinality
| | +-- SchemaContextService.java - high-level schema context: overview, table context, join paths, graph, lint, brief, query context
| +-- plan/
| | +-- ParsedPlan.java / PlanNode.java - unified engine-agnostic plan model
| | +-- PlanParser.java - parser interface
| | +-- PostgresPlanParser.java - JSON EXPLAIN -> tree
| | +-- OraclePlanParser.java - PLAN_TABLE -> tree
| | +-- SqlServerPlanParser.java - SHOWPLAN_XML -> tree
| | +-- PlanAnalyzer.java - summary: expensive / full scan / estimate error / nested loop / spill
| +-- usage/
| | +-- CatalogDataSourceConfig.java - SQLite WAL datasource + schema init
| | +-- CatalogStorageService.java - WAL checkpoint for distributable catalogs
| | +-- UsageCatalogService.java - ingest, lookups, observed-relationships aggregation
| | +-- format/
| | | +-- QueryUsage.java - canonical query usage record DTO
| +-- tools/
| +-- QueryTools.java - executeQuery, explainQuery, analyzePlan, validateQuery, inspectQuery, queryLint, resolveQueryLineage
| +-- MetadataTools.java - schemas / tables / describe / view / routines / sequences / search
| +-- AdminTools.java - rebuildCatalog (build structure snapshot + usage index into a distributable <catalog>.db)
| +-- SampleTools.java - sampleRows
| +-- DistributionTools.java - columnStats, columnDistribution, columnHistogram, nullRatio, estimateSelectivity, joinCardinality
| +-- StatsTools.java - tableStats, indexStats, unusedIndexes, redundantIndexes, fkIndexCoverage
| +-- BenchmarkTools.java - benchmarkQuery, timedQuery
| +-- SchemaContextTools.java - schemaBrief, tableContext, findJoinPaths, schemaLint, schemaGraph, queryContext, schemaGraphDot
| +-- UsageTools.java - usageCatalogStatus, invalidateUsageCatalogCache, getQuery, listQueries, findQueriesBy(Table|Column), observedRelationships, listKnownTags/Domains/Kinds
+-- src/main/resources/
+-- application.yml - MCP stdio + JDBC properties
+-- usage-catalog-schema.sql - DDL for the usage-catalog index (in <catalog>.db)
+-- structure-snapshot-schema.sql - DDL for the persistent structure snapshot (in <catalog>.db)
+-- logback-spring.xml - logs to stderr because stdout is used by MCPTroubleshooting
"Cannot find a Java installation ... matching languageVersion=21" - install JDK 21+ and set
JAVA_HOME. Gradle toolchains cannot download it without internet access.Connection refused / ORA-01017 / FATAL / SQL Server login failed - check the connection's
url,username, andpasswordinconnections.json. For PostgreSQL, test the URL withpsql; for Oracle, usesqlplus user/password@...; for SQL Server, test withsqlcmd -S host,1433 -d database -U user -P password.{"kind":"rejected","error":"Only SELECT / WITH / EXPLAIN statements are allowed"}- the guard worked. This is expected for any write operation. If the query is truly read-only, for example a read-only function call throughSELECT func(...), it will pass. For fully non-trivial cases, you can disable the guard with"readonlyGuard": "off"on that connection.Oracle write attempt reached the database - this should normally be blocked by the guard first. If
readonlyGuardisoff, rely on a read-only Oracle user; JDBCsetReadOnly(true)is only a best-effort hint for Oracle.Empty
describeTable/listTablesresult on Oracle - Oracle stores object names in uppercase. PassCUSTOMERS, notcustomers.SQL Server certificate errors - set the JDBC URL encryption options explicitly, for example
encrypt=true;trustServerCertificate=falsewith a trusted certificate, ortrustServerCertificate=trueonly for local/dev use.SQL Server
unusedIndexesunsupported - this tool intentionally avoidssys.dm_db_index_usage_statsbecause it usually requires elevated state-view permissions. UseindexStats,fkIndexCoverage, andredundantIndexesfor low-privilege SQL Server audits.
Available Tools
49 toolsanalyzePlananalyzePlanARead-onlyIdempotent
Diagnose query-plan performance with compact structured findings: expensive nodes, large-table full scans, estimation errors, risky nested loops and disk-sort spills. Use explainQuery when the full textual plan is required. Bind '?'->params, ':name'->namedParams; never mix. E.g. :status -> namedParams={status:'PAID'} — key is the bare name.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| params | No | Values for '?' placeholders, in order. | |
| analyze | No | Execute the query to collect runtime stats where supported (default false). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namedParams | No | Values for ':name' placeholders, keyed by name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| root | No | Root node of the execution plan. |
| engine | No | Database engine that produced the result, such as PostgreSQL, Oracle, or SQL Server. |
| analyzed | Yes | True when the plan includes actual execution metrics, not only estimates. |
| fullScans | No | Plan nodes that perform full table or index scans and may deserve attention. |
| nodeCount | Yes | Number of table nodes in the schema graph. |
| diskSpills | No | Sort or hash nodes that appear to spill to disk. |
| planningTimeMs | No | Planner time reported by the database, in milliseconds when available. |
| executionTimeMs | No | Execution time reported by the database, in milliseconds when available. |
| estimationErrors | No | Plan nodes where actual rows differ materially from estimated rows. |
| riskyNestedLoops | No | Nested-loop nodes that may be expensive because the outer side is large. |
| topExpensiveNodes | No | Plan nodes ranked as most expensive by cost or actual time. |
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. The description adds value by disclosing that output is 'compact structured findings' rather than a full textual plan and enumerates the diagnostic categories. It does not contradict annotations, though it doesn't discuss the runtime-execution implications of the analyze parameter, which is covered in the schema.
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 compact and front-loaded: first the purpose, then the alternative tool, then the binding rule with a concrete example. Every sentence earns its place with 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?
With an output schema present, detailed return structure is unnecessary. The description covers the key routing decision, the parameter binding convention, and the diagnostic scope, while remaining fields like connection and analyze are already documented in the schema. This is complete for the tool's complexity.
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 already high, but the description adds critical binding semantics beyond the schema: '?' maps to params, ':name' maps to namedParams, never mix, and the example clarifies that the object key should be the bare name without the colon. This directly helps an agent construct valid calls.
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 explicitly states the tool diagnoses query-plan performance and lists concrete findings it returns: expensive nodes, large-table full scans, estimation errors, risky nested loops, and disk-sort spills. It uses a specific verb ('Diagnose') with a clear resource ('query-plan performance') and differentiates itself from explainQuery in the next sentence.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit selection guidance: 'Use explainQuery when the full textual plan is required.' This directly tells the agent when not to use analyzePlan and which sibling tool is appropriate instead. It also includes binding instructions that guide correct invocation.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
benchmarkQuerybenchmarkQueryARead-onlyIdempotent
Measure repeatable query latency with separate cold runs and min/median/max warm-run timings. Use for comparing query rewrites, not retrieving data; timedQuery is the one-run alternative that returns rows. Bind '?'->params, ':name'->namedParams; never mix. E.g. :status -> namedParams={status:'PAID'} — key is the bare name. Returns the size of the last result (rows, columns, truncated), not the rows.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| limit | Yes | Row limit per run (> 0). | |
| params | No | Values for '?' placeholders, in order. | |
| coldRuns | No | Cold runs (default 1); executed first. | |
| warmRuns | No | Warm runs (default 3). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namedParams | No | Values for ':name' placeholders, keyed by name. | |
| timeoutSeconds | Yes | Timeout per run in seconds (> 0). |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Additional context about support, limits, interpretation, or engine-specific behavior. |
| runs | Yes | Number of measured runs included in these timing statistics. |
| allMs | No | Individual elapsed times for all benchmark executions, in milliseconds. |
| limit | Yes | Row limit applied to the query or page size requested by the caller. |
| coldMs | No | Timing statistics for cold benchmark runs in milliseconds. |
| engine | No | Database engine that produced the result, such as PostgreSQL, Oracle, or SQL Server. |
| warmMs | No | Timing statistics for warm benchmark runs in milliseconds. |
| coldRuns | Yes | Number of cold runs executed before warm measurements. |
| warmRuns | Yes | Number of warm runs used for the primary benchmark statistics. |
| resultSize | No | |
| timeoutSeconds | Yes | Per-statement timeout applied during execution, in seconds. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnly/idempotent/destructive annotations, the description discloses key behavior: it returns only the size of the last result (rows, columns, truncated) rather than the rows themselves. It also explains the binding model ('?' vs ':name') and warns against mixing them. These are meaningful behavioral details not visible in the annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three sentences deliver purpose, usage guidance, binding rules, and return behavior without filler. Information is front-loaded: the core purpose appears first, then usage alternatives, then parameter and return semantics. 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 an 8-parameter tool with an output schema, the description covers the critical invocation context: when to use it, how to bind parameters, what it returns, and why it differs from timedQuery. Remaining details like default run counts, timeout, and valid connection names are already present in the parameter schema, so nothing necessary for correct use is missing.
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 schema already documents 88% of parameters, including descriptions for 'params' and 'namedParams', so the baseline is 3. The description adds a concrete example (':status -> namedParams={status:'PAID'}'), clarifies that the key is the bare name, and warns never to mix binding styles. This adds value but is not essential given the schema's 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?
The description states a specific verb ('Measure') on a specific resource ('repeatable query latency') and defines the output as cold runs plus min/median/max warm-run timings. It also distinguishes itself from the sibling timedQuery by noting that timedQuery is the one-run alternative that returns rows. This makes the tool's purpose unambiguous and separable from 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?
It explicitly says 'Use for comparing query rewrites, not retrieving data' and names timedQuery as the alternative that returns rows. This gives the agent both a positive and negative usage condition, which is strong guidance for tool selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
columnDistributioncolumnDistributionARead-onlyIdempotent
Measure value frequency and skew for one known column by returning top-N values, counts and row shares. Use columnStats for only cardinality/extremes; runs GROUP BY + COUNT and may be expensive on large tables.
| Name | Required | Description | Default |
|---|---|---|---|
| topN | No | Top values to return (default 20, max 1000). | |
| table | Yes | ||
| column | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| topN | Yes | Maximum number of most-frequent values requested for the distribution. |
| table | No | |
| column | No | Column whose value frequencies were measured. |
| schema | No | |
| values | No | Most frequent values and their frequencies for the column. |
| topRows | Yes | Rows covered by the returned top-N value buckets. |
| topRatio | Yes | Share of all rows covered by the returned top-N buckets, from 0.0 to 1.0. |
| otherRows | Yes | Rows not represented by the returned top-N value buckets. |
| totalRows | Yes | Total number of rows considered for this statistic. |
| otherRatio | Yes | Share of all rows outside the returned top-N buckets, from 0.0 to 1.0. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is known. The description adds value beyond annotations by disclosing that execution performs GROUP BY + COUNT and may be expensive on large tables. This is useful behavioral context.
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 with no fluff. It front-loads the core purpose, immediately gives the sibling distinction, and ends with a concise performance warning. Every sentence contributes useful 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?
Given the output schema exists, the description does not need to explain return values. It covers purpose, usage distinction, and cost. The only minor gap is that it doesn't mention that schema is optional, but required parameters and the connection hint largely compensate.
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 description adds some meaning beyond the schema by clarifying that column must be a single known column and by referencing top-N values, which maps to the topN parameter. However, with only 40% schema description coverage, the description does not fully compensate for the lack of documentation on schema and table parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Measure') with a clear resource ('value frequency and skew for one known column') and states the output shape ('top-N values, counts and row shares'). It also distinguishes itself from a sibling tool, columnStats, by naming what that tool is for.
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 explicitly says when to use columnStats instead ('for only cardinality/extremes'), which implies when to use this tool (i.e., when distribution and skew are needed). It also warns that the tool runs GROUP BY + COUNT and may be expensive, giving practical usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
columnHistogramcolumnHistogramARead-onlyIdempotent
Measure percentile distribution for one orderable numeric, date, timestamp or text column: min/max, P25/P50/P75/P90/P95/P99 and null counts. Use columnDistribution for top frequent values instead.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| column | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| max | No | Maximum observed non-null column value. |
| min | No | Minimum observed non-null column value. |
| p25 | No | 25th percentile value for the column. |
| p50 | No | Median, or 50th percentile, value for the column. |
| p75 | No | 75th percentile value for the column. |
| p90 | No | 90th percentile value for the column. |
| p95 | No | 95th percentile value for the column. |
| p99 | No | 99th percentile value for the column. |
| table | No | |
| column | No | Column whose percentile distribution was measured. |
| schema | No | |
| nullRows | Yes | Number of rows where the column value is NULL. |
| nullRatio | Yes | Share of rows where the column value is NULL, from 0.0 to 1.0. |
| totalRows | Yes | Total number of rows considered for this statistic. |
| columnType | No | Database type of the column used to choose percentile behavior. |
| nonNullRows | Yes | Number of rows where the column value is not NULL. |
| percentileFunction | No | Database percentile function used, such as continuous or discrete percentile. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior, so the safety profile is covered. The description adds meaningful behavioral context beyond annotations: the accepted column types (numeric, date, timestamp, text), the requirement that the column be orderable, and the precise set of statistics returned including null 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?
The description is two sentences with no filler: the first front-loads the purpose and exact output statistics, and the second gives a clear alternative. Every word contributes to selecting or invoking the tool correctly.
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 presence of a full output schema, the description does not need to explain return values. Combined with annotations for read-only behavior and the explicit sibling routing, it covers the essential information an agent needs. A minor gap is the lack of guidance on how to specify tables/schemas, but the schema's standard parameter names make this largely self-evident.
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 only 25%; the connection parameter is well-documented in the schema itself. The description partially compensates for the undocumented column parameter by specifying that it must be an orderable numeric, date, timestamp, or text column. However, the table and schema parameters receive no added meaning, and the description does not clarify how to qualify the table or handle the optional schema parameter.
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 ('Measure') and resource ('percentile distribution for one orderable numeric, date, timestamp or text column') and enumerates exact outputs (min/max, P25/P50/P75/P90/P95/P99, null counts). It also distinguishes itself from columnDistribution by explicitly naming that sibling as the alternative for top frequent values.
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 clear context for when to use this tool: when percentile distribution for a single orderable column is needed. It explicitly instructs to use columnDistribution for top frequent values instead, providing a direct exclusion and routing the agent to a sibling tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
columnStatscolumnStatsARead-onlyIdempotent
Measure basic extremes and cardinality for one known column: total/non-null rows, distinct count and min/max. Use columnDistribution for frequent values or columnHistogram for percentiles.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| column | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| table | No | |
| column | No | Column whose basic statistics were measured. |
| schema | No | |
| maxValue | No | Maximum observed non-null value for the column. |
| minValue | No | Minimum observed non-null value for the column. |
| totalRows | Yes | Total number of rows considered for this statistic. |
| nonNullRows | Yes | Number of rows where the column value is not NULL. |
| distinctValues | Yes | Estimated or exact number of distinct non-null values. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark it read-only and idempotent, and the description adds behavioral scope: it operates on a single known column rather than scanning all columns, and it specifies exactly which statistics are computed. It does not mention return shape, but an output schema exists and the annotations cover safety.
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 clauses in a single sentence: the first states purpose and outputs, the second gives routing to siblings. Every word earns its place, with no 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 simple read-only statistics tool with an output schema, the description covers what it computes and how it differs from related tools. Remaining gaps, such as how schema is selected or null handling, are minor given the output schema and annotation set.
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 only 25% (only connection is described). The description clarifies that the column parameter targets one known column, but it does not explain table/schema semantics, the optionality of schema, or naming conventions. This insufficiently compensates for the low 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?
The description uses 'Measure' as a specific verb, identifies the resource as 'one known column', and enumerates the exact outputs (total/non-null rows, distinct count, min/max). It also names sibling tools columnDistribution and columnHistogram, distinguishing this from 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?
Explicitly states when to use this tool – for basic extremes and cardinality on one column – and when to use alternatives: columnDistribution for frequent values, columnHistogram for percentiles. The connection parameter guidance in the schema also directs the agent to listConnections for valid names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
describeTabledescribeTableARead-onlyIdempotent
Inspect one known table or view. Use for its fields/columns, types, nullability, defaults, comments, keys, indexes, constraints or triggers. Returns full metadata for that object only; use tableContext when nearby relationships or joins are also needed.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | |
| type | No | Described object type, such as TABLE, VIEW, or MATERIALIZED VIEW. |
| schema | No | |
| columns | No | Column list in database order; for keys, indexes, and joins the order is significant. |
| indexes | No | Indexes available on the table or returned by an index-statistics scan. |
| remarks | No | Database comment or description attached to the object, when the driver exposes it. |
| triggers | No | Triggers attached to the table, usually without full body unless requested (opaque). |
| primaryKey | No | |
| foreignKeys | No | Outgoing foreign keys declared by the table. |
| referencedBy | No | Incoming foreign keys from other tables that reference this table (opaque). |
| checkConstraints | No | CHECK constraints declared on the table, with raw expression and parsed allowed values when available. |
| uniqueConstraints | No | Unique constraints declared on the table. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior Mend, so the description mainly adds scope context. It discloses that it works on one known object, returns metadata for that object only, and that full metadata is the output. 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 sentences with strong front-loading: the first states the primary action and benefits, the second clarifies scope and the sibling alternative. Every phrase earns its place and there is no 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 metadata inspection tool with rich annotations and an output schema, the description is largely complete. It provides scope, alternative routing, and behavior. The only meaningful gap is the undocumented 'schema' parameter, which prevents a perfect score.
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 only 33%: only 'connection' is described in the schema. The tool description does not compensate by explaining what 'table' and 'schema' mean, whether schema is optional, or how the table identifier should be qualified. This leaves a gap for an agent selecting parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Inspect one known table or view.' It clarifies the scope and lists concrete metadata facets (fields, columns, types, nullability, defaults, comments, keys, indexes, constraints, triggers), making it distinct from sibling tools like tableContext.
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 states when to use this tool ('Inspect one known table or view') and explicitly names the alternative for related needs: 'use tableContext when nearby relationships or joins are also needed.' This gives clear routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
estimateSelectivityestimateSelectivityARead-onlyIdempotent
Estimate how selective one proposed table predicate is without executing the query. Returns planner-estimated rows, the unfiltered baseline and their ratio; use when evaluating filters or composite-index column order.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | No | ||
| predicate | Yes | Raw boolean SQL without WHERE or ';'. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Additional context about support, limits, interpretation, or engine-specific behavior. |
| table | No | Table on which the predicate selectivity was estimated. |
| schema | No | |
| predicate | No | Raw SQL predicate without the WHERE keyword used for selectivity estimation. |
| selectivity | No | Estimated predicate selectivity, calculated as estimated rows divided by baseline rows. |
| baselineRows | No | Planner row estimate for the table without the predicate. |
| estimatedRows | No | Planner or catalog estimate of rows for this object or operation. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, and the description adds the important behavior that no query is executed and that results are planner estimates rather than actual row counts. It also discloses the output shape (rows, baseline, ratio) beyond what the input schema provides, though it does not address error behavior or limits.
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 tightly packed sentences lead with the core action, then state the return values and usage context without repetition or filler. 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?
For a read-only estimation tool with idempotence annotations and an output schema present, the description provides the essential behavioral distinction (no execution), the output semantics, and the two primary use cases. Nothing critical is missing for an agent to decide whether and how to call 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?
With schema description coverage at 50%, the schema already documents predicate and connection. The description clarifies that the predicate is a proposed table filter and that the baseline is the unfiltered count, but table and schema parameters remain mostly implicit and are not described in the text, so the description only partially compensates for the coverage gap.
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 opening verb 'Estimate' plus the object 'selectivity of one proposed table predicate' states exactly what the tool computes, and 'without executing the query' sets it apart from execution-oriented siblings such as executeQuery and timedQuery. The return values and intended use cases further clarify the resource being analyzed.
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?
'Use when evaluating filters or composite-index column order' gives explicit context for choosing this tool. It does not name alternatives or explicit when-not-to-use conditions, but the 'proposed... without executing' wording makes the boundary versus query execution clear enough.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
executeQueryexecuteQueryARead-onlyIdempotent
Run a read-only SQL SELECT / WITH / EXPLAIN when actual result rows are needed. Use timedQuery for one timed execution or benchmarkQuery for repeated latency measurements. Bind '?'->params, ':name'->namedParams; never mix. E.g. :status -> namedParams={status:'PAID'} — key is the bare name. Sets 'truncated' when the row cap is hit.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| limit | No | Row limit (default JDBC_MAX_ROWS). | |
| params | No | Values for '?' placeholders, in order. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namedParams | No | Values for ':name' placeholders, keyed by name. | |
| timeoutSeconds | No | Timeout in seconds (default JDBC_QUERY_TIMEOUT_SECONDS). |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | No | Rows. |
| columns | No | Columns. |
| rowCount | Yes | Row Count. |
| truncated | Yes | Truncated. |
| columnTypes | No | Column Types. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only and non-destructive behavior, and the description adds meaningful behavioral context: 'Sets truncated when the row cap is hit.' The binding rule 'never mix' also discloses a constraint not present in the annotations. No contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences cover purpose, alternatives, binding semantics, example, and truncation behavior. The most important usage guidance 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?
The description is complete for an agent invoking the tool: it states the query types allowed, the sibling tools for timing, parameter binding rules, and the truncation signal. The output schema and annotations cover return values and safety, so nothing essential is missing.
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 83%, but the description adds real value by explaining the relationship between '?' placeholders and params, ':name' placeholders and namedParams, and gives a concrete example with the bare-name rule. This goes beyond the schema's short descriptions.
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 and resource: 'Run a read-only SQL SELECT / WITH / EXPLAIN when actual result rows are needed.' It also distinguishes the tool from timedQuery and benchmarkQuery, making it clear this is the general row-returning query tool.
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 explicitly says 'Use timedQuery for one timed execution or benchmarkQuery for repeated latency measurements,' giving an agent concrete alternative-selection criteria. The phrase 'when actual result rows are needed' further clarifies the intended use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
explainQueryexplainQueryARead-onlyIdempotent
Return the full engine-specific textual execution plan for a SELECT / WITH statement. Use when raw plan detail is needed; prefer analyzePlan for compact performance findings. Bind '?'->params, ':name'->namedParams; never mix. E.g. :status -> namedParams={status:'PAID'} — key is the bare name.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| params | No | Values for '?' placeholders, in order. | |
| analyze | No | Execute the query to collect runtime stats where supported (default false). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namedParams | No | Values for ':name' placeholders, keyed by name. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, covering the safety profile. The description adds useful behavioral context beyond that: the return is a full engine-specific textual plan, and parameter binding follows strict '?' vs ':name' conventions that must not be mixed. This is meaningful operational transparency for an agent.
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 three sentences with no filler. It front-loads the core purpose, then gives usage guidance, then explains parameter binding with an example. Every sentence contributes essential 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?
Despite having no output schema, the description tells the agent the return kind ('textual execution plan') and the tool's scope. Combined with the schema's parameter descriptions and the annotations' safety profile, the agent has enough information to select and invoke the tool correctly. The explicit binding rule and sibling alternative complete the picture.
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 80%, so the schema already documents most parameters. The description adds value by clarifying the binding model: '?' maps to params, ':name' maps to namedParams, and the example shows that the key is the bare name without the colon. This goes beyond the schema descriptions and reduces ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Return the full engine-specific textual execution plan for a SELECT / WITH statement.' It also distinguishes itself from analyzePlan by contrasting raw plan detail with compact performance findings, making sibling differentiation clear.
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 explicitly states when to use the tool ('Use when raw plan detail is needed') and names the preferred alternative for compact performance findings ('prefer analyzePlan'). This gives an agent concrete routing guidance rather than leaving the choice implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
findJoinPathsfindJoinPathsARead-onlyIdempotent
Find join paths when both endpoint tables are known but the intermediate relationships are not. Traverses declared FK and optional observed join edges in both directions; for one table's immediate neighborhood, use tableContext.
| Name | Required | Description | Default |
|---|---|---|---|
| toTable | Yes | ||
| maxDepth | No | Maximum FK hops. Default 4. | |
| maxPaths | No | Maximum paths to return. Default 5, max 25. | |
| toSchema | No | ||
| fromTable | Yes | ||
| scanLimit | No | Maximum tables to scan (default 300). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| fromSchema | No | ||
| includeObserved | No | Include usage-catalog equi-joins (default: catalog enabled). |
Output Schema
| Name | Required | Description |
|---|---|---|
| paths | No | Join paths from the source table to the target table; each path is an ordered list of steps. |
| toTable | No | |
| maxDepth | Yes | Maximum relationship traversal depth that was applied. |
| toSchema | No | |
| fromTable | No | |
| pathCount | Yes | Number of join paths returned after caps were applied. |
| fromSchema | No | |
| includeObserved | Yes | True when usage-catalog observed joins were included as relationship evidence. |
| schemaTablesScanned | Yes | Number of schema tables inspected while searching the relationship graph. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral detail beyond annotations: it traverses 'declared FK and optional observed join edges in both directions,' which clarifies the search mechanics and the includeObserved parameter intent.
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 with no filler. The purpose is front-loaded, the traversal behavior is summarized, and the sibling routing is delivered in a compact closing clause.
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 has a rich output schema and annotations covering read-only, idempotent, and non-destructive behavior, the description provides the needed selection and invocation context without forcing the agent to infer usage. It explains when to use it, what it traverses, and how it differs from a key sibling.
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 56%, so several parameters (fromTable, toTable, fromSchema, toSchema) lack schema-level descriptions. The description compensates by framing these as 'endpoint tables' and clarifying the task involves unknown 'intermediate relationships,' which directly informs how to set fromTable and toTable. It does not elaborate schema parameters, but the core ambiguity is addressed.
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 action and resource: 'Find join paths when both endpoint tables are known but the intermediate relationships are not.' It clearly distinguishes the tool from tableContext by stating that the immediate neighborhood case belongs to that sibling, so an agent can tell them apart without inspecting schemas.
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 states the precise condition to use the tool ('when both endpoint tables are known but the intermediate relationships are not') and explicitly points to the alternative ('for one table's immediate neighborhood, use tableContext'). This gives actionable selection guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
findQueriesByColumnfindQueriesByColumnARead-onlyIdempotent
Find stored application/report queries that actually reference one column and show whether it appears in SELECT, WHERE, JOIN, ORDER BY or HAVING. Use describeTable to discover declared columns; schema/table filters are optional and case-insensitive.
| Name | Required | Description | Default |
|---|---|---|---|
| table | No | ||
| column | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of matching catalog queries returned for the column. |
| table | No | Table containing the searched column. |
| column | No | |
| schema | No | |
| matches | No | Usage-catalog matches returned for the requested table, column, or filter. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only, idempotent, non-destructive behavior. The description adds meaningful details beyond that: it searches stored queries rather than live data, checks specific SQL clauses, and emphasizes that column references are 'actual' rather than merely declared. This aligns with annotations and enriches the agent's expectations.
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-loads the core behavior in the first sentence, and uses the second sentence for actionable guidance. Every phrase earns its place with no repetition of schema or annotation 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?
Given the presence of an output schema, return-value details are not required. The description covers scope, filtering behavior, and a discovery workflow. It is slightly incomplete in not explicitly steering the agent away from sibling tools like findQueriesByTable, but the core calling context is sufficiently covered.
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 only 25%, so the description must compensate. It clarifies that 'column' is the search target and that schema/table act as optional, case-insensitive filters. The connection parameter is already documented in the schema, but the description could still say more about how table/schema values are matched.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's purpose: find stored application/report queries that reference one column and show where the column appears (SELECT, WHERE, JOIN, ORDER BY, HAVING). This specific verb+resource combination distinguishes it from sibling tools like findQueriesByTable and searchObjects.
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 useful context: use describeTable to discover declared columns, and schema/table filters are optional and case-insensitive. It does not explicitly name alternatives or exclusions, but the workflow and filter behavior are clear enough for an agent to call it appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
findQueriesByTablefindQueriesByTableARead-onlyIdempotent
Find stored application/report queries that actually reference one known table. Use to learn observed filters, joins and business usage, not to inspect declared table structure; resolved names are matched case-insensitively.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of matching catalog queries returned for the table. |
| table | No | Table searched in the usage catalog. |
| schema | No | |
| matches | No | Usage-catalog matches returned for the requested table, column, or filter. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark the tool as read-only and non-destructive. The description adds meaningful behavioral details beyond that: results are based on 'actually reference[d]' tables, names are matched case-insensitively, and the focus is on observed query usage rather than declared schema. This gives the agent useful runtime expectations.
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 focused sentences deliver the core purpose, usage guidance, and a key matching rule without redundancy. The main action is front-loaded alerting an agent immediately what the tool is for.
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 output schema exists and annotations cover safety, the description is largely complete for invoking the tool correctly. It covers purpose, usage boundary, matching behavior, and required input intent. The only minor gap is not naming a sibling alternative for declared table structure, but this is not essential to making a correct call.
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 only 33%, so the description must carry parameter meaning. It partially does by explaining that the tool resolves a 'known table' and matches names case-insensitively, but it does not clarify the optional 'schema' parameter or how it constrains the search. The connection parameter is already documented in 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 opens with a specific verb and resource: 'Find stored application/report queries that actually reference one known table.' It also clarifies the intended purpose ('observe filters, joins and business usage') and explicitly contrasts with table structure inspection, making it easy to distinguish from schema-focused siblings like describeTable.
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 states when to use the tool: to learn observed filters, joins, and business usage. It also gives a when-not: 'not to inspect declared table structure.' However, it does not explicitly name the alternative tool for inspecting structure, so it falls just short of fully explicit routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fkIndexCoveragefkIndexCoverageARead-onlyIdempotent
Audit child-side foreign keys for missing supporting indexes. Returns only FKs not covered by an index starting with the FK columns in order, plus suggested index columns; use describeTable to inspect all keys and indexes of one table.
| Name | Required | Description | Default |
|---|---|---|---|
| table | No | Omit to scan the schema. | |
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| table | No | |
| schema | No | |
| uncovered | No | Foreign keys that lack a supporting child-side index. |
| tablesScanned | Yes | Number of tables inspected by the tool before caps were applied. |
| uncoveredCount | Yes | Number of foreign keys without a supporting child-side index. |
| foreignKeysTotal | Yes | Total number of foreign keys inspected for index coverage. |
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. The description adds the specific output behavior (only returns uncovF FKs, includes suggested index columns), which is useful beyond annotations. It does not mention edge cases or side effects, but for a read-only audit tool this is adequate.
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 with the core purpose first and the alternative second. No redundant wording, every sentence 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?
An output schema exists, so return-value details are covered. The description explains behavior, output filtering, and an alternative tool. The only notable gap is the undocumented schema parameter, which prevents a perfect score.
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 67%, with table and connection documented in the schema but the schema parameter is undocumented. The tool description adds no additional parameter semantics beyond the schema, leaving the schema parameter ambiguous. A score of 3 reflects the adequate but not complete parameter guidance.
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 audit task (child-side foreign keys), the precise filter (FKs not covered by an index starting with FK columns in order), and the output (suggested index columns). It also distinguishes itself from describeTable by noting what describeTable is for, making its purpose unambiguous relative to at least one sibling.
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 an explicit alternative ('use describeTable to inspect all keys and indexes of one table') and a usage condition for the table parameter ('Omit to scan the schema'). It does not enumerate when-not conditions for other sibling tools like redundantIndexes, but the context for when to use this tool is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
getQuerygetQueryARead-onlyIdempotent
Retrieve the complete stored record for one query whose source identity is already known. Returns SQL, parameters, parsed tables/columns/joins, outputs and field usages; use listQueries, findQueriesByTable or findQueriesByColumn to discover matching records first.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| sourceKind | Yes | Source kind, e.g. dao, report, database-view. | |
| sourcePath | Yes | Stable source path, e.g. file path. | |
| sourceUnit | No | Optional sub-unit, e.g. method name. |
Output Schema
| Name | Required | Description |
|---|---|---|
| tags | No | Business tags attached to the usage-catalog query. |
| rawSql | No | Original SQL text stored in the usage catalog. |
| tables | No | Tables included in this context, graph, query inspection, or usage record. |
| columns | No | Resolved column references extracted from the known query. |
| outputs | No | Documented output fields produced by the query. |
| joinPairs | No | Join pairs extracted from the query and stored in the usage catalog. |
| parameters | No | Documented parameters for this known query. |
| sourceKind | No | Kind of source that produced the catalog query, such as file, view, routine, or configured import. |
| sourcePath | No | Path or database object name where the catalog query came from. |
| sourceUnit | No | Stable unit identifier inside the source, such as query id, method name, view name, or routine name. |
| fieldUsages | No | Semantic field usages attached to the query outputs or expressions. |
| parseStatus | No | SQL parse status for a catalog query, such as parsed or failed. |
| businessLabel | No | |
| normalizedSql | No | Normalized SQL text produced by parser or usage-catalog indexing. |
| businessDomain | No | Business domain assigned to the catalog query or usage record. |
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 value by specifying exactly what the returned record contains (SQL, parameters, parsed components, outputs, field usages), which is behavioral detail beyond the annotations. It does not contradict annotations and does not discuss edge cases like pagination, but that is minor for a read-only retrieval tool.
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 with zero waste: the first states purpose and return content, the second gives routing to sibling tools. The most important info is front-loaded, 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?
For a read-only retrieval tool with a full output schema and complete parameter documentation, the description is complete. It covers purpose, what is returned, and how to discover the required identity. The existence of an output schema means return-value details need not be repeated, and annotations cover safety. Nothing an agent needs to call it correctly is missing.
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 (connection, sourceKind, sourcePath, sourceUnit) having a description. The description adds the concept of 'source identity' and that these parameters identify the query, but it does not add syntax or format details beyond what the schema already provides. Since the schema carries the heavy lifting, the baseline 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 verb ('Retrieve') with a clear resource ('the complete stored record for one query') and explicitly enumerates the returned content (SQL, parameters, parsed tables/columns/joins, outputs, field usages). It also names sibling tools (listQueries, findQueriesByTable, findQueriesByColumn) as the discovery path, distinguishing this retrieval tool from search 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 explicitly tells the agent when to use this tool: when the source identity is already known, and instructs to use listQueries, findQueriesByTable, or findQueriesByColumn to discover matching records first. This provides clear context and exclusions, leaving no ambiguity about when to select this tool over its siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
getRoutineDefinitiongetRoutineDefinitionARead-onlyIdempotent
Return the source code of one known function, procedure or package, including its body where available. Use listRoutines to discover routine names.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint, so the safety profile is covered. The description adds one useful behavioral nuance: the body is included 'where available', implying some routines may have no body. It does not contradict annotations, though it does not discuss error behavior or permissions.
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 with no filler: the primary behavior is front-loaded and the discovery pointer is a single clear clause. 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?
The description covers the core return value (source code, body where available) and directs agents to listRoutines for discovery, while annotations cover the safety profile. The main gap is the undocumented optional schema parameter and absence of not-found/error behavior, but for a simple read-only getter this is nearly complete.
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 only 33%, with only connection documented. The description adds meaning for name by calling it a known routine and pointing to listRoutines, but the optional schema parameter is never explained and name lacks format details. With low schema coverage, the description only partially compensates.
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 ('Return the source code') on a defined resource ('one known function, procedure or package') and clarifies scope with 'including its body where available.' It also points to listRoutines for discovery, which helps differentiate it from search-oriented 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?
It explicitly tells agents to use listRoutines to discover routine names, which provides clear context for when to use that sibling first. It does not spell out exclusions like triggers/views, but the 'known' routine requirement implies this tool is for direct retrieval, not discovery.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
getTriggerDefinitiongetTriggerDefinitionARead-onlyIdempotent
Return the full definition/body of one known table trigger. For trigger names and compact metadata, use describeTable first.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | No | ||
| trigger | Yes | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already convey read-only, idempotent, and non-destructive behavior. The description adds a small amount of context: it returns the 'full definition/body' and requires a 'known' trigger. It does not contradict annotations, nor does it provide extra detail on errors or missing-trigger behavior.
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 with no filler. The primary purpose is front-loaded, and the routing guidance is placed second. Every clause adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only lookup by identifier, the description is sufficient: it tells the agent what to retrieve and directs it to find identifiers when absent. Gaps are minor: it does not explicitly describe return format, missing-trigger behavior, or whether schema is optional, but the simple nature of the tool and the annotations reduce the burden.
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 only 25% (connection only). The description partially compensates by saying 'one known table trigger' and routing to describeTable for trigger names, which implies what table and trigger mean. However, it leaves schema semantics, the optional nature of schema, and trigger/table formatting details to be inferred.
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-resource pair: 'Return the full definition/body of one known table trigger.' It is clearly distinct from the metadata-focused describeTable, and the phrase 'table trigger' differentiates it from sibling tools like getRoutineDefinition or getViewDefinition.
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 second sentence gives an explicit precondition: use describeTable first when you need trigger names or compact metadata. It makes clear the tool expects a known, specific trigger, which is exactly the guidance an agent needs to decide between this tool and its sibling metadata tools.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
getViewDefinitiongetViewDefinitionARead-onlyIdempotent
Return the SQL text that defines one known view or materialized view. For its exposed fields, keys and other object metadata, use describeTable.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
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 'known view' constraint and the return type (SQL text), which is useful but not deeply behavioral; it does not describe error cases or catalog assumptions.
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 with no filler. The core behavior is front-loaded, and the alternative tool is mentioned immediately after the main statement. Every word 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 simple read-only metadata tool with rich annotations, the description is mostly complete: it states what is returned, scopes the operation to known views, and names the sibling for metadata. The main gap is the lack of parameter-level guidance for name/schema, but the overall shape is adequate.
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 only 33%, with only 'connection' described in the schema. The description does not explain the 'name' or 'schema' parameters or how they relate to the 'known view' concept, so it fails to compensate for the low 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?
The description uses a specific verb ('Return') and resource ('SQL text that defines one known view or materialized view'), making the tool's function immediately clear. It also distinguishes itself from describeTable by explicitly routing metadata needs elsewhere.
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 clear usage context: use this when you need the defining SQL of a known view/materialized view. It also names describeTable as the alternative when exposed fields, keys, or object metadata are needed, which is an explicit when-not condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
indexStatsindexStatsARead-onlyIdempotent
Inspect index definitions together with operational size, usage and cardinality counters for one table or a schema. Use describeTable for structural metadata of one table without live index statistics.
| Name | Required | Description | Default |
|---|---|---|---|
| table | No | Omit to scan the schema. | |
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| indexes | No | Indexes available on the table or returned by an index-statistics scan. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false, and idempotentHint=true, so the safety profile is covered. The description adds context about the nature of the returned data (live counters) but does not describe pagination, empty-result behavior, or permission requirements. Given the annotation coverage, a 3 is appropriate – it adds some value but not extensive behavioral detail.
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 with zero redundancy: the first states the core purpose and scope, the second provides the key alternative. The most important information (what it does and its scope) is front-loaded, and every word 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 read-only inspection tool with an output schema present, the description covers the essential use case and scope (table or schema), and explicitly points to the alternative when live stats are not needed. It omits any mention of performance implications or result size, but these are not critical for a tool of this type, and the annotations cover safety. The definition is sufficiently complete for an agent 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?
Schema description coverage is 67% (connection and table have descriptions, schema does not). The description clarifies that table is optional ('Omit to scan the schema') and that the tool works for 'one table or a schema', giving meaning to the schema parameter beyond the schema field. However, it does not explicitly document the schema parameter's format or interplay with table, so the compensation is partial. Baseline 3 is fair.
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 ('Inspect'), a clear resource ('index definitions'), and the precise data returned (operational size, usage, cardinality counters) for a table or schema. It explicitly differentiates itself from describeTable by contrasting 'live index statistics' with structural metadata, so an agent can distinguish it from a sibling without opening schemas.
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?
Gives explicit when-to-use context (inspecting index stats) and names describeTable as the alternative for structural metadata without live stats. It does not address other index-focused siblings like unusedIndexes or redundantIndexes, but the primary differentiation is clear and the usage scenario is unambiguous.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
inspectQueryinspectQueryARead-onlyIdempotent
Inspect SQL syntax and structure without accessing a database. Returns a parser-derived AST summary of tables, aliases, expressions, joins, predicates, ordering, columns and parameters; use validateQuery for driver validation or queryLint for metadata-aware advice.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| joins | No | Join clauses detected in the query. |
| tables | No | Table references extracted from the query, including CTEs and subqueries where possible. |
| aliases | No | Map of SQL alias to referenced table or expression. |
| columns | No | Column references extracted from all inspectable SQL clauses. |
| explain | No | True when the inspected statement is an EXPLAIN statement. |
| orderBy | No | ORDER BY expressions in the query. |
| cteNames | No | Common table expression names declared by the query. |
| features | No | |
| warnings | No | Warnings produced while parsing and inspecting the query. |
| parseable | No | True when SQL parsing succeeded well enough to produce structured inspection data. |
| parameters | No | SQL placeholders or documented query parameters. |
| predicates | No | Predicate expressions extracted from WHERE, JOIN, HAVING, and related scopes. |
| selectItems | No | Expressions in the SELECT list, in output order. |
| normalizedSql | No | Normalized SQL text produced by parser or usage-catalog indexing. |
| statementType | No | Top-level SQL statement type detected by the parser. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the readOnlyHint annotation, the description adds the significant behavioral detail that the tool does not access a database and that the result is parser-derived. It also lists what the AST summary contains, giving the agent accurate expectations of the tool's behavior.
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 compact and front-loaded: purpose, behavioral claim, output, and alternatives all appear in one efficient sentence. Every clause earns its place, with no redundant elaboration.
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 two-parameter parser tool with an output schema and read-only annotations, this description is complete. It covers the tool's scope, output nature, and sibling alternatives, and the remaining connection nuance is at least partially handled by the schema's instructions.
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 description explains what the SQL input is used for, but the connection parameter remains ambiguous: the schema says 'Database to run against' while the description says 'without accessing a database.' With only 50% schema description coverage, the description should clarify why the connection is needed despite no database access.
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 action ('Inspect SQL syntax and structure') and a clear resource (SQL), and immediately distinguishes the tool from close siblings by listing what it returns and by naming validateQuery and queryLint as alternatives. An agent can tell exactly what this tool does without inspecting schemas.
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 explicitly tells the agent when not to use this tool: 'use validateQuery for driver validation or queryLint for metadata-aware advice.' This provides concrete routing among siblings and enough context to select inspectQuery for syntax/structure inspection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
invalidateUsageCatalogCacheinvalidateUsageCatalogCacheARead-onlyIdempotent
Force the server-local usage index to be rebuilt after its configured sources change. Invalidates only the runtime/local index; the next usage lookup rebuilds it synchronously and no inspected database data is modified.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| state | No | Current usage-catalog index state, such as not_started, indexing, ready, or failed. |
| sources | No | Configured usage-catalog source paths and database-native sources considered for indexing. |
| indexing | Yes | True while the usage catalog index is being built. |
| connection | No | Name of the connection this catalog belongs to. |
| catalogEnabled | Yes | False when the usage catalog is disabled; true when indexing and lookups are allowed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false; the description reinforces this with 'no inspected database data is modified' and adds specifics about synchronous rebuild on next lookup, which is 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?
Two sentences, front-loaded with purpose, no fluff. Every sentence contributes essential 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 one parameter, an output schema present, and annotations covering safety, the description fully covers purpose, trigger, scope, and behavior. Nothing an agent needs to call it correctly is missing.
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 schema description already fully documents the single parameter at 100% coverage ('Call listConnections for valid names; do not guess'). The tool description adds no additional parameter context, so 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?
States a specific verb+resource ('Force the server-local usage index to be rebuilt') and distinguishes the scope ('runtime/local index' only). Clearly differentiates from a full rebuild by noting it invalidates and rebuilds on next lookup.
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 a clear trigger ('after its configured sources change') and clarifies that it only affects the runtime/local index, implying when to use it over a full rebuild. However, it does not explicitly name alternative tools like rebuildCatalog.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
joinCardinalityjoinCardinalityARead-onlyIdempotent
Estimate the output size and selectivity of a proposed equi-join between two known tables without executing it. Returns planner estimates for both sides and versus the Cartesian product; use findJoinPaths when the join route itself is unknown.
| Name | Required | Description | Default |
|---|---|---|---|
| toTable | Yes | ||
| joinType | No | Join type: INNER (default), LEFT, RIGHT, FULL | |
| toSchema | No | ||
| fromTable | Yes | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| fromSchema | No | ||
| leftColumn | Yes | Column in fromTable. | |
| rightColumn | Yes | Column in toTable. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Additional context about support, limits, interpretation, or engine-specific behavior. |
| toTable | No | Right or joined target table for the join estimate. |
| joinType | No | Join type used for the estimate or parsed join, such as INNER, LEFT, RIGHT, or FULL. |
| toSchema | No | |
| fromTable | No | Left or preserved source table for the join estimate. |
| fromSchema | No | |
| leftColumn | No | Column from the source table used on the left side of the join estimate. |
| rightColumn | No | Column from the target table used on the right side of the join estimate. |
| cartesianRows | No | Product of the two side row estimates before applying join selectivity. |
| estimatedRows | No | Planner or catalog estimate of rows for this object or operation. |
| toRowEstimate | No | Planner row estimate for the target table before joining. |
| fromRowEstimate | No | Planner row estimate for the source table before joining. |
| selectivityVsCartesian | No | Estimated join output divided by cartesian row count, from 0.0 to 1.0 when known. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, destructiveHint, and idempotentHint. The description adds behavioral value by stating it returns planner estimates (not actual results) and compares against the Cartesian product, which goes beyond the annotation. 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 sentences, no filler, purpose front-loaded, and the alternative is stated succinctly. Every word contributes.
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 cardinality estimation tool, it covers the core behavior (what it estimates, that it doesn't execute, what it returns) and the key alternative. It does not mention error conditions or catalog prerequisites, but given the output schema is provided separately, it is sufficiently complete for an agent to use correctly in most cases.
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 50%; the schema describes joinType, connection, leftColumn, and rightColumn, but not the table/schema parameters. The description mentions 'known tables' and 'equi-join' but does not clarify the meaning or relationship of parameters beyond what the schema already offers. It adds minimal value for parameter understanding.
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 ('estimate'), a specific resource ('output size and selectivity of a proposed equi-join between two known tables'), and explicitly notes it does not execute. It distinguishes itself from findJoinPaths by naming the alternative, making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides an explicit when-not condition ('use findJoinPaths when the join route itself is unknown'), giving clear usage context. However, it doesn't address other potential siblings like estimateSelectivity or analyzePlan, leaving some routing ambiguity for an agent.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listConnectionslistConnectionsARead-onlyIdempotent
Discover the databases served here and the valid name to pass as 'connection'. Call when the target connection is not already established; returns purpose, engine, default schema and local-catalog availability without opening a database connection.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| connections | No | Configured connections, in configuration order. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and no destructiveness. The description adds valuable behavioral context beyond annotations by stating it returns purpose, engine, default schema, and local-catalog availability, and notably that it works 'without opening a database connection.'
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 with no filler: the first states the core capability and output, the second gives a usage condition and return details. Information is front-loaded 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?
For a parameterless discovery tool with rich annotations and an output schema, the description fully explains what the tool does, when to call it, what behavior to expect, and what the results contain. Nothing essential is missing.
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 still adds useful semantic context by explaining that the output provides the valid name to pass as 'connection' to other tools.
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 ('Discover') and resource ('databases served here' and valid 'connection' names), clearly differentiating this discovery tool from siblings like listSchemas or listTables. It also specifies the exact output purpose: returning a valid name to pass as the 'connection' parameter.
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 an explicit condition: 'Call when the target connection is not already established.' This implies the inverse case clearly, but it does not name alternative sibling tools or explicitly state when not to call beyond that condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listKnownDomainslistKnownDomainsARead-onlyIdempotent
Discover the existing business-domain vocabulary and query counts for reuse in listQueries filters.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| domains | No | Known business domains and their usage counts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds behavioral value by disclosing that the result contains existing vocabulary and query counts, which is useful beyond the annotation-only picture.
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 sentence carries the purpose, the resource, and the intended reuse without any filler. Every word contributes, and the key discriminator ('for reuse in listQueries filters') appears at the end for natural reading.
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 one documented parameter, an output schema, and safety annotations, the description is complete enough. An agent can infer what it returns, why to call it, and that it is non-destructive without needing 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 description coverage is 100% for the single required parameter, and the schema already documents that 'connection' is a database name and instructs agents to call listConnections rather than guess. The tool description itself adds no parameter-level detail, so 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 specific verb ('Discover') and a precise resource: 'existing business-domain vocabulary and query counts.' It also names the downstream use ('reuse in listQueries filters'), which clearly distinguishes it from plain enumeration tools like listKnownKinds or listKnownTags.
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 clear context by saying the output is meant for reuse in listQueries filters, so an agent knows when it is relevant. It does not explicitly say when not to use alternatives like listKnownKinds or listKnownTags, but the intended use case is specific enough to route selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listKnownKindslistKnownKindsARead-onlyIdempotent
Discover valid usage-catalog source-kind values and their query counts for reuse in listQueries filters.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| kinds | No | Known source-kind values and their usage counts. |
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 useful context by mentioning query counts and the usage-catalog source, but it does not disclose potential caveats like cache freshness or open-world value variability, which would have added more value.
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 phrase earns its place: what is discovered, what is included, and why the result matters.
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 one-parameter, read-only tool with a rich output schema and strong annotations, the description is complete. The agent knows when to call it, what it returns, and how the result should be used.
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 single connection parameter is well documented, including guidance to call listConnections for valid names. The description itself does not add new parameter-level meaning, but the schema already carries the full burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Discover') with a specific resource ('valid usage-catalog source-kind values and their query counts') and states the intended downstream use ('for reuse in listQueries filters'). This clearly differentiates it from sibling tools like listKnownDomains, listKnownTags, and listQueries.
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 when to use this tool: when valid source-kind values are needed for listQueries filters. It provides clear context but does not explicitly name alternatives or state when not to use it, so it stops short of the strongest guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listKnownTagslistKnownTagsARead-onlyIdempotent
Discover the existing business-tag vocabulary and query counts for reuse in listQueries filters.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| tags | No | Business tags attached to the usage-catalog query. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds no extra behavioral traits such as performance expectations, cache dependence, or return volume, but it doesn't contradict the annotations either.
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 sentence of 14 words, with the core action and resource front-loaded and the context at the end. There is zero filler; every word contributes to explaining what the tool does or why it should be used.
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, read-only discovery tool with a rich output schema and full annotation coverage, the description is complete. It tells the agent what will be returned (tag vocabulary and counts) and how to use it (for listQueries filters), leaving no critical gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The only parameter, connection, is fully documented in the schema with a description that even points to listConnections for valid values. The tool description adds no additional meaning beyond the schema, which has 100% coverage, so the baseline 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 uses a specific verb ('Discover') and resource ('business-tag vocabulary and query counts') and immediately states its integration purpose ('for reuse in listQueries filters'). This clearly distinguishes it from siblings like listKnownDomains and listKnownKinds, which handle other vocabularies.
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 a clear context for when to use the tool: when building filters for listQueries. However, it does not explicitly mention alternatives or when not to use it (e.g., when domains/kinds are needed), so it stops short of full exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listQuerieslistQueriesARead-onlyIdempotent
Browse or search stored usage-catalog queries by source, business metadata, parse status or free text. Returns summaries newest-ingest first; use getQuery for the complete SQL and evidence of one selected record.
| Name | Required | Description | Default |
|---|---|---|---|
| tag | No | Exact tag. | |
| limit | No | Rows to return (default 100, max 1000). | |
| offset | No | Paging offset (default 0). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| searchText | No | Case-insensitive full-text search over SQL, labels, domains and source paths. | |
| sourceKind | No | Source kind, e.g. bi-publisher-report or dao. | |
| sourcePath | No | Source path LIKE pattern ('%'/'_'). | |
| parseStatus | No | Parse status: parsed or failed. | |
| businessDomain | No | Exact business domain. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of query entries returned in this page. |
| limit | Yes | Row limit applied to the query or page size requested by the caller. |
| offset | Yes | Zero-based result offset for pagination, or true when SQL contains OFFSET depending on context. |
| queries | No | Usage-catalog query entries returned by the current filter or disabled-catalog response. |
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 valuable behavioral context beyond annotations by specifying that results are 'summaries newest-ingest first' and that the complete SQL and evidence require a follow-up getQuery call. This informs ordering and return granularity without contradicting 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 with no filler. The first sentence states the tool's purpose and filter dimensions; the second explains result ordering and directs the agent to getQuery for deeper detail. This is efficient, front-loaded, and every clause adds useful 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?
For a read-only browsing/search tool, the description is complete: it explains the resource, the search dimensions, the result type ('summaries'), the sort order ('newest-ingest first'), and the relationship to getQuery for full detail. An output schema exists, so return-value details are not required in the description. Combined with the schema's thorough parameter documentation and the non-destructive annotations, an agent has everything needed to call this tool 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?
Schema description coverage is 100%, so the baseline is 3 because the schema already documents all nine parameters. The description does add a light conceptual grouping ('source, business metadata, parse status or free text'), but this mostly mirrors parameter names like sourceKind, sourcePath, businessDomain, parseStatus, and searchText. It does not introduce new semantic detail such as value formats, LIKE patterns, or interaction between filters 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 states a specific verb ('Browse or search') on a specific resource ('stored usage-catalog queries') and lists the filtering dimensions: source, business metadata, parse status, and free text. It also distinguishes itself from getQuery by noting that listQueries returns summaries while getQuery provides complete SQL and evidence. This makes the tool's purpose immediately clear and separable from its 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?
The description gives clear context for when to use the tool versus getQuery: use listQueries for browsing/searching summaries, then getQuery for full SQL and evidence of a selected record. It does not explicitly mention exclusions against searchObjects or other sibling search-like tools, but the emphasis on 'usage-catalog queries' implies the intended scope. The guidance is clear enough for an agent to make a sound initial selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listRoutineslistRoutinesARead-onlyIdempotent
Discover function, procedure and package names in a schema, optionally by name pattern. Use getRoutineDefinition when the source of one known routine is needed.
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namePattern | No | JDBC name pattern, e.g. '%calculate%'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| routines | No | Function, procedure, and package entries. |
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 value by specifying the resource types (functions, procedures, packages) and optional pattern filtering, which goes beyond annotations. It doesn't describe pagination or ordering, but output schema 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?
Two sentences, zero waste. Purpose is front-loaded, and the alternative is given immediately after. Very efficient.
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 listing tool with an output schema and read-only annotations, the description covers key decision points: what is listed, optional pattern, and when to use the alternative. It doesn't mention pagination or limits, but those are likely in the output schema. It's sufficiently complete for an agent to call 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?
Schema coverage is 67%, so the baseline is 3. The description mentions 'in a schema' and 'by name pattern' which adds meaning to the schema and namePattern parameters. The connection parameter is documented in-schema with a directive to call listConnections. The schema parameter lacks in-schema documentation but is implied in the description, though not explicitly detailed.
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 'Discover function, procedure and package names in a schema' – a clear verb, resource, and scope. It also explicitly distinguishes from getRoutineDefinition, making it easy to select the right tool.
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?
Explicitly states when to use the alternative getRoutineDefinition ('when the source of one known routine is needed') and mentions the optional name pattern, which implies when to use it. Doesn't exhaustively cover all sibling listings but gives the primary decision.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listSchemaslistSchemasARead-onlyIdempotent
Discover schema names visible to the current user when the target schema is unknown. Use listTables next to enumerate objects in one schema.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| includeSystem | No | Include system schemas. Default false. |
Output Schema
| Name | Required | Description |
|---|---|---|
| schemas | No | Schema names. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, covering the safety profile. The description adds a small behavioral detail: it lists schemas 'visible to the current user,' which is helpful. It does not describe pagination, ordering, or potential system schema inclusion (though that is covered in the parameter). Given the annotations carry the main burden, a 3 is appropriate – the description adds some context but not rich behavioral detail.
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 with no redundancy. The primary purpose is stated first, and the follow-up action is provided succinctly. Every word earns its place, and it is appropriately short for a simple discovery tool.
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 low-complexity tool with an output schema (not shown but indicated), the description covers when to use it, what it returns, and the next step. It lacks explicit mention of error handling or permissions, but the annotations cover safety. The only minor gap is not stating what happens if the schema is already known, but that is implicit in the phrase 'when the target schema is unknown.' Overall, it is complete enough for correct usage.
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 covers 100% of parameters with descriptions, including guidance to call listConnections for valid names and the default for includeSystem. The tool description itself does not add parameter-level information beyond the purpose. Since the schema already provides the needed semantics, the baseline of 3 applies without additional value from the description.
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 ('Discover') and resource ('schema names'), and clearly scopes the use case: 'when the target schema is unknown.' It also distinguishes itself from a sibling tool by mentioning listTables for the next step, making it unambiguous which tool to use for schema discovery versus object enumeration.
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 provides a clear condition for use ('when the target schema is unknown') and suggests a follow-up action ('Use listTables next'). It also indirectly references listConnections in the parameter description for valid connection names. However, it does not explicitly mention when not to use this tool or alternatives like searchObjects, though the context is fairly clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listSequenceslistSequencesARead-onlyIdempotent
Discover sequence names and metadata in one schema, or across all schemas when schema is omitted.
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| sequences | No | Sequence entries. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry the safety profile (readOnlyHint, idempotentHint, destructiveHint=false), so the bar for the description is lower. The description adds the one non-obvious behavioral trait beyond those hints: the schema parameter is optional, and omitting it changes the result scope to 'across all schemas.' No contradiction with the annotations 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 17-word sentence with the verb and resource front-loaded, followed by the scoping conditional. Every word earns its place — no filler and no repetition of what the schema or annotations already state.
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 2-parameter, read-only discovery tool, the description plus an output schema and safety annotations cover everything an agent needs: connection-parameter behavior is in the schema, schema-omission behavior is in the description, and return values are covered by the output schema. Nothing required for correct invocation is missing.
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 only 50% — the schema parameter has no schema-level documentation. The description compensates by explaining the schema parameter's semantics ('in one schema, or across all schemas when schema is omitted'), telling the agent that omission is valid and changes the scope. The connection parameter is already documented in the schema, so the description need not repeat it.
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 pairs a specific verb ('Discover') with a precise resource ('sequence names and metadata') and states the scoping behavior ('in one schema, or across all schemas when schema is omitted'). This is a specific verb+resource that distinguishes it from sibling list tools like listSchemas, listTables, and listRoutines by its unique resource type.
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 schema-scoping statement ('across all schemas when schema is omitted') gives useful context on how to invoke the tool for different result sets, and the resource name clarifies its niche relative to list* siblings. However, it never explicitly names alternatives or states when NOT to use it, leaving tool selection among the 50+ siblings to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
listTableslistTablesARead-onlyIdempotent
Enumerate table and view names in a known schema, optionally filtered by name or type. Does not return fields/columns; use describeTable for one object's structure.
| Name | Required | Description | Default |
|---|---|---|---|
| types | No | JDBC table types CSV (default TABLE,VIEW,MATERIALIZED VIEW): TABLE,VIEW,MATERIALIZED VIEW,SYSTEM TABLE,GLOBAL TEMPORARY,LOCAL TEMPORARY,ALIAS,SYNONYM | |
| schema | No | Omit to use JDBC_DEFAULT_SCHEMA or the current schema. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namePattern | No | JDBC pattern ('%' any, '_' one character). |
Output Schema
| Name | Required | Description |
|---|---|---|
| tables | No | Table and view entries. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate readOnlyHint, idempotentHint, and destructiveHint false, so safety is covered. The description adds useful behavioral context beyond that: it returns only names, not columns, and supports optional filtering by name or type. This is modest but meaningful added disclosure.
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, zero filler, and the core purpose is front-loaded in the first phrase. Every word contributes to clarifying scope or routing to an alternative.
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 listing tool, the description covers purpose, filter options, and the key limitation (no columns). The output schema exists, and the parameter schema covers all inputs, so nothing essential for correct invocation is missing.
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 four parameters are fully documented in the schema itself. The description's phrase 'filtered by name or type' roughly maps to namePattern and types, but it adds no new semantic detail beyond what the schema already provides, so the baseline 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 uses a specific verb ('Enumerate') and names the resource ('table and view names'), with a clear scope ('in a known schema'). It also explicitly distinguishes itself from describeTable by stating it does not return fields/columns, which prevents confusion with a close sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit when-not guidance ('Does not return fields/columns') and names the specific alternative to use ('use describeTable for one object's structure'). This tells the agent exactly which tool to select for a different need.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
nullRationullRatioARead-onlyIdempotent
Find sparse or mostly-null fields across every column of one table in a single scan. Returns null/non-null counts and ratios sorted by sparsity; use describeTable when only declared nullability is needed.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| table | No | |
| schema | No | |
| columns | No | Per-column null-ratio entries, sorted by descending null ratio. |
| totalRows | Yes | Total number of rows considered for this statistic. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds valuable behavioral detail beyond that: it performs a single scan, scans every column, returns null/non-null counts and ratios, and sorts by sparsity. These are meaningful execution traits that help an agent anticipate behavior and cost. 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?
The description is a single, dense sentence that front-loads the core purpose, then specifies the output, then gives the routing alternative. There is zero fluff; every clause earns its place. It is highly efficient 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?
Given the tool's simplicity (3 parameters, 2 required), the description covers purpose, output shape (counts, ratios, sorting), scope (every column, one table), and usage routing. An output schema exists, so return details are already structured. Nothing an agent needs to correctly invoke this tool is missing.
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 only 33% (only the connection parameter has a description). The tool description does not add parameter-level semantics, but the parameter names (table, schema, connection) are self-explanatory, and the connection parameter has a useful schema description ('Call listConnections for valid names; do not guess'). The description implies that table and schema identify the target table, so the agent can infer usage. This is adequate but not enhanced 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 a specific verb ('Find') and resource ('sparse or mostly-null fields across every column of one table'), clearly stating what the tool does. It also differentiates from a sibling by naming describeTable as the alternative when only declared nullability is needed, so an agent can distinguish it without inspecting schemas.
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 explicitly tells the agent when to use this tool (when actual null counts/ratios are needed) and when to use the alternative ('use describeTable when only declared nullability is needed'). This is direct routing guidance that leaves no ambiguity about selection among siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
observedRelationshipsobservedRelationshipsARead-onlyIdempotent
Discover empirically observed equi-join column pairs from stored queries, with support counts and contributing query IDs. Use findJoinPaths for declared/combined paths between endpoints; non-equi joins are excluded.
| Name | Required | Description | Default |
|---|---|---|---|
| table | No | Require either join side to use this table. | |
| schema | No | Case-insensitive filter. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| minSupport | No | Minimum supporting queries (default 1). |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of observed relationships returned after filtering. |
| table | No | Optional table filter used when aggregating observed relationships. |
| schema | No | |
| minSupport | Yes | Minimum observed support threshold applied to relationship aggregation. |
| relationships | No | Relationship edges relevant to the context, graph, or observed-relationships result. |
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 agent knows this is a safe read operation. The description adds that it is 'empirically observed' from stored queries and that non-equi joins are excluded, which is useful context. However, it doesn't disclose details like whether results are paginated, how support counts are computed, or whether the catalog must be fresh. With annotations covering the safety profile, 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 with zero waste. The core purpose is front-loaded, and the alternative tool is named in the second sentence. Every word 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?
The tool has an output schema, so the description needn't explain return values. The description covers purpose, scope, exclusions, and the alternative tool. The only minor gap is that it doesn't mention whether the results are limited to the current catalog or whether the catalog needs to be populated, but given the output schema and annotations, this is nearly complete.
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 four parameters. The description adds the context that the tool returns support counts and contributing query IDs, which helps understand the minSupport parameter's meaning, but it doesn't add syntax or format details beyond what the schema provides. Baseline 3 is correct when the schema does the heavy lifting.
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 ('Discover'), a specific resource ('empirically observed equi-join column pairs from stored queries'), and the output includes support counts and contributing query IDs. It also explicitly distinguishes itself from findJoinPaths, which is a sibling tool, by noting that findJoinPaths is for declared/combined paths and that non-equi joins are excluded. This makes the tool's purpose unambiguous and differentiates it from 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?
The description explicitly says 'Use findJoinPaths for declared/combined paths between endpoints; non-equi joins are excluded.' This provides clear when-to-use and when-not-to-use guidance, naming the alternative tool and the condition that selects it. The connection parameter also instructs to call listConnections for valid names, which is a usage guideline.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryContextqueryContextARead-onlyIdempotent
Build multi-table SQL-authoring context from natural-language terms or an explicit table list. Use when relevant tables are unknown or a request spans several tables; for one known table's fields or structure, use describeTable.
| Name | Required | Description | Default |
|---|---|---|---|
| terms | No | User terms, e.g. 'customers order totals'. | |
| schema | No | ||
| tables | No | Force-include tables (CSV), e.g. customers,orders. | |
| maxTables | No | Tables to include (default 12). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| includeSamples | No | Include up to 3 rows per table (default false). |
Output Schema
| Name | Required | Description |
|---|---|---|
| terms | No | Natural-language terms used to select relevant schema context. |
| schema | No | |
| tables | No | Tables included in this context, graph, query inspection, or usage record. |
| joinPaths | No | Shortest or suggested join paths between selected tables. |
| tableCount | Yes | Number of tables selected into the query context. |
| relationships | No | Relationship edges relevant to the context, graph, or observed-relationships result. |
| includeSamples | Yes | True when small sample rows were requested for selected tables. |
| requestedTables | No | Explicit table names requested by the caller for query context. |
| semanticMatches | No | Tables matched by semantic usage-catalog terms before final context assembly (opaque). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly/idempotent/non-destructive behavior, so the description need not repeat safety information. It adds behavioral context that this is a context-building/selection operation rather than a query or analysis operation, and clarifies the multi-table scope. It does not detail all internal behavior, but that is not required given the rich 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 sentences with no filler, and the core operation plus the primary usage condition appear first. Every sentence earns its place by either defining the tool or guiding routing.
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 schema-introspection tool with an output schema, six parameters, and strong annotations, the description plus input schema fully cover selection and invocation. The only required parameter (connection) is marked required and referenced in its own schema description with a pointer to listConnections.
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 83%, and the schema already documents terms, tables, maxTables, connection, and includeSamples. The description adds only a high-level mapping from terms/tables to the purpose, which is useful but not materially 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?
Description opens with a specific verb and object ('Build multi-table SQL-authoring context') and specifies two input modes (natural-language terms, explicit table list). It names describeTable as the alternative, so the tool is distinguishable from its closest sibling 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?
'Use when relevant tables are unknown or a request spans several tables' gives explicit trigger conditions, and 'for one known table's fields or structure, use describeTable' gives an explicit exclusion and alternative. No inference is required.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
queryLintqueryLintARead-onlyIdempotent
Review authored SQL for advisory metadata and indexing problems without executing it. Reports unknown objects, SELECT *, conditionless joins, unindexed FKs and non-leading predicate/order columns; use validateQuery when database-driver acceptance is the question.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| lintable | Yes | True when query lint could combine parsed SQL with metadata checks. |
| warnings | No | Warnings produced by SQL inspection and metadata-aware lint checks. |
| inspection | No | Parsed query inspection that underpins lint (opaque; the inspectQuery tool returns the typed form). |
| warningCount | No | Number of warnings produced by inspection or lint. |
| tablesChecked | No | Tables whose metadata was checked during query lint. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, idempotent, and non-destructive. The description adds valuable behavioral detail by listing the specific problem categories it reports (unknown objects, SELECT *, conditionless joins, etc.) and reiterates that it does not execute the SQL, which is consistent with 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, dense sentence that front-loads the purpose and then enumerates the checks. It is efficient and well-structured, though the long list of issue types adds length without being verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose, scope, and a key alternative. An output schema exists, so return values are covered. However, the lack of parameter explanations (especially 'schema') and the absence of any prerequisite or connection context leave gaps for a 3-parameter tool.
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 only 33% (only 'connection' has a description). The tool description does not explain the 'sql' or 'schema' parameters, nor their relationship. With low schema coverage, the description should compensate, but it provides no parameter-level guidance.
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 ('Review'), a specific resource ('authored SQL'), and a clear scope (advisory metadata and indexing problems). It also distinguishes itself from siblings by explicitly noting it does not execute the SQL, and names validateQuery as a specific alternative.
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 an explicit when-not condition ('use validateQuery when database-driver acceptance is the question') and implicitly narrows its use case to advisory checks. It does not cover all sibling distinctions, but the provided exclusion is clear and useful.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
rebuildCatalogrebuildCatalogARead-onlyIdempotent
Create or refresh the persistent local catalog for offline/repeated metadata and usage lookups. Captures configured schema metadata, rebuilds the usage index and returns the distributable catalog file; writes only server-local data, never the inspected database.
| Name | Required | Description | Default |
|---|---|---|---|
| schemas | No | Schemas to capture (CSV); omit for configured/default scope. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| connection | No | Name of the connection whose catalog was rebuilt. |
| catalogFile | Yes | Absolute path of the built catalog file on disk; copy this file to distribute the catalog. |
| structureSchemas | No | Schemas captured into the structure snapshot. |
| usageSourceCount | Yes | Number of usage-catalog sources considered for indexing. |
| usageCatalogState | No | Usage-index state after the rebuild, e.g. not_started, indexing, ready, failed. |
| usageCatalogEnabled | Yes | False when the usage catalog is disabled. |
| structureSchemaCount | Yes | Number of schemas captured into the structure snapshot. |
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 meaningful behavioral context beyond annotations: it writes server-local data, never the inspected database, and returns a distributable catalog file. This clarifies side effects and scope without contradicting 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?
Two sentences with no filler. The core action and key constraints are front-loaded, and the safety clarification ('writes only server-local data, never the inspected database') is placed at the end without bloating the description.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is complete for a catalog-rebuild tool: it covers purpose, side effects, and output. It does not detail the return format, but an output schema exists, so that is not required. It could mention that the connection parameter is required, but the schema already marks it required, so the description does not need to repeat 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 the schema already documents both parameters. The description adds context that 'schemas' is optional and defaults to configured scope, which is useful, but it does not add much 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?
The description states a specific verb ('Create or refresh') and a specific resource ('persistent local catalog'), and distinguishes it from the inspected database by clarifying it writes only server-local data. It also names the key outputs (metadata capture, usage index rebuild, distributable catalog file), which clearly differentiates it from siblings like usageCatalogStatus or invalidateUsageCatalogCache.
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 explains when to use it ('for offline/repeated metadata and usage lookups') and what it does not do ('never the inspected database'). It does not explicitly name alternative tools or state when not to use it, but the context is clear enough for an agent to select it appropriately among the listed siblings.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
redundantIndexesredundantIndexesARead-onlyIdempotent
Find structurally overlapping non-unique indexes whose leading columns are a strict prefix of another same-type index. Unlike unusedIndexes, this does not depend on workload scan counters.
| Name | Required | Description | Default |
|---|---|---|---|
| table | No | Omit to scan the schema. | |
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of redundant-index findings returned. |
| table | No | |
| schema | No | |
| findings | No | Schema lint or redundant-index findings. |
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 meaningful behavioral context beyond those annotations: the analysis is structural, not workload-based, and only considers non-unique indexes with strict-prefix column overlap. There is no contradiction with 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 with no wasted words. The core matching rule is front-loaded, and the contrast with unusedIndexes is brief but informative. 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?
With an output schema present and annotations covering safety, the description provides enough detail about the tool's matching semantics to be actionable. The main gap is that schema/table scoping behavior is not fully elaborated in the description itself, though the schema partially covers 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?
The input schema documents 'table' and 'connection' reasonably, but the 'schema' parameter has no description. The tool description itself does not clarify any parameter semantics or explain how table/schema/connection interact, so it fails to compensate for the undocumented parameter.
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 and resource: 'Find structurally overlapping non-unique indexes' and gives a precise criterion: leading columns that are a strict prefix of another same-type index. It also differentiates the tool from unusedIndexes, so an agent can immediately tell this is the structural-redundancy analysis tool.
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 explicitly names unusedIndexes as the sibling alternative and explains the deciding difference: 'this does not depend on workload scan counters.' This gives clear selection guidance for choosing between the two tools. It does not go further into when to scope by table or schema, but the core alternative choice is well covered.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
resolveQueryLineageresolveQueryLineageARead-onlyIdempotent
Trace a query's data lineage from direct FROM/JOIN objects through views and optionally routines to underlying physical tables. Use inspectQuery for direct AST references only; routine expansion is best-effort and may miss dynamic SQL.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| schema | No | Default schema for unqualified names | |
| maxDepth | No | Maximum recursive expansion depth. Default 5, max 20. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| expandViews | No | Expand database views and materialized views recursively. Default true. | |
| expandRoutines | No | Expand database functions/procedures referenced by the query, best-effort. Default true. |
Output Schema
| Name | Required | Description |
|---|---|---|
| cycles | No | Possible relationship or lineage cycles found during traversal. |
| maxDepth | Yes | Maximum relationship traversal depth that was applied. |
| warnings | No | Non-fatal warnings produced while resolving or expanding lineage. |
| inspection | No | Parsed query inspection that underpins lineage (opaque; the inspectQuery tool returns the typed form). |
| directObjects | No | Objects directly referenced by the query before recursive expansion. |
| expandedObjects | No | All resolved objects visited during lineage expansion. |
| unresolvedObjects | No | Objects that could not be resolved against metadata during lineage analysis. |
| expandedPhysicalTables | No | Physical tables reached by recursively expanding views and routines. |
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. The description adds valuable behavioral context beyond annotations: it traverses views and routines, can optionally expand routines, and is best-effort with potential misses on dynamic SQL. This gives an agent a realistic expectation of completeness.
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-loads the core behavior, and includes the key differentiator and caveat without waste. 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?
Given the tool's complexity, the input schema covers defaults and constraints, annotations cover safety, and an output schema exists for return values. The description adds the essential behavioral scope and limitations, making the tool adequately specified for an agent to invoke 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?
Schema description coverage is 83%, so the input schema already documents most parameters with meanings and defaults. The description adds context about 'views' and 'optionally routines' that maps loosely to expandViews and expandRoutines, but it doesn't substantially enhance parameter understanding 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 states a specific action and resource: tracing a query's data lineage from direct FROM/JOIN objects through views and routines to physical tables. It explicitly differentiates from inspectQuery, which handles direct AST references only, making the tool's niche clear.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance on when to use this tool versus inspectQuery: use inspectQuery for direct AST references only, and this tool for deeper lineage. It also discloses the limitation that routine expansion is best-effort and may miss dynamic SQL, helping an agent decide based on the query's nature.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sampleRowssampleRowsARead-onlyIdempotent
Preview a small number of actual rows from one known table or view to understand data shape and example values. For fields, types and constraints without reading row data, use describeTable.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Rows to return (default 10, max 100). | |
| table | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | No | Rows. |
| columns | No | Columns. |
| rowCount | Yes | Row Count. |
| truncated | Yes | Truncated. |
| columnTypes | No | Column Types. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering the safety profile. The description adds only that it returns 'actual rows' (versus schema/metadata), which is mildly useful context. It does not contradict annotations and does not add significant behavioral detail beyond what annotations provide.
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 with no filler. The core purpose is front-loaded in the first sentence, and the alternative guidance is in the second. Every word 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 read-only, idempotent tool with an output schema and safety annotations, the description is mostly sufficient. The main gap is the unexplained table parameter and the optional schema parameter, but the presence of an output schema and annotations covers return values and safety, making this only slightly incomplete.
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 only 50%: limit and connection are described, but table and schema are not. The description hints that the table must be 'known' but does not explain how to obtain or format table names, nor does it mention the optional schema parameter. This leaves required parameters under-documented and the description fails to compensate for the schema coverage gap.
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 and resource: 'Preview a small number of actual rows from one known table or view.' It states the purpose (understanding data shape and example values) and explicitly distinguishes itself from describeTable, which is a sibling, making the tool's role unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear guidance on when to use this tool versus describeTable: use this to preview actual row data, use describeTable for fields, types, and constraints without reading rows. This is an explicit when/when-not pairing with a named alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schemaBriefschemaBriefARead-onlyIdempotent
Discover candidate tables and views across a schema when their names are unknown. Returns a broad plain-text map with column counts, PKs and relationship summaries; follow with queryContext for multi-table authoring detail or describeTable for one known object.
| Name | Required | Description | Default |
|---|---|---|---|
| terms | No | Terms to narrow discovery; falls back to full schema on no match. | |
| schema | No | ||
| maxTables | No | Tables/views to include (default 2000). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly, openWorld, idempotent, and non-destructive behavior. The description adds valuable context: it returns a 'broad plain-text map' (indicating output format) and implies a fallback to full schema when terms don't match (via the parameter description). It doesn't contradict annotations and enhances understanding of the tool's role as a discovery entry point.
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 with zero waste. The first sentence states the core purpose, and the second conveys output type and recommended follow-ups. The description is front-loaded with the key action and scope, then efficiently routes the agent to next steps.
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 discovery tool with rich annotations, no output schema, and 4 parameters, the description fully covers purpose, usage, output format, and next steps. It also leverages parameter descriptions for connection validation and maxTables. Nothing critical for correct invocation is missing.
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 75% (terms, maxTables, connection have descriptions; schema does not). The tool description doesn't add parameter-specific meaning beyond what the schema already provides. Baseline for high coverage is 3; the description's mention of 'names are unknown' reinforces the terms parameter but doesn't add new semantic detail.
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 ('Discover'), a specific resource ('candidate tables and views across a schema'), and a clear condition ('when their names are unknown'). It also differentiates from siblings by mentioning follow-ups (queryContext, describeTable) and implies searchObjects/listTables are for known names. This is a distinct, non-tautological purpose.
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?
Explicitly states the condition for using this tool ('when their names are unknown') and gives concrete follow-up actions ('follow with queryContext for multi-table authoring detail or describeTable for one known object'). This directly addresses when to use this tool versus alternatives, leaving no ambiguity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schemaGraphschemaGraphARead-onlyIdempotent
Analyze schema-wide relationship topology: graph nodes/edges, central or isolated tables, components, cycle hints and an optional shortest path. Use findJoinPaths when only paths between two known tables are needed.
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | ||
| toTable | No | Optional shortest-path target. | |
| maxDepth | No | Shortest-path hops (default 4). | |
| fromTable | No | Optional shortest-path start. | |
| maxTables | No | Tables to scan (default 50). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| edges | No | Relationship edges included in the graph response. |
| nodes | No | Table nodes included in the schema graph response. |
| cycles | No | Possible relationship or lineage cycles found during traversal. |
| schema | No | |
| edgeCount | Yes | Total number of relationship edges in the graph response. |
| nodeCount | Yes | Number of table nodes in the schema graph. |
| shortestPath | No | |
| centralTables | No | Highest-degree tables that are likely hubs in the schema. |
| tablesScanned | Yes | Number of tables inspected by the tool before caps were applied. |
| isolatedTables | No | Tables with no visible relationships in the scanned schema graph. |
| declaredEdgeCount | Yes | Number of graph edges backed by declared foreign keys. |
| connectedComponents | No | Connected components discovered in the schema relationship graph. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, openWorldHint=true, and destructiveHint=false, so the read-only safety profile is fully covered. The description adds functional output details but not extra constraints or caveats such as scan limits affecting 'schema-wide' results; that context is only available in the maxTables parameter. 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 sentences with no filler. The core purpose is front-loaded and the sibling routing is placed at the end. Every sentence contributes meaningful 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?
For a tool with an output schema, read-only annotations, and a clear sibling alternative, this is nearly complete. Minor gaps remain: the description doesn't clarify that the shortest-path inputs likely need both fromTable and toTable, and 'schema-wide' may be misleading given maxTables defaults to 50, though the parameter schema documents that.
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 high (83%), so the schema carries most parameter meaning. The tool description adds a little by linking 'optional shortest path' to the fromTable/toTable parameters, but it does not clarify relationships between parameters (e.g., whether both from and to are needed for a path) or the meaning of the undocumented 'schema' parameter.
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 ('Analyze') and resource ('schema-wide relationship topology'), and enumerates concrete outputs: graph nodes/edges, central or isolated tables, components, cycle hints, and optional shortest path. It also explicitly differentiates itself from findJoinPaths, so an agent can tell them apart.
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 an explicit alternative: 'Use findJoinPaths when only paths between two known tables are needed.' This clearly tells the agent when to prefer a sibling tool over schemaGraph, which is strong usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schemaGraphDotschemaGraphDotARead-onlyIdempotent
Export a schema or selected tables as DOT/Graphviz ERD text with columns, types, PK/FK markers and join edges. Use schemaGraph for graph metrics rather than renderable diagram source.
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | ||
| tables | No | Tables to include (CSV); omit for all. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already indicate read-only, idempotent, and non-destructive behavior, so the bar for additional behavioral disclosure is lower. The description adds clarity about the tool's output format (DOT/Graphviz ERD text) and the fact that it returns diagram source rather than metrics, which meaningfully supplements the annotation-only picture.
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 with no filler. The primary purpose and output details are in the first sentence, and the second sentence provides essential differentiation from schemaGraph. 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?
Given the simple read-only export behavior, the description covers the key aspects an agent needs: what the output is, what it contains, and which sibling tool to choose instead. Minor omissions like how schema names should be formatted are partially covered by sibling listSchemas and the similar connection guidance, so the overall context is strong but not exhaustive.
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 documents the tables and connection parameters well, and the description clarifies that the tool can operate on 'a schema or selected tables', which gives semantic meaning to the schema and tables parameters. Only the schema parameter lacks an explicit schema-side description, but the tool-level wording mitigates this gap.
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 ('Export') and names the exact resource ('schema or selected tables as DOT/Graphviz ERD text'), plus enumerates content details like columns, types, PK/FK markers, and join edges. It also explicitly contrasts itself with schemaGraph, making the tool's distinct purpose immediately clear.
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 an explicit alternative: 'Use schemaGraph for graph metrics rather than renderable diagram source.' This directly tells an agent when this tool is preferred and when schemaGraph would be better, which is strong routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
schemaLintschemaLintARead-onlyIdempotent
Audit one table or a schema for modeling and indexing risks: missing PKs, unindexed or mismatched FKs, nullable unique columns, missing CHECKs/remarks, orphan *_id columns, isolation and wide tables. Returns findings, not general table metadata.
| Name | Required | Description | Default |
|---|---|---|---|
| table | No | Omit to scan the schema. | |
| checks | No | Checks CSV, e.g. missingPrimaryKey,fkWithoutIndex; omit for defaults. | |
| schema | No | ||
| maxTables | No | Tables to scan (default 50). | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| maxFindings | No | Findings to return (default 200). |
Output Schema
| Name | Required | Description |
|---|---|---|
| table | No | |
| checks | No | Schema lint checks that were enabled for this audit. |
| schema | No | |
| findings | No | Schema lint or redundant-index findings. |
| truncated | Yes | True when the configured row or finding cap was reached and more data may exist. |
| findingCount | Yes | Number of lint findings returned or counted. |
| tablesScanned | Yes | Number of tables inspected by the tool before caps were applied. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover read-only/idempotent/non-destructive behavior, and the description reinforces this with 'Audit' and 'Returns findings.' It adds useful output-level context ('findings, not general table metadata') and clarifies the access scope (one table vs a schema) without contradicting any annotation.
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, with the action and resource front-loaded and every clause contributing signal. The enumerated checks are compact and the return-type clarification 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?
The description is sufficient for a read-only audit tool, especially with a rich input schema and an output schema present. It could have added a bit more about how the checks mapping works or when limits apply, but the structured fields already cover those details.
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 83% schema coverage, the schema carries most parameter semantics, but the description adds a concrete catalog of what audits are performed, making the 'checks' parameter more understandable than the CSV example alone. The 'one table or a schema' phrasing also clarifies the table/schema targeting and the undocumented schema parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb ('Audit') and a concrete target ('one table or a schema'), and enumerates exact risk categories. The closing clause 'Returns findings, not general table metadata' differentiates it from metadata-style siblings such as describeTable or schemaBrief.
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 a clear use context: use when you need modeling/indexing risk findings, and the 'not general table metadata' line tells an agent not to use it for metadata retrieval. It stops short of explicitly naming alternatives like redundantIndexes, fkIndexCoverage, or queryLint, so it is not fully explicit about sibling choices.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchObjectssearchObjectsARead-onlyIdempotent
Find database objects when only a full or partial name is known. Searches non-system tables, views, routines, packages, sequences and synonyms case-insensitively; use describeTable after finding a table or view whose structure is needed.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namePattern | Yes | Name pattern — plain substring (auto-wrapped in %..%) or explicit pattern with % / _ |
Output Schema
| Name | Required | Description |
|---|---|---|
| objects | No | Matching database objects across tables, views, routines, sequences, and synonyms. |
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 by structured data. The description adds genuinely useful behavior beyond that: the search is case-insensitive, excludes system objects, and the exact object types covered are enumerated. 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 sentences with zero waste. The purpose is front-loaded in the first clause, the behavioral scope follows immediately, and the follow-up tool recommendation is tacked on efficiently. Every element 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?
Complete for a search tool. Output schema covers return values, annotations cover the safety profile, both required parameters are documented, and the description covers purpose, scope, case-sensitivity, and follow-up guidance. Nothing an agent needs to invoke it correctly is missing.
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 both parameters are fully documented in the schema itself — the description need not repeat format details. The description's 'full or partial name' phrasing does reinforce the namePattern semantics (substring vs. explicit pattern), which is helpful context, but adds only marginal value over 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 opens with a specific verb and resource ('Find database objects') and immediately scopes the behavior: 'Searches non-system tables, views, routines, packages, sequences and synonyms case-insensitively'. This clearly distinguishes it from sibling listing tools like listTables and listRoutines, which enumerate all objects, versus this one which searches by name.
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 trigger condition is stated explicitly: use it 'when only a full or partial name is known'. It also names the follow-up action ('use describeTable after finding a table or view whose structure is needed'). It stops short of explicitly excluding enumeration tools like listTables/listRoutines for exhaustive discovery scenarios, so it's 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.
tableContexttableContextARead-onlyIdempotent
Explore the relationship neighborhood of one known table: compact root/nearby table metadata plus declared FK and optional observed join edges. Use when nearby joins are needed; for only the table's own fields or structure, use describeTable.
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | FK depth (default 1). | |
| table | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| includeStats | No | Include row/size/activity stats (default false). | |
| includeIncoming | No | Include child references (default true). | |
| includeObserved | No | Include declared/observed/semantic usage evidence (default: catalog enabled). |
Output Schema
| Name | Required | Description |
|---|---|---|
| depth | Yes | Relationship expansion depth from the root object. |
| tables | No | Tables included in this context, graph, query inspection, or usage record. |
| rootTable | No | Root table requested for table context. |
| rootSchema | No | Schema of the root table requested for table context. |
| includeStats | Yes | True when live table statistics were requested for context tables. |
| relationships | No | Relationship edges relevant to the context, graph, or observed-relationships result. |
| includeIncoming | Yes | True when tables that reference the root table were included. |
| includeObserved | Yes | True when usage-catalog observed joins were included as relationship evidence. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare read-only, open-world, idempotent, and non-destructive behavior, so the description does not need to repeat that. It adds context beyond annotations by specifying that output is 'compact root/nearby table metadata' with 'declared FK and optional observed join edges,' which conveys scope and non-exhaustiveness.
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 with no filler; the core behavior is front-loaded before the usage guidance. Every clause earns its place by conveying scope, output content, and when to prefer a sibling tool.
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 read-only annotations, the output schema, and schema-covered parameters, the description provides enough to invoke the tool correctly. It could be slightly more complete by noting default depth or the connection requirement, but those are already covered in the input 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 coverage is 71%, and most parameters (depth, connection, includeStats, includeIncoming, includeObserved) already have descriptions in the schema. The description adds high-level context like 'declared FK and optional observed join edges' that maps to includeObserved, but it does not explain individual parameters, so it mostly relies on 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 opens with a specific verb and resource: 'Explore the relationship neighborhood of one known table' and names the concrete outputs ('declared FK and optional observed join edges'). It explicitly distinguishes itself from describeTable ('for only the table's own fields or structure'), so an agent can tell siblings apart without inspecting schemas.
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 a clear selection rule: 'Use when nearby joins are needed' and states the alternative for a different need ('for only the table's own fields or structure, use describeTable'). This tells the agent both when to invoke this tool and when not to, with a named fallback.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
tableStatstableStatsARead-onlyIdempotent
Inspect operational size and activity statistics for one known table: estimated/live rows, storage, dead tuples, maintenance times and scan counters. For fields, keys and constraints, use describeTable; available statistics depend on engine and privileges.
| Name | Required | Description | Default |
|---|---|---|---|
| table | Yes | ||
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Error encountered while loading table statistics; other fields may be partial when set. |
| found | Yes | True when the requested object or path was found. |
| table | No | |
| blocks | No | Engine-reported allocated block count, when available. |
| schema | No | |
| tupDel | No | Number of deleted tuples recorded by engine statistics. |
| tupIns | No | Number of inserted tuples recorded by engine statistics. |
| tupUpd | No | Number of updated tuples recorded by engine statistics. |
| idxScan | No | Number of index scans recorded for the table. |
| relkind | No | Engine-specific relation kind for the table or view. |
| seqScan | No | Number of sequential scans recorded for the table. |
| avgRowLen | No | Average row length reported by optimizer statistics, when available. |
| temporary | No | Whether the table is temporary, when the engine reports it. |
| userStats | No | Oracle flag indicating whether user-defined statistics are present. |
| chainCount | No | Oracle chained row count, when available. |
| createDate | No | SQL Server object creation timestamp, when available. |
| deadTuples | No | Estimated number of dead tuples or obsolete row versions. |
| lastVacuum | No | Timestamp of the last manual vacuum, when available. |
| liveTuples | No | Estimated number of live tuples or rows. |
| modifyDate | No | SQL Server object modification timestamp, when available. |
| sampleSize | No | Sample size used for optimizer statistics, when available. |
| seqTupRead | No | Number of tuples read by sequential scans. |
| compression | No | Compression setting reported for the table, when available. |
| emptyBlocks | No | Engine-reported empty block count, when available. |
| globalStats | No | Oracle flag indicating whether global statistics are present. |
| idxTupFetch | No | Number of table tuples fetched through this index, when available. |
| isFiletable | No | SQL Server flag indicating a FileTable. |
| lastAnalyze | No | Timestamp of the last manual analyze/statistics collection, when available. |
| partitioned | No | Whether the table is partitioned, when the engine reports it. |
| deadTuplePct | No | Approximate percentage of dead tuples among total tuples. |
| lastAnalyzed | No | Timestamp when database optimizer statistics were last collected, when available. |
| segmentBytes | No | Oracle segment size in bytes, when segment metadata is accessible. |
| estimatedRows | No | Planner or catalog estimate of rows for this object or operation. |
| lastAutovacuum | No | Timestamp of the last automatic vacuum, when available. |
| tableSizeBytes | No | Storage used by the table heap or base data, in bytes. |
| toastSizeBytes | No | PostgreSQL TOAST storage used by the table, in bytes. |
| totalSizeBytes | No | Total storage used by the table, indexes, and auxiliary storage, in bytes. |
| lastAutoanalyze | No | Timestamp of the last automatic analyze/statistics collection, when available. |
| indexesSizeBytes | No | Storage used by indexes on the table, in bytes. |
| temporalTypeDesc | No | SQL Server temporal table type description. |
| isMemoryOptimized | No | SQL Server flag indicating a memory-optimized table. |
| segmentBytesError | No | Permission or lookup error encountered while reading segment size. |
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 engine/privilege dependency, which is useful context about what stats may be available. It doesn't disclose performance or error behavior, but that's less critical given 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?
Two sentences, no filler. The core purpose is front-loaded, and the alternative is given in a separate clause. Every part serves a purpose.
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 3-parameter tool with an output schema, the description covers the essential purpose and a key caveat. It lacks explicit parameter guidance, but the schema and output schema fill in the rest. It is adequate for a well-scoped tool, though a bit more on parameter semantics would make it fully complete.
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 schema has only 33% description coverage (only connection is described). The description does not elaborate on 'table', 'schema', or 'connection' beyond what their names imply. It mentions 'one known table' but doesn't explain required vs optional parameters or how to specify schema. With low schema coverage, the description should compensate but does not, leaving parameter meaning thin.
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 explicitly states it inspects operational size and activity statistics for a known table, listing specific metrics (rows, storage, dead tuples, maintenance, scans). It differentiates from describeTable by noting that tool covers fields/keys/constraints, so a clear purpose and distinction from siblings is provided.
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 an explicit alternative for a different task ('For fields, keys and constraints, use describeTable'), which helps route the agent. It also cautions that stats depend on engine/privileges, implying context-dependent behavior. It doesn't mention when to prefer this over other stats tools like indexStats or columnStats, but the primary guidance is present.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
timedQuerytimedQueryARead-onlyIdempotent
Measure one read-only SQL SELECT / WITH / EXPLAIN while still returning its rows and elapsed time. Use executeQuery when timing is irrelevant or benchmarkQuery for repeated cold/warm measurements. Bind '?'->params, ':name'->namedParams; never mix. E.g. :status -> namedParams={status:'PAID'} — key is the bare name. Adds available per-statement counter deltas (calls, execution time, rows, buffer hits/reads).
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| limit | No | Row limit (default JDBC_MAX_ROWS). | |
| params | No | Values for '?' placeholders, in order. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namedParams | No | Values for ':name' placeholders, keyed by name. | |
| timeoutSeconds | No | Timeout in seconds (default JDBC_QUERY_TIMEOUT_SECONDS). |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | No | Returned result rows as column-name to value maps, capped by the requested limit. |
| engine | No | Database engine that produced the result, such as PostgreSQL, Oracle, or SQL Server. |
| columns | No | Result column names in output order. |
| rowCount | Yes | |
| elapsedMs | Yes | Wall-clock elapsed time for the query execution, in milliseconds. |
| truncated | Yes | True when the configured row or finding cap was reached and more data may exist. |
| columnTypes | No | Database type names for the result columns, in the same order as columns. |
| pgStatStatements | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already provide readOnlyHint, idempotentHint, and non-destructive hints. The description adds meaningful behavior beyond that: it returns both rows and elapsed time, reports per-statement counter deltas, and warns against mixing '?' and ':name' placeholder styles. This gives the agent useful operational expectations without contradicting 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 front-loaded with the core purpose, immediately names alternatives, and then gives binding guidance with a concrete example. Every sentence adds distinct information and there is no filler or repetition of schema fields.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's purpose, when to use alternatives, parameter binding conventions, and supplementary return information. Given the output schema exists and annotations cover safety, the description is complete enough for an agent to select and invoke the tool 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?
Schema description coverage is 83%, so the schema already documents most parameters. The description adds valuable semantics by explaining the mapping of '?' to params and ':name' to namedParams, giving an explicit example, and stating that keys should be the bare name. This resolves ambiguity that the raw schema does not fully cover.
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 precise action and resource: measuring a single read-only SQL SELECT/WITH/EXPLAIN while returning rows and elapsed time. It also differentiates itself from executeQuery and benchmarkQuery by referencing them explicitly, so an agent can distinguish this tool from its closest 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?
It gives explicit routing guidance: use executeQuery when timing is irrelevant and benchmarkQuery for repeated cold/warm measurements. It also clarifies the one-shot nature of this tool ('Measure one') and provides binding rules, making the intended usage context very clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
unusedIndexesunusedIndexesARead-onlyIdempotent
Find non-PK/non-unique indexes with zero recorded scans as removal candidates. Unlike redundantIndexes, this uses workload counters, which are meaningful only after representative traffic and are not supported by every engine.
| Name | Required | Description | Default |
|---|---|---|---|
| schema | No | ||
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| minSizeBytes | No | Minimum size in bytes; omit tiny indexes. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Additional context about support, limits, interpretation, or engine-specific behavior. |
| count | Yes | Number of unused indexes returned. |
| schema | No | |
| indexes | No | Indexes available on the table or returned by an index-statistics scan. |
| supported | Yes | True when this tool is supported for the current database engine and privileges. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=false. The description adds useful behavioral context beyond these annotations by revealing reliance on workload counters and their limitations, which is important for interpreting 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?
Two efficient sentences front-load the core purpose and then add a differentiating caveat. Every word contributes value, with no redundant restatement of the tool 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?
Given an output schema, clear parameter documentation for most fields, and annotations already covering safety, the description supplies the remaining essential context: what the tool looks for, how it differs from a sibling, and when its results are valid. Nothing critical is missing.
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 already documents connection and minSizeBytes with descriptions, covering 67% of parameters. The description does not add new meaning about parameters; the only undocumented parameter 'schema' is not clarified in the description either, leaving a modest gap.
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 ('Find') and a clearly defined resource: non-PK/non-unique indexes with zero recorded scans, framed as removal candidates. It also explicitly differentiates itself from redundantIndexes, so an agent can distinguish the tool without inspecting schemas.
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 names redundantIndexes as the alternative and explains that this tool relies on workload counters, which are only meaningful after representative traffic and not supported by every engine. It provides clear context for when the tool is appropriate, though it does not give an explicit 'when not to use' list.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
usageCatalogStatususageCatalogStatusARead-onlyIdempotent
Check whether the usage catalog is enabled and ready before relying on observed-query or semantic evidence. Returns configured sources, indexing state, counts and load errors without searching for queries.
| Name | Required | Description | Default |
|---|---|---|---|
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. |
Output Schema
| Name | Required | Description |
|---|---|---|
| state | No | Current usage-catalog index state, such as not_started, indexing, ready, or failed. |
| sources | No | Configured usage-catalog source paths and database-native sources considered for indexing. |
| indexing | Yes | True while the usage catalog index is being built. |
| connection | No | Name of the connection this catalog belongs to. |
| catalogEnabled | Yes | False when the usage catalog is disabled; true when indexing and lookups are allowed. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, covering the safety profile. The description adds value beyond that by disclosing exactly what an agent can expect to learn from the call: configured sources, indexing state, counts, and load errors. This behavioral detail is useful context not present in 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 sentences, no filler. The purpose is front-loaded with the exact decision point ('before relying on observed-query or semantic evidence'), and the second sentence efficiently enumerates return contents. 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?
For a low-complexity status tool with one documented parameter, a full output schema, and safety annotations, the description is nearly complete. The only slight gap is that it doesn't explain what the 'usage catalog' is or how it gets populated, but that is unlikely to prevent correct invocation given the explicit readiness framing and rich 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%: the only parameter, connection, already has a clear description with guidance to call listConnections and not guess. The tool description itself adds no extra parameter detail, so a baseline 3 is appropriate; the schema carries the full semantic burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ('check whether enabled and ready') and a specific resource ('usage catalog'), and distinguishes itself from query-searching tools with 'without searching for queries'. It also states the exact return contents (configured sources, indexing state, counts, load errors), making the tool's purpose unmistakable.
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 explicitly tells the agent when to call this tool: before relying on observed-query or semantic evidence, as a readiness gate. It does not name alternative sibling tools, but the 'without searching for queries' phrase clarifies that this is not a query-lookup tool, and the sibling list contains obvious alternatives like findQueriesByTable and listQueries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
validateQueryvalidateQueryARead-onlyIdempotent
Check whether the database driver accepts a SELECT / WITH / EXPLAIN without executing it: prepares the statement and validates parameters, syntax and referenced objects. Use inspectQuery for parser-only AST inspection or queryLint for advisory metadata/index warnings. Bind '?'->params, ':name'->namedParams; never mix. E.g. :status -> namedParams={status:'PAID'} — key is the bare name.
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | ||
| params | No | Positional parameters for '?' placeholders, in order. Required when SQL contains '?'. | |
| connection | Yes | Database to run against. Call listConnections for valid names; do not guess. | |
| namedParams | No | Named parameters for ':name' placeholders. Required when SQL contains ':name'. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | |
| stage | No | Validation stage that failed, such as guard, params, or driver. |
| valid | Yes | True when the statement passed guard, parameter, and driver validation. |
| columns | No | Number of result columns reported by driver validation when available. |
| inspection | No | Parsed query inspection that underpins validation (opaque; the inspectQuery tool returns the typed form). |
| parameters | No | Number of SQL parameters expected or validated. |
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 substantial behavioral detail beyond those: 'without executing it', 'prepares the statement', and the specific validation dimensions (parameters, syntax, referenced objects). There is no contradiction with 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 compact, front-loaded with the core action, then adds sibling routing and binding details in two tightly written sentences plus an example. No filler or repetition of schema content; every sentence contributes distinct decision-relevant 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, return values need no explanation. The description covers what the tool does, what it does not do (execute), how to choose between siblings, and how to bind parameters. Combined with annotations and schema descriptions, an agent has all necessary context to call this tool 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 schema already documents params and namedParams with clear semantics. The description adds value by explaining the mapping between '?' and ':name' placeholders, warning against mixing, and providing a concrete example where the key is the bare name. The sql parameter itself lacks a schema description, but the tool's purpose statement ('SELECT / WITH / EXPLAIN') gives adequate implied meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Check whether the database driver accepts a SELECT / WITH / EXPLAIN without executing it.' It then details what validation covers (parameters, syntax, referenced objects) and explicitly contrasts with inspectQuery and queryLint, making the tool's unique role unmistakable.
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 direct routing guidance: use inspectQuery for parser-only AST inspection, and queryLint for advisory metadata/index warnings. It also provides binding rules ('never mix') and a concrete example, so the agent knows exactly when and how to invoke this tool versus alternatives.
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.
49 tool updates
v0.1.0- First observed
analyzePlan - First observed
benchmarkQuery - First observed
columnDistribution - First observed
columnHistogram - First observed
columnStats - First observed
describeTable - First observed
estimateSelectivity - First observed
executeQuery - First observed
explainQuery - First observed
findJoinPaths - First observed
findQueriesByColumn - First observed
findQueriesByTable - First observed
fkIndexCoverage - First observed
getQuery - First observed
getRoutineDefinition - First observed
getTriggerDefinition - First observed
getViewDefinition - First observed
indexStats - First observed
inspectQuery - First observed
invalidateUsageCatalogCache - First observed
joinCardinality - First observed
listConnections - First observed
listKnownDomains - First observed
listKnownKinds - First observed
listKnownTags - First observed
listQueries - First observed
listRoutines - First observed
listSchemas - First observed
listSequences - First observed
listTables - First observed
nullRatio - First observed
observedRelationships - First observed
queryContext - First observed
queryLint - First observed
rebuildCatalog - First observed
redundantIndexes - First observed
resolveQueryLineage - First observed
sampleRows - First observed
schemaBrief - First observed
schemaGraph - First observed
schemaGraphDot - First observed
schemaLint - First observed
searchObjects - First observed
tableContext - First observed
tableStats - First observed
timedQuery - First observed
unusedIndexes - First observed
usageCatalogStatus - First observed
validateQuery
TDQS
Scored across 49 tools
The tool set is generally well-separated, but there are several close clusters: query inspect/validate/lint/lineage, explain/analyze plan, columnStats/distribution/histogram, and redundant/unused/FK index tools. Descriptions and cross-references mostly disambiguate them, but with 49 tools an agent can still plausibly select the wrong member of such a cluster.
Names are uniformly lowerCamelCase and mostly follow a readable verb+object pattern like listTables, getViewDefinition, and executeQuery. Some noun-first names like schemaGraph, columnStats, and tableContext form a consistent secondary style rather than chaotic mixing, so the naming remains predictable.
49 tools far exceeds the 25-tool threshold for a well-scoped server. Many tools are highly granular variants—three column-stat tools, several query-analysis tools, and multiple index-audit tools—that could reasonably be consolidated, making the overall surface heavy for an agent.
For a read-only JDBC introspection and query-analysis server, coverage is very thorough: object discovery, metadata, sampling, relationships, query execution, plan diagnosis, index auditing, and usage-catalog lifecycle are all represented with few dead ends. Minor gaps such as table DDL generation or bulk cross-schema listing are workable via existing tools.
Maintenance
Related MCP Connectors
- dataOAuthco.thinair
PostgreSQL, MySQL, and SQL Server in one session. 26 read-only MCP tools for AI agents.
Query your warehouse or a CSV with Claude/ChatGPT over MCP, governed by table-level ACL + audit.
Read-only MCP server for The Quiet Protocol's engines, benchmarks, proof, and business data.
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceRead-only MCP server for SQL databases (SQL Server, Postgres, SQLite) with multi-server support and three-layer safety using AST validation and linting.MIT
- AlicenseAqualityBmaintenanceRead-only MCP server for querying PostgreSQL, MySQL, and SQLite from AI agents — multi-database, safe by default.417 npm1ISC
- FlicenseNot gradedqualityFmaintenanceA read-only MCP server that enables AI agents to explore database schemas and execute safe queries on PostgreSQL and MySQL.-
- FlicenseNot gradedqualityCmaintenanceRead-only MCP server that lets coding AI agents inspect Oracle Database schema through live metadata.-