mcp-server-motherduck 0.3.3__py3-none-any.whl → 0.3.4__py3-none-any.whl

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.
@@ -1,10 +1,15 @@
1
1
  from . import server
2
2
  import asyncio
3
3
  import argparse
4
+ import logging
5
+
6
+ logger = logging.getLogger("mcp_server_motherduck")
7
+ logging.basicConfig(level=logging.INFO, format="[%(name)s] %(levelname)s - %(message)s")
4
8
 
5
9
 
6
10
  def main():
7
11
  """Main entry point for the package."""
12
+
8
13
  parser = argparse.ArgumentParser(description="MotherDuck MCP Server")
9
14
  parser.add_argument(
10
15
  "--db-path",
@@ -19,6 +24,10 @@ def main():
19
24
  )
20
25
 
21
26
  args = parser.parse_args()
27
+ logger.info("🦆 MotherDuck MCP Server v" + server.SERVER_VERSION)
28
+ logger.info("Ready to execute SQL queries via DuckDB/MotherDuck")
29
+ logger.info("Waiting for client connection...\n")
30
+
22
31
  asyncio.run(server.main(db_path=args.db_path, result_format=args.result_format))
23
32
 
24
33
 
@@ -12,7 +12,7 @@ from mcp.server.models import InitializationOptions
12
12
  from .prompt import PROMPT_TEMPLATE
13
13
 
14
14
 
15
- SERVER_VERSION = "0.3.3"
15
+ SERVER_VERSION = "0.3.4"
16
16
 
17
17
  logger = logging.getLogger("mcp_server_motherduck")
18
18
 
@@ -20,26 +20,31 @@ logger = logging.getLogger("mcp_server_motherduck")
20
20
  class DatabaseClient:
21
21
  def __init__(
22
22
  self,
23
- db_path: str = None,
23
+ db_path: str | None = None,
24
24
  result_format: Literal["markdown", "duckbox", "text"] = "markdown",
25
25
  ):
26
26
  self.db_path, self.db_type = self._resolve_db_path_type(db_path)
27
- self.conn = self._initialize_connection()
27
+ logger.info(f"Database client initialized in `{self.db_type}` mode")
28
28
 
29
+ self.conn = self._initialize_connection()
29
30
  self.result_format = result_format
30
31
 
31
32
  def _initialize_connection(self) -> duckdb.DuckDBPyConnection:
32
33
  """Initialize connection to the MotherDuck or DuckDB database"""
33
34
 
34
- logger.info(f"Connecting to {self.db_type} database: `{self.db_path}`")
35
+ logger.info(f"🔌 Connecting to {self.db_type} database: {self.db_path}")
35
36
 
