mcp-server-motherduck 0.5__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of mcp-server-motherduck might be problematic. Click here for more details.

Files changed (23) hide show
  1. mcp_server_motherduck-0.6.0/.idea/workspace.xml +111 -0
  2. mcp_server_motherduck-0.5/README.md → mcp_server_motherduck-0.6.0/PKG-INFO +63 -33
  3. mcp_server_motherduck-0.5/PKG-INFO → mcp_server_motherduck-0.6.0/README.md +47 -46
  4. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/pyproject.toml +7 -4
  5. mcp_server_motherduck-0.6.0/src/mcp_server_motherduck/__init__.py +193 -0
  6. mcp_server_motherduck-0.6.0/src/mcp_server_motherduck/configs.py +32 -0
  7. mcp_server_motherduck-0.6.0/src/mcp_server_motherduck/database.py +139 -0
  8. mcp_server_motherduck-0.6.0/src/mcp_server_motherduck/server.py +149 -0
  9. mcp_server_motherduck-0.6.0/uv.lock +417 -0
  10. mcp_server_motherduck-0.5/.idea/workspace.xml +0 -66
  11. mcp_server_motherduck-0.5/src/mcp_server_motherduck/__init__.py +0 -66
  12. mcp_server_motherduck-0.5/src/mcp_server_motherduck/server.py +0 -299
  13. mcp_server_motherduck-0.5/uv.lock +0 -529
  14. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.github/workflows/python-publish.yml +0 -0
  15. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.gitignore +0 -0
  16. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.idea/.gitignore +0 -0
  17. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.idea/mcp-server-motherduck.iml +0 -0
  18. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.idea/misc.xml +0 -0
  19. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.idea/modules.xml +0 -0
  20. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/.idea/vcs.xml +0 -0
  21. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/LICENSE +0 -0
  22. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/makefile +0 -0
  23. {mcp_server_motherduck-0.5 → mcp_server_motherduck-0.6.0}/src/mcp_server_motherduck/prompt.py +0 -0
