sql-query-mcp 0.1.3__tar.gz → 0.2.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.
- {sql_query_mcp-0.1.3/sql_query_mcp.egg-info → sql_query_mcp-0.2.0}/PKG-INFO +55 -37
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/README.md +53 -36
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/pyproject.toml +2 -1
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/__init__.py +1 -1
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/adapters/mysql.py +8 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/adapters/postgres.py +10 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/app.py +24 -0
- sql_query_mcp-0.2.0/sql_query_mcp/importer.py +223 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0/sql_query_mcp.egg-info}/PKG-INFO +55 -37
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp.egg-info/SOURCES.txt +3 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp.egg-info/requires.txt +1 -0
- sql_query_mcp-0.2.0/tests/test_app.py +19 -0
- sql_query_mcp-0.2.0/tests/test_importer.py +330 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_validator.py +20 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/LICENSE +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/setup.cfg +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/__main__.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/adapters/__init__.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/audit.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/config.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/errors.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/executor.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/introspection.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/namespace.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/registry.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/release_metadata.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp/validator.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp.egg-info/dependency_links.txt +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp.egg-info/entry_points.txt +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/sql_query_mcp.egg-info/top_level.txt +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_audit.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_config.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_executor.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_metadata.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_namespace.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_registry.py +0 -0
- {sql_query_mcp-0.1.3 → sql_query_mcp-0.2.0}/tests/test_release_metadata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sql-query-mcp
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Read-only SQL MCP server for PostgreSQL and MySQL.
|
|
5
5
|
Author: Andy Wang
|
|
6
6
|
License-Expression: MIT
|
|
@@ -21,6 +21,7 @@ Requires-Python: >=3.10
|
|
|
21
21
|
Description-Content-Type: text/markdown
|
|
22
22
|
License-File: LICENSE
|
|
23
23
|
Requires-Dist: mcp>=1.12.4
|
|
24
|
+
Requires-Dist: openpyxl>=3.1
|
|
24
25
|
Requires-Dist: PyMySQL>=1.1
|
|
25
26
|
Requires-Dist: psycopg[binary]>=3.2
|
|
26
27
|
Requires-Dist: psycopg-pool>=3.2
|
|
@@ -35,6 +36,8 @@ Dynamic: license-file
|
|
|
35
36
|
A general-purpose MCP server that lets AI work with multiple databases within
|
|
36
37
|
clear boundaries.
|
|
37
38
|
|
|
39
|
+
[](https://glama.ai/mcp/servers/andyWang1688/sql-query-mcp)
|
|
40
|
+
|
|
38
41
|
## Current database support
|
|
39
42
|
|
|
40
43
|
| Database | Status | Current availability |
|
|
@@ -56,9 +59,10 @@ without exposing raw connection strings or flattening engine-specific concepts.
|
|
|
56
59
|
|
|
57
60
|
## What AI can do with it
|
|
58
61
|
|
|
59
|
-
The current tool set focuses on database discovery
|
|
60
|
-
|
|
61
|
-
it generates or
|
|
62
|
+
The current tool set focuses on database discovery, controlled query workflows,
|
|
63
|
+
and one narrow local file import path. You can use it to help an AI assistant
|
|
64
|
+
understand structure before it generates SQL or imports a prepared CSV/XLSX file
|
|
65
|
+
into an existing table.
|
|
62
66
|
|
|
63
67
|
MySQL supports `explain_query`, but not `explain_query(..., analyze=True)` in
|
|
64
68
|
the current implementation.
|
|
@@ -73,16 +77,18 @@ the current implementation.
|
|
|
73
77
|
| `run_select(connection_id, sql, limit?)` | Yes | Yes | Run read-only queries |
|
|
74
78
|
| `explain_query(connection_id, sql, analyze?)` | Yes | Yes | Inspect query plans |
|
|
75
79
|
| `get_table_sample(connection_id, table_name, schema?, database?, limit?)` | Yes | Yes | Fetch small table samples |
|
|
80
|
+
| `import_table_file(connection_id, table_name, file_path, schema?, database?, sheet_name?)` | Yes | Yes | Import local CSV/XLSX files |
|
|
76
81
|
|
|
77
82
|
These tools are useful for tasks such as listing namespaces, inspecting table
|
|
78
|
-
definitions, reviewing indexes, sampling records,
|
|
79
|
-
|
|
80
|
-
`docs/api-reference.md` (Chinese).
|
|
83
|
+
definitions, reviewing indexes, sampling records, analyzing read-only queries
|
|
84
|
+
with `EXPLAIN`, and importing prepared local files. For full request and
|
|
85
|
+
response details, see `docs/api-reference.md` (Chinese).
|
|
81
86
|
|
|
82
87
|
## How boundaries are constrained
|
|
83
88
|
|
|
84
89
|
The product boundary is intentionally narrow today. Only PostgreSQL and MySQL
|
|
85
|
-
are available today, and the
|
|
90
|
+
are available today. Query tools remain read-only, and the only write path is a
|
|
91
|
+
controlled local CSV/XLSX import into existing tables.
|
|
86
92
|
|
|
87
93
|
The service keeps those boundaries explicit in a few ways.
|
|
88
94
|
|
|
@@ -96,57 +102,69 @@ The service keeps those boundaries explicit in a few ways.
|
|
|
96
102
|
database.
|
|
97
103
|
- The server accepts only `SELECT` and `WITH ... SELECT`, rejects comments and
|
|
98
104
|
multi-statement input, and records audit logs for each call.
|
|
105
|
+
- `import_table_file` doesn't accept raw SQL. It inserts only file columns whose
|
|
106
|
+
headers exactly match existing table columns.
|
|
99
107
|
|
|
100
108
|
For MySQL, `explain_query(..., analyze=True)` is not available in the current
|
|
101
109
|
implementation.
|
|
102
110
|
|
|
103
111
|
## Quick start
|
|
104
112
|
|
|
105
|
-
|
|
106
|
-
|
|
113
|
+
`sql-query-mcp` supports two official PyPI-based setup modes. Both are intended
|
|
114
|
+
for real usage, not just local testing.
|
|
115
|
+
|
|
116
|
+
1. Choose how you want your MCP client to start the server.
|
|
107
117
|
|
|
108
|
-
|
|
118
|
+
Use installed command mode if you want a simple local command after one
|
|
119
|
+
install.
|
|
109
120
|
|
|
110
121
|
```bash
|
|
111
|
-
|
|
112
|
-
source .venv/bin/activate
|
|
113
|
-
python -m pip install --upgrade pip
|
|
114
|
-
pip install sql-query-mcp
|
|
122
|
+
pipx install sql-query-mcp
|
|
115
123
|
```
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Release.
|
|
120
|
-
|
|
121
|
-
2. Copy the example connection config.
|
|
125
|
+
Use managed launch mode if you want the package source declared directly in
|
|
126
|
+
your MCP client config.
|
|
122
127
|
|
|
123
128
|
```bash
|
|
124
|
-
|
|
129
|
+
pipx run --spec sql-query-mcp sql-query-mcp
|
|
125
130
|
```
|
|
126
131
|
|
|
127
|
-
|
|
132
|
+
Pin a version with `pipx install 'sql-query-mcp==X.Y.Z'` or
|
|
133
|
+
`pipx run --spec 'sql-query-mcp==X.Y.Z' sql-query-mcp`. Upgrade installed
|
|
134
|
+
command mode with `pipx upgrade sql-query-mcp`.
|
|
135
|
+
|
|
136
|
+
2. Create a config file.
|
|
128
137
|
|
|
129
|
-
|
|
138
|
+
The server configuration should live outside the repository so the same file
|
|
139
|
+
works with either startup mode.
|
|
130
140
|
|
|
131
141
|
```bash
|
|
132
|
-
|
|
133
|
-
export MYSQL_CONN_CRM_PROD_MUQIAO_RO='mysql://user:password@host:3306/crm'
|
|
134
|
-
export SQL_QUERY_MCP_CONFIG='/absolute/path/to/sql-query-mcp/config/connections.json'
|
|
142
|
+
mkdir -p ~/.config/sql-query-mcp
|
|
135
143
|
```
|
|
136
144
|
|
|
137
|
-
|
|
145
|
+
Then save the example JSON later in this section as
|
|
146
|
+
`~/.config/sql-query-mcp/connections.json`.
|
|
147
|
+
|
|
148
|
+
3. Register the server in your MCP client.
|
|
138
149
|
|
|
139
150
|
- Codex: `docs/codex-setup.md` (Chinese)
|
|
140
151
|
- OpenCode: `docs/opencode-setup.md` (Chinese)
|
|
141
152
|
|
|
153
|
+
Installed command mode means your client runs `sql-query-mcp` directly.
|
|
154
|
+
Managed launch mode means your client starts the server through `pipx run`.
|
|
155
|
+
|
|
156
|
+
In both modes, put `SQL_QUERY_MCP_CONFIG` and your real database DSNs in the
|
|
157
|
+
MCP client's environment block instead of exporting them in your shell.
|
|
158
|
+
|
|
142
159
|
The console entry point is `sql-query-mcp`, which maps to
|
|
143
160
|
`sql_query_mcp.app:main`.
|
|
144
161
|
|
|
145
162
|
The PyPI install name is `sql-query-mcp`, and the Python package import path is
|
|
146
163
|
`sql_query_mcp`.
|
|
147
164
|
|
|
148
|
-
|
|
149
|
-
|
|
165
|
+
For `pipx install` and `pipx run`, set `SQL_QUERY_MCP_CONFIG` explicitly to
|
|
166
|
+
your config file path. The default `config/connections.json` path is mainly for
|
|
167
|
+
source checkouts and local development.
|
|
150
168
|
|
|
151
169
|
The example config looks like this.
|
|
152
170
|
|
|
@@ -159,24 +177,24 @@ The example config looks like this.
|
|
|
159
177
|
},
|
|
160
178
|
"connections": [
|
|
161
179
|
{
|
|
162
|
-
"connection_id": "
|
|
180
|
+
"connection_id": "crm_prod_main_ro",
|
|
163
181
|
"engine": "postgres",
|
|
164
|
-
"label": "CRM PostgreSQL production /
|
|
182
|
+
"label": "CRM PostgreSQL production / Main / read-only",
|
|
165
183
|
"env": "prod",
|
|
166
|
-
"tenant": "
|
|
184
|
+
"tenant": "main",
|
|
167
185
|
"role": "ro",
|
|
168
|
-
"dsn_env": "
|
|
186
|
+
"dsn_env": "PG_CONN_CRM_PROD_MAIN_RO",
|
|
169
187
|
"enabled": true,
|
|
170
188
|
"default_schema": "public"
|
|
171
189
|
},
|
|
172
190
|
{
|
|
173
|
-
"connection_id": "
|
|
191
|
+
"connection_id": "crm_mysql_prod_main_ro",
|
|
174
192
|
"engine": "mysql",
|
|
175
|
-
"label": "CRM MySQL production /
|
|
193
|
+
"label": "CRM MySQL production / Main / read-only",
|
|
176
194
|
"env": "prod",
|
|
177
|
-
"tenant": "
|
|
195
|
+
"tenant": "main",
|
|
178
196
|
"role": "ro",
|
|
179
|
-
"dsn_env": "
|
|
197
|
+
"dsn_env": "MYSQL_CONN_CRM_PROD_MAIN_RO",
|
|
180
198
|
"enabled": true,
|
|
181
199
|
"default_database": "crm"
|
|
182
200
|
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
A general-purpose MCP server that lets AI work with multiple databases within
|
|
6
6
|
clear boundaries.
|
|
7
7
|
|
|
8
|
+
[](https://glama.ai/mcp/servers/andyWang1688/sql-query-mcp)
|
|
9
|
+
|
|
8
10
|
## Current database support
|
|
9
11
|
|
|
10
12
|
| Database | Status | Current availability |
|
|
@@ -26,9 +28,10 @@ without exposing raw connection strings or flattening engine-specific concepts.
|
|
|
26
28
|
|
|
27
29
|
## What AI can do with it
|
|
28
30
|
|
|
29
|
-
The current tool set focuses on database discovery
|
|
30
|
-
|
|
31
|
-
it generates or
|
|
31
|
+
The current tool set focuses on database discovery, controlled query workflows,
|
|
32
|
+
and one narrow local file import path. You can use it to help an AI assistant
|
|
33
|
+
understand structure before it generates SQL or imports a prepared CSV/XLSX file
|
|
34
|
+
into an existing table.
|
|
32
35
|
|
|
33
36
|
MySQL supports `explain_query`, but not `explain_query(..., analyze=True)` in
|
|
34
37
|
the current implementation.
|
|
@@ -43,16 +46,18 @@ the current implementation.
|
|
|
43
46
|
| `run_select(connection_id, sql, limit?)` | Yes | Yes | Run read-only queries |
|
|
44
47
|
| `explain_query(connection_id, sql, analyze?)` | Yes | Yes | Inspect query plans |
|
|
45
48
|
| `get_table_sample(connection_id, table_name, schema?, database?, limit?)` | Yes | Yes | Fetch small table samples |
|
|
49
|
+
| `import_table_file(connection_id, table_name, file_path, schema?, database?, sheet_name?)` | Yes | Yes | Import local CSV/XLSX files |
|
|
46
50
|
|
|
47
51
|
These tools are useful for tasks such as listing namespaces, inspecting table
|
|
48
|
-
definitions, reviewing indexes, sampling records,
|
|
49
|
-
|
|
50
|
-
`docs/api-reference.md` (Chinese).
|
|
52
|
+
definitions, reviewing indexes, sampling records, analyzing read-only queries
|
|
53
|
+
with `EXPLAIN`, and importing prepared local files. For full request and
|
|
54
|
+
response details, see `docs/api-reference.md` (Chinese).
|
|
51
55
|
|
|
52
56
|
## How boundaries are constrained
|
|
53
57
|
|
|
54
58
|
The product boundary is intentionally narrow today. Only PostgreSQL and MySQL
|
|
55
|
-
are available today, and the
|
|
59
|
+
are available today. Query tools remain read-only, and the only write path is a
|
|
60
|
+
controlled local CSV/XLSX import into existing tables.
|
|
56
61
|
|
|
57
62
|
The service keeps those boundaries explicit in a few ways.
|
|
58
63
|
|
|
@@ -66,57 +71,69 @@ The service keeps those boundaries explicit in a few ways.
|
|
|
66
71
|
database.
|
|
67
72
|
- The server accepts only `SELECT` and `WITH ... SELECT`, rejects comments and
|
|
68
73
|
multi-statement input, and records audit logs for each call.
|
|
74
|
+
- `import_table_file` doesn't accept raw SQL. It inserts only file columns whose
|
|
75
|
+
headers exactly match existing table columns.
|
|
69
76
|
|
|
70
77
|
For MySQL, `explain_query(..., analyze=True)` is not available in the current
|
|
71
78
|
implementation.
|
|
72
79
|
|
|
73
80
|
## Quick start
|
|
74
81
|
|
|
75
|
-
|
|
76
|
-
|
|
82
|
+
`sql-query-mcp` supports two official PyPI-based setup modes. Both are intended
|
|
83
|
+
for real usage, not just local testing.
|
|
84
|
+
|
|
85
|
+
1. Choose how you want your MCP client to start the server.
|
|
77
86
|
|
|
78
|
-
|
|
87
|
+
Use installed command mode if you want a simple local command after one
|
|
88
|
+
install.
|
|
79
89
|
|
|
80
90
|
```bash
|
|
81
|
-
|
|
82
|
-
source .venv/bin/activate
|
|
83
|
-
python -m pip install --upgrade pip
|
|
84
|
-
pip install sql-query-mcp
|
|
91
|
+
pipx install sql-query-mcp
|
|
85
92
|
```
|
|
86
93
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
Release.
|
|
90
|
-
|
|
91
|
-
2. Copy the example connection config.
|
|
94
|
+
Use managed launch mode if you want the package source declared directly in
|
|
95
|
+
your MCP client config.
|
|
92
96
|
|
|
93
97
|
```bash
|
|
94
|
-
|
|
98
|
+
pipx run --spec sql-query-mcp sql-query-mcp
|
|
95
99
|
```
|
|
96
100
|
|
|
97
|
-
|
|
101
|
+
Pin a version with `pipx install 'sql-query-mcp==X.Y.Z'` or
|
|
102
|
+
`pipx run --spec 'sql-query-mcp==X.Y.Z' sql-query-mcp`. Upgrade installed
|
|
103
|
+
command mode with `pipx upgrade sql-query-mcp`.
|
|
104
|
+
|
|
105
|
+
2. Create a config file.
|
|
98
106
|
|
|
99
|
-
|
|
107
|
+
The server configuration should live outside the repository so the same file
|
|
108
|
+
works with either startup mode.
|
|
100
109
|
|
|
101
110
|
```bash
|
|
102
|
-
|
|
103
|
-
export MYSQL_CONN_CRM_PROD_MUQIAO_RO='mysql://user:password@host:3306/crm'
|
|
104
|
-
export SQL_QUERY_MCP_CONFIG='/absolute/path/to/sql-query-mcp/config/connections.json'
|
|
111
|
+
mkdir -p ~/.config/sql-query-mcp
|
|
105
112
|
```
|
|
106
113
|
|
|
107
|
-
|
|
114
|
+
Then save the example JSON later in this section as
|
|
115
|
+
`~/.config/sql-query-mcp/connections.json`.
|
|
116
|
+
|
|
117
|
+
3. Register the server in your MCP client.
|
|
108
118
|
|
|
109
119
|
- Codex: `docs/codex-setup.md` (Chinese)
|
|
110
120
|
- OpenCode: `docs/opencode-setup.md` (Chinese)
|
|
111
121
|
|
|
122
|
+
Installed command mode means your client runs `sql-query-mcp` directly.
|
|
123
|
+
Managed launch mode means your client starts the server through `pipx run`.
|
|
124
|
+
|
|
125
|
+
In both modes, put `SQL_QUERY_MCP_CONFIG` and your real database DSNs in the
|
|
126
|
+
MCP client's environment block instead of exporting them in your shell.
|
|
127
|
+
|
|
112
128
|
The console entry point is `sql-query-mcp`, which maps to
|
|
113
129
|
`sql_query_mcp.app:main`.
|
|
114
130
|
|
|
115
131
|
The PyPI install name is `sql-query-mcp`, and the Python package import path is
|
|
116
132
|
`sql_query_mcp`.
|
|
117
133
|
|
|
118
|
-
|
|
119
|
-
|
|
134
|
+
For `pipx install` and `pipx run`, set `SQL_QUERY_MCP_CONFIG` explicitly to
|
|
135
|
+
your config file path. The default `config/connections.json` path is mainly for
|
|
136
|
+
source checkouts and local development.
|
|
120
137
|
|
|
121
138
|
The example config looks like this.
|
|
122
139
|
|
|
@@ -129,24 +146,24 @@ The example config looks like this.
|
|
|
129
146
|
},
|
|
130
147
|
"connections": [
|
|
131
148
|
{
|
|
132
|
-
"connection_id": "
|
|
149
|
+
"connection_id": "crm_prod_main_ro",
|
|
133
150
|
"engine": "postgres",
|
|
134
|
-
"label": "CRM PostgreSQL production /
|
|
151
|
+
"label": "CRM PostgreSQL production / Main / read-only",
|
|
135
152
|
"env": "prod",
|
|
136
|
-
"tenant": "
|
|
153
|
+
"tenant": "main",
|
|
137
154
|
"role": "ro",
|
|
138
|
-
"dsn_env": "
|
|
155
|
+
"dsn_env": "PG_CONN_CRM_PROD_MAIN_RO",
|
|
139
156
|
"enabled": true,
|
|
140
157
|
"default_schema": "public"
|
|
141
158
|
},
|
|
142
159
|
{
|
|
143
|
-
"connection_id": "
|
|
160
|
+
"connection_id": "crm_mysql_prod_main_ro",
|
|
144
161
|
"engine": "mysql",
|
|
145
|
-
"label": "CRM MySQL production /
|
|
162
|
+
"label": "CRM MySQL production / Main / read-only",
|
|
146
163
|
"env": "prod",
|
|
147
|
-
"tenant": "
|
|
164
|
+
"tenant": "main",
|
|
148
165
|
"role": "ro",
|
|
149
|
-
"dsn_env": "
|
|
166
|
+
"dsn_env": "MYSQL_CONN_CRM_PROD_MAIN_RO",
|
|
150
167
|
"enabled": true,
|
|
151
168
|
"default_database": "crm"
|
|
152
169
|
}
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "sql-query-mcp"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.2.0"
|
|
8
8
|
description = "Read-only SQL MCP server for PostgreSQL and MySQL."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -24,6 +24,7 @@ classifiers = [
|
|
|
24
24
|
]
|
|
25
25
|
dependencies = [
|
|
26
26
|
"mcp>=1.12.4",
|
|
27
|
+
"openpyxl>=3.1",
|
|
27
28
|
"PyMySQL>=1.1",
|
|
28
29
|
"psycopg[binary]>=3.2",
|
|
29
30
|
"psycopg-pool>=3.2",
|
|
@@ -115,6 +115,14 @@ class MySQLAdapter:
|
|
|
115
115
|
f"{self._quote_identifier(table_name)} LIMIT {int(sentinel_limit)}"
|
|
116
116
|
)
|
|
117
117
|
|
|
118
|
+
def build_insert_query(self, database: str, table_name: str, columns: List[str]) -> str:
|
|
119
|
+
quoted_columns = ", ".join(self._quote_identifier(column) for column in columns)
|
|
120
|
+
placeholders = ", ".join(["%s"] * len(columns))
|
|
121
|
+
return (
|
|
122
|
+
f"INSERT INTO {self._quote_identifier(database)}."
|
|
123
|
+
f"{self._quote_identifier(table_name)} ({quoted_columns}) VALUES ({placeholders})"
|
|
124
|
+
)
|
|
125
|
+
|
|
118
126
|
def build_explain_query(self, sql_text: str, analyze: bool = False) -> str:
|
|
119
127
|
if analyze:
|
|
120
128
|
raise SecurityError("MySQL 首版不支持 analyze=True。")
|
|
@@ -155,6 +155,16 @@ class PostgresAdapter:
|
|
|
155
155
|
sql.Literal(sentinel_limit),
|
|
156
156
|
)
|
|
157
157
|
|
|
158
|
+
def build_insert_query(self, schema: str, table_name: str, columns: List[str]):
|
|
159
|
+
if sql is None:
|
|
160
|
+
raise ConfigurationError("缺少 psycopg 依赖,请先安装项目依赖。")
|
|
161
|
+
return sql.SQL("INSERT INTO {}.{} ({}) VALUES ({})").format(
|
|
162
|
+
sql.Identifier(schema),
|
|
163
|
+
sql.Identifier(table_name),
|
|
164
|
+
sql.SQL(", ").join(sql.Identifier(column) for column in columns),
|
|
165
|
+
sql.SQL(", ").join(sql.Placeholder() for _ in columns),
|
|
166
|
+
)
|
|
167
|
+
|
|
158
168
|
def build_explain_query(self, sql_text: str, analyze: bool = False) -> str:
|
|
159
169
|
return f"EXPLAIN (FORMAT JSON, ANALYZE {'TRUE' if analyze else 'FALSE'}) {sql_text}"
|
|
160
170
|
|
|
@@ -10,6 +10,7 @@ from .audit import AuditLogger
|
|
|
10
10
|
from .config import load_config
|
|
11
11
|
from .errors import SqlQueryMCPError
|
|
12
12
|
from .executor import QueryExecutor
|
|
13
|
+
from .importer import TableFileImporter
|
|
13
14
|
from .introspection import MetadataService
|
|
14
15
|
from .registry import ConnectionRegistry
|
|
15
16
|
|
|
@@ -20,6 +21,7 @@ def create_app() -> FastMCP:
|
|
|
20
21
|
audit_logger = AuditLogger(app_config.settings.audit_log_path)
|
|
21
22
|
metadata = MetadataService(registry, app_config.settings, audit_logger)
|
|
22
23
|
executor = QueryExecutor(registry, app_config.settings, audit_logger)
|
|
24
|
+
importer = TableFileImporter(registry, app_config.settings, audit_logger)
|
|
23
25
|
|
|
24
26
|
mcp = FastMCP("sql-query-mcp", json_response=True)
|
|
25
27
|
|
|
@@ -86,6 +88,28 @@ def create_app() -> FastMCP:
|
|
|
86
88
|
|
|
87
89
|
return _run_tool(lambda: executor.get_table_sample(connection_id, table_name, schema, database, limit))
|
|
88
90
|
|
|
91
|
+
@mcp.tool()
|
|
92
|
+
def import_table_file(
|
|
93
|
+
connection_id: str,
|
|
94
|
+
table_name: str,
|
|
95
|
+
file_path: str,
|
|
96
|
+
schema: Optional[str] = None,
|
|
97
|
+
database: Optional[str] = None,
|
|
98
|
+
sheet_name: Optional[str] = None,
|
|
99
|
+
) -> dict:
|
|
100
|
+
"""Import a local CSV or XLSX file into an existing table."""
|
|
101
|
+
|
|
102
|
+
return _run_tool(
|
|
103
|
+
lambda: importer.import_table_file(
|
|
104
|
+
connection_id,
|
|
105
|
+
table_name,
|
|
106
|
+
file_path,
|
|
107
|
+
schema,
|
|
108
|
+
database,
|
|
109
|
+
sheet_name,
|
|
110
|
+
)
|
|
111
|
+
)
|
|
112
|
+
|
|
89
113
|
return mcp
|
|
90
114
|
|
|
91
115
|
|