36
- return duckdb.connect(
37
+ conn = duckdb.connect(
37
38
  self.db_path,
38
39
  config={"custom_user_agent": f"mcp-server-motherduck/{SERVER_VERSION}"},
39
40
  )
40
41
 
42
+ logger.info(f"✅ Successfully connected to {self.db_type} database")
43
+
44
+ return conn
45
+
41
46
  def _resolve_db_path_type(
42
- self, db_path: str = None
47
+ self, db_path: str | None = None
43
48
  ) -> tuple[str, Literal["duckdb", "motherduck"]]:
44
49
  """Resolve and validate the database path"""
45
50
  # Use MotherDuck if token is available and no path specified
@@ -70,7 +75,12 @@ class DatabaseClient:
70
75
  try:
71
76
  if self.result_format == "markdown":
72
77
  # Markdown version of the output
73
- return self.conn.execute(query).fetchdf().to_markdown()
78
+ logger.info(
79
+ f"🔍 Executing query: {query[:60]}{'...' if len(query) > 60 else ''}"
80
+ )
81
+ result = self.conn.execute(query).fetchdf().to_markdown()
82
+ logger.info("✅ Query executed successfully")
83
+ return result
74
84
  elif self.result_format == "duckbox":
75
85
  # Duckbox version of the output
76
86
  buffer = io.StringIO()
@@ -82,10 +92,9 @@ class DatabaseClient:
82
92
  return str(self.conn.execute(query).fetchall())
83
93
 
84
94
  except Exception as e:
85
- logger.error(f"Database error executing query: {e}")
86
- raise ValueError(f"Error executing query: {e}")
95
+ raise ValueError(f" Error executing query: {e}")
87
96
 
88
- def mcp_config(self) -> str:
97
+ def mcp_config(self) -> dict[str, str]:
89
98
  """Used for debugging purposes to show the current MCP config"""
90
99
  return {
91
100
  "current_working_directory": os.getcwd(),
@@ -94,7 +103,9 @@ class DatabaseClient:
94
103
  }
95
104
 
96
105
 
97
- async def main(db_path: str, result_format: Literal["markdown", "duckbox", "text"] = "markdown"):
106
+ async def main(
107
+ db_path: str, result_format: Literal["markdown", "duckbox", "text"] = "markdown"
108
+ ):
98
109
  logger.info(f"Starting MotherDuck MCP Server with DB path: {db_path}")
99
110
  server = Server("mcp-server-motherduck")
100
111
  db_client = DatabaseClient(db_path=db_path, result_format=result_format)
@@ -194,9 +205,15 @@ async def main(db_path: str, result_format: Literal["markdown", "duckbox", "text
194
205
  logger.info(f"Calling tool: {name}::{arguments}")
195
206
  try:
196
207
  if name == "query":
208
+ if arguments is None:
209
+ return [
210
+ types.TextContent(type="text", text="Error: No query provided")
211
+ ]
197
212
  tool_response = db_client.query(arguments["query"])
198
213
  return [types.TextContent(type="text", text=str(tool_response))]
199
214
 
215
+ return [types.TextContent(type="text", text=f"Unsupported tool: {name}")]
216
+
200
217
  except Exception as e:
201
218
  logger.error(f"Error executing tool {name}: {e}")
202
219
  raise ValueError(f"Error executing tool {name}: {str(e)}")
@@ -215,3 +232,7 @@ async def main(db_path: str, result_format: Literal["markdown", "duckbox", "text
215
232
  ),
216
233
  ),
217
234
  )
235
+
236
+ # This will only be reached when the server is shutting down
237
+ logger.info("\n🦆 MotherDuck MCP Server shutting down...")
238
+ logger.info(f"Database connection to {db_client.db_path} closed.")
@@ -0,0 +1,164 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-server-motherduck
3
+ Version: 0.3.4
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.1
9
+ Requires-Dist: mcp>=1.3.0
10
+ Requires-Dist: pandas>=2.0.0
11
+ Requires-Dist: pydantic-settings>=2.8.1
12
+ Requires-Dist: tabulate>=0.9.0
13
+ Description-Content-Type: text/markdown
14
+
15
+ # MotherDuck MCP Server
16
+
17
+ An MCP server implementation that integrates MotherDuck and local DuckDB, providing SQL analytics capabilities to Claude.
18
+
19
+ ## Features
20
+
21
+ - **Hybrid execution**: query data from both cloud-based MotherDuck and local DuckDB
22
+ - **Cloud storage integration**: access data stored in Amazon S3 or other cloud storage thanks to MotherDuck's integrations
23
+ - **Data sharing**: create and share databases
24
+ - **SQL analytics**: use DuckDB's SQL dialect to query any size of data directly from Claude
25
+ - **Serverless architecture**: run analytics without needing to configure instances or clusters
26
+
27
+ ## Components
28
+
29
+ ### Prompts
30
+
31
+ The server provides one prompt:
32
+
33
+ - `duckdb-motherduck-initial-prompt`: A prompt to initialize a connection to DuckDB or MotherDuck and start working with it
34
+
35
+ ### Tools
36
+
37
+ The server offers one tool:
38
+
39
+ - `query`: Execute a SQL query on the MotherDuck/DuckDB database
40
+ - **Inputs**:
41
+ - `query` (string, required): The SQL query to execute
42
+
43
+ All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
44
+
45
+ ## Getting Started
46
+
47
+ ### Prerequisites
48
+
49
+ - A MotherDuck account (sign up at [motherduck.com](https://motherduck.com))
50
+ - A MotherDuck access token
51
+ - `uvx` installed, you can install it using `pip install uvx` or `brew install uvx`
52
+
53
+ If you plan to use MotherDuck MCP with Claude Desktop, you will also need Claude Desktop installed.
54
+
55
+ ### Setting up your MotherDuck token
56
+
57
+ 1. Sign up for a [MotherDuck account](https://app.motherduck.com/?auth_flow=signup)
58
+ 2. Generate an access token via the [MotherDuck UI](https://app.motherduck.com/settings/tokens?auth_flow=signup)
59
+ 3. Store the token securely for use in the configuration
60
+
61
+ ### Usage with Claude Desktop
62
+
63
+ 1. Install Claude Desktop from [claude.ai/download](https://claude.ai/download) if you haven't already
64
+
65
+ 2. Open the Claude Desktop configuration file:
66
+
67
+ - To quickly access it or create it the first time, open the Claude Desktop app, select Settings, and click on the "Developer" tab, finally click on the "Edit Config" button.
68
+ - Add the following configuration to your `claude_desktop_config.json`:
69
+
70
+ ```json
71
+ "mcpServers": {
72
+ "mcp-server-motherduck": {
73
+ "command": "uvx",
74
+ "args": [
75
+ "mcp-server-motherduck"
76
+ ],
77
+ "env": {
78
+ "motherduck_token": "YOUR_MOTHERDUCK_TOKEN_HERE",
79
+ "HOME": "YOUR_HOME_FOLDER_PATH"
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ **Important Notes**:
86
+
87
+ - Replace `YOUR_MOTHERDUCK_TOKEN_HERE` with your actual MotherDuck token
88
+ - 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`
89
+ - The `HOME` environment variable is required for DuckDB to function properly.
90
+
91
+ ## Example Queries
92
+
93
+ Once configured, you can ask Claude to run queries like:
94
+
95
+ - "Create a new database and table in MotherDuck"
96
+ - "Query data from my local CSV file"
97
+ - "Join data from my local DuckDB database with a table in MotherDuck"
98
+ - "Analyze data stored in Amazon S3"
99
+
100
+ ## Testing
101
+
102
+ The server is designed to be run by tools like Claude Desktop, 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:
103
+
104
+ 1. **Default MotherDuck database**:
105
+
106
+ - To connect to the default MotherDuck database, you will need to export the `motherduck_token` environment variable.
107
+
108
+ ```bash
109
+ export motherduck_token=<your_motherduck_token>
110
+ uvx mcp-server-motherduck --db-path md:
111
+ ```
112
+
113
+ - Alternatively, you can pass the token directly:
114
+
115
+ ```bash
116
+ motherduck_token=<your_motherduck_token> uvx mcp-server-motherduck --db-path md:
117
+ ```
118
+
119
+ 2. **Specific MotherDuck database**:
120
+
121
+ ```bash
122
+ uvx mcp-server-motherduck --db-path md:your_database_name
123
+ ```
124
+
125
+ 3. **Local DuckDB database**:
126
+
127
+ ```bash
128
+ uvx mcp-server-motherduck --db-path /path/to/your/local.db
129
+ ```
130
+
131
+ 4. **In-memory database** (default if no path and no token):
132
+
133
+ ```bash
134
+ uvx mcp-server-motherduck
135
+ ```
136
+
137
+ 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:`).
138
+
139
+ ## Running in SSE mode
140
+
141
+ The server could also be run ing SSE mode using `supergateway` by running the following command:
142
+
143
+ ```bash
144
+ motherduck_token=<your_motherduck_token> HOME=<your_home_folder_path> npx -y supergateway --stdio "uvx mcp-server-motherduck"
145
+ ```
146
+
147
+ And you can point your clients such as Claude Desktop, Cursor to this endpoint.
148
+
149
+ ### Environment Variables
150
+
151
+ The server uses the following environment variables:
152
+
153
+ - `motherduck_token`: Your MotherDuck authentication token
154
+ - `HOME`: Directory used by DuckDB for file operations
155
+
156
+ ## Troubleshooting
157
+
158
+ - If you encounter connection issues, verify your MotherDuck token is correct
159
+ - For local file access problems, ensure the `HOME` environment variable is set correctly
160
+ - Check that the `uvx` command is available in your PATH
161
+
162
+ ## License
163
+
164
+ This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
@@ -0,0 +1,8 @@
1
+ mcp_server_motherduck/__init__.py,sha256=fvkO3-wgyUVAdIzy-As4pl3_LYHFMgO9STVTHAyTyKA,1078
2
+ mcp_server_motherduck/prompt.py,sha256=P7BrmhVXwDkPeSHQ3f25WMP6lpBpN2BxDzYPOQ3fxX8,56699
3
+ mcp_server_motherduck/server.py,sha256=N7ySKj43BtMRGE_9HGhWr8_3wGSsjxKD9xIJJv7W4Eg,8841
4
+ mcp_server_motherduck-0.3.4.dist-info/METADATA,sha256=jhdryCCXMVJdKKi0o7E6v9NiJBakx_d9HRECRn21mks,5623
5
+ mcp_server_motherduck-0.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
6
+ mcp_server_motherduck-0.3.4.dist-info/entry_points.txt,sha256=dRTgcvWJn40bz0PVuKPylK6w92cFN32lwunZOgo5j4s,69
7
+ mcp_server_motherduck-0.3.4.dist-info/licenses/LICENSE,sha256=Tj68w9jCiceFKTvZ3jET-008NjhozcQMXpm-fyL9WUI,1067
8
+ mcp_server_motherduck-0.3.4.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- from . import server
2
- import asyncio
3
- import argparse
4
-
5
-
6
- def main():
7
- """Main entry point for the package."""
8
- parser = argparse.ArgumentParser(description="MotherDuck MCP Server")
9
- parser.add_argument(
10
- "--db-path",
11
- help="Path to local DuckDB database file",
12
- )
13
-
14
- args = parser.parse_args()
15
- asyncio.run(server.main(db_path=args.db_path))
16
-
17
-
18
- if __name__ == "__main__":
19
- main()
@@ -1,64 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: mcp-server-motherduck
3
- Version: 0.3.3
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.1.3
9
- Requires-Dist: mcp>=1.0.0
10
- Requires-Dist: pandas>=2.0.0
11
- Requires-Dist: tabulate>=0.9.0
12
- Description-Content-Type: text/markdown
13
-
14
- # mcp-server-motherduck MCP server
15
-
16
- An [MCP server](https://modelcontextprotocol.io/introduction) for MotherDuck and local DuckDB.
17
-
18
- ## Components
19
-
20
- ### Prompts
21
-
22
- The server provides one prompt:
23
-
24
- - duckdb-motherduck-prompt: A prompt to initialize a connection to duckdb or motherduck and start working with it
25
-
26
- ### Tools
27
-
28
- The server offers one tool:
29
-
30
- - query: Execute a query on the MotherDuck (DuckDB) database
31
- - Takes "query" as required string arguments
32
-
33
- This is because all the interactions with both the DuckDB and MotherDuck are done through writing SQL queries.
34
-
35
- ## Usage with Claude Desktop
36
-
37
- Add the snippet below to your Claude Desktop config and make sure to set the HOME var to your home folder (needed by DuckDB).
38
-
39
- When using MotherDuck, you also need to set a [MotherDuck token](https://motherduck.com/docs/key-tasks/authenticating-and-connecting-to-motherduck/authenticating-to-motherduck/#storing-the-access-token-as-an-environment-variable) env var.
40
-
41
- On MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
42
-
43
- On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
44
-
45
- ### Servers Configuration
46
-
47
- ```
48
- "mcpServers": {
49
- "mcp-server-motherduck": {
50
- "command": "uvx",
51
- "args": [
52
- "mcp-server-motherduck"
53
- ],
54
- "env": {
55
- "motherduck_token": "<your-motherduck-token>",
56
- "HOME": "<your-home-folder-for-project-files>"
57
- }
58
- }
59
- }
60
- ```
61
-
62
- ## License
63
-
64
- This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
@@ -1,9 +0,0 @@
1
- mcp_server_motherduck/__init__.py,sha256=0BPvfyJm7xnVEIZD7JLiuHuR0FFhf_Xa9xt7ieTZHWQ,723
2
- mcp_server_motherduck/__main__.py,sha256=zx-Zgf5qrL280vm9L9vM64kBGfdvneJhZcU8pWSYLOw,410
3
- mcp_server_motherduck/prompt.py,sha256=P7BrmhVXwDkPeSHQ3f25WMP6lpBpN2BxDzYPOQ3fxX8,56699
4
- mcp_server_motherduck/server.py,sha256=ROYQvC2fRkLRyWj_SW8NYC1omlms6lnlhdLLMBn_Aiw,7979
5
- mcp_server_motherduck-0.3.3.dist-info/METADATA,sha256=CTtfZg5sIqoPmAIPk49lYg6xE-lE1fLOfDsf754AGWU,2015
6
- mcp_server_motherduck-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
7
- mcp_server_motherduck-0.3.3.dist-info/entry_points.txt,sha256=dRTgcvWJn40bz0PVuKPylK6w92cFN32lwunZOgo5j4s,69
8
- mcp_server_motherduck-0.3.3.dist-info/licenses/LICENSE,sha256=Tj68w9jCiceFKTvZ3jET-008NjhozcQMXpm-fyL9WUI,1067
9
- mcp_server_motherduck-0.3.3.dist-info/RECORD,,