mcp-dbutils 0.2.8__py3-none-any.whl → 0.3.0__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.
mcp_dbutils/__init__.py CHANGED
@@ -6,12 +6,16 @@ import os
6
6
  import sys
7
7
  from pathlib import Path
8
8
  import yaml
9
+ from importlib.metadata import metadata
9
10
 
10
11
  from .log import create_logger
11
12
  from .base import DatabaseServer
12
13
 
14
+ # 获取包信息
15
+ pkg_meta = metadata("mcp-dbutils")
16
+
13
17
  # 创建全局logger
14
- log = create_logger("mcp-dbutils")
18
+ log = create_logger(pkg_meta["Name"])
15
19
 
16
20
  async def run_server():
17
21
  """服务器运行逻辑"""
@@ -26,8 +30,9 @@ async def run_server():
26
30
 
27
31
  # 更新logger的debug状态
28
32
  global log
29
- log = create_logger("mcp-dbutils", debug)
33
+ log = create_logger(pkg_meta["Name"], debug)
30
34
 
35
+ log("info", f"MCP Database Utilities Service v{pkg_meta['Version']}")
31
36
  if debug:
32
37
  log("debug", "Debug模式已开启")
33
38
 
mcp_dbutils/base.py CHANGED
@@ -17,12 +17,18 @@ from typing import Any, List, Optional, AsyncContextManager
17
17
  from contextlib import asynccontextmanager
18
18
  import json
19
19
  import yaml
20
+ from importlib.metadata import metadata
20
21
  from mcp.server import Server, NotificationOptions
21
22
  import mcp.server.stdio
22
23
  import mcp.types as types
24
+ from mcp.shared.session import RequestResponder
25
+
23
26
  from .log import create_logger
24
27
  from .stats import ResourceStats
25
28
 
29
+ # 获取包信息用于日志命名
30
+ pkg_meta = metadata("mcp-dbutils")
31
+
26
32
  class DatabaseHandler(ABC):
27
33
  """Abstract base class defining common interface for database handlers"""
28
34
 
@@ -37,9 +43,15 @@ class DatabaseHandler(ABC):
37
43
  self.config_path = config_path
38
44
  self.database = database
39
45
  self.debug = debug
40
- self.log = create_logger(f"db-handler-{database}", debug)
46
+ self.log = create_logger(f"{pkg_meta['Name']}.handler.{database}", debug)
41
47
  self.stats = ResourceStats()
42
48
 
49
+ @property
50
+ @abstractmethod
51
+ def db_type(self) -> str:
52
+ """Return database type"""
53
+ pass
54
+
43
55
  @abstractmethod
44
56
  async def get_tables(self) -> list[types.Resource]:
45
57
  """Get list of table resources from database"""
@@ -85,18 +97,27 @@ class DatabaseServer:
85
97
  """
86
98
  self.config_path = config_path
87
99
  self.debug = debug
88
- self.logger = create_logger("db-server", debug)
89
- self.server = Server("database-server")
100
+ # 获取包信息用于服务器配置
101
+ pkg_meta = metadata("mcp-dbutils")
102
+ self.logger = create_logger(f"{pkg_meta['Name']}.server", debug)
103
+ self.server = Server(
104
+ name=pkg_meta["Name"],
105
+ version=pkg_meta["Version"]
106
+ )
90
107
  self._setup_handlers()
91
108
  self._setup_prompts()
92
109
 
93
110
  def _setup_prompts(self):
94
111
  """Setup prompts handlers"""
112
+ @self.server.list_prompts()
95
113
  async def handle_list_prompts() -> list[types.Prompt]:
96
- """Return empty list of prompts for now"""
97
- return []
98
-
99
- self.server.request_handlers["prompts/list"] = handle_list_prompts
114
+ """Handle prompts/list request"""
115
+ try:
116
+ self.logger("debug", "Handling list_prompts request")
117
+ return []
118
+ except Exception as e:
119
+ self.logger("error", f"Error in list_prompts: {str(e)}")
120
+ raise
100
121
 
101
122
  @asynccontextmanager
102
123
  async def get_handler(self, database: str) -> AsyncContextManager[DatabaseHandler]:
@@ -226,10 +247,8 @@ class DatabaseServer:
226
247
  async def run(self):
227
248
  """Run server"""
228
249
  async with mcp.server.stdio.stdio_server() as streams:
229
- init_options = self.server.create_initialization_options()
230
- init_options.capabilities.prompts = types.PromptsCapability(list=True)
231
250
  await self.server.run(
232
251
  streams[0],
233
252
  streams[1],
234
- init_options
253
+ self.server.create_initialization_options()
235
254
  )
mcp_dbutils/log.py CHANGED
@@ -20,8 +20,8 @@ def create_logger(name: str, is_debug: bool = False) -> Callable:
20
20
  if level == "debug" and not is_debug:
21
21
  return
22
22
 
23
- timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f')[:-3]
24
- log_message = f"[{timestamp}] [{name}] [{level}] {message}"
23
+ timestamp = datetime.utcnow().isoformat(timespec='milliseconds') + 'Z'
24
+ log_message = f"{timestamp} [{name}] [{level}] {message}"
25
25
 
26
26
  # 始终输出到stderr
27
27
  print(log_message, file=sys.stderr, flush=True)
@@ -30,4 +30,4 @@ def create_logger(name: str, is_debug: bool = False) -> Callable:
30
30
  if notify:
31
31
  notify(level=level, data=message)
32
32
 
33
- return log
33
+ return log
@@ -8,6 +8,10 @@ from ..base import DatabaseHandler, DatabaseError
8
8
  from .config import PostgresConfig
9
9
 
10
10
  class PostgresHandler(DatabaseHandler):
11
+ @property
12
+ def db_type(self) -> str:
13
+ return 'postgres'
14
+
11
15
  def __init__(self, config_path: str, database: str, debug: bool = False):
12
16
  """Initialize PostgreSQL handler
