当前位置: 首页 > news >正文

在本地部署mcp服务器实现自然语言操作mysql数据库,轻松实现数据表的增~ 删~ 改~ 查~

1.将写好的mcp_server代码放在本地任意盘!

import asyncio
import logging
import os
import sys
from mysql.connector import connect, Error
from mcp.server import Server
from mcp.types import Resource, Tool, TextContent
from pydantic import AnyUrl# Configure logging
logging.basicConfig(level=logging.INFO,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("mysql_mcp_server")def get_db_config():"""Get database configuration from environment variables."""config = {"host": os.getenv("MYSQL_HOST", "localhost"),"port": int(os.getenv("MYSQL_PORT", "3306")),"user": os.getenv("MYSQL_USER"),"password": os.getenv("MYSQL_PASSWORD"),"database": os.getenv("MYSQL_DATABASE"),# Add charset and collation to avoid utf8mb4_0900_ai_ci issues with older MySQL versions# These can be overridden via environment variables for specific MySQL versions"charset": os.getenv("MYSQL_CHARSET", "utf8mb4"),"collation": os.getenv("MYSQL_COLLATION", "utf8mb4_unicode_ci"),# Disable autocommit for better transaction control"autocommit": True,# Set SQL mode for better compatibility - can be overridden"sql_mode": os.getenv("MYSQL_SQL_MODE", "TRADITIONAL")}# Remove None values to let MySQL connector use defaults if not specifiedconfig = {k: v for k, v in config.items() if v is not None}if not all([config.get("user"), config.get("password"), config.get("database")]):logger.error("Missing required database configuration. Please check environment variables:")logger.error("MYSQL_USER, MYSQL_PASSWORD, and MYSQL_DATABASE are required")raise ValueError("Missing required database configuration")return config# Initialize server
app = Server("mysql_mcp_server")@app.list_resources()
async def list_resources() -> list[Resource]:"""List MySQL tables as resources."""config = get_db_config()try:logger.info(f"Connecting to MySQL with charset: {config.get('charset')}, collation: {config.get('collation')}")with connect(**config) as conn:logger.info(f"Successfully connected to MySQL server version: {conn.get_server_info()}")with conn.cursor() as cursor:cursor.execute("SHOW TABLES")tables = cursor.fetchall()logger.info(f"Found tables: {tables}")resources = []for table in tables:resources.append(Resource(uri=f"mysql://{table[0]}/data",name=f"Table: {table[0]}",mimeType="text/plain",description=f"Data in table: {table[0]}"))return resourcesexcept Error as e:logger.error(f"Failed to list resources: {str(e)}")logger.error(f"Error code: {e.errno}, SQL state: {e.sqlstate}")return []@app.read_resource()
async def read_resource(uri: AnyUrl) -> str:"""Read table contents."""config = get_db_config()uri_str = str(uri)logger.info(f"Reading resource: {uri_str}")if not uri_str.startswith("mysql://"):raise ValueError(f"Invalid URI scheme: {uri_str}")parts = uri_str[8:].split('/')table = parts[0]try:logger.info(f"Connecting to MySQL with charset: {config.get('charset')}, collation: {config.get('collation')}")with connect(**config) as conn:logger.info(f"Successfully connected to MySQL server version: {conn.get_server_info()}")with conn.cursor() as cursor:cursor.execute(f"SELECT * FROM {table} LIMIT 100")columns = [desc[0] for desc in cursor.description]rows = cursor.fetchall()result = [",".join(map(str, row)) for row in rows]return "\n".join([",".join(columns)] + result)except Error as e:logger.error(f"Database error reading resource {uri}: {str(e)}")logger.error(f"Error code: {e.errno}, SQL state: {e.sqlstate}")raise RuntimeError(f"Database error: {str(e)}")@app.list_tools()
async def list_tools() -> list[Tool]:"""List available MySQL tools."""logger.info("Listing tools...")return [Tool(name="execute_sql",description="Execute an SQL query on the MySQL server",inputSchema={"type": "object","properties": {"query": {"type": "string","description": "The SQL query to execute"}},"required": ["query"]})]@app.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:"""Execute SQL commands."""config = get_db_config()logger.info(f"Calling tool: {name} with arguments: {arguments}")if name != "execute_sql":raise ValueError(f"Unknown tool: {name}")query = arguments.get("query")if not query:raise ValueError("Query is required")try:logger.info(f"Connecting to MySQL with charset: {config.get('charset')}, collation: {config.get('collation')}")with connect(**config) as conn:logger.info(f"Successfully connected to MySQL server version: {conn.get_server_info()}")with conn.cursor() as cursor:cursor.execute(query)# Special handling for SHOW TABLESif query.strip().upper().startswith("SHOW TABLES"):tables = cursor.fetchall()result = ["Tables_in_" + config["database"]]  # Headerresult.extend([table[0] for table in tables])return [TextContent(type="text", text="\n".join(result))]# Handle all other queries that return result sets (SELECT, SHOW, DESCRIBE etc.)elif cursor.description is not None:columns = [desc[0] for desc in cursor.description]try:rows = cursor.fetchall()result = [",".join(map(str, row)) for row in rows]return [TextContent(type="text", text="\n".join([",".join(columns)] + result))]except Error as e:logger.warning(f"Error fetching results: {str(e)}")return [TextContent(type="text", text=f"Query executed but error fetching results: {str(e)}")]# Non-SELECT querieselse:conn.commit()return [TextContent(type="text", text=f"Query executed successfully. Rows affected: {cursor.rowcount}")]except Error as e:logger.error(f"Error executing SQL '{query}': {e}")logger.error(f"Error code: {e.errno}, SQL state: {e.sqlstate}")return [TextContent(type="text", text=f"Error executing query: {str(e)}")]async def main():"""Main entry point to run the MCP server."""from mcp.server.stdio import stdio_server# Add additional debug outputprint("Starting MySQL MCP server with config:", file=sys.stderr)config = get_db_config()print(f"Host: {config['host']}", file=sys.stderr)print(f"Port: {config['port']}", file=sys.stderr)print(f"User: {config['user']}", file=sys.stderr)print(f"Database: {config['database']}", file=sys.stderr)logger.info("Starting MySQL MCP server...")logger.info(f"Database config: {config['host']}/{config['database']} as {config['user']}")async with stdio_server() as (read_stream, write_stream):try:await app.run(read_stream,write_stream,app.create_initialization_options())except Exception as e:logger.error(f"Server error: {str(e)}", exc_info=True)raiseif __name__ == "__main__":asyncio.run(main())

2.再cherry studio中导入json配置参数

{"mcpServers": {"mysql": {"command": "uv","args": ["--directory","path/to/mysql_mcp_server","run","mysql_mcp_server"],"env": {"MYSQL_HOST": "localhost","MYSQL_PORT": "3306","MYSQL_USER": "your_username","MYSQL_PASSWORD": "your_password","MYSQL_DATABASE": "your_database"}}}
}

其中args中的参数说明:~
“–directory”, # 目录参数
“path/to/mysql_mcp_server.py”, # mcpserver端程序放置绝对路径!
“run”, # uv启动python脚本!
“mysql_mcp_server.py” # mcpserver代码 !

其中env中为本地或者远程数据库配置参数:~
“MYSQL_HOST”: “localhost”, #mysql主机IP
“MYSQL_PORT”: “3306”, #mysql服务端口
“MYSQL_USER”: “your_username”, #数据库用户名
“MYSQL_PASSWORD”: “your_password”, #数据库密码
“MYSQL_DATABASE”: “your_database” #数据库名

3.再cherry studio中新建会话,选择mysql mcp服务器

在这里插入图片描述

即可使用自然语言对数据表进行增删改查!

http://www.dtcms.com/a/268679.html

相关文章:

  • 七牛云Java开发面试题及参考答案
  • Unity接入Steamworks.NET实现通信功能
  • C#和SQL Server连接常用通讯方式
  • MsSql 其他(2)
  • Excel 的多线程特性
  • JavaWeb笔记07
  • LLM(大语言模型)能识别图像的核心原因:图像和文本记性特征识别且对其
  • [C语言笔记]11、结构体
  • 实用机器学习
  • 算法————模拟算法
  • Oracle实用参考(13)——Oracle for Linux PSR及PSU升级
  • C++系列(七):深度探索C++内存 --- 分区、堆栈、new/delete与高效编程实践
  • 动态规划递归与迭代实现对比
  • Data Agent:从技术本质到企业级实践的全景解析
  • LeetCode Hot 100 除自身以外数组的乘积
  • 16th Day| 222.完全二叉树的节点个数,110.平衡二叉树,257.二叉树的所有路径,404.左叶子之和
  • 分布式推客系统架构设计:从微服务到高性能计算的实践路径
  • WebView 中 Cookie 丢失怎么办?跨域状态不同步的调试与修复经验
  • 6,Receiving Messages:@KafkaListener Annotation
  • 诊断工程师进阶篇 --- 车载诊断怎么与时俱进?
  • vue3 字符包含
  • vue openlayer 找出直线上的某一个点 , 点距离直线 最短路径的点 WKT坐标转换为GeoJSON坐标
  • iOS Widget 开发-1:什么是 iOS Widget?开发前的基本认知
  • 亚马逊运营进阶指南:如何用AI工具赋能广告运营
  • 期待在 VR 森林体验模拟中实现与森林的 “虚拟复现”​
  • 华锐视点 VR 污水处理技术对激发学习兴趣的作用​
  • 北京-4年功能测试2年空窗-报培训班学测开-第四十四天
  • UI + MCP Client + MCP Server实验案例
  • 【机器学习笔记 Ⅱ】11 决策树模型
  • Spring Boot 操作 Redis 时 KeySerializer 和 HashKeySerializer 有什么区别?