@@ -0,0 +1,111 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project version="4">
3
+ <component name="AutoImportSettings">
4
+ <option name="autoReloadType" value="SELECTIVE" />
5
+ </component>
6
+ <component name="CMakeProjectFlavorService">
7
+ <option name="flavorId" value="CMakePlainProjectFlavor" />
8
+ </component>
9
+ <component name="CMakeSettings">
10
+ <configurations>
11
+ <configuration PROFILE_NAME="Debug" ENABLED="true" CONFIG_NAME="Debug" />
12
+ </configurations>
13
+ </component>
14
+ <component name="ChangeListManager">
15
+ <list default="true" id="8bdee1d4-886c-4093-b4cf-95b120034c9e" name="Changes" comment="">
16
+ <change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
17
+ <change beforePath="$PROJECT_DIR$/src/mcp_server_motherduck/__init__.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/mcp_server_motherduck/__init__.py" afterDir="false" />
18
+ <change beforePath="$PROJECT_DIR$/src/mcp_server_motherduck/database.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/mcp_server_motherduck/database.py" afterDir="false" />
19
+ <change beforePath="$PROJECT_DIR$/src/mcp_server_motherduck/server.py" beforeDir="false" afterPath="$PROJECT_DIR$/src/mcp_server_motherduck/server.py" afterDir="false" />
20
+ <change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
21
+ </list>
22
+ <option name="SHOW_DIALOG" value="false" />
23
+ <option name="HIGHLIGHT_CONFLICTS" value="true" />
24
+ <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
25
+ <option name="LAST_RESOLUTION" value="IGNORE" />
26
+ </component>
27
+ <component name="ClangdSettings">
28
+ <option name="formatViaClangd" value="false" />
29
+ </component>
30
+ <component name="FlaskConsoleOptions" custom-start-script="import sys&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;from flask.cli import ScriptInfo&#10;locals().update(ScriptInfo(create_app=None).load_app().make_shell_context())&#10;print(&quot;Python %s on %s\nApp: %s [%s]\nInstance: %s&quot; % (sys.version, sys.platform, app.import_name, app.env, app.instance_path))">
31
+ <envs>
32
+ <env key="FLASK_APP" value="app" />
33
+ </envs>
34
+ <option name="myCustomStartScript" value="import sys&#10;sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS])&#10;from flask.cli import ScriptInfo&#10;locals().update(ScriptInfo(create_app=None).load_app().make_shell_context())&#10;print(&quot;Python %s on %s\nApp: %s [%s]\nInstance: %s&quot; % (sys.version, sys.platform, app.import_name, app.env, app.instance_path))" />
35
+ <option name="myEnvs">
36
+ <map>
37
+ <entry key="FLASK_APP" value="app" />
38
+ </map>
39
+ </option>
40
+ </component>
41
+ <component name="Git.Settings">
42
+ <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
43
+ </component>
44
+ <component name="MarkdownSettingsMigration">
45
+ <option name="stateVersion" value="1" />
46
+ </component>
47
+ <component name="ProjectColorInfo">{
48
+ &quot;associatedIndex&quot;: 3
49
+ }</component>
50
+ <component name="ProjectId" id="2vcb2orYlzlw5ZHOvoXgpTtCdVi" />
51
+ <component name="ProjectViewState">
52
+ <option name="hideEmptyMiddlePackages" value="true" />
53
+ <option name="showLibraryContents" value="true" />
54
+ </component>
55
+ <component name="PropertiesComponent"><![CDATA[{
56
+ "keyToString": {
57
+ "RunOnceActivity.OpenProjectViewOnStart": "true",
58
+ "RunOnceActivity.ShowReadmeOnStart": "true",
59
+ "RunOnceActivity.cidr.known.project.marker": "true",
60
+ "RunOnceActivity.git.unshallow": "true",
61
+ "RunOnceActivity.readMode.enableVisualFormatting": "true",
62
+ "WebServerToolWindowFactoryState": "false",
63
+ "cf.first.check.clang-format": "false",
64
+ "cidr.known.project.marker": "true",
65
+ "git-widget-placeholder": "adi/add-inapp-sse",
66
+ "last_opened_file_path": "/Users/doehmen/Documents/motherduck/mcp-server-motherduck",
67
+ "node.js.detected.package.eslint": "true",
68
+ "node.js.detected.package.tslint": "true",
69
+ "node.js.selected.package.eslint": "(autodetect)",
70
+ "node.js.selected.package.tslint": "(autodetect)",
71
+ "nodejs_package_manager_path": "npm",
72
+ "project.structure.last.edited": "Project",
73
+ "project.structure.proportion": "0.0",
74
+ "project.structure.side.proportion": "0.0",
75
+ "settings.editor.selected.configurable": "preferences.updates",
76
+ "vue.rearranger.settings.migration": "true"
77
+ }
78
+ }]]></component>
79
+ <component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
80
+ <component name="TaskManager">
81
+ <task active="true" id="Default" summary="Default task">
82
+ <changelist id="8bdee1d4-886c-4093-b4cf-95b120034c9e" name="Changes" comment="" />
83
+ <created>1744447105618</created>
84
+ <option name="number" value="Default" />
85
+ <option name="presentableId" value="Default" />
86
+ <updated>1744447105618</updated>
87
+ <workItem from="1744447107447" duration="7470000" />
88
+ <workItem from="1744787944049" duration="599000" />
89
+ <workItem from="1744896732489" duration="6070000" />
90
+ <workItem from="1747725447463" duration="5949000" />
91
+ <workItem from="1747924921526" duration="17579000" />
92
+ <workItem from="1749541956173" duration="67000" />
93
+ <workItem from="1749546948380" duration="272000" />
94
+ <workItem from="1749547445107" duration="2288000" />
95
+ <workItem from="1750068892931" duration="1202000" />
96
+ <workItem from="1750076934923" duration="598000" />
97
+ <workItem from="1750084124415" duration="194000" />
98
+ <workItem from="1750084439422" duration="575000" />
99
+ <workItem from="1750086684829" duration="92000" />
100
+ <workItem from="1750099676834" duration="5651000" />
101
+ </task>
102
+ <servers />
103
+ </component>
104
+ <component name="TypeScriptGeneratedFilesManager">
105
+ <option name="version" value="3" />
106
+ </component>
107
+ <component name="XSLT-Support.FileAssociations.UIState">
108
+ <expand />
109
+ <select />
110
+ </component>
111
+ </project>
@@ -1,7 +1,25 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-server-motherduck
3
+ Version: 0.6.0
4
+ Summary: A MCP server for MotherDuck and local DuckDB
5
+ Author-email: tdoehmen <till@motherduck.com>
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: anyio>=4.8.0
9
+ Requires-Dist: click>=8.1.8
10
+ Requires-Dist: duckdb==1.3.0
11
+ Requires-Dist: mcp>=1.9.4
12
+ Requires-Dist: starlette>=0.46.1
13
+ Requires-Dist: tabulate>=0.9.0
14
+ Requires-Dist: uvicorn>=0.34.0
15
+ Description-Content-Type: text/markdown
16
+
1
17
  # MotherDuck's DuckDB MCP Server
