mcp-server-mysql-py 0.1.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.
- mcp_server_mysql_py-0.1.0/.gitignore +7 -0
- mcp_server_mysql_py-0.1.0/PKG-INFO +56 -0
- mcp_server_mysql_py-0.1.0/README.md +46 -0
- mcp_server_mysql_py-0.1.0/pyproject.toml +21 -0
- mcp_server_mysql_py-0.1.0/src/mcp_server_mysql/__init__.py +1 -0
- mcp_server_mysql_py-0.1.0/src/mcp_server_mysql/server.py +135 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mcp-server-mysql-py
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python MCP server for MySQL database queries
|
|
5
|
+
License: MIT
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Requires-Dist: mcp>=1.0.0
|
|
8
|
+
Requires-Dist: pymysql>=1.1.0
|
|
9
|
+
Description-Content-Type: text/markdown
|
|
10
|
+
|
|
11
|
+
# mcp-server-mysql-py
|
|
12
|
+
|
|
13
|
+
A Python MCP server for MySQL database queries.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install mcp-server-mysql-py
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Configuration
|
|
22
|
+
|
|
23
|
+
Set environment variables:
|
|
24
|
+
|
|
25
|
+
- `MYSQL_HOST` - Database host (default: 127.0.0.1)
|
|
26
|
+
- `MYSQL_PORT` - Database port (default: 3306)
|
|
27
|
+
- `MYSQL_USER` - Database user (default: root)
|
|
28
|
+
- `MYSQL_PASS` - Database password
|
|
29
|
+
- `MYSQL_DB` - Database name
|
|
30
|
+
|
|
31
|
+
## Usage
|
|
32
|
+
|
|
33
|
+
### MCP Client Configuration
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"mysql": {
|
|
39
|
+
"command": "mcp-server-mysql-py",
|
|
40
|
+
"env": {
|
|
41
|
+
"MYSQL_HOST": "127.0.0.1",
|
|
42
|
+
"MYSQL_PORT": "3306",
|
|
43
|
+
"MYSQL_USER": "root",
|
|
44
|
+
"MYSQL_PASS": "password",
|
|
45
|
+
"MYSQL_DB": "mydb"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Tools
|
|
53
|
+
|
|
54
|
+
- **mysql_query** - Execute SQL queries
|
|
55
|
+
- **mysql_tables** - List all tables
|
|
56
|
+
- **mysql_describe** - Show table columns
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# mcp-server-mysql-py
|
|
2
|
+
|
|
3
|
+
A Python MCP server for MySQL database queries.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install mcp-server-mysql-py
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Configuration
|
|
12
|
+
|
|
13
|
+
Set environment variables:
|
|
14
|
+
|
|
15
|
+
- `MYSQL_HOST` - Database host (default: 127.0.0.1)
|
|
16
|
+
- `MYSQL_PORT` - Database port (default: 3306)
|
|
17
|
+
- `MYSQL_USER` - Database user (default: root)
|
|
18
|
+
- `MYSQL_PASS` - Database password
|
|
19
|
+
- `MYSQL_DB` - Database name
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### MCP Client Configuration
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"mysql": {
|
|
29
|
+
"command": "mcp-server-mysql-py",
|
|
30
|
+
"env": {
|
|
31
|
+
"MYSQL_HOST": "127.0.0.1",
|
|
32
|
+
"MYSQL_PORT": "3306",
|
|
33
|
+
"MYSQL_USER": "root",
|
|
34
|
+
"MYSQL_PASS": "password",
|
|
35
|
+
"MYSQL_DB": "mydb"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Tools
|
|
43
|
+
|
|
44
|
+
- **mysql_query** - Execute SQL queries
|
|
45
|
+
- **mysql_tables** - List all tables
|
|
46
|
+
- **mysql_describe** - Show table columns
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "mcp-server-mysql-py"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A Python MCP server for MySQL database queries"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
dependencies = [
|
|
13
|
+
"mcp>=1.0.0",
|
|
14
|
+
"pymysql>=1.1.0",
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
[project.scripts]
|
|
18
|
+
mcp-server-mysql-py = "mcp_server_mysql.server:main"
|
|
19
|
+
|
|
20
|
+
[tool.hatch.build.targets.wheel]
|
|
21
|
+
packages = ["src/mcp_server_mysql"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""MCP Server for MySQL database queries."""
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"""MCP Server for MySQL - Python implementation."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
import pymysql
|
|
9
|
+
from mcp.server import Server
|
|
10
|
+
from mcp.server.stdio import stdio_server
|
|
11
|
+
from mcp.types import TextContent, Tool
|
|
12
|
+
|
|
13
|
+
# ── 配置 ──────────────────────────────────────────────
|
|
14
|
+
MYSQL_HOST = os.environ.get("MYSQL_HOST", "127.0.0.1")
|
|
15
|
+
MYSQL_PORT = int(os.environ.get("MYSQL_PORT", "3306"))
|
|
16
|
+
MYSQL_USER = os.environ.get("MYSQL_USER", "root")
|
|
17
|
+
MYSQL_PASS = os.environ.get("MYSQL_PASS", "")
|
|
18
|
+
MYSQL_DB = os.environ.get("MYSQL_DB", "")
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_connection() -> pymysql.Connection:
|
|
22
|
+
return pymysql.connect(
|
|
23
|
+
host=MYSQL_HOST,
|
|
24
|
+
port=MYSQL_PORT,
|
|
25
|
+
user=MYSQL_USER,
|
|
26
|
+
password=MYSQL_PASS,
|
|
27
|
+
database=MYSQL_DB,
|
|
28
|
+
charset="utf8mb4",
|
|
29
|
+
cursorclass=pymysql.cursors.DictCursor,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def execute_query(sql: str) -> list[dict[str, Any]]:
|
|
34
|
+
conn = get_connection()
|
|
35
|
+
try:
|
|
36
|
+
with conn.cursor() as cursor:
|
|
37
|
+
cursor.execute(sql)
|
|
38
|
+
if cursor.description: # 有结果集
|
|
39
|
+
return cursor.fetchall()
|
|
40
|
+
else: # INSERT/UPDATE/DELETE
|
|
41
|
+
conn.commit()
|
|
42
|
+
return [{"affected_rows": cursor.rowcount}]
|
|
43
|
+
except Exception as e:
|
|
44
|
+
conn.rollback()
|
|
45
|
+
raise e
|
|
46
|
+
finally:
|
|
47
|
+
conn.close()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# ── MCP Server ────────────────────────────────────────
|
|
51
|
+
server = Server("mcp-server-mysql-py")
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@server.list_tools()
|
|
55
|
+
async def list_tools() -> list[Tool]:
|
|
56
|
+
return [
|
|
57
|
+
Tool(
|
|
58
|
+
name="mysql_query",
|
|
59
|
+
description="Execute a SQL query against the MySQL database",
|
|
60
|
+
inputSchema={
|
|
61
|
+
"type": "object",
|
|
62
|
+
"properties": {
|
|
63
|
+
"sql": {
|
|
64
|
+
"type": "string",
|
|
65
|
+
"description": "The SQL query to execute",
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"required": ["sql"],
|
|
69
|
+
},
|
|
70
|
+
),
|
|
71
|
+
Tool(
|
|
72
|
+
name="mysql_tables",
|
|
73
|
+
description="List all tables in the current database",
|
|
74
|
+
inputSchema={
|
|
75
|
+
"type": "object",
|
|
76
|
+
"properties": {},
|
|
77
|
+
},
|
|
78
|
+
),
|
|
79
|
+
Tool(
|
|
80
|
+
name="mysql_describe",
|
|
81
|
+
description="Show columns of a specific table",
|
|
82
|
+
inputSchema={
|
|
83
|
+
"type": "object",
|
|
84
|
+
"properties": {
|
|
85
|
+
"table": {
|
|
86
|
+
"type": "string",
|
|
87
|
+
"description": "The table name to describe",
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"required": ["table"],
|
|
91
|
+
},
|
|
92
|
+
),
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@server.call_tool()
|
|
97
|
+
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
|
|
98
|
+
try:
|
|
99
|
+
if name == "mysql_query":
|
|
100
|
+
sql = arguments["sql"]
|
|
101
|
+
rows = execute_query(sql)
|
|
102
|
+
result = json.dumps(rows, default=str, ensure_ascii=False)
|
|
103
|
+
return [TextContent(type="text", text=result)]
|
|
104
|
+
|
|
105
|
+
elif name == "mysql_tables":
|
|
106
|
+
rows = execute_query("SHOW TABLES")
|
|
107
|
+
tables = [list(row.values())[0] for row in rows]
|
|
108
|
+
return [TextContent(type="text", text="\n".join(tables))]
|
|
109
|
+
|
|
110
|
+
elif name == "mysql_describe":
|
|
111
|
+
table = arguments["table"]
|
|
112
|
+
rows = execute_query(f"DESCRIBE `{table}`")
|
|
113
|
+
result = json.dumps(rows, default=str, ensure_ascii=False)
|
|
114
|
+
return [TextContent(type="text", text=result)]
|
|
115
|
+
|
|
116
|
+
else:
|
|
117
|
+
return [TextContent(type="text", text=f"Unknown tool: {name}")]
|
|
118
|
+
|
|
119
|
+
except Exception as e:
|
|
120
|
+
return [TextContent(type="text", text=f"Error: {e}")]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
# ── 入口 ──────────────────────────────────────────────
|
|
124
|
+
async def _run():
|
|
125
|
+
async with stdio_server() as (read_stream, write_stream):
|
|
126
|
+
await server.run(read_stream, write_stream, server.create_initialization_options())
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def main():
|
|
130
|
+
import asyncio
|
|
131
|
+
asyncio.run(_run())
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
if __name__ == "__main__":
|
|
135
|
+
main()
|