mcp-server-motherduck 0.7.1__tar.gz → 0.8.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.
Files changed (17) hide show
  1. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/.github/workflows/bump-version.yml +32 -10
  2. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/.github/workflows/publish-mcp.yml +1 -4
  3. mcp_server_motherduck-0.7.1/README.md → mcp_server_motherduck-0.8.1/PKG-INFO +59 -7
  4. mcp_server_motherduck-0.7.1/PKG-INFO → mcp_server_motherduck-0.8.1/README.md +42 -24
  5. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/pyproject.toml +4 -4
  6. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/server.json +58 -4
  7. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/src/mcp_server_motherduck/__init__.py +52 -5
  8. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/src/mcp_server_motherduck/configs.py +1 -1
  9. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/src/mcp_server_motherduck/database.py +72 -13
  10. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/src/mcp_server_motherduck/server.py +6 -0
  11. mcp_server_motherduck-0.8.1/uv.lock +858 -0
  12. mcp_server_motherduck-0.7.1/uv.lock +0 -424
  13. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/.bumpver.toml +0 -0
  14. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/.gitignore +0 -0
  15. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/LICENSE +0 -0
  16. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/makefile +0 -0
  17. {mcp_server_motherduck-0.7.1 → mcp_server_motherduck-0.8.1}/src/mcp_server_motherduck/prompt.py +0 -0
@@ -13,6 +13,8 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  permissions:
15
15
  contents: write
16
+ outputs:
17
+ new_version: ${{ steps.set-version.outputs.version }}
16
18
 
17
19
  steps:
18
20
  - name: Checkout code
@@ -38,28 +40,48 @@ jobs:
38
40
  run: |
39
41
  git config --global user.name "github-actions[bot]"
40
42
  git config --global user.email "github-actions[bot]@users.noreply.github.com"
