DuckDB MCP server: MotherDuck's, the extension, or your own
By Arshad Ansari
A DuckDB MCP server lets Claude, Cursor or any MCP client run SQL against your DuckDB files. There are three common ways to get one: MotherDuck's open-source server, the duckdb_mcp community extension, or a small server of your own. There is also MotherDuck's hosted MCP endpoint, if your data already lives in MotherDuck.
Their READMEs all say "read-only". So I tested what read-only means in each. I pointed two of them at the same 50,000-row DuckDB file and sent the same five queries: a count, a DELETE, a read of a file outside the database, a SELECT * with no limit, and a query built never to finish. The results differ more than the READMEs suggest.
Is there an official DuckDB MCP server?
Not from DuckDB Labs, as far as I could find on 1 October 2026. Several third-party pages describe an official npm package called @duckdb/mcp. The npm registry returns 404 for that name.
What does exist:
| Option | Who makes it | Runs where | Version I checked |
|---|---|---|---|
| mcp-server-motherduck | MotherDuck | Your machine, Python, stdio or HTTP | 1.0.8 (PyPI, 19 Aug 2026) |
| MotherDuck remote MCP | MotherDuck | MotherDuck's cloud | hosted |
| duckdb_mcp | Community (teaguesterling) | Inside DuckDB, stdio or HTTP | 2.3.2 |
| Your own | You | Anywhere | — |
The warehouses have their own too, for comparison. Snowflake's managed MCP server became generally available on 4 November 2025. BigQuery has a remote one at https://bigquery.googleapis.com/mcp, where execute_sql can write and execute_sql_readonly cannot.
The test
One DuckDB 1.5.6 file with an orders table of 50,000 rows. I drove each server over stdio from a Python MCP client (FastMCP 4.0.10), the same way Claude Code drives it. Five calls:
SELECT kind, count(*) ... GROUP BY kind, a normal question.DELETE FROM orders, a write.SELECT count(*) FROM read_csv('/etc/passwd', ...), a file outside the database.SELECT * FROM orders, with no limit.- A cross join of 100 million by 100,000 rows, which never finishes.
MotherDuck's local server (mcp-server-motherduck)
I started it the way you would for a local file, adding only a 5-second timeout:
uvx mcp-server-motherduck@1.0.8 --db-path shop.duckdb --query-timeout 5
It logged Database mode: read-only and Query result limits: 1024 rows, 50,000 characters. It served four tools: execute_query, list_databases, list_tables and list_columns.
| Probe | Result |
|---|---|
| Group-by | Correct, 3 rows |
DELETE | Refused: "attached in read-only mode" |
read_csv('/etc/passwd') | Ran. Returned 55, the file's line count |
SELECT * | 1,024 rows, "truncated": true, with a warning; about 80,000 characters of JSON |
| Never-ending query | Stopped: "timed out after 5 seconds" |
Two of those need a note.
Read-only stops writes, not reads. DuckDB's read-only mode protects the database file. It does not stop SQL from reading other files the process can see. I checked the same thing with plain DuckDB: a read_only=True connection read /etc/passwd without complaint. If the server runs as you, the model can read whatever you can, including ~/.aws/credentials. The DuckDB setting that closes this is enable_external_access = false. As far as I can tell, this server has no flag for it. It does have --init-sql, which runs SQL at startup. I did not test whether the setting works through it.
The timeout is off unless you set it. --query-timeout defaults to -1, which means disabled. Without my flag, call 5 would have held a CPU core until something killed the process.
Two more defaults to know. In-memory databases are always writable; the --help text says so. And the README's own Claude Code example uses --db-path :memory: --read-write --allow-switch-databases. That is a sandbox for exploring, not a read-only setup.
The duckdb_mcp extension
This one runs the MCP server inside DuckDB, with no Python server code at all:
INSTALL duckdb_mcp FROM community;
LOAD duckdb_mcp;
PRAGMA mcp_server_start('stdio');
I started it on a read-only connection to the same file. With the default configuration it served five tools: query, describe, list_tables, database_info and export.
| Probe | Result |
|---|---|
| Group-by | Correct, 3 rows |
DELETE | Refused: "Query tool only allows read-only statements" |
read_csv('/etc/passwd') | Refused: "disallowed file-access function ('read_csv')" |
SELECT * | All 50,000 rows, 3.7 MB of JSON |
| Never-ending query | No server-side timeout; my client gave up after 40 s |
The query tool checks the statement itself, which is why it refused the file read that MotherDuck's server ran. It has no row cap and no query timeout, though, and I found neither in its configuration reference. One SELECT * on a real table sends megabytes into the model's context.
Writes go through a separate execute tool, which is off by default. Its finer switches for LOAD, ATTACH and SET stay off even when you turn it on. The extension can also serve over HTTP with a bearer token:
PRAGMA mcp_server_start('http', 'localhost', 8080,
'{"auth_token": "...", "require_auth": true, "enable_export_tool": false}');
Its other trick is publishing named tools with mcp_publish_tool, each a fixed SQL template with typed parameters. Combined with builtin_tools: false, the model gets only the questions you wrote, and no free-form SQL. For a database other people depend on, that is the strongest option in this post.
The MotherDuck remote MCP server
If your data is in MotherDuck, there is nothing to install. The remote server lives at https://api.motherduck.com/mcp. It authenticates with OAuth, or with an Authorization: Bearer header carrying a MotherDuck token for backend clients. Its docs say it exposes read-only and read-write tools by default, with read-only restrictions available through configuration. So set that before you hand it to anyone. I did not test the remote server for this post.
The choice between local and remote is mostly made by where the data lives. Local DuckDB files mean the local server or the extension. Data in MotherDuck means remote, unless you need a flag only the local server has.
How to connect Claude Code to DuckDB
The Claude Code docs put options before the server name and the server's own command after --:
# MotherDuck's server on a local file, with a timeout
claude mcp add --transport stdio duckdb -- \
uvx mcp-server-motherduck@1.0.8 --db-path /path/to/analytics.duckdb --query-timeout 30
# The remote MotherDuck server, then run /mcp in Claude Code to sign in
claude mcp add --transport http motherduck https://api.motherduck.com/mcp
Add --scope project to write the server into .mcp.json for the team, or --scope user for all your projects. The default scope is the current project, kept private to you. Pin the version with @1.0.8 so an upstream release doesn't change your defaults without warning. Then run /mcp inside Claude Code to check that the server connected.
When to write your own
Each server above makes choices for you, and I found a gap in each: file reads in one, row caps and timeouts in the other. Writing your own server is about 70 lines of Python, and you decide every one of those defaults. These four lines close the file-read hole on any DuckDB connection you serve:
db = duckdb.connect("analytics.duckdb", read_only=True)
db.execute("SET enable_external_access = false") # no read_csv('/etc/passwd')
db.execute("SET autoload_known_extensions = false")
db.execute("SET lock_configuration = true") # the model can't SET them back
When I ran a server built this way, read_csv('/etc/passwd') failed with "file system operations are disabled by configuration", and SET enable_external_access = true failed with "the configuration has been locked".
Which DuckDB MCP server to run
- Exploring your own files on your own laptop: MotherDuck's local server, with
--query-timeoutset, on a file path rather than:memory:. - Anything other people's data is in: the
duckdb_mcpextension withbuiltin_tools: falseand named tools you published. Or your own server. - Data already in MotherDuck: the remote server, set to read-only.
- Any of the above: run it as a user that can read only the files it should. The process's file permissions are the real boundary.
The wider guardrails for any database (roles, views, PII, audit) are in how to connect an LLM to your database safely. The Postgres version of this choice is Postgres MCP server.
Local-First Analytics doesn't cover MCP. It covers the data these servers expose: DuckDB over Parquet files as a warehouse (Chapter 5), and a local model turning questions into SQL against it (Chapter 12). Chapter 1 is free to read; the rest is on Amazon.
If you are putting an assistant in front of data your team depends on and want a second opinion on the setup, that is the kind of work I do. If all you need is a timeout and enable_external_access = false, you have both above.
More in this series: building an MCP server with FastMCP, MCP security and authentication and Postgres MCP server.
Common questions
- Is there an official DuckDB MCP server?
- Not from DuckDB Labs, as far as I could find on 1 October 2026. The two most used options are MotherDuck's open-source mcp-server-motherduck, which works on plain local DuckDB files as well as MotherDuck, and duckdb_mcp, a community extension that turns DuckDB itself into an MCP server. Some third-party pages describe an official npm package called @duckdb/mcp; the npm registry returned 404 for that name when I checked.
- Is the DuckDB MCP server read-only?
- MotherDuck's local server is read-only by default for DuckDB files and MotherDuck databases; you opt in to writes with --read-write. In-memory databases are always writable. Read-only does not stop file reads: in my test it returned the line count of /etc/passwd through read_csv. The duckdb_mcp extension's query tool refused both a DELETE and that read_csv call by default.
- What is the difference between the local and remote MotherDuck MCP server?
- The local server, mcp-server-motherduck, is open source and runs on your machine over stdio. It can open a local DuckDB file, an in-memory database or a MotherDuck database, and is read-only by default. The remote server at https://api.motherduck.com/mcp is hosted by MotherDuck, works only with MotherDuck, and uses OAuth or a bearer token. MotherDuck's docs say it exposes read-only and read-write tools by default, so restrict it if you want reads only.
- How do I connect Claude Code to DuckDB?
- Add a stdio MCP server with claude mcp add, putting the server command after a double dash. For a local file with MotherDuck's server: claude mcp add --transport stdio duckdb -- uvx mcp-server-motherduck --db-path /path/to/analytics.duckdb --query-timeout 30. Add --scope project to share it through .mcp.json, or --scope user for all your projects. Then run /mcp inside Claude Code to check that it connected.
- Can I use DuckDB as an MCP server without Python?
- Yes. The duckdb_mcp community extension runs the server inside DuckDB: INSTALL duckdb_mcp FROM community, LOAD it, then PRAGMA mcp_server_start('stdio'). It also supports HTTP with a bearer token. By default it serves query, describe, list_tables, database_info and export tools; execute, which runs writes, is off unless you enable it.
Does DuckDB fit your system?
The 16-question production-fit checklist I run before putting DuckDB on a critical path — writers, working set, durability, memory, and who talks to it. Each question comes with what a bad answer sounds like.
The whole checklist, sent at once. No confirmation step.
What breaks and what it costs — pipelines, warehouse bills, and the failures that only show up in production. A few a month, never padded to hit a schedule. No sequence, no pitch deck. Reply 'stop' once and you're off — it reaches me, not a queue.
Want the whole playbook?
If this was useful, the long version is my book. Local-First Analytics — 313 pages, runnable code for every chapter — is the full build: DuckDB, Parquet and Arrow, from install to production. On Amazon, and chapter 1 is free to read here.
Get the bookNot ready to buy? Read chapter 1 free — the whole chapter, no email required.
Rather talk it through? Book a free 30-minute call. No slot that suits your time zone? Email info@hikmahtech.in.