mcp-dbutils 0.3.0__py3-none-any.whl → 0.5.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.
@@ -1,8 +1,40 @@
1
1
  """PostgreSQL configuration module"""
2
2
  from dataclasses import dataclass
3
3
  from typing import Optional, Dict, Any, Literal
4
+ from urllib.parse import urlparse
4
5
  from ..config import DatabaseConfig
5
6
 
7
+ def parse_jdbc_url(jdbc_url: str) -> Dict[str, str]:
8
+ """Parse JDBC URL into connection parameters
9
+
10
+ Args:
11
+ jdbc_url: JDBC URL (e.g. jdbc:postgresql://host:port/dbname)
12
+
13
+ Returns:
14
+ Dictionary of connection parameters
15
+ """
16
+ if not jdbc_url.startswith('jdbc:postgresql://'):
17
+ raise ValueError("Invalid PostgreSQL JDBC URL format")
18
+
19
+ # Remove jdbc: prefix and ensure no credentials in URL
20
+ url = jdbc_url[5:]
21
+ if '@' in url:
22
+ raise ValueError("JDBC URL should not contain credentials. Please provide username and password separately.")
23
+
24
+ # Parse URL
25
+ parsed = urlparse(url)
26
+
27
+ params = {
28
+ 'host': parsed.hostname or 'localhost',
29
+ 'port': str(parsed.port or 5432),
30
+ 'dbname': parsed.path.lstrip('/') if parsed.path else '',
31
+ }
32
+
33
+ if not params['dbname']:
34
+ raise ValueError("Database name must be specified in URL")
35
+
36
+ return params
37
+
6
38
  @dataclass
7
39
  class PostgresConfig(DatabaseConfig):
8
40
  dbname: str
@@ -35,12 +67,64 @@ class PostgresConfig(DatabaseConfig):
35
67
  if db_config['type'] != 'postgres':
36
68
  raise ValueError(f"Configuration is not PostgreSQL type: {db_config['type']}")
37
69
 
70
+ # Check required credentials
71
+ if not db_config.get('user'):
72
+ raise ValueError("User must be specified in database configuration")
73
+ if not db_config.get('password'):
74
+ raise ValueError("Password must be specified in database configuration")
75
+
76
+ # Get connection parameters
77
+ if 'jdbc_url' in db_config:
78
+ # Parse JDBC URL for connection parameters
79
+ params = parse_jdbc_url(db_config['jdbc_url'])
80
+ config = cls(
81
+ dbname=params['dbname'],
82
+ user=db_config['user'],
83
+ password=db_config['password'],
84
+ host=params['host'],
85
+ port=params['port'],
86
+ local_host=local_host,
87
+ )
88
+ else:
89
+ if not db_config.get('dbname'):
90
+ raise ValueError("Database name must be specified in configuration")
91
+ if not db_config.get('host'):
92
+ raise ValueError("Host must be specified in configuration")
93
+ if not db_config.get('port'):
94
+ raise ValueError("Port must be specified in configuration")
95
+ config = cls(
96
+ dbname=db_config['dbname'],
97
+ user=db_config['user'],
98
+ password=db_config['password'],
99
+ host=db_config['host'],
100
+ port=str(db_config['port']),
101
+ local_host=local_host,
102
+ )
103
+ config.debug = cls.get_debug_mode()
104
+ return config
105
+
106
+ @classmethod
107
+ def from_jdbc_url(cls, jdbc_url: str, user: str, password: str,
108
+ local_host: Optional[str] = None) -> 'PostgresConfig':
109
+ """Create configuration from JDBC URL and credentials
110
+
111
+ Args:
112
+ jdbc_url: JDBC URL (jdbc:postgresql://host:port/dbname)
113
+ user: Username for database connection
114
+ password: Password for database connection
115
+ local_host: Optional local host address
116
+
117
+ Raises:
118
+ ValueError: If URL format is invalid or required parameters are missing
119
+ """
120
+ params = parse_jdbc_url(jdbc_url)
121
+
38
122
  config = cls(
39
- dbname=db_config.get('dbname', ''),
40
- user=db_config.get('user', ''),
41
- password=db_config.get('password', ''),
42
- host=db_config.get('host', 'localhost'),
43
- port=str(db_config.get('port', 5432)),
123
+ dbname=params['dbname'],
124
+ user=user,
125
+ password=password,
126
+ host=params['host'],
127
+ port=params['port'],
44
128
  local_host=local_host,
45
129
  )
