doc/MCP/Tool_Discovery_Guide.md
This guide explains how to discover and interact with MCP tools available on all endpoints, with a focus on the Query endpoint which includes database exploration and two-phase discovery tools.
The MCP (Model Context Protocol) Query endpoint provides dynamic tool discovery through the tools/list method. This allows clients to:
https://127.0.0.1:6071/mcp/querycurl -k -X POST https://127.0.0.1:6071/mcp/query \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}' | jq
If authentication is configured:
curl -k -X POST https://127.0.0.1:6071/mcp/query \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}' | jq
If header authentication is not available:
curl -k -X POST "https://127.0.0.1:6071/mcp/query?token=YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
}' | jq
{
"id": "1",
"jsonrpc": "2.0",
"result": {
"tools": [
{
"name": "tool_name",
"description": "Tool description",
"inputSchema": {
"type": "object",
"properties": {
"param_name": {
"type": "string|integer",
"description": "Parameter description"
}
},
"required": ["param1", "param2"]
}
}
]
}
}
List logical query targets. Each target identifier maps internally to a ProxySQL hostgroup and routing policy.
Notes:
target_id; backend credentials are never sent in tool calls.Parameters:
List all available schemas/databases.
Parameters:
page_token (string, optional) - Pagination tokenpage_size (integer, optional) - Results per page (default: 50)target_id (string, optional) - Logical query target identifierList tables in a schema.
Parameters:
schema (string, required) - Schema namepage_token (string, optional) - Pagination tokenpage_size (integer, optional) - Results per page (default: 50)name_filter (string, optional) - Filter table names by patterntarget_id (string, optional) - Logical query target identifierRouting behavior:
SHOW TABLES for MySQL targets and information_schema.tables for PostgreSQL targets.Get detailed table schema including columns, types, keys, and indexes.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table nameGet constraints (foreign keys, unique constraints, etc.) for a table.
Parameters:
schema (string, required) - Schema nametable (string, optional) - Table nameGet table statistics including row count, size estimates, and data distribution.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namemode (string, optional) - Profile mode: "quick" or "full" (default: "quick")Get column statistics including distinct values, null count, and top values.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namecolumn (string, required) - Column namemax_top_values (integer, optional) - Maximum top values to return (default: 20)Get sample rows from a table (with hard cap on rows returned).
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namecolumns (string, optional) - Comma-separated column nameswhere (string, optional) - WHERE clause filterorder_by (string, optional) - ORDER BY clauselimit (integer, optional) - Maximum rows (default: 20)Sample distinct values from a column.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namecolumn (string, required) - Column namewhere (string, optional) - WHERE clause filterlimit (integer, optional) - Maximum values (default: 50)Execute a read-only SQL query with safety guardrails enforced.
Parameters:
sql (string, required) - SQL query to executetarget_id (string, optional) - Logical query target identifiermax_rows (integer, optional) - Maximum rows to return (default: 200)timeout_sec (integer, optional) - Query timeout (default: 2)Routing behavior:
target_id points to a MySQL target, query executes with MySQL protocol.target_id points to a PostgreSQL target, query executes with PostgreSQL protocol.Safety rules:
Explain a query execution plan using EXPLAIN or EXPLAIN ANALYZE.
Parameters:
sql (string, required) - SQL query to explaintarget_id (string, optional) - Logical query target identifierRouting behavior:
target_id (mysql or pgsql target).Suggest table joins based on heuristic analysis of column names and types.
Parameters:
schema (string, required) - Schema nametable_a (string, required) - First tabletable_b (string, optional) - Second table (if omitted, checks all)max_candidates (integer, optional) - Maximum join candidates (default: 5)Find tables that might be referenced by a foreign key column.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namecolumn (string, required) - Column namemax_tables (integer, optional) - Maximum tables to check (default: 50)Store or update an entry in the catalog (LLM external memory).
Parameters:
kind (string, required) - Entry kind (e.g., "table", "relationship", "insight")key (string, required) - Unique identifierdocument (string, required) - JSON document with datatags (string, optional) - Comma-separated tagslinks (string, optional) - Comma-separated related keysRetrieve an entry from the catalog.
Parameters:
kind (string, required) - Entry kindkey (string, required) - Entry keySearch the catalog for entries matching a query.
Parameters:
query (string, required) - Search querykind (string, optional) - Filter by kindtags (string, optional) - Filter by tagslimit (integer, optional) - Maximum results (default: 20)offset (integer, optional) - Results offset (default: 0)List catalog entries by kind.
Parameters:
kind (string, optional) - Filter by kindlimit (integer, optional) - Maximum results (default: 50)offset (integer, optional) - Results offset (default: 0)Merge multiple catalog entries into a single consolidated entry.
Parameters:
keys (string, required) - Comma-separated keys to mergetarget_key (string, required) - Target key for merged entrykind (string, optional) - Entry kind (default: "domain")instructions (string, optional) - Merge instructionsDelete an entry from the catalog.
Parameters:
kind (string, required) - Entry kindkey (string, required) - Entry keyRun Phase 1 of two-phase discovery: static harvest of database metadata.
Parameters:
schema_filter (string, optional) - Filter schemas by name patterntable_filter (string, optional) - Filter tables by name patternrun_id (string, optional) - Custom run identifierReturns:
run_id - Unique identifier for this discovery runobjects_count - Number of database objects discoveredschemas_count - Number of schemas processedtables_count - Number of tables processedcolumns_count - Number of columns processedindexes_count - Number of indexes processedconstraints_count - Number of constraints processedStart a new agent run for discovery coordination.
Parameters:
run_id (string, required) - Discovery run identifieragent_id (string, required) - Agent identifiercapabilities (array, optional) - List of agent capabilitiesMark an agent run as completed.
Parameters:
run_id (string, required) - Discovery run identifieragent_id (string, required) - Agent identifierstatus (string, required) - Final status ("success", "error", "timeout")summary (string, optional) - Summary of work performedAppend an event to an agent run.
Parameters:
run_id (string, required) - Discovery run identifieragent_id (string, required) - Agent identifierevent_type (string, required) - Type of eventdata (object, required) - Event datatimestamp (string, optional) - ISO8601 timestampStore or update a table/column summary generated by LLM.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namecolumn (string, optional) - Column name (if column-level summary)summary (string, required) - LLM-generated summaryconfidence (number, optional) - Confidence score (0.0-1.0)Retrieve LLM-generated summary for a table or column.
Parameters:
schema (string, required) - Schema nametable (string, required) - Table namecolumn (string, optional) - Column nameStore or update an inferred relationship between tables.
Parameters:
source_schema (string, required) - Source schemasource_table (string, required) - Source tabletarget_schema (string, required) - Target schematarget_table (string, required) - Target tableconfidence (number, required) - Confidence score (0.0-1.0)description (string, required) - Relationship descriptiontype (string, optional) - Relationship type ("fk", "semantic", "usage")Store or update a business domain classification.
Parameters:
domain_id (string, required) - Domain identifiername (string, required) - Domain namedescription (string, required) - Domain descriptionconfidence (number, optional) - Confidence score (0.0-1.0)tags (array, optional) - Domain tagsSet the members (tables) of a business domain.
Parameters:
domain_id (string, required) - Domain identifiermembers (array, required) - List of table identifiersconfidence (number, optional) - Confidence score (0.0-1.0)Store or update a business metric definition.
Parameters:
metric_id (string, required) - Metric identifiername (string, required) - Metric namedescription (string, required) - Metric descriptionformula (string, required) - SQL formula or descriptiondomain_id (string, optional) - Associated domaintags (array, optional) - Metric tagsAdd a question template that can be answered using this data.
Parameters:
template_id (string, required) - Template identifierquestion (string, required) - Question template with placeholdersanswer_plan (object, required) - Steps to answer the questioncomplexity (string, optional) - Complexity level ("low", "medium", "high")estimated_time (number, optional) - Estimated time in minutestags (array, optional) - Template tagsAdd a general note or insight about the data.
Parameters:
note_id (string, required) - Note identifiercontent (string, required) - Note contenttype (string, optional) - Note type ("insight", "warning", "recommendation")confidence (number, optional) - Confidence score (0.0-1.0)tags (array, optional) - Note tagsSearch LLM-generated content and insights.
Parameters:
query (string, required) - Search querytype (string, optional) - Content type to search ("summary", "relationship", "domain", "metric", "note")schema (string, optional) - Filter by schemalimit (number, optional) - Maximum results (default: 10)curl -k -X POST https://127.0.0.1:6071/mcp/query \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": "list_tables",
"arguments": {
"schema": "testdb"
}
},
"id": 2
}' | jq
{
"id": "2",
"jsonrpc": "2.0",
"result": {
"success": true,
"data": [...]
}
}
{
"id": "2",
"jsonrpc": "2.0",
"result": {
"success": false,
"error": "Error message"
}
}
import requests
import json
# Get tool list
response = requests.post(
"https://127.0.0.1:6071/mcp/query",
json={
"jsonrpc": "2.0",
"method": "tools/list",
"id": 1
},
verify=False # For self-signed cert
)
tools = response.json()["result"]["tools"]
# Print all tools
for tool in tools:
print(f"\n{tool['name']}")
print(f" Description: {tool['description']}")
print(f" Required: {tool['inputSchema'].get('required', [])}")
def call_tool(tool_name, arguments):
response = requests.post(
"https://127.0.0.1:6071/mcp/query",
json={
"jsonrpc": "2.0",
"method": "tools/call",
"params": {
"name": tool_name,
"arguments": arguments
},
"id": 2
},
verify=False
)
return response.json()["result"]
# List tables
result = call_tool("list_tables", {"schema": "testdb"})
print(json.dumps(result, indent=2))
# Describe a table
result = call_tool("describe_table", {
"schema": "testdb",
"table": "customers"
})
print(json.dumps(result, indent=2))
# Run a query
result = call_tool("run_sql_readonly", {
"sql": "SELECT * FROM customers LIMIT 10"
})
print(json.dumps(result, indent=2))
import requests
import json
class MCPQueryClient:
def __init__(self, host="127.0.0.1", port=6071, token=None):
self.url = f"https://{host}:{port}/mcp/query"
self.headers = {
"Content-Type": "application/json",
**({"Authorization": f"Bearer {token}"} if token else {})
}
def list_tools(self):
response = requests.post(
self.url,
json={"jsonrpc": "2.0", "method": "tools/list", "id": 1},
headers=self.headers,
verify=False
)
return response.json()["result"]["tools"]
def call_tool(self, name, arguments):
response = requests.post(
self.url,
json={
"jsonrpc": "2.0",
"method": "tools/call",
"params": {"name": name, "arguments": arguments},
"id": 2
},
headers=self.headers,
verify=False
)
return response.json()["result"]
def explore_schema(self, schema):
"""Explore a schema: list tables and their structures"""
print(f"\n=== Exploring schema: {schema} ===\n")
# List tables
tables = self.call_tool("list_tables", {"schema": schema})
for table in tables.get("data", []):
table_name = table["name"]
print(f"\nTable: {table_name}")
print(f" Type: {table['type']}")
print(f" Rows: {table.get('row_count', 'unknown')}")
# Describe table
schema_info = self.call_tool("describe_table", {
"schema": schema,
"table": table_name
})
if schema_info.get("success"):
print(f" Columns: {', '.join([c['name'] for c in schema_info['data']['columns']])}")
# Usage
client = MCPQueryClient()
client.explore_schema("testdb")
The test script provides a convenient way to discover and test tools:
# List all discovered tools (without testing)
./scripts/mcp/test_mcp_tools.sh --list-only
# Test only query endpoint
./scripts/mcp/test_mcp_tools.sh --endpoint query
# Test specific tool with verbose output
./scripts/mcp/test_mcp_tools.sh --endpoint query --tool list_tables -v
# Test all endpoints
./scripts/mcp/test_mcp_tools.sh
The same discovery pattern works for all MCP endpoints:
/mcp/config - Configuration management tools/mcp/query - Database exploration, query, and discovery tools/mcp/admin - Administrative operations/mcp/cache - Cache management tools/mcp/stats - Monitoring and metrics tools/mcp/ai - AI and LLM featuresSimply change the endpoint URL:
curl -k -X POST https://127.0.0.1:6071/mcp/config \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "method": "tools/list", "id": 1}'