2
18
 
3
19
  An MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
4
20
 
21
+ [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=DuckDB&config=eyJjb21tYW5kIjoidXZ4IG1jcC1zZXJ2ZXItbW90aGVyZHVjayAtLWRiLXBhdGggbWQ6IiwiZW52Ijp7Im1vdGhlcmR1Y2tfdG9rZW4iOiIifX0%3D)
22
+
5
23
  ## Resources
6
24
  - [Close the Loop: Faster Data Pipelines with MCP, DuckDB & AI (Blogpost)](https://motherduck.com/blog/faster-data-pipelines-with-mcp-duckdb-ai/)
7
25
  - [Faster Data Pipelines development with MCP and DuckDB (YouTube)](https://www.youtube.com/watch?v=yG1mv8ZRxcU)
@@ -32,6 +50,37 @@ The server offers one tool:
32
50
 
33
51
  All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
34
52
 
53
+ ## Command Line Parameters
54
+
55
+ The MCP server supports the following parameters:
56
+
57
+ | Parameter | Type | Default | Description |
58
+ |-----------|------|---------|-------------|
59
+ | `--transport` | Choice | `stdio` | Transport type. Options: `stdio`, `sse`, `stream` |
60
+ | `--port` | Integer | `8000` | Port to listen on for sse and stream transport mode |
61
+ | `--db-path` | String | `md:` | Path to local DuckDB database file or MotherDuck database |
62
+ | `--motherduck-token` | String | `None` | Access token to use for MotherDuck database connections (uses `motherduck_token` env var by default) |
63
+ | `--read-only` | Flag | `False` | Flag for connecting to DuckDB in read-only mode. Only supported for local DuckDB databases. Uses short-lived connections for concurrent access |
64
+ | `--home-dir` | String | `None` | Home directory for DuckDB (uses `HOME` env var by default) |
65
+ | `--saas-mode` | Flag | `False` | Flag for connecting to MotherDuck in SaaS mode |
66
+ | `--json-response` | Flag | `False` | Enable JSON responses for HTTP stream. Only supported for `stream` transport |
67
+
68
+ ### Quick Usage Examples
69
+
70
+ ```bash
71
+ # Connect to local DuckDB file in read-only mode with stream transport mode
72
+ uvx mcp-server-motherduck --transport stream --db-path /path/to/local.db --read-only
73
+
74
+ # Connect to MotherDuck with token with stream transport mode
75
+ uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN
76
+
77
+ # Connect to local DuckDB file in read-only mode with stream transport mode
78
+ uvx mcp-server-motherduck --transport stream --db-path /path/to/local.db --read-only
79
+
80
+ # Connect to MotherDuck in SaaS mode for enhanced security with stream transport mode
81
+ uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN --saas-mode
82
+ ```
83
+
35
84
  ## Getting Started
36
85
 
37
86
  ### General Prerequisites
@@ -81,11 +130,11 @@ See [Connect to local DuckDB](#connect-to-local-duckdb).
81
130
 
82
131
  ### Usage with VS Code
83
132
 
84
- [![Install with UV in VS Code](https://img.shields.io/badge/VS_Code-UV-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with UV in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-UV-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders)
133
+ [![Install with UV in VS Code](https://img.shields.io/badge/VS_Code-Install_with_UV-0098FF?style=plastic)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with UV in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_with_UV-24bfa5?style=plastic&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders)
85
134
 
86
- 1. For the quickest installation, click one of the "Install with UV" buttons at the top of this README.
135
+ For the quickest installation, click one of the "Install with UV" buttons at the top.
87
136
 
88
- ### Manual Installation
137
+ #### Manual Installation
89
138
 
90
139
  Add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`.
91
140
 
@@ -172,7 +221,6 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
172
221
  **Important Notes**:
173
222
 
174
223
  - Replace `YOUR_MOTHERDUCK_TOKEN_HERE` with your actual MotherDuck token
175
- - Replace `YOUR_HOME_FOLDER_PATH` with the path to your home directory (needed by DuckDB for file operations). For example, on macOS, it would be `/Users/your_username`
176
224
  - The `HOME` environment variable is required for DuckDB to function properly.
177
225
 
178
226
  ## Securing your MCP Server when querying MotherDuck
@@ -277,47 +325,29 @@ Once configured, you can e.g. ask Claude to run queries like:
277
325
  - "Join data from my local DuckDB database with a table in MotherDuck"
278
326
  - "Analyze data stored in Amazon S3"
279
327
 
280
- ## Testing
281
-
282
- The server is designed to be run by tools like Claude Desktop and Cursor, but you can start it manually for testing purposes. When testing the server manually, you can specify which database to connect to using the `--db-path` parameter:
283
-
284
- 1. **Default MotherDuck database**:
285
-
286
- - To connect to the default MotherDuck database, you will need to pass the auth token using the `--motherduck-token` parameter.
287
-
288
- ```bash
289
- uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>
290
- ```
291
-
292
- 2. **Specific MotherDuck database**:
293
-
294
- ```bash
295
- uvx mcp-server-motherduck --db-path md:your_database_name --motherduck-token <your_motherduck_token>
296
- ```
328
+ ## Running in SSE mode
297
329
 
298
- 3. **Local DuckDB database**:
330
+ The server can run in SSE mode in two ways:
299
331
 
300
- ```bash
301
- uvx mcp-server-motherduck --db-path /path/to/your/local.db
302
- ```
332
+ ### Direct SSE mode
303
333
 
304
- 4. **In-memory database**:
334
+ Run the server directly in SSE mode using the `--transport sse` flag:
305
335
 
306
- ```bash
307
- uvx mcp-server-motherduck --db-path :memory:
308
- ```
336
+ ```bash
337
+ uvx mcp-server-motherduck --transport sse --port 8000 --db-path md: --motherduck-token <your_motherduck_token>
338
+ ```
309
339
 
310
- If you don't specify a database path but have set the `motherduck_token` environment variable, the server will automatically connect to the default MotherDuck database (`md:`).
340
+ This will start the server listening on the specified port (default 8000) and you can point your clients directly to this endpoint.
311
341
 
312
- ## Running in SSE mode
342
+ ### Using supergateway
313
343
 
314
- The server could also be running SSE mode using `supergateway` by running the following command:
344
+ Alternatively, you can run SSE mode using `supergateway`:
315
345
 
316
346
  ```bash
317
347
  npx -y supergateway --stdio "uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>"
318
348
  ```
319
349
 
320
- And you can point your clients such as Claude Desktop, Cursor to this endpoint.
350
+ Both methods allow you to point your clients such as Claude Desktop, Cursor to the SSE endpoint.
321
351
 
322
352
  ## Development configuration
323
353
 
@@ -1,20 +1,9 @@
1
- Metadata-Version: 2.4
2
- Name: mcp-server-motherduck
3
- Version: 0.5
4
- Summary: A MCP server for MotherDuck and local DuckDB
5
- Author-email: tdoehmen <till@motherduck.com>
6
- License-File: LICENSE
7
- Requires-Python: >=3.10
8
- Requires-Dist: duckdb==1.2.2
9
- Requires-Dist: mcp>=1.3.0
10
- Requires-Dist: pandas>=2.0.0
11
- Requires-Dist: tabulate>=0.9.0
12
- Description-Content-Type: text/markdown
13
-
14
1
  # MotherDuck's DuckDB MCP Server
15
2
 
16
3
  An MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
17
4
 
5
+ [![Install MCP Server](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/install-mcp?name=DuckDB&config=eyJjb21tYW5kIjoidXZ4IG1jcC1zZXJ2ZXItbW90aGVyZHVjayAtLWRiLXBhdGggbWQ6IiwiZW52Ijp7Im1vdGhlcmR1Y2tfdG9rZW4iOiIifX0%3D)
6
+
18
7
  ## Resources
19
8
  - [Close the Loop: Faster Data Pipelines with MCP, DuckDB & AI (Blogpost)](https://motherduck.com/blog/faster-data-pipelines-with-mcp-duckdb-ai/)
20
9
  - [Faster Data Pipelines development with MCP and DuckDB (YouTube)](https://www.youtube.com/watch?v=yG1mv8ZRxcU)
@@ -45,6 +34,37 @@ The server offers one tool:
45
34
 
46
35
  All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
47
36
 
37
+ ## Command Line Parameters
38
+
39
+ The MCP server supports the following parameters:
40
+
41
+ | Parameter | Type | Default | Description |
42
+ |-----------|------|---------|-------------|
43
+ | `--transport` | Choice | `stdio` | Transport type. Options: `stdio`, `sse`, `stream` |
44
+ | `--port` | Integer | `8000` | Port to listen on for sse and stream transport mode |
45
+ | `--db-path` | String | `md:` | Path to local DuckDB database file or MotherDuck database |
46
+ | `--motherduck-token` | String | `None` | Access token to use for MotherDuck database connections (uses `motherduck_token` env var by default) |
47
+ | `--read-only` | Flag | `False` | Flag for connecting to DuckDB in read-only mode. Only supported for local DuckDB databases. Uses short-lived connections for concurrent access |
48
+ | `--home-dir` | String | `None` | Home directory for DuckDB (uses `HOME` env var by default) |
49
+ | `--saas-mode` | Flag | `False` | Flag for connecting to MotherDuck in SaaS mode |
50
+ | `--json-response` | Flag | `False` | Enable JSON responses for HTTP stream. Only supported for `stream` transport |
51
+
52
+ ### Quick Usage Examples
53
+
54
+ ```bash
55
+ # Connect to local DuckDB file in read-only mode with stream transport mode
56
+ uvx mcp-server-motherduck --transport stream --db-path /path/to/local.db --read-only
57
+
58
+ # Connect to MotherDuck with token with stream transport mode
59
+ uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN
60
+
61
+ # Connect to local DuckDB file in read-only mode with stream transport mode
62
+ uvx mcp-server-motherduck --transport stream --db-path /path/to/local.db --read-only
63
+
64
+ # Connect to MotherDuck in SaaS mode for enhanced security with stream transport mode
65
+ uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN --saas-mode
66
+ ```
67
+
48
68
  ## Getting Started
49
69
 
50
70
  ### General Prerequisites
@@ -94,11 +114,11 @@ See [Connect to local DuckDB](#connect-to-local-duckdb).
94
114
 
95
115
  ### Usage with VS Code
96
116
 
97
- [![Install with UV in VS Code](https://img.shields.io/badge/VS_Code-UV-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with UV in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-UV-24bfa5?style=flat-square&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders)
117
+ [![Install with UV in VS Code](https://img.shields.io/badge/VS_Code-Install_with_UV-0098FF?style=plastic)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D) [![Install with UV in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install_with_UV-24bfa5?style=plastic&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=mcp-server-motherduck&config=%7B%22command%22%3A%22uvx%22%2C%22args%22%3A%5B%22mcp-server-motherduck%22%2C%22--db-path%22%2C%22md%3A%22%2C%22--motherduck-token%22%2C%22%24%7Binput%3Amotherduck_token%7D%22%5D%7D&inputs=%5B%7B%22type%22%3A%22promptString%22%2C%22id%22%3A%22motherduck_token%22%2C%22description%22%3A%22MotherDuck+Token%22%2C%22password%22%3Atrue%7D%5D&quality=insiders)
98
118
 
99
- 1. For the quickest installation, click one of the "Install with UV" buttons at the top of this README.
119
+ For the quickest installation, click one of the "Install with UV" buttons at the top.
100
120
 
101
- ### Manual Installation
121
+ #### Manual Installation
102
122
 
103
123
  Add the following JSON block to your User Settings (JSON) file in VS Code. You can do this by pressing `Ctrl + Shift + P` and typing `Preferences: Open User Settings (JSON)`.
104
124
 
@@ -185,7 +205,6 @@ Optionally, you can add it to a file called `.vscode/mcp.json` in your workspace
185
205
  **Important Notes**:
186
206
 
187
207
  - Replace `YOUR_MOTHERDUCK_TOKEN_HERE` with your actual MotherDuck token
188
- - Replace `YOUR_HOME_FOLDER_PATH` with the path to your home directory (needed by DuckDB for file operations). For example, on macOS, it would be `/Users/your_username`
189
208
  - The `HOME` environment variable is required for DuckDB to function properly.
190
209
 
191
210
  ## Securing your MCP Server when querying MotherDuck
@@ -290,47 +309,29 @@ Once configured, you can e.g. ask Claude to run queries like:
290
309
  - "Join data from my local DuckDB database with a table in MotherDuck"
291
310
  - "Analyze data stored in Amazon S3"
292
311
 
293
- ## Testing
294
-
295
- The server is designed to be run by tools like Claude Desktop and Cursor, but you can start it manually for testing purposes. When testing the server manually, you can specify which database to connect to using the `--db-path` parameter:
296
-
297
- 1. **Default MotherDuck database**:
298
-
299
- - To connect to the default MotherDuck database, you will need to pass the auth token using the `--motherduck-token` parameter.
300
-
301
- ```bash
302
- uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>
303
- ```
304
-
305
- 2. **Specific MotherDuck database**:
306
-
307
- ```bash
308
- uvx mcp-server-motherduck --db-path md:your_database_name --motherduck-token <your_motherduck_token>
309
- ```
312
+ ## Running in SSE mode
310
313
 
311
- 3. **Local DuckDB database**:
314
+ The server can run in SSE mode in two ways:
312
315
 
313
- ```bash
314
- uvx mcp-server-motherduck --db-path /path/to/your/local.db
315
- ```
316
+ ### Direct SSE mode
316
317
 
317
- 4. **In-memory database**:
318
+ Run the server directly in SSE mode using the `--transport sse` flag:
318
319
 
319
- ```bash
320
- uvx mcp-server-motherduck --db-path :memory:
321
- ```
320
+ ```bash
321
+ uvx mcp-server-motherduck --transport sse --port 8000 --db-path md: --motherduck-token <your_motherduck_token>
322
+ ```
322
323
 
323
- If you don't specify a database path but have set the `motherduck_token` environment variable, the server will automatically connect to the default MotherDuck database (`md:`).
324
+ This will start the server listening on the specified port (default 8000) and you can point your clients directly to this endpoint.
324
325
 
325
- ## Running in SSE mode
326
+ ### Using supergateway
326
327
 
327
- The server could also be running SSE mode using `supergateway` by running the following command:
328
+ Alternatively, you can run SSE mode using `supergateway`:
328
329
 
329
330
  ```bash
330
331
  npx -y supergateway --stdio "uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>"
331
332
  ```
332
333
 
333
- And you can point your clients such as Claude Desktop, Cursor to this endpoint.
334
+ Both methods allow you to point your clients such as Claude Desktop, Cursor to the SSE endpoint.
334
335
 
335
336
  ## Development configuration
336
337
 
@@ -1,14 +1,17 @@
1
1
  [project]
2
2
  name = "mcp-server-motherduck"
3
- version = "0.5"
3
+ version = "0.6.0"
4
4
  description = "A MCP server for MotherDuck and local DuckDB"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
7
  dependencies = [
8
- "mcp>=1.3.0",
9
- "duckdb==1.2.2",
10
- "pandas>=2.0.0",
8
+ "duckdb==1.3.0",
11
9
  "tabulate>=0.9.0",
10
+ "click>=8.1.8",
11
+ "starlette>=0.46.1",
12
+ "uvicorn>=0.34.0",
13
+ "anyio>=4.8.0",
14
+ "mcp>=1.9.4",
12
15
  ]
13
16
 
14
17
  [[project.authors]]
@@ -0,0 +1,193 @@
1
+ import anyio
2
+ import logging
3
+ import click
4
+ from .server import build_application
5
+ from .configs import SERVER_VERSION, SERVER_LOCALHOST, UVICORN_LOGGING_CONFIG
6
+
7
+ __version__ = SERVER_VERSION
8
+
9
+ logger = logging.getLogger("mcp_server_motherduck")
10
+ logging.basicConfig(
11
+ level=logging.INFO, format="[motherduck] %(levelname)s - %(message)s"
12
+ )
13
+
14
+
15
+ @click.command()
16
+ @click.option("--port", default=8000, help="Port to listen on for SSE")
17
+ @click.option(
18
+ "--transport",
19
+ type=click.Choice(["stdio", "sse", "stream"]),
20
+ default="stdio",
21
+ help="(Default: `stdio`) Transport type",
22
+ )
23
+ @click.option(
24
+ "--db-path",
25
+ default="md:",
26
+ help="(Default: `md:`) Path to local DuckDB database file or MotherDuck database",
27
+ )
28
+ @click.option(
29
+ "--motherduck-token",
30
+ default=None,
31
+ help="(Default: env var `motherduck_token`) Access token to use for MotherDuck database connections",
32
+ )
33
+ @click.option(
34
+ "--home-dir",
35
+ default=None,
36
+ help="(Default: env var `HOME`) Home directory for DuckDB",
37
+ )
38
+ @click.option(
39
+ "--saas-mode",
40
+ is_flag=True,
41
+ help="Flag for connecting to MotherDuck in SaaS mode",
42
+ )
43
+ @click.option(
44
+ "--read-only",
45
+ is_flag=True,
46
+ help="Flag for connecting to DuckDB in read-only mode. Only supported for local DuckDB databases. Also makes use of short lived connections so multiple MCP clients or other systems can remain active (though each operation must be done sequentially).",
47
+ )
48
+ @click.option(
49
+ "--json-response",
50
+ is_flag=True,
51
+ default=False,
52
+ help="(Default: `False`) Enable JSON responses instead of SSE streams. Only supported for `stream` transport.",
53
+ )
54
+ def main(
55
+ port,
56
+ transport,
57
+ db_path,
58
+ motherduck_token,
59
+ home_dir,
60
+ saas_mode,
61
+ read_only,
62
+ json_response,
63
+ ):
64
+ """Main entry point for the package."""
65
+
66
+ logger.info("🦆 MotherDuck MCP Server v" + SERVER_VERSION)
67
+ logger.info("Ready to execute SQL queries via DuckDB/MotherDuck")
68
+
69
+ app, init_opts = build_application(
70
+ db_path=db_path,
71
+ motherduck_token=motherduck_token,
72
+ home_dir=home_dir,
73
+ saas_mode=saas_mode,
74
+ read_only=read_only,
75
+ )
76
+
77
+ if transport == "sse":
78
+ from mcp.server.sse import SseServerTransport
79
+ from starlette.applications import Starlette
80
+ from starlette.responses import Response
81
+ from starlette.routing import Mount, Route
82
+
83
+ logger.info("MCP server initialized in \033[32msse\033[0m mode")
84
+
85
+ sse = SseServerTransport("/messages/")
86
+
87
+ async def handle_sse(request):
88
+ async with sse.connect_sse(
89
+ request.scope, request.receive, request._send
90
+ ) as (read_stream, write_stream):
91
+ await app.run(read_stream, write_stream, init_opts)
92
+ return Response()
93
+
94
+ logger.info(
95
+ f"🦆 Connect to MotherDuck MCP Server at \033[1m\033[36mhttp://{SERVER_LOCALHOST}:{port}/sse\033[0m"
96
+ )
97
+
98
+ starlette_app = Starlette(
99
+ debug=True,
100
+ routes=[
101
+ Route("/sse", endpoint=handle_sse, methods=["GET"]),
102
+ Mount("/messages/", app=sse.handle_post_message),
103
+ ],
104
+ )
105
+
106
+ import uvicorn
107
+
108
+ uvicorn.run(
109
+ starlette_app,
110
+ host=SERVER_LOCALHOST,
111
+ port=port,
112
+ log_config=UVICORN_LOGGING_CONFIG,
113
+ )
114
+
115
+ elif transport == "stream":
116
+ from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
117
+ from collections.abc import AsyncIterator
118
+ from starlette.applications import Starlette
119
+ from starlette.routing import Mount
120
+ from starlette.types import Receive, Scope, Send
121
+ import contextlib
122
+
123
+ logger.info("MCP server initialized in \033[32mhttp-streamable\033[0m mode")
124
+
125
+ # Create the session manager with true stateless mode
126
+ session_manager = StreamableHTTPSessionManager(
127
+ app=app,
128
+ event_store=None,
129
+ json_response=json_response,
130
+ stateless=True,
131
+ )
132
+
133
+ async def handle_streamable_http(
134
+ scope: Scope, receive: Receive, send: Send
135
+ ) -> None:
136
+ await session_manager.handle_request(scope, receive, send)
137
+
138
+ @contextlib.asynccontextmanager
139
+ async def lifespan(app: Starlette) -> AsyncIterator[None]:
140
+ """Context manager for session manager."""
141
+ async with session_manager.run():
142
+ logger.info("MCP server started with StreamableHTTP session manager")
143
+ try:
144
+ yield
145
+ finally:
146
+ logger.info(
147
+ "🦆 MotherDuck MCP Server in \033[32mhttp-streamable\033[0m mode shutting down"
148
+ )
149
+
150
+ logger.info(
151
+ f"🦆 Connect to MotherDuck MCP Server at \033[1m\033[36mhttp://{SERVER_LOCALHOST}:{port}/mcp\033[0m"
152
+ )
153
+
154
+ # Create an ASGI application using the transport
155
+ starlette_app = Starlette(
156
+ debug=True,
157
+ routes=[
158
+ Mount("/mcp", app=handle_streamable_http),
159
+ ],
160
+ lifespan=lifespan,
161
+ )
162
+
163
+ import uvicorn
164
+
165
+ uvicorn.run(
166
+ starlette_app,
167
+ host=SERVER_LOCALHOST,
168
+ port=port,
169
+ log_config=UVICORN_LOGGING_CONFIG,
170
+ )
171
+
172
+ else:
173
+ from mcp.server.stdio import stdio_server
174
+
175
+ logger.info("MCP server initialized in \033[32mstdio\033[0m mode")
176
+ logger.info("Waiting for client connection")
177
+
178
+ async def arun():
179
+ async with stdio_server() as (read_stream, write_stream):
180
+ await app.run(read_stream, write_stream, init_opts)
181
+
182
+ anyio.run(arun)
183
+ # This will only be reached when the server is shutting down
184
+ logger.info(
185
+ "🦆 MotherDuck MCP Server in \033[32mstdio\033[0m mode shutting down"
186
+ )
187
+
188
+
189
+ # Optionally expose other important items at package level
190
+ __all__ = ["main"]
191
+
192
+ if __name__ == "__main__":
193
+ main()
@@ -0,0 +1,32 @@
1
+ from typing import Any
2
+
3
+ SERVER_VERSION = "0.6.0"
4
+
5
+ SERVER_LOCALHOST = "127.0.0.1"
6
+
7
+ UVICORN_LOGGING_CONFIG: dict[str, Any] = {
8
+ "version": 1,
9
+ "disable_existing_loggers": False,
10
+ "formatters": {
11
+ "default": {
12
+ "()": "uvicorn.logging.DefaultFormatter",
13
+ "fmt": "[uvicorn] %(levelname)s - %(message)s",
14
+ "use_colors": None,
15
+ },
16
+ },
17
+ "handlers": {
18
+ "default": {
19
+ "formatter": "default",
20
+ "class": "logging.StreamHandler",
21
+ "stream": "ext://sys.stderr",
22
+ },
23
+ },
24
+ "loggers": {
25
+ "uvicorn": {
26
+ "handlers": ["default"],
27
+ "level": "INFO",
28
+ "propagate": False,
29
+ },
30
+ "uvicorn.error": {"level": "INFO"},
31
+ },
32
+ }