46
130
  config.debug = cls.get_debug_mode()
@@ -3,8 +3,50 @@
3
3
  from dataclasses import dataclass
4
4
  from pathlib import Path
5
5
  from typing import Dict, Any, Optional, Literal
6
+ from urllib.parse import urlparse, parse_qs
6
7
  from ..config import DatabaseConfig
7
8
 
9
+ def parse_jdbc_url(jdbc_url: str) -> Dict[str, str]:
10
+ """Parse JDBC URL into connection parameters
11
+
12
+ Args:
13
+ jdbc_url: JDBC URL (e.g. jdbc:sqlite:file:/path/to/database.db or jdbc:sqlite:/path/to/database.db)
14
+
15
+ Returns:
16
+ Dictionary of connection parameters
17
+
18
+ Raises:
19
+ ValueError: If URL format is invalid
20
+ """
21
+ if not jdbc_url.startswith('jdbc:sqlite:'):
22
+ raise ValueError("Invalid SQLite JDBC URL format")
23
+
24
+ # Remove jdbc:sqlite: prefix
25
+ url = jdbc_url[12:]
26
+
27
+ # Handle file: prefix
28
+ if url.startswith('file:'):
29
+ url = url[5:]
30
+
31
+ # Parse URL
32
+ parsed = urlparse(url)
33
+ path = parsed.path
34
+
35
+ # Extract query parameters
36
+ params = {}
37
+ if parsed.query:
38
+ query_params = parse_qs(parsed.query)
39
+ for key, values in query_params.items():
40
+ params[key] = values[0]
41
+
42
+ if not path:
43
+ raise ValueError("Database path must be specified in URL")
44
+
45
+ return {
46
+ 'path': path,
47
+ 'parameters': params
48
+ }
49
+
8
50
  @dataclass
9
51
  class SqliteConfig(DatabaseConfig):
10
52
  path: str
@@ -12,6 +54,30 @@ class SqliteConfig(DatabaseConfig):
12
54
  uri: bool = True # Enable URI mode to support parameters like password
13
55
  type: Literal['sqlite'] = 'sqlite'
14
56
 
57
+ @classmethod
58
+ def from_jdbc_url(cls, jdbc_url: str, password: Optional[str] = None) -> 'SqliteConfig':
59
+ """Create configuration from JDBC URL
60
+
61
+ Args:
62
+ jdbc_url: JDBC URL (e.g. jdbc:sqlite:file:/path/to/database.db)
63
+ password: Optional password for database encryption
64
+
65
+ Returns:
66
+ SqliteConfig instance
67
+
68
+ Raises:
69
+ ValueError: If URL format is invalid
70
+ """
71
+ params = parse_jdbc_url(jdbc_url)
72
+
73
+ config = cls(
74
+ path=params['path'],
75
+ password=password,
76
+ uri=True
77
+ )
78
+ config.debug = cls.get_debug_mode()
79
+ return config
80
+
15
81
  @property
16
82
  def absolute_path(self) -> str:
17
83
  """Return absolute path to database file"""
@@ -62,13 +128,23 @@ class SqliteConfig(DatabaseConfig):
62
128
  raise ValueError("Database configuration must include 'type' field")
63
129
  if db_config['type'] != 'sqlite':
64
130
  raise ValueError(f"Configuration is not SQLite type: {db_config['type']}")
65
- if 'path' not in db_config:
66
- raise ValueError("SQLite configuration must include 'path' field")
67
131
 
68
- config = cls(
69
- path=db_config['path'],
70
- password=db_config.get('password'),
71
- uri=True
72
- )
132
+ # Check if using JDBC URL configuration
133
+ if 'jdbc_url' in db_config:
134
+ params = parse_jdbc_url(db_config['jdbc_url'])
135
+ config = cls(
136
+ path=params['path'],
137
+ password=db_config.get('password'),
138
+ uri=True
139
+ )
140
+ else:
141
+ if 'path' not in db_config:
142
+ raise ValueError("SQLite configuration must include 'path' field")
143
+ config = cls(
144
+ path=db_config['path'],
145
+ password=db_config.get('password'),
146
+ uri=True
147
+ )
148
+
73
149
  config.debug = cls.get_debug_mode()
74
150
  return config
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mcp-dbutils
3
- Version: 0.3.0
3
+ Version: 0.5.0
4
4
  Summary: MCP Database Utilities Service
