Repository navigation
feat: schema context, estimated plans and table search for agents - #12
Merged
Merged
Conversation
- describe_table lists the foreign keys a table holds and those of other tables that reference it, so agents pick join columns instead of guessing from names. Keys whose other table the login can't read are left out. - Table and column comments (COMMENT ON, SQL Server's MS_Description, MySQL's COMMENT) appear in describe_table, and table comments in list_tables, shortened to 200 characters there. - list_tables and describe_table give each table's estimated row count from the database's statistics, so an agent can tell a lookup table from one it shouldn't scan. Absent for views and for tables never analyzed.
- explain_query takes the same arguments and checks as query_database but returns the database's estimated plan instead of running the query, so an agent can see a full scan of a large table before it runs into the timeout. EXPLAIN on Postgres and MySQL, SHOWPLAN_ALL on SQL Server (with each operator's estimated rows and cost), EXPLAIN PLAN with DBMS_XPLAN on Oracle. - SQL Server's SHOWPLAN plans a parameterized command as its sp_executesql call, so parameters are declared in the batch, typed from their values. Oracle plans its placeholders unbound. - Oracle's EXPLAIN PLAN writes to PLAN_TABLE, which a read-only transaction refuses, so there it runs in an ordinary transaction that is still rolled back; the query is only parsed. - list_tables takes search: text the table's name or comment contains, ignoring case, with LIKE wildcards matched as text. The truncation note suggests it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follows #11. Agents could see table and column names, but not how tables join, what a code column means, how big a table is, or what a query would cost. In a large schema they also couldn't search for a table.
Schema context
describe_tablelists the keys a table holds (foreignKeys) and the keys of other tables that reference it (referencedBy), so join columns come from the schema instead of name-matching. Keys whose other table the login can't read are left out. That matters most on Postgres, wherepg_constraintis visible to every login.COMMENT ON, SQL Server'sMS_Description, MySQL'sCOMMENT) appear indescribe_table, and table comments inlist_tables, shortened to 200 characters there.list_tablesanddescribe_tablegiveapproxRowsfrom the database's statistics, so an agent can tell a lookup table from one it shouldn't scan. Absent for views and for tables never analyzed.{ "schema": "public", "name": "sqlmcp_child", "type": "table", "comment": "Rows that point at a keyed row", "columns": [ …, { "name": "keyed_id", "dataType": "integer", "nullable": true, "primaryKey": false, "comment": "The keyed row this one belongs to" }, … ], "foreignKeys": [{ "columns": ["keyed_id"], "referencedTable": "public.sqlmcp_keyed", "referencedColumns": ["id"] }], "referencedBy": [] }Checking and finding before querying
explain_query. Takes the same arguments and checks asquery_database, but returns the estimated plan instead of running the query. An agent can see a full scan of a large table before it runs into the timeout. Plans come fromEXPLAINon Postgres (neverANALYZE),EXPLAIN FORMAT=TREEon MySQL,SHOWPLAN_ALLon SQL Server (with each operator's estimated rows and cost), andEXPLAIN PLAN+DBMS_XPLANon Oracle.sp_executesqlcall that carries it, so parameters are declared in the batch, typed from their values. Nothing runs under SHOWPLAN, so the values aren't needed. Oracle plans its placeholders unbound.EXPLAIN PLANwrites toPLAN_TABLE, which a read-only transaction refuses (ORA-01456). So on Oracle it runs in an ordinary transaction, still rolled back. The query itself is only parsed, and the README's Security section says so.list_tablessearch.searchmatches text in a table's name or comment, ignoring case, with%,_and[matched as text. The truncation note suggests it.{ "plan": "Nested Loop (cost=0.15..27.08 rows=4 width=168)\n -> Index Scan using sqlmcp_keyed_pkey on sqlmcp_keyed k (cost=0.15..8.17 rows=1 width=82)\n Index Cond: (id = '1'::bigint)\n -> Seq Scan on sqlmcp_child c (cost=0.00..18.88 rows=4 width=86)\n Filter: (keyed_id = '1'::bigint)" }Tested locally: the full suite against all four databases (351 tests). New tests cover:
explain_queryI also called the tools over MCP against Postgres and got the output shown above.