43
+
44
+ - name: Validate version input
45
+ run: |
46
+ version="${{ inputs.version }}"
47
+ if ! [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
48
+ echo "Version must be in MAJOR.MINOR.PATCH format (e.g., 0.8.0)."
49
+ exit 1
50
+ fi
51
+ git fetch --tags --force
52
+ if git rev-parse "v$version" >/dev/null 2>&1; then
53
+ echo "Tag v$version already exists."
54
+ exit 1
55
+ fi
41
56
 
42
57
  - name: Update version to ${{ inputs.version }}
58
+ id: set-version
43
59
  run: |
44
60
  uv tool run bumpver update --set-version ${{ inputs.version }}
45
61
  echo "NEW_VERSION=${{ inputs.version }}" >> $GITHUB_ENV
62
+ echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
46
63
 
47
64
  - name: Push changes
48
65
  run: |
49
- git push origin main
66
+ git push origin "HEAD:${{ github.event.repository.default_branch }}"
50
67
  git push origin --tags
51
68
 
52
- - name: Create GitHub Release
53
- env:
54
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
55
- run: |
56
- gh release create "v${{ env.NEW_VERSION }}" \
57
- --title "v${{ env.NEW_VERSION }}" \
58
- --generate-notes
59
-
60
- # Publish job will be triggered automatically by the tag push
69
+ # Publish job runs via workflow_call
61
70
  call-publish:
62
71
  needs: bump-version
63
72
  uses: ./.github/workflows/publish-mcp.yml
64
73
  secrets: inherit
65
74
 
75
+ create-release:
76
+ needs: [bump-version, call-publish]
77
+ runs-on: ubuntu-latest
78
+ permissions:
79
+ contents: write
80
+ steps:
81
+ - name: Create GitHub Release
82
+ env:
83
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
84
+ run: |
85
+ gh release create "v${{ needs.bump-version.outputs.new_version }}" \
86
+ --title "v${{ needs.bump-version.outputs.new_version }}" \
87
+ --generate-notes
@@ -3,9 +3,6 @@ name: Publish to PyPI and MCP Registry
3
3
  on:
4
4
  workflow_dispatch: # Allows manual triggering from GitHub Actions UI
5
5
  workflow_call: # Allows triggering from other workflows
6
- push:
7
- tags:
8
- - 'v*' # Trigger on version tags like v0.7.0
9
6
 
10
7
  jobs:
11
8
  publish:
@@ -75,4 +72,4 @@ jobs:
75
72
  run: ./mcp-publisher login github-oidc
76
73
 
77
74
  - name: Publish to MCP Registry
78
- run: ./mcp-publisher publish
75
+ run: ./mcp-publisher publish
@@ -1,6 +1,32 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-server-motherduck
3
+ Version: 0.8.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.4.3
11
+ Requires-Dist: mcp>=1.23.0
12
+ Requires-Dist: pytz>=2025.2
13
+ Requires-Dist: starlette>=0.49.1
14
+ Requires-Dist: tabulate>=0.9.0
15
+ Requires-Dist: uvicorn>=0.34.0
16
+ Description-Content-Type: text/markdown
17
+
1
18
  # MotherDuck's DuckDB MCP Server
2
19
 
3
- An MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
20
+ ## What is the main difference between MotherDuck's remote MCP and this local MCP?
21
+
22
+ If you are choosing between MotherDuck's hosted/remote MCP and this local MCP:
23
+
24
+ - **Remote MCP (hosted by MotherDuck)**: read-only, zero-setup, and the recommended default for most users who just need query access. See the [MotherDuck MCP docs](https://motherduck.com/docs/sql-reference/mcp/).
25
+ - **Local MCP (this repo)**: self-hosted and supports write access when you need to create, modify, or manage data in a controlled environment.
26
+
27
+ A local MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
28
+
29
+ > This repository contains the **self-hosted/local** MCP server implementation.
4
30
 
5
31
  [<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install in Cursor">](https://cursor.com/en/install-mcp?name=DuckDB&config=eyJjb21tYW5kIjoidXZ4IG1jcC1zZXJ2ZXItbW90aGVyZHVjayAtLWRiLXBhdGggOm1lbW9yeToiLCJlbnYiOnsibW90aGVyZHVja190b2tlbiI6IiJ9fQ%3D%3D)
6
32
 
@@ -34,6 +60,11 @@ The server offers one tool:
34
60
 
35
61
  All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
36
62
 
63
+ **Result Limiting**: Query results are automatically limited to prevent using up too much context:
64
+ - Maximum 1024 rows by default (configurable with `--max-rows`)
65
+ - Maximum 50,000 characters by default (configurable with `--max-chars`)
66
+ - Truncated responses include a note about truncation
67
+
37
68
  ## Command Line Parameters
38
69
 
39
70
  The MCP server supports the following parameters:
@@ -42,27 +73,37 @@ The MCP server supports the following parameters:
42
73
  |-----------|------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
43
74
  | `--transport` | Choice | `stdio` | Transport type. Options: `stdio`, `sse`, `stream` |
44
75
  | `--port` | Integer | `8000` | Port to listen on for sse and stream transport mode |
76
+ | `--host` | String | `127.0.0.1` | Host to bind the MCP server for sse and stream transport mode |
45
77
  | `--db-path` | String | `md:` | Path to local DuckDB database file, MotherDuck database, or S3 URL (e.g., `s3://bucket/path/to/db.duckdb`) |
46
78
  | `--motherduck-token` | String | `None` | Access token to use for MotherDuck database connections (uses `motherduck_token` env var by default) |
47
79
  | `--read-only` | Flag | `False` | Flag for connecting to DuckDB or MotherDuck in read-only mode. For DuckDB it uses short-lived connections to enable concurrent access |
48
80
  | `--home-dir` | String | `None` | Home directory for DuckDB (uses `HOME` env var by default) |
49
81
  | `--saas-mode` | Flag | `False` | Flag for connecting to MotherDuck in [SaaS mode](https://motherduck.com/docs/key-tasks/authenticating-and-connecting-to-motherduck/authenticating-to-motherduck/#authentication-using-saas-mode). (disables filesystem and write permissions for local DuckDB) |
50
82
  | `--json-response` | Flag | `False` | Enable JSON responses for HTTP stream. Only supported for `stream` transport |
83
+ | `--max-rows` | Integer | `1024` | Maximum number of rows to return from queries. |
84
+ | `--max-chars` | Integer | `50000` | Maximum number of characters in query results. |
85
+ | `--query-timeout` | Integer | `-1` | Query execution timeout in seconds. Set to -1 to disable timeout (default). |
51
86
 
52
87
  ### Quick Usage Examples
53
88
 
54
89
  ```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
90
+ # Connect to local DuckDB file in read-only mode
91
+ uvx mcp-server-motherduck --db-path /path/to/local.db --read-only
57
92
 
58
- # Connect to MotherDuck with token with stream transport mode
59
- uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN
93
+ # Connect to MotherDuck with token
94
+ uvx mcp-server-motherduck --db-path md: --motherduck-token YOUR_TOKEN
60
95
 
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
96
+ # Connect to local DuckDB file in read-only mode
97
+ uvx mcp-server-motherduck --db-path /path/to/local.db --read-only
63
98
 
64
99
  # Connect to MotherDuck in SaaS mode for enhanced security with stream transport mode
65
100
  uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN --saas-mode
101
+
102
+ # Customize result truncation limits
103
+ uvx mcp-server-motherduck --db-path md: --motherduck-token YOUR_TOKEN --max-rows 2048 --max-chars 100000
104
+
105
+ # Enable query timeout (5 minutes)
106
+ uvx mcp-server-motherduck --db-path md: --motherduck-token YOUR_TOKEN --query-timeout 300
66
107
  ```
67
108
 
68
109
  ## Getting Started
@@ -364,6 +405,7 @@ You can connect to DuckDB databases stored on Amazon S3 by providing an S3 URL a
364
405
 
365
406
  **Note**: For S3 connections:
366
407
  - AWS credentials must be provided via environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and optionally `AWS_DEFAULT_REGION`)
408
+ - For temporary credentials (AWS SSO), set the `AWS_SESSION_TOKEN` environment variable (and optionally `AWS_DEFAULT_REGION`) to automatically use DuckDB's `credential_chain` provider.
367
409
  - The S3 database is attached to an in-memory DuckDB instance
368
410
  - The httpfs extension is automatically installed and configured for S3 access
369
411
  - Both read and write operations are supported
@@ -425,6 +467,16 @@ To run the server from a local development environment, use the following config
425
467
  }
426
468
  ```
427
469
 
470
+ ## Release process
471
+
472
+ This repo uses a GitHub Actions workflow to bump, tag, publish, and create a release.
473
+
474
+ 1. Use the Github action `Release New Version`
475
+ 2. Enter the new version in `MAJOR.MINOR.PATCH` format (for example: `0.8.1`)
476
+ 3. Run the workflow
477
+
478
+ The workflow will update all versioned files, commit and tag `vX.Y.Z`, publish to PyPI and the MCP registry, then create the GitHub release.
479
+
428
480
  ## Troubleshooting
429
481
 
430
482
  - If you encounter connection issues, verify your MotherDuck token is correct
@@ -1,23 +1,15 @@
1
- Metadata-Version: 2.4
2
- Name: mcp-server-motherduck
3
- Version: 0.7.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.4.1
11
- Requires-Dist: mcp>=1.9.4
12
- Requires-Dist: pytz>=2025.2
13
- Requires-Dist: starlette>=0.46.1
14
- Requires-Dist: tabulate>=0.9.0
15
- Requires-Dist: uvicorn>=0.34.0
16
- Description-Content-Type: text/markdown
17
-
18
1
  # MotherDuck's DuckDB MCP Server
19
2
 
20
- An MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
3
+ ## What is the main difference between MotherDuck's remote MCP and this local MCP?
4
+
5
+ If you are choosing between MotherDuck's hosted/remote MCP and this local MCP:
6
+
7
+ - **Remote MCP (hosted by MotherDuck)**: read-only, zero-setup, and the recommended default for most users who just need query access. See the [MotherDuck MCP docs](https://motherduck.com/docs/sql-reference/mcp/).
8
+ - **Local MCP (this repo)**: self-hosted and supports write access when you need to create, modify, or manage data in a controlled environment.
9
+
10
+ A local MCP server implementation that interacts with DuckDB and MotherDuck databases, providing SQL analytics capabilities to AI Assistants and IDEs.
11
+
12
+ > This repository contains the **self-hosted/local** MCP server implementation.
21
13
 
22
14
  [<img src="https://cursor.com/deeplink/mcp-install-dark.svg" alt="Install in Cursor">](https://cursor.com/en/install-mcp?name=DuckDB&config=eyJjb21tYW5kIjoidXZ4IG1jcC1zZXJ2ZXItbW90aGVyZHVjayAtLWRiLXBhdGggOm1lbW9yeToiLCJlbnYiOnsibW90aGVyZHVja190b2tlbiI6IiJ9fQ%3D%3D)
23
15
 
@@ -51,6 +43,11 @@ The server offers one tool:
51
43
 
52
44
  All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
53
45
 
46
+ **Result Limiting**: Query results are automatically limited to prevent using up too much context:
47
+ - Maximum 1024 rows by default (configurable with `--max-rows`)
48
+ - Maximum 50,000 characters by default (configurable with `--max-chars`)
49
+ - Truncated responses include a note about truncation
50
+
54
51
  ## Command Line Parameters
55
52
 
56
53
  The MCP server supports the following parameters:
@@ -59,27 +56,37 @@ The MCP server supports the following parameters:
59
56
  |-----------|------|---------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
60
57
  | `--transport` | Choice | `stdio` | Transport type. Options: `stdio`, `sse`, `stream` |
61
58
  | `--port` | Integer | `8000` | Port to listen on for sse and stream transport mode |
59
+ | `--host` | String | `127.0.0.1` | Host to bind the MCP server for sse and stream transport mode |
62
60
  | `--db-path` | String | `md:` | Path to local DuckDB database file, MotherDuck database, or S3 URL (e.g., `s3://bucket/path/to/db.duckdb`) |
63
61
  | `--motherduck-token` | String | `None` | Access token to use for MotherDuck database connections (uses `motherduck_token` env var by default) |
64
62
  | `--read-only` | Flag | `False` | Flag for connecting to DuckDB or MotherDuck in read-only mode. For DuckDB it uses short-lived connections to enable concurrent access |
65
63
  | `--home-dir` | String | `None` | Home directory for DuckDB (uses `HOME` env var by default) |
66
64
  | `--saas-mode` | Flag | `False` | Flag for connecting to MotherDuck in [SaaS mode](https://motherduck.com/docs/key-tasks/authenticating-and-connecting-to-motherduck/authenticating-to-motherduck/#authentication-using-saas-mode). (disables filesystem and write permissions for local DuckDB) |
67
65
  | `--json-response` | Flag | `False` | Enable JSON responses for HTTP stream. Only supported for `stream` transport |
66
+ | `--max-rows` | Integer | `1024` | Maximum number of rows to return from queries. |
67
+ | `--max-chars` | Integer | `50000` | Maximum number of characters in query results. |
68
+ | `--query-timeout` | Integer | `-1` | Query execution timeout in seconds. Set to -1 to disable timeout (default). |
68
69
 
69
70
  ### Quick Usage Examples
70
71
 
71
72
  ```bash
72
- # Connect to local DuckDB file in read-only mode with stream transport mode
73
- uvx mcp-server-motherduck --transport stream --db-path /path/to/local.db --read-only
73
+ # Connect to local DuckDB file in read-only mode
74
+ uvx mcp-server-motherduck --db-path /path/to/local.db --read-only
74
75
 
75
- # Connect to MotherDuck with token with stream transport mode
76
- uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN
76
+ # Connect to MotherDuck with token
77
+ uvx mcp-server-motherduck --db-path md: --motherduck-token YOUR_TOKEN
77
78
 
78
- # Connect to local DuckDB file in read-only mode with stream transport mode
79
- uvx mcp-server-motherduck --transport stream --db-path /path/to/local.db --read-only
79
+ # Connect to local DuckDB file in read-only mode
80
+ uvx mcp-server-motherduck --db-path /path/to/local.db --read-only
80
81
 
81
82
  # Connect to MotherDuck in SaaS mode for enhanced security with stream transport mode
82
83
  uvx mcp-server-motherduck --transport stream --db-path md: --motherduck-token YOUR_TOKEN --saas-mode
84
+
85
+ # Customize result truncation limits
86
+ uvx mcp-server-motherduck --db-path md: --motherduck-token YOUR_TOKEN --max-rows 2048 --max-chars 100000
87
+
88
+ # Enable query timeout (5 minutes)
89
+ uvx mcp-server-motherduck --db-path md: --motherduck-token YOUR_TOKEN --query-timeout 300
83
90
  ```
84
91
 
85
92
  ## Getting Started
@@ -381,6 +388,7 @@ You can connect to DuckDB databases stored on Amazon S3 by providing an S3 URL a
381
388
 
382
389
  **Note**: For S3 connections:
383
390
  - AWS credentials must be provided via environment variables (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and optionally `AWS_DEFAULT_REGION`)
391
+ - For temporary credentials (AWS SSO), set the `AWS_SESSION_TOKEN` environment variable (and optionally `AWS_DEFAULT_REGION`) to automatically use DuckDB's `credential_chain` provider.
384
392
  - The S3 database is attached to an in-memory DuckDB instance
385
393
  - The httpfs extension is automatically installed and configured for S3 access
386
394
  - Both read and write operations are supported
@@ -442,6 +450,16 @@ To run the server from a local development environment, use the following config
442
450
  }
443
451
  ```
444
452
 
453
+ ## Release process
454
+
455
+ This repo uses a GitHub Actions workflow to bump, tag, publish, and create a release.
456
+
457
+ 1. Use the Github action `Release New Version`
458
+ 2. Enter the new version in `MAJOR.MINOR.PATCH` format (for example: `0.8.1`)
459
+ 3. Run the workflow
460
+
461
+ The workflow will update all versioned files, commit and tag `vX.Y.Z`, publish to PyPI and the MCP registry, then create the GitHub release.
462
+
445
463
  ## Troubleshooting
446
464
 
447
465
  - If you encounter connection issues, verify your MotherDuck token is correct
@@ -1,17 +1,17 @@
1
1
  [project]
2
2
  name = "mcp-server-motherduck"
3
- version = "0.7.1"
3
+ version = "0.8.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
- "duckdb==1.4.1",
8
+ "duckdb==1.4.3",
9
9
  "tabulate>=0.9.0",
10
10
  "click>=8.1.8",
11
- "starlette>=0.46.1",
11
+ "starlette>=0.49.1",
12
12
  "uvicorn>=0.34.0",
13
13
  "anyio>=4.8.0",
14
- "mcp>=1.9.4",
14
+ "mcp>=1.23.0",
15
15
  "pytz>=2025.2"
16
16
  ]
17
17
 
@@ -1,18 +1,18 @@
1
1
  {
2
- "$schema": "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json",
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
3
3
  "name": "io.github.motherduckdb/mcp-server-motherduck",
4
4
  "description": "Fast analytics and data processing with DuckDB and MotherDuck",
5
5
  "repository": {
6
6
  "url": "https://github.com/motherduckdb/mcp-server-motherduck",
7
7
  "source": "github"
8
8
  },
9
- "version": "0.7.1",
9
+ "version": "0.8.1",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "pypi",
13
13
  "registryBaseUrl": "https://pypi.org",
14
14
  "identifier": "mcp-server-motherduck",
15
- "version": "0.7.1",
15
+ "version": "0.8.1",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },
@@ -33,6 +33,13 @@
33
33
  "format": "number",
34
34
  "isRequired": false
35
35
  },
36
+ {
37
+ "type": "named",
38
+ "name": "--host",
39
+ "description": "Host to bind the MCP server for sse and stream transport mode",
40
+ "default": "127.0.0.1",
41
+ "isRequired": false
42
+ },
36
43
  {
37
44
  "type": "named",
38
45
  "name": "--db-path",
@@ -70,6 +77,30 @@
70
77
  "name": "--json-response",
71
78
  "description": "Enable JSON responses for HTTP stream (only supported for stream transport)",
72
79
  "isRequired": false
80
+ },
81
+ {
82
+ "type": "named",
83
+ "name": "--max-rows",
84
+ "description": "Maximum number of rows to return from queries",
85
+ "default": "1024",
86
+ "format": "number",
87
+ "isRequired": false
88
+ },
89
+ {
90
+ "type": "named",
91
+ "name": "--max-chars",
92
+ "description": "Maximum number of characters in query results",
93
+ "default": "50000",
94
+ "format": "number",
95
+ "isRequired": false
96
+ },
97
+ {
98
+ "type": "named",
99
+ "name": "--query-timeout",
100
+ "description": "Query execution timeout in seconds. Set to -1 to disable timeout",
101
+ "default": "-1",
102
+ "format": "number",
103
+ "isRequired": false
73
104
  }
74
105
  ],
75
106
  "environmentVariables": [
@@ -83,8 +114,31 @@
83
114
  "name": "HOME",
84
115
  "description": "Home directory for DuckDB (used as default if --home-dir not specified)",
85
116
  "isRequired": false
117
+ },
118
+ {
119
+ "name": "AWS_ACCESS_KEY_ID",
120
+ "description": "AWS access key for S3 database connections",
121
+ "isRequired": false,
122
+ "isSecret": true
123
+ },
124
+ {
125
+ "name": "AWS_SECRET_ACCESS_KEY",
126
+ "description": "AWS secret access key for S3 database connections",
127
+ "isRequired": false,
128
+ "isSecret": true
129
+ },
130
+ {
131
+ "name": "AWS_SESSION_TOKEN",
132
+ "description": "AWS session token for temporary credentials (IAM roles, AWS SSO, EC2 instance profiles)",
133
+ "isRequired": false,
134
+ "isSecret": true
135
+ },
136
+ {
137
+ "name": "AWS_DEFAULT_REGION",
138
+ "description": "AWS region for S3 database connections",
139
+ "isRequired": false
86
140
  }
87
141
  ]
88
142
  }
89
143
  ]
90
- }
144
+ }
@@ -14,6 +14,7 @@ logging.basicConfig(
14
14
 
15
15
  @click.command()
16
16
  @click.option("--port", default=8000, help="Port to listen on for SSE")
17
+ @click.option("--host", default=SERVER_LOCALHOST, help="Host to bind the MCP server")
17
18
  @click.option(
18
19
  "--transport",
19
20
  type=click.Choice(["stdio", "sse", "stream"]),
@@ -51,8 +52,27 @@ logging.basicConfig(
51
52
  default=False,
52
53
  help="(Default: `False`) Enable JSON responses instead of SSE streams. Only supported for `stream` transport.",
53
54
  )
55
+ @click.option(
56
+ "--max-rows",
57
+ type=int,
58
+ default=1024,
59
+ help="(Default: `1024`) Maximum number of rows to return from queries. Use LIMIT in your SQL for specific row counts.",
60
+ )
61
+ @click.option(
62
+ "--max-chars",
63
+ type=int,
64
+ default=50000,
65
+ help="(Default: `50000`) Maximum number of characters in query results. Prevents issues with wide rows or large text columns.",
66
+ )
67
+ @click.option(
68
+ "--query-timeout",
69
+ type=int,
70
+ default=-1,
71
+ help="(Default: `-1`) Query execution timeout in seconds. Set to -1 to disable timeout.",
72
+ )
54
73
  def main(
55
74
  port,
75
+ host,
56
76
  transport,
57
77
  db_path,
58
78
  motherduck_token,
@@ -60,11 +80,19 @@ def main(
60
80
  saas_mode,
61
81
  read_only,
62
82
  json_response,
83
+ max_rows,
84
+ max_chars,
85
+ query_timeout,
63
86
  ):
64
87
  """Main entry point for the package."""
65
88
 
66
89
  logger.info("🦆 MotherDuck MCP Server v" + SERVER_VERSION)
67
90
  logger.info("Ready to execute SQL queries via DuckDB/MotherDuck")
91
+ logger.info(f"Query result limits: {max_rows} rows, {max_chars:,} characters")
92
+ if query_timeout == -1:
93
+ logger.info("Query timeout: disabled")
94
+ else:
95
+ logger.info(f"Query timeout: {query_timeout}s")
68
96
 
69
97
  app, init_opts = build_application(
70
98
  db_path=db_path,
@@ -72,6 +100,9 @@ def main(
72
100
  home_dir=home_dir,
73
101
  saas_mode=saas_mode,
74
102
  read_only=read_only,
103
+ max_rows=max_rows,
104
+ max_chars=max_chars,
105
+ query_timeout=query_timeout,
75
106
  )
76
107
 
77
108
  if transport == "sse":
@@ -92,7 +123,7 @@ def main(
92
123
  return Response()
93
124
 
94
125
  logger.info(
95
- f"🦆 Connect to MotherDuck MCP Server at \033[1m\033[36mhttp://{SERVER_LOCALHOST}:{port}/sse\033[0m"
126
+ f"🦆 Connect to MotherDuck MCP Server at \033[1m\033[36mhttp://{host}:{port}/sse\033[0m"
96
127
  )
97
128
 
98
129
  starlette_app = Starlette(
@@ -107,7 +138,7 @@ def main(
107
138
 
108
139
  uvicorn.run(
109
140
  starlette_app,
110
- host=SERVER_LOCALHOST,
141
+ host=host,
111
142
  port=port,
112
143
  log_config=UVICORN_LOGGING_CONFIG,
113
144
  )
@@ -148,7 +179,7 @@ def main(
148
179
  )
149
180
 
150
181
  logger.info(
151
- f"🦆 Connect to MotherDuck MCP Server at \033[1m\033[36mhttp://{SERVER_LOCALHOST}:{port}/mcp\033[0m"
182
+ f"🦆 Connect to MotherDuck MCP Server at \033[1m\033[36mhttp://{host}:{port}/mcp\033[0m"
152
183
  )
153
184
 
154
185
  # Create an ASGI application using the transport
@@ -164,7 +195,7 @@ def main(
164
195
 
165
196
  uvicorn.run(
166
197
  starlette_app,
167
- host=SERVER_LOCALHOST,
198
+ host=host,
168
199
  port=port,
169
200
  log_config=UVICORN_LOGGING_CONFIG,
170
201
  )
@@ -179,7 +210,23 @@ def main(
179
210
  async with stdio_server() as (read_stream, write_stream):
180
211
  await app.run(read_stream, write_stream, init_opts)
181
212
 
182
- anyio.run(arun)
213
+ try:
214
+ anyio.run(arun)
215
+ except (BrokenPipeError, ConnectionResetError, anyio.BrokenResourceError):
216
+ logger.info("Client disconnected")
217
+ except KeyboardInterrupt:
218
+ logger.info("Server interrupted by user")
219
+ except BaseException as e:
220
+ # Handle exception groups from anyio (Python 3.11+)
221
+ if type(e).__name__ == 'ExceptionGroup':
222
+ if any(isinstance(exc, (BrokenPipeError, ConnectionResetError, anyio.BrokenResourceError))
223
+ for exc in getattr(e, 'exceptions', [])):
224
+ logger.info("Client disconnected")
225
+ else:
226
+ raise
227
+ else:
228
+ raise
229
+
183
230
  # This will only be reached when the server is shutting down
184
231
  logger.info(
185
232
  "🦆 MotherDuck MCP Server in \033[32mstdio\033[0m mode shutting down"
@@ -1,6 +1,6 @@
1
1
  from typing import Any
2
2
 
3
- SERVER_VERSION = "0.7.1"
3
+ SERVER_VERSION = "0.8.1"
4
4
 
5
5
  SERVER_LOCALHOST = "127.0.0.1"
6
6