5
5
  Author: Dong Hao
6
6
  License-Expression: MIT
@@ -148,7 +148,7 @@ The project requires a YAML configuration file, specified via the `--config` par
148
148
 
149
149
  ```yaml
150
150
  databases:
151
- # PostgreSQL example (when using Docker)
151
+ # Standard PostgreSQL configuration example
152
152
  my_postgres:
153
153
  type: postgres
154
154
  dbname: test_db
@@ -158,6 +158,13 @@ databases:
158
158
  # host: 172.17.0.1 # For Linux (docker0 IP)
159
159
  port: 5432
160
160
 
161
+ # PostgreSQL with JDBC URL example
162
+ my_postgres_jdbc:
163
+ type: postgres
164
+ jdbc_url: jdbc:postgresql://host.docker.internal:5432/test_db
165
+ user: postgres # Credentials must be provided separately
166
+ password: secret # Not included in JDBC URL for security
167
+
161
168
  # SQLite example (when using Docker)
162
169
  my_sqlite:
163
170
  type: sqlite
@@ -165,6 +172,10 @@ databases:
165
172
  password: optional_password # optional
166
173
  ```
167
174
 
175
+ The configuration supports two formats for PostgreSQL:
176
+ 1. Standard configuration with individual parameters
177
+ 2. JDBC URL configuration with separate credentials (recommended for better compatibility)
178
+
168
179
  ### Debug Mode
169
180
  Set environment variable `MCP_DEBUG=1` to enable debug mode for detailed logging output.
170
181
 
@@ -4,15 +4,15 @@ mcp_dbutils/config.py,sha256=EwnPNuQVCBKd5WOXQfROyDTM-YpM_Odp0GhCPRg8YwE,1863
4
4
  mcp_dbutils/log.py,sha256=fibVIwsb1HVU5zriGrDZTMEirKjgIuxuN_B_YTdAJ7I,996
5
5
  mcp_dbutils/stats.py,sha256=2hiKi_M8V4xhVHlH5FS-Df5GuMEpuzif12C8ik06Khs,2538
6
6
  mcp_dbutils/postgres/__init__.py,sha256=Y6v_RsI79pqAfpKM3SrT1T1I9r5yWuKT0GUUNmHD3DE,146
7
- mcp_dbutils/postgres/config.py,sha256=ipjskdlv3u949R9rC2AKPCINRrtEAiKDjeogpFfM6aE,2401
7
+ mcp_dbutils/postgres/config.py,sha256=Np0GS5iUaUuWpYI8QfnyjUDy7v-vResQEAexR4W92-o,5447
8
8
  mcp_dbutils/postgres/handler.py,sha256=JC_Qyw1s6qjVR0tdH7FLAEAs9EPl_-wgFQLryQyMq5c,6089
9
9
  mcp_dbutils/postgres/server.py,sha256=_S3HF1KooxPB9gX1FedoOOGn93tHlIevCab6vjCt2TU,8715
10
10
  mcp_dbutils/sqlite/__init__.py,sha256=QV4th2ywzUmCCa3GHCcBf8blJ_E8OYy0dJ2fSf1TfSU,134
11
- mcp_dbutils/sqlite/config.py,sha256=QK1JlY-ZBB5VyhydbiU-aAKNESTWMtyBfawbv2DAVCQ,2452
11
+ mcp_dbutils/sqlite/config.py,sha256=RTHT2Xx--g-osD73CpT8DrCk0VHpHfPil3D6YUzXD-g,4519
12
12
  mcp_dbutils/sqlite/handler.py,sha256=bf_k93rCcJn09zc7tsqrlbiTGUg3FspimfWKxK_JQTs,4970
13
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,,
14
+ mcp_dbutils-0.5.0.dist-info/METADATA,sha256=g3WO-pqGFLsXxu1RcLQg9KjHEjVSG9ncrjqTzcgkm3A,9966
15
+ mcp_dbutils-0.5.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ mcp_dbutils-0.5.0.dist-info/entry_points.txt,sha256=XTjt0QmYRgKOJQT6skR9bp1EMUfIrgpHeZJPZ3CJffs,49
17
+ mcp_dbutils-0.5.0.dist-info/licenses/LICENSE,sha256=1A_CwpWVlbjrKdVEYO77vYfnXlW7oxcilZ8FpA_BzCI,1065
18
+ mcp_dbutils-0.5.0.dist-info/RECORD,,