Connecting to Local Files
Local DuckDB files (.duckdb extension) provide persistent storage with file-based databases.
Read-Only Connection (Recommended)
Read-only mode allows concurrent access from multiple processes:
{
"mcpServers" : {
"DuckDB (read-only)" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/absolute/path/to/your.duckdb"
]
}
}
}
Read-only mode uses ephemeral connections (enabled by default with --ephemeral-connections) that don’t hold file locks, allowing multiple readers.
Read-Write Connection
For write operations, enable read-write mode:
{
"mcpServers" : {
"DuckDB (read-write)" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/absolute/path/to/your.duckdb" ,
"--read-write"
]
}
}
}
Read-write mode holds an exclusive lock on the database file. Only one read-write connection can be active at a time.
Creating New Databases
Create a new DuckDB file automatically when it doesn’t exist:
{
"mcpServers" : {
"DuckDB (new)" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/path/to/new_database.duckdb" ,
"--read-write"
]
}
}
}
The database file will be created on first connection.
Working with Local Data
Create Tables
{
"name" : "execute_query" ,
"arguments" : {
"sql" : "CREATE TABLE users (id INTEGER PRIMARY KEY, name VARCHAR, email VARCHAR, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)"
}
}
Insert Data
INSERT INTO users (id, name , email) VALUES
( 1 , 'Alice' , '[email protected] ' ),
( 2 , 'Bob' , '[email protected] ' ),
( 3 , 'Charlie' , '[email protected] ' );
Query Data
{
"name" : "execute_query" ,
"arguments" : {
"sql" : "SELECT * FROM users ORDER BY id"
}
}
Update and Delete
Importing and Exporting Data
Import from CSV
CREATE TABLE sales AS
SELECT * FROM read_csv_auto( '/path/to/sales_data.csv' );
DuckDB’s read_csv_auto() automatically detects column types, delimiters, and headers.
Import from Parquet
CREATE TABLE events AS
SELECT * FROM read_parquet( '/path/to/events/*.parquet' );
Import from JSON
CREATE TABLE logs AS
SELECT * FROM read_json_auto( '/path/to/logs.json' );
Export to CSV
COPY ( SELECT * FROM users WHERE created_at > '2024-01-01' )
TO '/path/to/export/users.csv'
WITH (HEADER, DELIMITER ',' );
Export to Parquet
COPY users TO '/path/to/export/users.parquet' (FORMAT PARQUET );
Export operations require --read-write mode and may be restricted by --motherduck-saas-mode.
Export to JSON
COPY ( SELECT * FROM users) TO '/path/to/export/users.json' (FORMAT JSON );
Switching Between Databases
The switch_database_connection tool lets you change databases dynamically.
Requires --allow-switch-databases flag to be enabled when starting the server.
Enable Database Switching
{
"mcpServers" : {
"DuckDB (flexible)" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , ":memory:" ,
"--read-write" ,
"--allow-switch-databases"
]
}
}
}
Switch to Existing Database
{
"name" : "switch_database_connection" ,
"arguments" : {
"path" : "/path/to/another.duckdb"
}
}
Create New Database on Switch
{
"name" : "switch_database_connection" ,
"arguments" : {
"path" : "/path/to/new_db.duckdb" ,
"create_if_not_exists" : true
}
}
Creating databases requires the server to be started with --read-write mode.
Switch Between Local and In-Memory
To In-Memory
To Local File
{
"name" : "switch_database_connection" ,
"arguments" : {
"path" : ":memory:"
}
}
Concurrent Access Patterns
Multiple Read-Only Clients
Multiple processes can read from the same file simultaneously:
Client 1 (Read-Only)
Client 2 (Read-Only)
{
"command" : "uvx" ,
"args" : [ "mcp-server-motherduck" , "--db-path" , "/shared/data.duckdb" ]
}
Single Writer, Multiple Readers
One read-write connection alongside multiple read-only connections:
{
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/shared/data.duckdb" ,
"--read-write"
]
}
If a file lock error occurs, ensure --ephemeral-connections is enabled (it’s on by default) and you’re not running multiple read-write connections.
Use Absolute Paths
{
"args" : [ "--db-path" , "/home/user/data/analytics.duckdb" ]
}
Persistent vs Ephemeral Connections
Ephemeral (Default)
Persistent
# Releases file lock between queries
uvx mcp-server-motherduck --db-path /path/to/db.duckdb
Initialize with SQL
Run setup SQL on connection:
{
"mcpServers" : {
"DuckDB" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/path/to/db.duckdb" ,
"--read-write" ,
"--init-sql" , "PRAGMA threads=4; PRAGMA memory_limit='4GB';"
]
}
}
}
Or use an SQL file:
--init-sql /path/to/init.sql
Real-World Examples
Analytics Dashboard Backend
{
"mcpServers" : {
"Analytics DB" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/data/analytics.duckdb" ,
"--max-rows" , "5000" ,
"--query-timeout" , "30"
]
}
}
}
ETL Pipeline Database
{
"mcpServers" : {
"ETL Staging" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , "/etl/staging.duckdb" ,
"--read-write" ,
"--init-sql" , "PRAGMA temp_directory='/fast/ssd/temp';"
]
}
}
}
Local Data Exploration
{
"mcpServers" : {
"Data Explorer" : {
"command" : "uvx" ,
"args" : [
"mcp-server-motherduck" ,
"--db-path" , ":memory:" ,
"--read-write" ,
"--allow-switch-databases"
]
}
}
}
Now you can dynamically load different datasets:
-- Load dataset 1
CREATE TABLE sales AS SELECT * FROM read_csv_auto( '/datasets/sales.csv' );
-- Switch to different database
-- Use switch_database_connection tool
-- Load dataset 2
CREATE TABLE customers AS SELECT * FROM read_parquet( '/datasets/customers.parquet' );
Troubleshooting
File Locked Error
Error : “Database file is locked” or “spawn uvx ENOENT”
Solution :
Ensure --ephemeral-connections is enabled (default)
Close other read-write connections to the file
Check that no other process has the file open
Permission Denied
Error : “Permission denied” when accessing database file
Solution : Verify file permissions and that the path is accessible:
ls -la /path/to/database.duckdb
chmod 644 /path/to/database.duckdb # If needed
Relative Path Error
Error : “Relative paths are not allowed”
Solution : Use absolute paths:
// Bad
"--db-path" , "./data.duckdb"
// Good
"--db-path" , "/home/user/project/data.duckdb"
Database Does Not Exist
Error : “Database file does not exist”
Solution : Either create the file first or use create_if_not_exists when switching:
{
"name" : "switch_database_connection" ,
"arguments" : {
"path" : "/path/to/new.duckdb" ,
"create_if_not_exists" : true
}
}