Add MCP Tool Discovery Guide

Comprehensive guide for discovering and using MCP Query endpoint tools:
- Tool discovery via tools/list method
- Complete list of all Query endpoint tools with parameters
- cURL and Python examples for tool discovery and execution
- Complete database exploration example
- Test script usage guide
pull/5310/head
Rene Cannao 1 month ago
parent 5846cd8b40
commit 07dc887af2

@ -0,0 +1,475 @@
# MCP Tool Discovery Guide
This guide explains how to discover and interact with MCP tools available on the Query endpoint.
## Overview
The MCP (Model Context Protocol) Query endpoint provides dynamic tool discovery through the `tools/list` method. This allows clients to:
1. Discover all available tools at runtime
2. Get detailed schemas for each tool (parameters, requirements, descriptions)
3. Dynamically adapt to new tools without code changes
## Endpoint Information
- **URL**: `https://127.0.0.1:6071/mcp/query`
- **Protocol**: JSON-RPC 2.0 over HTTPS
- **Authentication**: Bearer token (optional, if configured)
## Getting the Tool List
### Basic Request
```bash
curl -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
```
### With Authentication
If authentication is configured:
```bash
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
```
### Using Query Parameter (Alternative)
If header authentication is not available:
```bash
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
```
## Response Format
```json
{
"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"]
}
}
]
}
}
```
## Available Query Endpoint Tools
### Inventory Tools
#### list_schemas
List all available schemas/databases.
**Parameters:**
- `page_token` (string, optional) - Pagination token
- `page_size` (integer, optional) - Results per page (default: 50)
#### list_tables
List tables in a schema.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `page_token` (string, optional) - Pagination token
- `page_size` (integer, optional) - Results per page (default: 50)
- `name_filter` (string, optional) - Filter table names by pattern
### Structure Tools
#### describe_table
Get detailed table schema including columns, types, keys, and indexes.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, **required**) - Table name
#### get_constraints
Get constraints (foreign keys, unique constraints, etc.) for a table.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, optional) - Table name
### Profiling Tools
#### table_profile
Get table statistics including row count, size estimates, and data distribution.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, **required**) - Table name
- `mode` (string, optional) - Profile mode: "quick" or "full" (default: "quick")
#### column_profile
Get column statistics including distinct values, null count, and top values.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, **required**) - Table name
- `column` (string, **required**) - Column name
- `max_top_values` (integer, optional) - Maximum top values to return (default: 20)
### Sampling Tools
#### sample_rows
Get sample rows from a table (with hard cap on rows returned).
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, **required**) - Table name
- `columns` (string, optional) - Comma-separated column names
- `where` (string, optional) - WHERE clause filter
- `order_by` (string, optional) - ORDER BY clause
- `limit` (integer, optional) - Maximum rows (default: 20)
#### sample_distinct
Sample distinct values from a column.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, **required**) - Table name
- `column` (string, **required**) - Column name
- `where` (string, optional) - WHERE clause filter
- `limit` (integer, optional) - Maximum values (default: 50)
### Query Tools
#### run_sql_readonly
Execute a read-only SQL query with safety guardrails enforced.
**Parameters:**
- `sql` (string, **required**) - SQL query to execute
- `max_rows` (integer, optional) - Maximum rows to return (default: 200)
- `timeout_sec` (integer, optional) - Query timeout (default: 2)
**Safety rules:**
- Must start with SELECT
- No dangerous keywords (DROP, DELETE, INSERT, UPDATE, etc.)
- SELECT * requires LIMIT clause
#### explain_sql
Explain a query execution plan using EXPLAIN or EXPLAIN ANALYZE.
**Parameters:**
- `sql` (string, **required**) - SQL query to explain
### Relationship Inference Tools
#### suggest_joins
Suggest table joins based on heuristic analysis of column names and types.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table_a` (string, **required**) - First table
- `table_b` (string, optional) - Second table (if omitted, checks all)
- `max_candidates` (integer, optional) - Maximum join candidates (default: 5)
#### find_reference_candidates
Find tables that might be referenced by a foreign key column.
**Parameters:**
- `schema` (string, **required**) - Schema name
- `table` (string, **required**) - Table name
- `column` (string, **required**) - Column name
- `max_tables` (integer, optional) - Maximum tables to check (default: 50)
### Catalog Tools (LLM Memory)
#### catalog_upsert
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 identifier
- `document` (string, **required**) - JSON document with data
- `tags` (string, optional) - Comma-separated tags
- `links` (string, optional) - Comma-separated related keys
#### catalog_get
Retrieve an entry from the catalog.
**Parameters:**
- `kind` (string, **required**) - Entry kind
- `key` (string, **required**) - Entry key
#### catalog_search
Search the catalog for entries matching a query.
**Parameters:**
- `query` (string, **required**) - Search query
- `kind` (string, optional) - Filter by kind
- `tags` (string, optional) - Filter by tags
- `limit` (integer, optional) - Maximum results (default: 20)
- `offset` (integer, optional) - Results offset (default: 0)
#### catalog_list
List catalog entries by kind.
**Parameters:**
- `kind` (string, optional) - Filter by kind
- `limit` (integer, optional) - Maximum results (default: 50)
- `offset` (integer, optional) - Results offset (default: 0)
#### catalog_merge
Merge multiple catalog entries into a single consolidated entry.
**Parameters:**
- `keys` (string, **required**) - Comma-separated keys to merge
- `target_key` (string, **required**) - Target key for merged entry
- `kind` (string, optional) - Entry kind (default: "domain")
- `instructions` (string, optional) - Merge instructions
#### catalog_delete
Delete an entry from the catalog.
**Parameters:**
- `kind` (string, **required**) - Entry kind
- `key` (string, **required**) - Entry key
## Calling a Tool
### Request Format
```bash
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
```
### Response Format
```json
{
"id": "2",
"jsonrpc": "2.0",
"result": {
"success": true,
"data": [...]
}
}
```
### Error Response
```json
{
"id": "2",
"jsonrpc": "2.0",
"result": {
"success": false,
"error": "Error message"
}
}
```
## Python Examples
### Basic Tool Discovery
```python
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', [])}")
```
### Calling a Tool
```python
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))
```
### Complete Example: Database Discovery
```python
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")
```
## Using the Test Script
The test script provides a convenient way to discover and test tools:
```bash
# 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
```
## Other Endpoints
The same discovery pattern works for all MCP endpoints:
- **Config**: `/mcp/config` - Configuration management tools
- **Query**: `/mcp/query` - Database exploration and query tools
- **Admin**: `/mcp/admin` - Administrative operations
- **Cache**: `/mcp/cache` - Cache management tools
- **Observe**: `/mcp/observe` - Monitoring and metrics tools
Simply change the endpoint URL:
```bash
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}'
```
## Related Documentation
- [Architecture.md](Architecture.md) - Overall MCP architecture
- [Database_Discovery_Agent.md](Database_Discovery_Agent.md) - AI agent architecture
- [README.md](README.md) - Module overview
Loading…
Cancel
Save