mcp-server-motherduck 0.5.1__tar.gz → 0.6.1__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.
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.idea/workspace.xml +44 -2
- mcp_server_motherduck-0.5.1/README.md → mcp_server_motherduck-0.6.1/PKG-INFO +63 -32
- mcp_server_motherduck-0.5.1/PKG-INFO → mcp_server_motherduck-0.6.1/README.md +47 -44
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/pyproject.toml +7 -3
- mcp_server_motherduck-0.6.1/src/mcp_server_motherduck/__init__.py +193 -0
- mcp_server_motherduck-0.6.1/src/mcp_server_motherduck/configs.py +32 -0
- mcp_server_motherduck-0.6.1/src/mcp_server_motherduck/database.py +134 -0
- mcp_server_motherduck-0.6.1/src/mcp_server_motherduck/server.py +149 -0
- mcp_server_motherduck-0.6.1/uv.lock +417 -0
- mcp_server_motherduck-0.5.1/src/mcp_server_motherduck/__init__.py +0 -66
- mcp_server_motherduck-0.5.1/src/mcp_server_motherduck/server.py +0 -300
- mcp_server_motherduck-0.5.1/uv.lock +0 -374
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.github/workflows/python-publish.yml +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.gitignore +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.idea/.gitignore +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.idea/mcp-server-motherduck.iml +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.idea/misc.xml +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.idea/modules.xml +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/.idea/vcs.xml +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/LICENSE +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/makefile +0 -0
- {mcp_server_motherduck-0.5.1 → mcp_server_motherduck-0.6.1}/src/mcp_server_motherduck/prompt.py +0 -0
|
@@ -3,16 +3,38 @@
|
|
|
3
3
|
<component name="AutoImportSettings">
|
|
4
4
|
<option name="autoReloadType" value="SELECTIVE" />
|
|
5
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>
|
|
6
14
|
<component name="ChangeListManager">
|
|
7
15
|
<list default="true" id="8bdee1d4-886c-4093-b4cf-95b120034c9e" name="Changes" comment="">
|
|
8
16
|
<change beforePath="$PROJECT_DIR$/pyproject.toml" beforeDir="false" afterPath="$PROJECT_DIR$/pyproject.toml" afterDir="false" />
|
|
9
|
-
<change beforePath="$PROJECT_DIR$/
|
|
17
|
+
<change beforePath="$PROJECT_DIR$/uv.lock" beforeDir="false" afterPath="$PROJECT_DIR$/uv.lock" afterDir="false" />
|
|
10
18
|
</list>
|
|
11
19
|
<option name="SHOW_DIALOG" value="false" />
|
|
12
20
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
13
21
|
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
14
22
|
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
15
23
|
</component>
|
|
24
|
+
<component name="ClangdSettings">
|
|
25
|
+
<option name="formatViaClangd" value="false" />
|
|
26
|
+
</component>
|
|
27
|
+
<component name="FlaskConsoleOptions" custom-start-script="import sys sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) from flask.cli import ScriptInfo locals().update(ScriptInfo(create_app=None).load_app().make_shell_context()) print("Python %s on %s\nApp: %s [%s]\nInstance: %s" % (sys.version, sys.platform, app.import_name, app.env, app.instance_path))">
|
|
28
|
+
<envs>
|
|
29
|
+
<env key="FLASK_APP" value="app" />
|
|
30
|
+
</envs>
|
|
31
|
+
<option name="myCustomStartScript" value="import sys sys.path.extend([WORKING_DIR_AND_PYTHON_PATHS]) from flask.cli import ScriptInfo locals().update(ScriptInfo(create_app=None).load_app().make_shell_context()) print("Python %s on %s\nApp: %s [%s]\nInstance: %s" % (sys.version, sys.platform, app.import_name, app.env, app.instance_path))" />
|
|
32
|
+
<option name="myEnvs">
|
|
33
|
+
<map>
|
|
34
|
+
<entry key="FLASK_APP" value="app" />
|
|
35
|
+
</map>
|
|
36
|
+
</option>
|
|
37
|
+
</component>
|
|
16
38
|
<component name="Git.Settings">
|
|
17
39
|
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
|
18
40
|
</component>
|
|
@@ -31,7 +53,12 @@
|
|
|
31
53
|
"keyToString": {
|
|
32
54
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
|
33
55
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
56
|
+
"RunOnceActivity.cidr.known.project.marker": "true",
|
|
57
|
+
"RunOnceActivity.git.unshallow": "true",
|
|
58
|
+
"RunOnceActivity.readMode.enableVisualFormatting": "true",
|
|
34
59
|
"WebServerToolWindowFactoryState": "false",
|
|
60
|
+
"cf.first.check.clang-format": "false",
|
|
61
|
+
"cidr.known.project.marker": "true",
|
|
35
62
|
"git-widget-placeholder": "main",
|
|
36
63
|
"last_opened_file_path": "/Users/doehmen/Documents/motherduck/mcp-server-motherduck",
|
|
37
64
|
"node.js.detected.package.eslint": "true",
|
|
@@ -42,6 +69,7 @@
|
|
|
42
69
|
"project.structure.last.edited": "Project",
|
|
43
70
|
"project.structure.proportion": "0.0",
|
|
44
71
|
"project.structure.side.proportion": "0.0",
|
|
72
|
+
"settings.editor.selected.configurable": "preferences.updates",
|
|
45
73
|
"vue.rearranger.settings.migration": "true"
|
|
46
74
|
}
|
|
47
75
|
}</component>
|
|
@@ -57,11 +85,25 @@
|
|
|
57
85
|
<workItem from="1744787944049" duration="599000" />
|
|
58
86
|
<workItem from="1744896732489" duration="6070000" />
|
|
59
87
|
<workItem from="1747725447463" duration="5949000" />
|
|
60
|
-
<workItem from="1747924921526" duration="
|
|
88
|
+
<workItem from="1747924921526" duration="17579000" />
|
|
89
|
+
<workItem from="1749541956173" duration="67000" />
|
|
90
|
+
<workItem from="1749546948380" duration="272000" />
|
|
91
|
+
<workItem from="1749547445107" duration="2288000" />
|
|
92
|
+
<workItem from="1750068892931" duration="1202000" />
|
|
93
|
+
<workItem from="1750076934923" duration="598000" />
|
|
94
|
+
<workItem from="1750084124415" duration="194000" />
|
|
95
|
+
<workItem from="1750084439422" duration="575000" />
|
|
96
|
+
<workItem from="1750086684829" duration="92000" />
|
|
97
|
+
<workItem from="1750099676834" duration="5651000" />
|
|
98
|
+
<workItem from="1750235697329" duration="602000" />
|
|
61
99
|
</task>
|
|
62
100
|
<servers />
|
|
63
101
|
</component>
|
|
64
102
|
<component name="TypeScriptGeneratedFilesManager">
|
|
65
103
|
<option name="version" value="3" />
|
|
66
104
|
</component>
|
|
105
|
+
<component name="XSLT-Support.FileAssociations.UIState">
|
|
106
|
+
<expand />
|
|
107
|
+
<select />
|
|
108
|
+
</component>
|
|
67
109
|
</project>
|
|
@@ -1,7 +1,25 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-server-motherduck
|
|
3
|
+
Version: 0.6.1
|
|
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.1
|
|
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
|
+
[](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
|
-
[](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) [](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
|
-
|
|
135
|
+
For the quickest installation, click one of the "Install with UV" buttons at the top.
|
|
87
136
|
|
|
88
|
-
|
|
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
|
|
|
@@ -276,47 +325,29 @@ Once configured, you can e.g. ask Claude to run queries like:
|
|
|
276
325
|
- "Join data from my local DuckDB database with a table in MotherDuck"
|
|
277
326
|
- "Analyze data stored in Amazon S3"
|
|
278
327
|
|
|
279
|
-
##
|
|
280
|
-
|
|
281
|
-
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:
|
|
282
|
-
|
|
283
|
-
1. **Default MotherDuck database**:
|
|
284
|
-
|
|
285
|
-
- To connect to the default MotherDuck database, you will need to pass the auth token using the `--motherduck-token` parameter.
|
|
286
|
-
|
|
287
|
-
```bash
|
|
288
|
-
uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
2. **Specific MotherDuck database**:
|
|
292
|
-
|
|
293
|
-
```bash
|
|
294
|
-
uvx mcp-server-motherduck --db-path md:your_database_name --motherduck-token <your_motherduck_token>
|
|
295
|
-
```
|
|
328
|
+
## Running in SSE mode
|
|
296
329
|
|
|
297
|
-
|
|
330
|
+
The server can run in SSE mode in two ways:
|
|
298
331
|
|
|
299
|
-
|
|
300
|
-
uvx mcp-server-motherduck --db-path /path/to/your/local.db
|
|
301
|
-
```
|
|
332
|
+
### Direct SSE mode
|
|
302
333
|
|
|
303
|
-
|
|
334
|
+
Run the server directly in SSE mode using the `--transport sse` flag:
|
|
304
335
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
336
|
+
```bash
|
|
337
|
+
uvx mcp-server-motherduck --transport sse --port 8000 --db-path md: --motherduck-token <your_motherduck_token>
|
|
338
|
+
```
|
|
308
339
|
|
|
309
|
-
|
|
340
|
+
This will start the server listening on the specified port (default 8000) and you can point your clients directly to this endpoint.
|
|
310
341
|
|
|
311
|
-
|
|
342
|
+
### Using supergateway
|
|
312
343
|
|
|
313
|
-
|
|
344
|
+
Alternatively, you can run SSE mode using `supergateway`:
|
|
314
345
|
|
|
315
346
|
```bash
|
|
316
347
|
npx -y supergateway --stdio "uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>"
|
|
317
348
|
```
|
|
318
349
|
|
|
319
|
-
|
|
350
|
+
Both methods allow you to point your clients such as Claude Desktop, Cursor to the SSE endpoint.
|
|
320
351
|
|
|
321
352
|
## Development configuration
|
|
322
353
|
|
|
@@ -1,19 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: mcp-server-motherduck
|
|
3
|
-
Version: 0.5.1
|
|
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.3.0
|
|
9
|
-
Requires-Dist: mcp>=1.3.0
|
|
10
|
-
Requires-Dist: tabulate>=0.9.0
|
|
11
|
-
Description-Content-Type: text/markdown
|
|
12
|
-
|
|
13
1
|
# MotherDuck's DuckDB MCP Server
|
|
14
2
|
|
|
15
3
|
An MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
|
|
16
4
|
|
|
5
|
+
[](https://cursor.com/install-mcp?name=DuckDB&config=eyJjb21tYW5kIjoidXZ4IG1jcC1zZXJ2ZXItbW90aGVyZHVjayAtLWRiLXBhdGggbWQ6IiwiZW52Ijp7Im1vdGhlcmR1Y2tfdG9rZW4iOiIifX0%3D)
|
|
6
|
+
|
|
17
7
|
## Resources
|
|
18
8
|
- [Close the Loop: Faster Data Pipelines with MCP, DuckDB & AI (Blogpost)](https://motherduck.com/blog/faster-data-pipelines-with-mcp-duckdb-ai/)
|
|
19
9
|
- [Faster Data Pipelines development with MCP and DuckDB (YouTube)](https://www.youtube.com/watch?v=yG1mv8ZRxcU)
|
|
@@ -44,6 +34,37 @@ The server offers one tool:
|
|
|
44
34
|
|
|
45
35
|
All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
|
|
46
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
|
+
|
|
47
68
|
## Getting Started
|
|
48
69
|
|
|
49
70
|
### General Prerequisites
|
|
@@ -93,11 +114,11 @@ See [Connect to local DuckDB](#connect-to-local-duckdb).
|
|
|
93
114
|
|
|
94
115
|
### Usage with VS Code
|
|
95
116
|
|
|
96
|
-
[](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) [](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)
|
|
97
118
|
|
|
98
|
-
|
|
119
|
+
For the quickest installation, click one of the "Install with UV" buttons at the top.
|
|
99
120
|
|
|
100
|
-
|
|
121
|
+
#### Manual Installation
|
|
101
122
|
|
|
102
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)`.
|
|
103
124
|
|
|
@@ -288,47 +309,29 @@ Once configured, you can e.g. ask Claude to run queries like:
|
|
|
288
309
|
- "Join data from my local DuckDB database with a table in MotherDuck"
|
|
289
310
|
- "Analyze data stored in Amazon S3"
|
|
290
311
|
|
|
291
|
-
##
|
|
292
|
-
|
|
293
|
-
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:
|
|
294
|
-
|
|
295
|
-
1. **Default MotherDuck database**:
|
|
296
|
-
|
|
297
|
-
- To connect to the default MotherDuck database, you will need to pass the auth token using the `--motherduck-token` parameter.
|
|
298
|
-
|
|
299
|
-
```bash
|
|
300
|
-
uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
2. **Specific MotherDuck database**:
|
|
304
|
-
|
|
305
|
-
```bash
|
|
306
|
-
uvx mcp-server-motherduck --db-path md:your_database_name --motherduck-token <your_motherduck_token>
|
|
307
|
-
```
|
|
312
|
+
## Running in SSE mode
|
|
308
313
|
|
|
309
|
-
|
|
314
|
+
The server can run in SSE mode in two ways:
|
|
310
315
|
|
|
311
|
-
|
|
312
|
-
uvx mcp-server-motherduck --db-path /path/to/your/local.db
|
|
313
|
-
```
|
|
316
|
+
### Direct SSE mode
|
|
314
317
|
|
|
315
|
-
|
|
318
|
+
Run the server directly in SSE mode using the `--transport sse` flag:
|
|
316
319
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
+
```bash
|
|
321
|
+
uvx mcp-server-motherduck --transport sse --port 8000 --db-path md: --motherduck-token <your_motherduck_token>
|
|
322
|
+
```
|
|
320
323
|
|
|
321
|
-
|
|
324
|
+
This will start the server listening on the specified port (default 8000) and you can point your clients directly to this endpoint.
|
|
322
325
|
|
|
323
|
-
|
|
326
|
+
### Using supergateway
|
|
324
327
|
|
|
325
|
-
|
|
328
|
+
Alternatively, you can run SSE mode using `supergateway`:
|
|
326
329
|
|
|
327
330
|
```bash
|
|
328
331
|
npx -y supergateway --stdio "uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>"
|
|
329
332
|
```
|
|
330
333
|
|
|
331
|
-
|
|
334
|
+
Both methods allow you to point your clients such as Claude Desktop, Cursor to the SSE endpoint.
|
|
332
335
|
|
|
333
336
|
## Development configuration
|
|
334
337
|
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "mcp-server-motherduck"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.1"
|
|
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
|
-
"
|
|
9
|
-
"duckdb==1.3.0",
|
|
8
|
+
"duckdb==1.3.1",
|
|
10
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",
|
|
11
15
|
]
|
|
12
16
|
|
|
13
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.1"
|
|
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
|
+
}
|