13
17
 
@@ -128,6 +132,7 @@ class PostgresHandler(DatabaseHandler):
128
132
  formatted_results = [dict(zip(columns, row)) for row in results]
129
133
 
130
134
  result_text = str({
135
+ 'type': self.db_type,
131
136
  'columns': columns,
132
137
  'rows': formatted_results,
133
138
  'row_count': len(results)
@@ -138,7 +143,7 @@ class PostgresHandler(DatabaseHandler):
138
143
  finally:
139
144
  cur.execute("ROLLBACK")
140
145
  except psycopg2.Error as e:
141
- error_msg = f"Query execution failed: [Code: {e.pgcode}] {e.pgerror or str(e)}"
146
+ error_msg = f"[{self.db_type}] Query execution failed: [Code: {e.pgcode}] {e.pgerror or str(e)}"
142
147
  raise DatabaseError(error_msg)
143
148
  finally:
144
149
  if conn:
@@ -3,9 +3,13 @@ import psycopg2
3
3
  from psycopg2.pool import SimpleConnectionPool
4
4
  from typing import Optional, List
5
5
  import mcp.types as types
6
+ from importlib.metadata import metadata
6
7
  from ..base import DatabaseServer
7
8
  from ..log import create_logger
8
9
  from .config import PostgresConfig
10
+
11
+ # 获取包信息用于日志命名
12
+ pkg_meta = metadata("mcp-dbutils")
9
13
  class PostgresServer(DatabaseServer):
10
14
  def __init__(self, config: PostgresConfig, config_path: Optional[str] = None):
11
15
  """初始化PostgreSQL服务器
@@ -13,10 +17,10 @@ class PostgresServer(DatabaseServer):
13
17
  config: 数据库配置
14
18
  config_path: 配置文件路径(可选)
15
19
  """
16
- super().__init__("postgres-server", config.debug)
20
+ super().__init__(config_path, config.debug)
17
21
  self.config = config
18
22
  self.config_path = config_path
19
- self.log = create_logger("postgres", config.debug)
23
+ self.log = create_logger(f"{pkg_meta['Name']}.db.postgres", config.debug)
20
24
  # 创建连接池
21
25
  try:
22
26
  conn_params = config.get_connection_params()
@@ -9,6 +9,10 @@ from ..base import DatabaseHandler, DatabaseError
9
9
  from .config import SqliteConfig
10
10
 
11
11
  class SqliteHandler(DatabaseHandler):
12
+ @property
13
+ def db_type(self) -> str:
14
+ return 'sqlite'
15
+
12
16
  def __init__(self, config_path: str, database: str, debug: bool = False):
13
17
  """Initialize SQLite handler
14
18
 
@@ -110,6 +114,7 @@ class SqliteHandler(DatabaseHandler):
110
114
  formatted_results = [dict(zip(columns, row)) for row in results]
111
115
 
112
116
  result_text = str({
117
+ 'type': self.db_type,
113
118
  'columns': columns,
114
119
  'rows': formatted_results,
115
120
  'row_count': len(results)
@@ -119,7 +124,7 @@ class SqliteHandler(DatabaseHandler):
119
124
  return result_text
120
125
 
121
126
  except sqlite3.Error as e:
122
- error_msg = f"Query execution failed: {str(e)}"
127
+ error_msg = f"[{self.db_type}] Query execution failed: {str(e)}"
123
128
  raise DatabaseError(error_msg)
124
129
 
125
130
  async def cleanup(self):
@@ -5,11 +5,15 @@ from pathlib import Path
5
5
  from contextlib import closing
6
6
  from typing import Optional, List
7
7
  import mcp.types as types
8
+ from importlib.metadata import metadata
8
9
 
9
10
  from ..base import DatabaseServer
10
11
  from ..log import create_logger
11
12
  from .config import SqliteConfig
12
13
 
14
+ # 获取包信息用于日志命名
15
+ pkg_meta = metadata("mcp-dbutils")
16
+
13
17
  class SqliteServer(DatabaseServer):
14
18
  def __init__(self, config: SqliteConfig, config_path: Optional[str] = None):
15
19
  """初始化 SQLite 服务器
@@ -17,10 +21,10 @@ class SqliteServer(DatabaseServer):
17
21
  Args:
18
22
  config: SQLite 配置
19
23
  """
20
- super().__init__("sqlite-server", config.debug)
24
+ super().__init__(config_path, config.debug)
21
25
  self.config = config
22
26
  self.config_path = config_path
23
- self.log = create_logger("sqlite", config.debug)
27
+ self.log = create_logger(f"{pkg_meta['Name']}.db.sqlite", config.debug)
24
28
 
25
29
  # 确保数据库目录存在
26
30
  db_file = Path(self.config.absolute_path)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-dbutils
3
- Version: 0.2.8
3
+ Version: 0.3.0
4
4
  Summary: MCP Database Utilities Service
5
5
  Author: Dong Hao
6
6
  License-Expression: MIT
@@ -62,7 +62,7 @@ uvx mcp-dbutils --config /path/to/config.yaml
62
62
  Add to Claude configuration:
63
63
  ```json
64
64
  "mcpServers": {
65
- "dbutils": {
65
+ "mcp-dbutils": {
66
66
  "command": "uvx",
67
67
  "args": [
68
68
  "mcp-dbutils",
@@ -84,7 +84,7 @@ pip install mcp-dbutils
84
84
  Add to Claude configuration:
85
85
  ```json
86
86
  "mcpServers": {
87
- "dbutils": {
87
+ "mcp-dbutils": {
88
88
  "command": "python",
89
89
  "args": [
90
90
  "-m",
@@ -111,7 +111,7 @@ docker run -i --rm \
111
111
  Add to Claude configuration:
112
112
  ```json
113
113
  "mcpServers": {
114
- "dbutils": {
114
+ "mcp-dbutils": {
115
115
  "command": "docker",
116
116
  "args": [
117
117
  "run",
@@ -0,0 +1,18 @@
1
+ mcp_dbutils/__init__.py,sha256=xcfE1spAaONAoxBYB1ZyDX8tw7nxV1PMqo_RwxLDp0A,1892
2
+ mcp_dbutils/base.py,sha256=xdeLOKv9-dbMUzlIbD-BbRVbqAf1a3RjO25aw61vAzY,9691
3
+ mcp_dbutils/config.py,sha256=EwnPNuQVCBKd5WOXQfROyDTM-YpM_Odp0GhCPRg8YwE,1863
4
+ mcp_dbutils/log.py,sha256=fibVIwsb1HVU5zriGrDZTMEirKjgIuxuN_B_YTdAJ7I,996
5
+ mcp_dbutils/stats.py,sha256=2hiKi_M8V4xhVHlH5FS-Df5GuMEpuzif12C8ik06Khs,2538
6
+ mcp_dbutils/postgres/__init__.py,sha256=Y6v_RsI79pqAfpKM3SrT1T1I9r5yWuKT0GUUNmHD3DE,146
7
+ mcp_dbutils/postgres/config.py,sha256=ipjskdlv3u949R9rC2AKPCINRrtEAiKDjeogpFfM6aE,2401
8
+ mcp_dbutils/postgres/handler.py,sha256=JC_Qyw1s6qjVR0tdH7FLAEAs9EPl_-wgFQLryQyMq5c,6089
9
+ mcp_dbutils/postgres/server.py,sha256=_S3HF1KooxPB9gX1FedoOOGn93tHlIevCab6vjCt2TU,8715
10
+ mcp_dbutils/sqlite/__init__.py,sha256=QV4th2ywzUmCCa3GHCcBf8blJ_E8OYy0dJ2fSf1TfSU,134
11
+ mcp_dbutils/sqlite/config.py,sha256=QK1JlY-ZBB5VyhydbiU-aAKNESTWMtyBfawbv2DAVCQ,2452
12
+ mcp_dbutils/sqlite/handler.py,sha256=bf_k93rCcJn09zc7tsqrlbiTGUg3FspimfWKxK_JQTs,4970
13
+ mcp_dbutils/sqlite/server.py,sha256=7Bbq9l7Ca_4dzkAbbdRcXxvHoO_NFLzZHwlhKB0HIJc,7724
14
+ mcp_dbutils-0.3.0.dist-info/METADATA,sha256=hy1Xl8rcvFAxmLRq_FHP8Ow1LM_x6Ujz5NO_TkzUtXY,9478
15
+ mcp_dbutils-0.3.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ mcp_dbutils-0.3.0.dist-info/entry_points.txt,sha256=XTjt0QmYRgKOJQT6skR9bp1EMUfIrgpHeZJPZ3CJffs,49
17
+ mcp_dbutils-0.3.0.dist-info/licenses/LICENSE,sha256=1A_CwpWVlbjrKdVEYO77vYfnXlW7oxcilZ8FpA_BzCI,1065
18
+ mcp_dbutils-0.3.0.dist-info/RECORD,,
@@ -1,18 +0,0 @@
1
- mcp_dbutils/__init__.py,sha256=_zVdjN2P_G5qEye7f5vQxiXAd6EwX2gyTL1wpFpqKck,1718
2
- mcp_dbutils/base.py,sha256=Hj35seBlmYgcq0qyoZchnUbKzDMPlhUxsCw7U79OA2c,9186
3
- mcp_dbutils/config.py,sha256=EwnPNuQVCBKd5WOXQfROyDTM-YpM_Odp0GhCPRg8YwE,1863
4
- mcp_dbutils/log.py,sha256=RJwWtHyZnJA2YRcyCK-WgnFadNuwtJeYKSxPbE-DCG0,991
5
- mcp_dbutils/stats.py,sha256=2hiKi_M8V4xhVHlH5FS-Df5GuMEpuzif12C8ik06Khs,2538
6
- mcp_dbutils/postgres/__init__.py,sha256=Y6v_RsI79pqAfpKM3SrT1T1I9r5yWuKT0GUUNmHD3DE,146
7
- mcp_dbutils/postgres/config.py,sha256=ipjskdlv3u949R9rC2AKPCINRrtEAiKDjeogpFfM6aE,2401
8
- mcp_dbutils/postgres/handler.py,sha256=mvktsgak0tR-L4oknqv7UhOZ0_R8KPB9JRWiswh0bl4,5955
9
- mcp_dbutils/postgres/server.py,sha256=3AdQyQfgrClkCmWOZ-xFXTeI9t3tpFkrY3qmyOR0b-U,8586
10
- mcp_dbutils/sqlite/__init__.py,sha256=QV4th2ywzUmCCa3GHCcBf8blJ_E8OYy0dJ2fSf1TfSU,134
11
- mcp_dbutils/sqlite/config.py,sha256=QK1JlY-ZBB5VyhydbiU-aAKNESTWMtyBfawbv2DAVCQ,2452
12
- mcp_dbutils/sqlite/handler.py,sha256=7mD50sQRii7UKX-8dE9RNicIXGwMDPB59Ee1dmncSlg,4842
13
- mcp_dbutils/sqlite/server.py,sha256=Q29O2YOW4kqDGc3z1hMXVv4M0KSkuZbqvVDMgZE8Fd8,7593
14
- mcp_dbutils-0.2.8.dist-info/METADATA,sha256=YdBbIw37bEGOtLGOE1XTjZaE7ESHog-y6rXxIp5N5y8,9466
15
- mcp_dbutils-0.2.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- mcp_dbutils-0.2.8.dist-info/entry_points.txt,sha256=XTjt0QmYRgKOJQT6skR9bp1EMUfIrgpHeZJPZ3CJffs,49
17
- mcp_dbutils-0.2.8.dist-info/licenses/LICENSE,sha256=1A_CwpWVlbjrKdVEYO77vYfnXlW7oxcilZ8FpA_BzCI,1065
18
- mcp_dbutils-0.2.8.dist-info/RECORD,,