Server Functions Reference¶
These functions are used when DuckDB runs as an MCP server, exposing your database to AI assistants and other MCP clients.
Server Lifecycle¶
All server lifecycle functions are available as both SELECT (returns a result) and PRAGMA (silent, no output). Use PRAGMA in init scripts where you don't need the return value.
mcp_server_start¶
Start the MCP server.
-- As PRAGMA (recommended for init scripts — no output)
PRAGMA mcp_server_start('transport');
PRAGMA mcp_server_start('transport', 'config_json');
PRAGMA mcp_server_start('transport', 'host', port, 'config_json');
-- As SELECT (returns status struct)
SELECT mcp_server_start('transport');
SELECT mcp_server_start('transport', 'config_json');
SELECT mcp_server_start('transport', 'host', port, 'config_json');
Parameters:
| Parameter | Type | Description |
|---|---|---|
transport |
VARCHAR | Transport type: stdio, memory, http, https |
host |
VARCHAR | Host to bind (used for http/https) |
port |
INTEGER | Port number (used for http/https, 0 for stdio) |
config |
VARCHAR | JSON configuration object (see Configuration) |
Transport Types:
| Transport | Description | Use Case |
|---|---|---|
stdio |
Standard input/output | CLI integration, Claude Desktop |
memory |
In-process (no I/O) | Testing, unit tests |
http |
HTTP server | REST clients, web applications |
https |
HTTPS server (SSL/TLS) | Secure web applications |
Examples:
-- Stdio for Claude Desktop integration (PRAGMA — clean, no output)
PRAGMA mcp_server_start('stdio');
-- With configuration
PRAGMA mcp_server_start('stdio', '{"default_result_format": "markdown"}');
-- Full form with host/port for HTTP
PRAGMA mcp_server_start('http', 'localhost', 8080, '{"auth_token": "secret"}');
-- SELECT form when you need the status struct
SELECT mcp_server_start('memory');
mcp_server_stop¶
Stop the running MCP server.
-- As PRAGMA (no output)
PRAGMA mcp_server_stop; -- no-arg form (no parentheses)
PRAGMA mcp_server_stop(true); -- with force option
-- As SELECT (returns status struct)
SELECT mcp_server_stop();
SELECT mcp_server_stop(true);
PRAGMA Statement syntax
No-argument PRAGMAs use statement syntax: PRAGMA mcp_server_stop; (no parentheses). PRAGMAs with arguments use call syntax: PRAGMA mcp_server_stop(true);.
Returns (SELECT form): Status struct confirming shutdown.
mcp_server_status¶
Get the current server status and statistics.
Returns: JSON object containing:
| Field | Type | Description |
|---|---|---|
running |
boolean | Whether the server is active |
transport |
string | Active transport type |
requests_received |
integer | Total requests processed |
responses_sent |
integer | Total responses sent |
errors_returned |
integer | Total error responses |
Example:
SELECT mcp_server_status();
-- {"running": true, "transport": "stdio", "requests_received": 42, "responses_sent": 42, "errors_returned": 2}
Publishing Resources¶
mcp_publish_table¶
Publish a table as an MCP resource.
-- As PRAGMA (no output)
PRAGMA mcp_publish_table('table_name');
PRAGMA mcp_publish_table('table_name', 'uri', 'format');
-- As SELECT (returns status string)
SELECT mcp_publish_table('table_name', 'uri', 'format');
Parameters:
| Parameter | Type | Description |
|---|---|---|
table_name |
VARCHAR | Name of the table to publish |
uri |
VARCHAR | Resource URI (default: data://tables/<table_name>) |
format |
VARCHAR | Output format: json, csv, markdown |
Example:
-- Simple (auto-generates URI)
PRAGMA mcp_publish_table('products');
-- With explicit URI and format
PRAGMA mcp_publish_table('products', 'data://tables/products', 'json');
-- SELECT form when you need the status message
SELECT mcp_publish_table('users', 'data://tables/users', 'csv');
Note
Published tables are static snapshots. The resource content is captured when published and won't reflect subsequent table changes unless republished.
Publish Before Server Starts
You can call mcp_publish_table before starting the server. The registration will be queued and automatically applied when the server starts. This is useful for initialization scripts.
mcp_publish_query¶
Publish a query result as an MCP resource.
-- As PRAGMA (no output)
PRAGMA mcp_publish_query('sql', 'uri');
PRAGMA mcp_publish_query('sql', 'uri', 'format', refresh_interval);
-- As SELECT (returns status string)
SELECT mcp_publish_query('sql', 'uri', 'format', refresh_interval);
Parameters:
| Parameter | Type | Description |
|---|---|---|
sql |
VARCHAR | SQL query to execute |
uri |
VARCHAR | Resource URI |
format |
VARCHAR | Output format: json, csv, markdown |
refresh_interval |
INTEGER | Refresh interval in seconds (minimum 60) |
Example:
-- Publish a summary that refreshes every hour
PRAGMA mcp_publish_query(
'SELECT category, COUNT(*) as count, AVG(price) as avg_price FROM products GROUP BY category',
'data://reports/product_summary',
'json',
3600
);
Publish Before Server Starts
You can call mcp_publish_query before starting the server. The registration will be queued and automatically applied when the server starts.
mcp_publish_resource¶
Publish static content as an MCP resource. This is useful for configuration files, documentation, or any static data.
-- As PRAGMA (no output)
PRAGMA mcp_publish_resource('uri', 'content', 'mime_type', 'description');
-- As SELECT (returns status string)
SELECT mcp_publish_resource('uri', 'content', 'mime_type', 'description');
Parameters:
| Parameter | Type | Description |
|---|---|---|
uri |
VARCHAR | Resource URI (e.g., config://app-settings) |
content |
VARCHAR | The static content to publish |
mime_type |
VARCHAR | MIME type (default: text/plain) |
description |
VARCHAR | Human-readable description (optional) |
Examples:
-- Publish JSON configuration
SELECT mcp_publish_resource(
'config://app-settings',
'{"theme": "dark", "language": "en"}',
'application/json',
'Application settings'
);
-- Publish plain text documentation
SELECT mcp_publish_resource(
'docs://readme',
'Welcome to the API. Use the query tool to explore data.',
'text/plain',
'API documentation'
);
-- Publish with defaults (text/plain, no description)
SELECT mcp_publish_resource(
'info://version',
'v2.1.0',
NULL,
NULL
);
Publish Before Server Starts
You can call mcp_publish_resource before starting the server. The registration will be queued and automatically applied when the server starts.
Publishing Tools¶
mcp_publish_tool¶
Publish a custom SQL-based tool that MCP clients can execute.
-- As PRAGMA (no output)
PRAGMA mcp_publish_tool('name', 'description', 'sql_template', 'properties', 'required');
PRAGMA mcp_publish_tool('name', 'description', 'sql_template', 'properties', 'required', 'format');
-- As SELECT (returns status string)
SELECT mcp_publish_tool('name', 'description', 'sql_template', 'properties', 'required');
SELECT mcp_publish_tool('name', 'description', 'sql_template', 'properties', 'required', 'format');
Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
VARCHAR | Tool name (used by clients) |
description |
VARCHAR | Human-readable description |
sql_template |
VARCHAR | SQL with $param placeholders |
properties |
VARCHAR | JSON Schema for parameters |
required |
VARCHAR | JSON array of required parameter names |
format |
VARCHAR | Output format: json, csv, markdown (default: json) |
All parameters are VARCHAR
Pass JSON as string literals, not json_object(...) or JSON type expressions. Using json_object() produces a JSON type which won't match the function signature.
Parameter Binding:
When the SQL template can be prepared as a parameterized statement, parameters are bound using DuckDB's prepared statement API with proper type conversion based on the JSON Schema types (string → VARCHAR, integer → BIGINT, number → DOUBLE, boolean → BOOLEAN). This is safer and more efficient than string interpolation.
If the template cannot be prepared (e.g., it uses macros or other non-preparable constructs), the system automatically falls back to string interpolation with $name syntax. Optional parameters (not listed in required) are substituted as SQL NULL when omitted or passed as JSON null:
Examples:
-- Simple search tool
SELECT mcp_publish_tool(
'search_products',
'Search products by name',
'SELECT * FROM products WHERE name ILIKE ''%'' || $query || ''%''',
'{"query": {"type": "string", "description": "Search term"}}',
'["query"]'
);
-- Tool with multiple parameters
SELECT mcp_publish_tool(
'sales_by_region',
'Get sales totals by region for a date range',
'SELECT region, SUM(amount) as total
FROM sales
WHERE sale_date BETWEEN $start_date AND $end_date
GROUP BY region
ORDER BY total DESC',
'{
"start_date": {"type": "string", "description": "Start date (YYYY-MM-DD)"},
"end_date": {"type": "string", "description": "End date (YYYY-MM-DD)"}
}',
'["start_date", "end_date"]'
);
-- Tool with markdown output for AI assistants
SELECT mcp_publish_tool(
'inventory_report',
'Generate inventory status report',
'SELECT category, COUNT(*) as items, SUM(quantity) as total_qty
FROM inventory
GROUP BY category',
'{}',
'[]',
'markdown'
);
Publish Before Server Starts
You can call mcp_publish_tool before starting the server. The registration will be queued and automatically applied when the server starts. This is useful for setting up tools in initialization scripts.
mcp_publish_execution_tool¶
Publish a multi-statement SQL tool. Unlike mcp_publish_tool (which executes a single statement), this supports multiple semicolon-separated SQL statements with per-statement parameter bindings. The result of the last statement is returned.
-- As PRAGMA (no output)
PRAGMA mcp_publish_execution_tool('name', 'description', 'sql_template', 'properties', 'required', 'bindings');
PRAGMA mcp_publish_execution_tool('name', 'description', 'sql_template', 'properties', 'required', 'bindings', 'format');
-- As SELECT (returns status string)
SELECT mcp_publish_execution_tool('name', 'description', 'sql_template', 'properties', 'required', 'bindings');
SELECT mcp_publish_execution_tool('name', 'description', 'sql_template', 'properties', 'required', 'bindings', 'format');
Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
VARCHAR | Tool name (used by clients) |
description |
VARCHAR | Human-readable description |
sql_template |
VARCHAR | Multiple SQL statements separated by ; |
properties |
VARCHAR | JSON Schema for parameters |
required |
VARCHAR | JSON array of required parameter names |
bindings |
VARCHAR | Binding spec: JSON object (global) or array (per-statement) |
format |
VARCHAR | Output format (default: json) |
Binding Specs:
The bindings parameter controls how tool arguments map to prepared statement parameters. Two forms are supported:
-
Object form — all parameters bind to every statement:
-
Array form — per-statement bindings (array length must match statement count):
Examples:
-- SET a variable, then query using it
SELECT mcp_publish_execution_tool(
'filtered_report',
'Run a report with a configurable threshold',
'SET VARIABLE my_threshold = $threshold; SELECT * FROM sales WHERE amount > getvariable(''my_threshold'');',
'{"threshold": {"type": "integer", "description": "Minimum amount"}}',
'["threshold"]',
'[{}, {"threshold": "integer"}]'
);
-- Multi-step with global bindings
SELECT mcp_publish_execution_tool(
'create_and_query',
'Create a temp table and query it',
'CREATE TEMP TABLE tmp AS SELECT * FROM products WHERE category = $cat; SELECT * FROM tmp ORDER BY price;',
'{"cat": {"type": "string", "description": "Product category"}}',
'["cat"]',
'{"cat": "string"}'
);
Publish Before Server Starts
You can call mcp_publish_execution_tool before starting the server. The registration will be queued and automatically applied when the server starts.
State Introspection¶
Added in v2.1, these table functions expose the running server's published tools, resources, and configuration as queryable tables. They follow DuckDB's "everything is a table" philosophy and work both before and after mcp_server_start() is called — entries registered before start appear with status = 'pending' (queued), and active entries appear with status = 'active'.
Typical uses:
- Init script validation — assert that every tool/resource you expected to publish is actually registered
- Auto-generated help — render a tool catalog for client-side discovery
- Diagnostics — inspect effective configuration without parsing the
mcp_server_status()JSON - SQL composability — join tool metadata with other tables, filter by status, etc.
mcp_tools¶
Table function listing all published tools — both user-published (via mcp_publish_tool / mcp_publish_execution_tool) and server built-ins.
Schema:
| Column | Type | Description |
|---|---|---|
name |
VARCHAR | Tool name |
description |
VARCHAR | Human-readable description |
sql_template |
VARCHAR | SQL template for user-published tools; NULL for built-ins |
parameters |
VARCHAR | JSON Schema properties object |
required |
VARCHAR | JSON array of required parameter names |
format |
VARCHAR | Output format |
status |
VARCHAR | pending (queued), active (registered on a running server), or error |
is_builtin |
BOOLEAN | true for server-provided tools (query, describe, etc.), false for user-published |
Example — verify init script published what you expected:
-- After your init script runs
SELECT name, status, is_builtin FROM mcp_tools() WHERE NOT is_builtin ORDER BY name;
-- Assert every expected tool is registered
SELECT COUNT(*) FILTER (WHERE status = 'pending' OR status = 'active') AS published,
COUNT(*) FILTER (WHERE status = 'error') AS failed
FROM mcp_tools()
WHERE NOT is_builtin;
mcp_list_tools¶
No-argument alias for mcp_tools(). Provided as a convenience for symmetry with the client-side mcp_list_tools(server_name) scalar function.
Schema is identical to mcp_tools(). Use whichever name reads better in context — they are interchangeable.
Scalar vs table form
mcp_list_tools(server_name) (one VARCHAR argument) is the client function that queries a remote MCP server. The no-arg table form shown here is the server introspection function for the local DuckDB instance. Both names coexist because DuckDB's function registry disambiguates by arity.
mcp_resources¶
Table function listing all published resources — tables, queries, and static content.
Schema:
| Column | Type | Description |
|---|---|---|
uri |
VARCHAR | Resource URI (e.g. data://tables/products) |
type |
VARCHAR | Resource type: table, query, or resource |
description |
VARCHAR | Human-readable description |
mime_type |
VARCHAR | MIME type (e.g. application/json, text/plain) |
source |
VARCHAR | Source table name, SQL query, or inline content preview |
format |
VARCHAR | Output format |
status |
VARCHAR | pending, active, or error |
Example — list everything a client would see:
mcp_server_config¶
Table function returning the effective server configuration as key-value pairs.
Schema:
| Column | Type | Description |
|---|---|---|
key |
VARCHAR | Configuration key (e.g. enable_execute_tool) |
value |
VARCHAR | Stringified value — booleans as true/false, numbers as decimal strings |
Every option documented in Configuration Reference is available as a row. Before the server starts this reflects the pending config; after start it reflects the live server's config.
Example — sanity-check a hardened server:
SELECT key, value
FROM mcp_server_config()
WHERE key IN (
'enable_execute_tool',
'execute_allow_load',
'execute_allow_attach',
'cors_origins',
'require_auth'
);
Example — filter to just the enable_* flags:
Diagnostics¶
mcp_get_diagnostics¶
Return extension diagnostic information as a JSON object.
Returns: JSON object containing:
| Field | Type | Description |
|---|---|---|
log_level |
string | Active log level: trace, debug, info, warn, error, off |
extension_version |
string | Loaded extension version (e.g. 2.1.0) |
logging_available |
boolean | Whether MCP logging is wired into DuckDB's logging facility |
Example:
SELECT mcp_get_diagnostics();
-- {"log_level":"info","extension_version":"2.1.0","logging_available":true}
Use this when filing bug reports — it captures the exact extension version and log level without requiring a separate duckdb_extensions() query.
Prompt Templates¶
Register reusable prompt templates that this DuckDB instance will serve over MCP. Registered templates appear in the prompts/list response and can be rendered via prompts/get by connected clients. They can also be rendered locally in SQL for preview or testing.
Templates use {variable} placeholder syntax.
Local vs remote
The functions below manage prompts that this DuckDB instance exposes as an MCP server. To retrieve prompts from a remote MCP server that DuckDB is attached to, use mcp_list_prompts(server_name) / mcp_get_prompt(server_name, ...) — see Remote Prompt Functions in the client reference.
mcp_register_prompt_template¶
Register a new prompt template with the local server.
-- As PRAGMA (no output)
PRAGMA mcp_register_prompt_template('name', 'description', 'template_content');
-- As SELECT (returns status string)
SELECT mcp_register_prompt_template('name', 'description', 'template_content');
Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
VARCHAR | Unique template name (used by clients as the prompt name) |
description |
VARCHAR | Human-readable description |
template_content |
VARCHAR | Template body with {variable} placeholders |
Example:
PRAGMA mcp_register_prompt_template(
'sql_query',
'Generate a SQL query',
'Write a SQL query to {action} from the {table} table where {condition}.'
);
Once registered (and after the server starts), this template is discoverable by clients via prompts/list and retrievable via prompts/get.
mcp_list_prompt_templates¶
List all registered templates on the local server.
Example:
mcp_render_prompt_template¶
Render a registered template with supplied arguments — useful for previewing prompts or driving them from SQL without going through the MCP protocol.
Parameters:
| Parameter | Type | Description |
|---|---|---|
name |
VARCHAR | Template name |
arguments_json |
VARCHAR | JSON object mapping placeholder names to values |
Example:
SELECT mcp_render_prompt_template(
'sql_query',
'{"action": "count users", "table": "users", "condition": "created_at > ''2024-01-01''"}'
);
-- Returns: "Write a SQL query to count users from the users table where created_at > '2024-01-01'."
Built-in Server Tools¶
When running as an MCP server, these tools are automatically available to clients:
query¶
Execute read-only SQL queries.
Arguments:
| Argument | Type | Required | Description |
|---|---|---|---|
sql |
string | Yes | SQL SELECT statement |
format |
string | No | Output format: json (default), jsonl, csv, markdown, text |
The default can be changed server-wide via default_result_format (see Configuration).
Example request:
{
"name": "query",
"arguments": {
"sql": "SELECT * FROM products LIMIT 10",
"format": "markdown"
}
}
describe¶
Get schema information for a table or query.
Arguments:
| Argument | Type | Required | Description |
|---|---|---|---|
table |
string | No | Table name to describe |
query |
string | No | Query to analyze (returns result schema) |
Provide either table or query, not both.
list_tables¶
List all tables and views in the database.
Arguments:
| Argument | Type | Required | Description |
|---|---|---|---|
schema |
string | No | Filter by schema name |
include_views |
boolean | No | Include views (default: true) |
database_info¶
Get comprehensive database information including schemas, tables, and extensions.
Arguments: None.
Returns: JSON with databases, schemas, tables, views, and extensions.
export¶
Export query results inline or to a file.
Arguments:
| Argument | Type | Required | Description |
|---|---|---|---|
query |
string | Yes | Read-only SQL query to export |
output |
string | No | Output file path — only available when export_allow_file_output is enabled |
format |
string | No | Output format (see below) |
Supported formats:
| Mode | Formats |
|---|---|
Inline (no output) |
json, jsonl, csv, markdown, text |
File export (with output) |
json, csv, parquet |
File output is disabled by default
export_allow_file_output defaults to false — inline return is the only mode available until you explicitly enable file output in the server config. The tool's advertised inputSchema reflects this: the output argument only appears when file output is allowed.
Warning
The export tool only allows read-only statements. Use the execute tool for DDL/DML.
execute¶
Execute DDL/DML statements (CREATE, INSERT, UPDATE, DELETE, etc.).
Arguments:
| Argument | Type | Required | Description |
|---|---|---|---|
sql |
string | Yes | SQL statement to execute |
Security Warning
The execute tool is disabled by default because it allows modifying the database. Only enable it when you trust the MCP clients connecting to your server.
Memory Transport (Testing)¶
The memory transport is designed for testing MCP server functionality without external processes.
mcp_server_send_request¶
Send a JSON-RPC request directly to the memory transport server.
Parameters:
| Parameter | Type | Description |
|---|---|---|
request_json |
VARCHAR | Complete JSON-RPC 2.0 request |
Example:
-- Start memory server
PRAGMA mcp_server_start('memory');
-- Send initialize request
SELECT mcp_server_send_request('{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": {"name": "test", "version": "1.0"},
"capabilities": {}
}
}');
-- List tools
SELECT mcp_server_send_request('{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}');
-- Execute a query
SELECT mcp_server_send_request('{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "query",
"arguments": {"sql": "SELECT 1 + 1 as result"}
}
}');
This is invaluable for writing automated tests that verify MCP protocol compliance.
Config Mode¶
Config mode suppresses output from MCP scalar functions, useful when calling SELECT versions of side-effectful functions in init scripts where you don't want result rows cluttering the output.
PRAGMA mcp_config_begin;
-- All SELECT mcp_* calls below return empty/minimal output
SELECT mcp_server_start('memory', '{"background": true}');
SELECT mcp_publish_tool('search', 'Search', 'SELECT * FROM t WHERE name ILIKE $q', '{}', '[]');
SELECT mcp_publish_table('products', NULL, NULL);
PRAGMA mcp_config_end;
-- Normal output resumes
Prefer PRAGMA syntax
Config mode exists for backward compatibility with existing SELECT-based init scripts. For new scripts, use PRAGMA syntax instead — PRAGMA functions naturally produce no output, making mcp_config_begin/mcp_config_end unnecessary.
HTTP Transport¶
The http and https transports provide an HTTP server for MCP clients, enabling browser-based applications and standard HTTP tools to interact with DuckDB.
Endpoints¶
| Endpoint | Method | Description |
|---|---|---|
/health |
GET | Health check, returns {"status":"ok"} |
/ |
POST | MCP JSON-RPC endpoint |
/mcp |
POST | Alternative MCP JSON-RPC endpoint |
Authentication¶
When auth_token is configured, all MCP endpoints require Bearer token authentication:
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-secret-token" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
Response codes:
| Status | Condition |
|---|---|
| 200 OK | Request successful |
| 401 Unauthorized | No Authorization header provided |
| 403 Forbidden | Invalid token provided |
CORS¶
CORS is disabled by default. To enable CORS for browser-based clients, set the cors_origins configuration option:
-- Allow all origins
PRAGMA mcp_server_start('http', 'localhost', 8080, '{"cors_origins": "*"}');
-- Allow specific origins
PRAGMA mcp_server_start('http', 'localhost', 8080, '{"cors_origins": "https://example.com, https://app.example.com"}');
Example: Using curl¶
# Start server
duckdb -c "LOAD duckdb_mcp; SELECT mcp_server_start('http', 'localhost', 8080, '{}');"
# Health check
curl http://localhost:8080/health
# Initialize
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": {"name": "curl", "version": "1.0"},
"capabilities": {}
}
}'
# List tools
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}'
# Execute query
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "query",
"arguments": {"sql": "SELECT 1 + 1 as result"}
}
}'
HTTPS Configuration¶
For production use, enable HTTPS with SSL certificates:
PRAGMA mcp_server_start('https', '0.0.0.0', 8443, '{
"auth_token": "secure-token-here",
"ssl_cert_path": "/etc/ssl/certs/server.crt",
"ssl_key_path": "/etc/ssl/private/server.key"
}');
Security Recommendations
- Always use HTTPS in production
- Use strong, randomly-generated auth tokens
- Bind to specific interfaces rather than
0.0.0.0when possible - Consider firewall rules to restrict access