mcp-server-motherduck 0.3.3__tar.gz → 0.4.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.
Files changed (22) hide show
  1. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/.gitignore +3 -0
  2. mcp_server_motherduck-0.4.0/PKG-INFO +150 -0
  3. mcp_server_motherduck-0.4.0/README.md +137 -0
  4. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/pyproject.toml +8 -2
  5. mcp_server_motherduck-0.4.0/src/mcp_server_motherduck/__init__.py +53 -0
  6. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/src/mcp_server_motherduck/server.py +70 -38
  7. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/uv.lock +158 -136
  8. mcp_server_motherduck-0.3.3/.idea/.gitignore +0 -8
  9. mcp_server_motherduck-0.3.3/.idea/mcp-server-motherduck.iml +0 -9
  10. mcp_server_motherduck-0.3.3/.idea/misc.xml +0 -6
  11. mcp_server_motherduck-0.3.3/.idea/modules.xml +0 -8
  12. mcp_server_motherduck-0.3.3/.idea/vcs.xml +0 -6
  13. mcp_server_motherduck-0.3.3/.idea/workspace.xml +0 -65
  14. mcp_server_motherduck-0.3.3/.python-version +0 -1
  15. mcp_server_motherduck-0.3.3/PKG-INFO +0 -64
  16. mcp_server_motherduck-0.3.3/README.md +0 -51
  17. mcp_server_motherduck-0.3.3/src/mcp_server_motherduck/__init__.py +0 -26
  18. mcp_server_motherduck-0.3.3/src/mcp_server_motherduck/__main__.py +0 -19
  19. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/.github/workflows/python-publish.yml +0 -0
  20. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/LICENSE +0 -0
  21. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/makefile +0 -0
  22. {mcp_server_motherduck-0.3.3 → mcp_server_motherduck-0.4.0}/src/mcp_server_motherduck/prompt.py +0 -0
@@ -1,5 +1,8 @@
1
1
  .DS_Store
2
2
 
3
+ # Custom
4
+ .python-version
5
+
3
6
  # Byte-compiled / optimized / DLL files
4
7
  __pycache__/
5
8
  *.py[cod]
@@ -0,0 +1,150 @@
1
+ Metadata-Version: 2.4
2
+ Name: mcp-server-motherduck
3
+ Version: 0.4.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: duckdb>=1.2.1
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
+ # MotherDuck MCP Server
15
+
16
+ An MCP server implementation that integrates MotherDuck and local DuckDB, providing SQL analytics capabilities to Claude.
17
+
18
+ ## Features
19
+
20
+ - **Hybrid execution**: query data from both cloud-based MotherDuck and local DuckDB
21
+ - **Cloud storage integration**: access data stored in Amazon S3 or other cloud storage thanks to MotherDuck's integrations
22
+ - **Data sharing**: create and share databases
23
+ - **SQL analytics**: use DuckDB's SQL dialect to query any size of data directly from Claude
24
+ - **Serverless architecture**: run analytics without needing to configure instances or clusters
25
+
26
+ ## Components
27
+
28
+ ### Prompts
29
+
30
+ The server provides one prompt:
31
+
32
+ - `duckdb-motherduck-initial-prompt`: A prompt to initialize a connection to DuckDB or MotherDuck and start working with it
33
+
34
+ ### Tools
35
+
36
+ The server offers one tool:
37
+
38
+ - `query`: Execute a SQL query on the MotherDuck/DuckDB database
39
+ - **Inputs**:
40
+ - `query` (string, required): The SQL query to execute
41
+
42
+ All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
43
+
44
+ ## Getting Started
45
+
46
+ ### Prerequisites
47
+
48
+ - A MotherDuck account (sign up at [motherduck.com](https://motherduck.com))
49
+ - A MotherDuck access token
50
+ - `uvx` installed, you can install it using `pip install uvx` or `brew install uvx`
51
+
52
+ If you plan to use MotherDuck MCP with Claude Desktop, you will also need Claude Desktop installed.
53
+
54
+ ### Setting up your MotherDuck token
55
+
56
+ 1. Sign up for a [MotherDuck account](https://app.motherduck.com/?auth_flow=signup)
57
+ 2. Generate an access token via the [MotherDuck UI](https://app.motherduck.com/settings/tokens?auth_flow=signup)
58
+ 3. Store the token securely for use in the configuration
59
+
60
+ ### Usage with Claude Desktop
61
+
62
+ 1. Install Claude Desktop from [claude.ai/download](https://claude.ai/download) if you haven't already
63
+
64
+ 2. Open the Claude Desktop configuration file:
65
+
66
+ - 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.
67
+ - Add the following configuration to your `claude_desktop_config.json`:
68
+
69
+ ```json
70
+ "mcpServers": {
71
+ "mcp-server-motherduck": {
72
+ "command": "uvx",
73
+ "args": [
74
+ "mcp-server-motherduck",
75
+ "--db-path",
76
+ "md:",
77
+ "--motherduck-token",
78
+ "<YOUR_MOTHERDUCK_TOKEN_HERE>",
79
+ ],
80
+ }
81
+ }
82
+ ```
83
+
84
+ **Important Notes**:
85
+
86
+ - Replace `YOUR_MOTHERDUCK_TOKEN_HERE` with your actual MotherDuck token
87
+ - 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`
88
+ - The `HOME` environment variable is required for DuckDB to function properly.
89
+
90
+ ## Example Queries
91
+
92
+ Once configured, you can ask Claude to run queries like:
93
+
94
+ - "Create a new database and table in MotherDuck"
95
+ - "Query data from my local CSV file"
96
+ - "Join data from my local DuckDB database with a table in MotherDuck"
97
+ - "Analyze data stored in Amazon S3"
98
+
99
+ ## Testing
100
+
101
+ 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:
102
+
103
+ 1. **Default MotherDuck database**:
104
+
105
+ - To connect to the default MotherDuck database, you will need to pass the auth token using the `--motherduck-token` parameter.
106
+
107
+ ```bash
108
+ uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>
109
+ ```
110
+
111
+ 2. **Specific MotherDuck database**:
112
+
113
+ ```bash
114
+ uvx mcp-server-motherduck --db-path md:your_database_name --motherduck-token <your_motherduck_token>
115
+ ```
116
+
117
+ 3. **Local DuckDB database**:
118
+
119
+ ```bash
120
+ uvx mcp-server-motherduck --db-path /path/to/your/local.db
121
+ ```
122
+
123
+ 4. **In-memory database**:
124
+
125
+ ```bash
126
+ uvx mcp-server-motherduck --db-path :memory:
127
+ ```
128
+
129
+ 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:`).
130
+
131
+ ## Running in SSE mode
132
+
133
+ The server could also be run ing SSE mode using `supergateway` by running the following command:
134
+
135
+ ```bash
136
+ npx -y supergateway --stdio "uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>"
137
+ ```
138
+
139
+ And you can point your clients such as Claude Desktop, Cursor to this endpoint.
140
+
141
+ ## Troubleshooting
142
+
143
+ - If you encounter connection issues, verify your MotherDuck token is correct
144
+ - For local file access problems, ensure the `--home-dir` parameter is set correctly
145
+ - Check that the `uvx` command is available in your PATH
146
+ - In version previous for v0.4.0 we used environment variables, now we use parameters
147
+
148
+ ## License
149
+
150
+ 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,137 @@
1
+ # MotherDuck MCP Server
2
+
3
+ An MCP server implementation that integrates MotherDuck and local DuckDB, providing SQL analytics capabilities to Claude.
4
+
5
+ ## Features
6
+
7
+ - **Hybrid execution**: query data from both cloud-based MotherDuck and local DuckDB
8
+ - **Cloud storage integration**: access data stored in Amazon S3 or other cloud storage thanks to MotherDuck's integrations
9
+ - **Data sharing**: create and share databases
10
+ - **SQL analytics**: use DuckDB's SQL dialect to query any size of data directly from Claude
11
+ - **Serverless architecture**: run analytics without needing to configure instances or clusters
12
+
13
+ ## Components
14
+
15
+ ### Prompts
16
+
17
+ The server provides one prompt:
18
+
19
+ - `duckdb-motherduck-initial-prompt`: A prompt to initialize a connection to DuckDB or MotherDuck and start working with it
20
+
21
+ ### Tools
22
+
23
+ The server offers one tool:
24
+
25
+ - `query`: Execute a SQL query on the MotherDuck/DuckDB database
26
+ - **Inputs**:
27
+ - `query` (string, required): The SQL query to execute
28
+
29
+ All interactions with both DuckDB and MotherDuck are done through writing SQL queries.
30
+
31
+ ## Getting Started
32
+
33
+ ### Prerequisites
34
+
35
+ - A MotherDuck account (sign up at [motherduck.com](https://motherduck.com))
36
+ - A MotherDuck access token
37
+ - `uvx` installed, you can install it using `pip install uvx` or `brew install uvx`
38
+
39
+ If you plan to use MotherDuck MCP with Claude Desktop, you will also need Claude Desktop installed.
40
+
41
+ ### Setting up your MotherDuck token
42
+
43
+ 1. Sign up for a [MotherDuck account](https://app.motherduck.com/?auth_flow=signup)
44
+ 2. Generate an access token via the [MotherDuck UI](https://app.motherduck.com/settings/tokens?auth_flow=signup)
45
+ 3. Store the token securely for use in the configuration
46
+
47
+ ### Usage with Claude Desktop
48
+
49
+ 1. Install Claude Desktop from [claude.ai/download](https://claude.ai/download) if you haven't already
50
+
51
+ 2. Open the Claude Desktop configuration file:
52
+
53
+ - 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.
54
+ - Add the following configuration to your `claude_desktop_config.json`:
55
+
56
+ ```json
57
+ "mcpServers": {
58
+ "mcp-server-motherduck": {
59
+ "command": "uvx",
60
+ "args": [
61
+ "mcp-server-motherduck",
62
+ "--db-path",
63
+ "md:",
64
+ "--motherduck-token",
65
+ "<YOUR_MOTHERDUCK_TOKEN_HERE>",
66
+ ],
67
+ }
68
+ }
69
+ ```
70
+
71
+ **Important Notes**:
72
+
73
+ - Replace `YOUR_MOTHERDUCK_TOKEN_HERE` with your actual MotherDuck token
74
+ - 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`
75
+ - The `HOME` environment variable is required for DuckDB to function properly.
76
+
77
+ ## Example Queries
78
+
79
+ Once configured, you can ask Claude to run queries like:
80
+
81
+ - "Create a new database and table in MotherDuck"
82
+ - "Query data from my local CSV file"
83
+ - "Join data from my local DuckDB database with a table in MotherDuck"
84
+ - "Analyze data stored in Amazon S3"
85
+
86
+ ## Testing
87
+
88
+ 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:
89
+
90
+ 1. **Default MotherDuck database**:
91
+
92
+ - To connect to the default MotherDuck database, you will need to pass the auth token using the `--motherduck-token` parameter.
93
+
94
+ ```bash
95
+ uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>
96
+ ```
97
+
98
+ 2. **Specific MotherDuck database**:
99
+
100
+ ```bash
101
+ uvx mcp-server-motherduck --db-path md:your_database_name --motherduck-token <your_motherduck_token>
102
+ ```
103
+
104
+ 3. **Local DuckDB database**:
105
+
106
+ ```bash
107
+ uvx mcp-server-motherduck --db-path /path/to/your/local.db
108
+ ```
109
+
110
+ 4. **In-memory database**:
111
+
112
+ ```bash
113
+ uvx mcp-server-motherduck --db-path :memory:
114
+ ```
115
+
116
+ 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:`).
117
+
118
+ ## Running in SSE mode
119
+
120
+ The server could also be run ing SSE mode using `supergateway` by running the following command:
121
+
122
+ ```bash
123
+ npx -y supergateway --stdio "uvx mcp-server-motherduck --db-path md: --motherduck-token <your_motherduck_token>"
124
+ ```
125
+
126
+ And you can point your clients such as Claude Desktop, Cursor to this endpoint.
127
+
128
+ ## Troubleshooting
129
+
130
+ - If you encounter connection issues, verify your MotherDuck token is correct
131
+ - For local file access problems, ensure the `--home-dir` parameter is set correctly
132
+ - Check that the `uvx` command is available in your PATH
133
+ - In version previous for v0.4.0 we used environment variables, now we use parameters
134
+
135
+ ## License
136
+
137
+ 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,10 +1,16 @@
1
1
  [project]
2
2
  name = "mcp-server-motherduck"
3
- version = "0.3.3"
3
+ version = "0.4.0"
4
4
  description = "A MCP server for MotherDuck and local DuckDB"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
7
- dependencies = [ "mcp>=1.0.0", "duckdb>=1.1.3", "pandas>=2.0.0", "tabulate>=0.9.0" ]
7
+ dependencies = [
8
+ "mcp>=1.3.0",
9
+ "duckdb>=1.2.1",
10
+ "pandas>=2.0.0",
11
+ "tabulate>=0.9.0",
12
+ ]
13
+
8
14
  [[project.authors]]
9
15
  name = "tdoehmen"
10
16
  email = "till@motherduck.com"
@@ -0,0 +1,53 @@
1
+ from . import server
2
+ import asyncio
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")
8
+
9
+
10
+ def main():
11
+ """Main entry point for the package."""
12
+
13
+ parser = argparse.ArgumentParser(description="MotherDuck MCP Server")
14
+ parser.add_argument(
15
+ "--db-path",
16
+ default="md:",
17
+ help="(Default: `md:`) Path to local DuckDB database file or MotherDuck database",
18
+ )
19
+ parser.add_argument(
20
+ "--motherduck-token",
21
+ default=None,
22
+ help="(Default: env var `motherduck_token`) Access token to use for MotherDuck database connections",
23
+ )
24
+ parser.add_argument(
25
+ "--home-dir",
26
+ default=None,
27
+ help="(Default: env var `HOME`) Home directory for DuckDB",
28
+ )
29
+ # This is experimental and will change in the future
30
+ parser.add_argument(
31
+ "--result-format",
32
+ help="(Default: `markdown`) Format of the query result",
33
+ default="markdown",
34
+ choices=["markdown", "duckbox", "text"],
35
+ )
36
+
37
+ args = parser.parse_args()
38
+ logger.info("🦆 MotherDuck MCP Server v" + server.SERVER_VERSION)
39
+ logger.info("Ready to execute SQL queries via DuckDB/MotherDuck")
40
+ logger.info("Waiting for client connection...\n")
41
+
42
+ asyncio.run(
43
+ server.main(
44
+ db_path=args.db_path,
45
+ motherduck_token=args.motherduck_token,
46
+ result_format=args.result_format,
47
+ home_dir=args.home_dir,
48
+ )
49
+ )
50
+
51
+
52
+ # Optionally expose other important items at package level
53
+ __all__ = ["main", "server"]
@@ -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.4.0"
16
16
 
17
17
  logger = logging.getLogger("mcp_server_motherduck")
18
18
 
@@ -20,57 +20,79 @@ 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
+ motherduck_token: str | None = None,
24
25
  result_format: Literal["markdown", "duckbox", "text"] = "markdown",
26
+ home_dir: str | None = None,
25
27
  ):
26
- self.db_path, self.db_type = self._resolve_db_path_type(db_path)
27
- self.conn = self._initialize_connection()
28
+ self.db_path, self.db_type = self._resolve_db_path_type(
29
+ db_path, motherduck_token
30
+ )
31
+ logger.info(f"Database client initialized in `{self.db_type}` mode")
28
32
 
33
+ # Set the home directory for DuckDB
34
+ if home_dir:
35
+ os.environ["HOME"] = home_dir
36
+
37
+ self.conn = self._initialize_connection()
29
38
  self.result_format = result_format
30
39
 
31
40
  def _initialize_connection(self) -> duckdb.DuckDBPyConnection:
32
41
  """Initialize connection to the MotherDuck or DuckDB database"""
33
42
 
34
- logger.info(f"Connecting to {self.db_type} database: `{self.db_path}`")
43
+ logger.info(f"🔌 Connecting to {self.db_type} database")
35
44
 
36
- return duckdb.connect(
45
+ conn = duckdb.connect(
37
46
  self.db_path,
38
47
  config={"custom_user_agent": f"mcp-server-motherduck/{SERVER_VERSION}"},
39
48
  )
40
49
 
50
+ logger.info(f"✅ Successfully connected to {self.db_type} database")
51
+
52
+ return conn
53
+
41
54
  def _resolve_db_path_type(
42
- self, db_path: str = None
55
+ self, db_path: str, motherduck_token: str | None = None
43
56
  ) -> tuple[str, Literal["duckdb", "motherduck"]]:
44
57
  """Resolve and validate the database path"""
45
- # Use MotherDuck if token is available and no path specified
46
- if db_path is None and os.getenv("motherduck_token"):
47
- logger.info("Using MotherDuck token to connect to database `md:`")
48
- return "md:", "motherduck"
49
-
50
58
  # Handle MotherDuck paths
51
- if db_path and (db_path == "md:" or db_path.startswith("md:")):
52
- if not os.getenv("motherduck_token"):
59
+ if db_path.startswith("md:"):
60
+ if motherduck_token:
61
+ logger.info("Using MotherDuck token to connect to database `md:`")
62
+ return f"{db_path}?motherduck_token={motherduck_token}", "motherduck"
63
+ elif os.getenv("motherduck_token"):
64
+ logger.info(
65
+ "Using MotherDuck token from env to connect to database `md:`"
66
+ )
67
+ return (
68
+ f"{db_path}?motherduck_token={os.getenv('motherduck_token')}",
69
+ "motherduck",
70
+ )
71
+ else:
53
72
  raise ValueError(
54
- "Please set the `motherduck_token` environment variable when using `md:` as db_path."
73
+ "Please set the `motherduck_token` as an environment variable or pass it as an argument with `--motherduck-token` when using `md:` as db_path."
55
74
  )
56
- return db_path, "motherduck"
57
75
 
58
- # Handle local database paths
59
- if db_path:
60
- if not os.path.exists(db_path):
61
- raise FileNotFoundError(
62
- f"The database path `{db_path}` does not exist."
63
- )
76
+ if db_path == ":memory:":
64
77
  return db_path, "duckdb"
65
78
 
66
- # Default to in-memory database
67
- return ":memory:", "duckdb"
79
+ # Handle local database paths as the last check
80
+ if not os.path.exists(db_path):
81
+ raise FileNotFoundError(
82
+ f"The local database path `{db_path}` does not exist."
83
+ )
84
+ return db_path, "duckdb"
68
85
 
69
86
  def query(self, query: str) -> str:
70
87
  try:
71
88
  if self.result_format == "markdown":
72
89
  # Markdown version of the output
73
- return self.conn.execute(query).fetchdf().to_markdown()
90
+ logger.info(
91
+ f"🔍 Executing query: {query[:60]}{'...' if len(query) > 60 else ''}"
92
+ )
93
+ result = self.conn.execute(query).fetchdf().to_markdown()
94
+ logger.info("✅ Query executed successfully")
95
+ return result
74
96
  elif self.result_format == "duckbox":
75
97
  # Duckbox version of the output
76
98
  buffer = io.StringIO()
@@ -82,22 +104,23 @@ class DatabaseClient:
82
104
  return str(self.conn.execute(query).fetchall())
83
105
 
84
106
  except Exception as e:
85
- logger.error(f"Database error executing query: {e}")
86
- raise ValueError(f"Error executing query: {e}")
87
-
88
- def mcp_config(self) -> str:
89
- """Used for debugging purposes to show the current MCP config"""
90
- return {
91
- "current_working_directory": os.getcwd(),
92
- "database_type": self.db_type,
93
- "database_path": self.db_path,
94
- }
107
+ raise ValueError(f" Error executing query: {e}")
95
108
 
96
109
 
97
- async def main(db_path: str, result_format: Literal["markdown", "duckbox", "text"] = "markdown"):
98
- logger.info(f"Starting MotherDuck MCP Server with DB path: {db_path}")
110
+ async def main(
111
+ db_path: str,
112
+ motherduck_token: str | None = None,
113
+ result_format: Literal["markdown", "duckbox", "text"] = "markdown",
114
+ home_dir: str | None = None,
115
+ ):
116
+ logger.info("Starting MotherDuck MCP Server")
99
117
  server = Server("mcp-server-motherduck")
100
- db_client = DatabaseClient(db_path=db_path, result_format=result_format)
118
+ db_client = DatabaseClient(
119
+ db_path=db_path,
120
+ result_format=result_format,
121
+ motherduck_token=motherduck_token,
122
+ home_dir=home_dir,
123
+ )
101
124
 
102
125
  logger.info("Registering handlers")
103
126
 
@@ -194,9 +217,15 @@ async def main(db_path: str, result_format: Literal["markdown", "duckbox", "text
194
217
  logger.info(f"Calling tool: {name}::{arguments}")
195
218
  try:
196
219
  if name == "query":
220
+ if arguments is None:
221
+ return [
222
+ types.TextContent(type="text", text="Error: No query provided")
223
+ ]
197
224
  tool_response = db_client.query(arguments["query"])
198
225
  return [types.TextContent(type="text", text=str(tool_response))]
199
226
 
227
+ return [types.TextContent(type="text", text=f"Unsupported tool: {name}")]
228
+
200
229
  except Exception as e:
201
230
  logger.error(f"Error executing tool {name}: {e}")
202
231
  raise ValueError(f"Error executing tool {name}: {str(e)}")
@@ -215,3 +244,6 @@ async def main(db_path: str, result_format: Literal["markdown", "duckbox", "text
215
244
  ),
216
245
  ),
217
246
  )
247
+
248
+ # This will only be reached when the server is shutting down
249
+ logger.info("\n🦆 MotherDuck MCP Server shutting down...")