SQL 执行 MCP 工具开发(一)

效果展示

调用MCP执行SQL时会自动弹出消息框,倒计时结束前未审批会自动拒绝该SQL的执行,此外可以通过备注介入,给AI合理的建议。

构建 MCP 服务

导入的包

python 复制代码
import json
import os
import subprocess
import time
from functools import wraps
from pathlib import Path

from mcp.server import FastMCP

MIN_WINDOW_SIZE = (500, 300)
MAX_WINDOW_SIZE = (800, 550)
DATA_SAVE_PATH = "E:/Workspace/MCP/tools/execute_sql/data"
WAILS_EXE_PATH = "E:/Workspace/MCP/tools/execute_sql/build/bin/execute-sql.exe"
mcp = FastMCP("ExecuteSQLReview", host="127.0.0.1", port=50050)

if __name__ == "__main__":
    mcp.run(transport="streamable-http")

stdio 无法正常弹窗,请使用 streamable-http 模式。

装饰器

python 复制代码
def mcp_tool(enable=True, max_length=2000):
    def decorator(func):
        original_func = func

        @wraps(func)
        def wrapper(*args, **kwargs):
            if not enable:
                return original_func(*args, **kwargs)
            raw_response = original_func(*args, **kwargs)
            if len(str(raw_response)) > max_length:
                file_name = DATA_SAVE_PATH + f"/result-{time.time()}.json"
                with open(file_name, "w", encoding="utf-8") as f:
                    f.write(json.dumps(raw_response, ensure_ascii=False, indent=4))
                return {
                    "code": 200,
                    "msg": f"响应结果过长,请调用文件工具查看",
                    "file_path": os.path.abspath(file_name)
                }
            return raw_response

        if enable:
            return mcp.tool()(wrapper)
        else:
            return wrapper

    return decorator

装饰器的作用有两方面,一是方便快速启用停用MCP工具,二是保存SQL执行结果,因为执行SQL返回的结果往往较多,因此这里新增了返回长度判断,如果过长则自动保存至文件中并提示AI使用文本工具查看。

计算窗口尺寸

python 复制代码
def calc_window_size(content, min_window_size=MIN_WINDOW_SIZE, max_window_size=MAX_WINDOW_SIZE):
    if not content:
        return min_window_size
    # 计算行数和最大行长度
    lines = content.split('/n')
    line_count = len(lines)
    max_char_count = max(len(line) for line in lines) if lines else 0
    # 每个字符的预估宽度
    CHAR_WIDTH = 13
    # 每行的预估高度
    LINE_HEIGHT = 28
    # 基础边距
    BASE_PADDING = 20
    # 计算尺寸(考虑边距)
    window_width = max_char_count * CHAR_WIDTH + BASE_PADDING * 2
    window_height = line_count * LINE_HEIGHT + BASE_PADDING * 2

    # 边界处理
    def clamp(value, min_val, max_val):
        return max(min_val, min(value, max_val))

    width = clamp(window_width, min_window_size[0], max_window_size[0])
    height = clamp(window_height, min_window_size[1], max_window_size[1])
    return width, height

执行SQL

python 复制代码
@mcp_tool(enable=True)
def execute_sql_review(sql: str, tags: list[dict]) -> dict:
    """
    执行SQL语句
    sql: 执行的SQL语句
    tags: 标签列表, 执行SQL标签, 查询, 更新, 删除.... 例: [{"name": "更新语句", "color": "#ffcb6b"}]
    """
    data = {
        "sql": sql,
        "options": [
            {"name": "通过", "value": "accept"},
            {"name": "拒绝", "value": "reject", "is_default": True},
        ],
        "tags": tags,
        "auto_close": 50
    }
    data_save_path = DATA_SAVE_PATH + f"/data-{time.time()}.json"
    result_save_path = DATA_SAVE_PATH + f"/result-{time.time()}.json"
    with open(data_save_path, "w", encoding="utf-8") as f:
        f.write(json.dumps(data, ensure_ascii=False, indent=4))
    width, height = calc_window_size(sql)
    cmd = [
        str(Path(WAILS_EXE_PATH).resolve()),
        "-data_path", str(Path(data_save_path).resolve()),
        "-result_path", str(Path(result_save_path).resolve()),
        "-title", "ExecuteSQLReview",
        "-width", str(width),
        "-height", str(height),
        "-min_width", str(MIN_WINDOW_SIZE[0]),
        "-min_height", str(MIN_WINDOW_SIZE[1]),
        "-on_top", "true",
        "-disable_resize", "true",
        "-frameless", "false",
        "-close_confirm", "false"
    ]
    # 运行
    subprocess.run(
        cmd, capture_output=False, text=True, encoding='utf-8', errors='ignore', shell=False
    )
    # 获取执行结果
    with open(result_save_path, "r", encoding="utf-8") as f:
        result = json.load(f)
    # 判断执行结果
    if result["select"] == "reject":
        return result
    # 模拟执行SQL并返回
    return {
        "run_ti": 566,
        "run_result": [{"name": "a", "age": 15}, {"name": "b", "age": 16}]
    }

这里执行SQL的逻辑可以自定义实现。

MCP 配置

相关推荐
郝学胜-神的一滴6 分钟前
Socket实战:从单端聊天到多用户连接的实现秘籍
服务器·开发语言·python·网络协议·pycharm
zzwq.11 分钟前
线程池与进程池:concurrent.futures高效并发
python
taWSw5OjU11 分钟前
从模型评估、梯度难题到科学初始化:一步步解析深度学习的训练问题
人工智能·深度学习
刘佬GEO12 分钟前
【无标题】
网络·人工智能·搜索引擎·ai·语言模型
用户20187928316719 分钟前
/export之一个程序员与AI的“破案笔记”
人工智能
Ricardo-Yang26 分钟前
SCNP语义分割边缘logits策略
数据结构·人工智能·python·深度学习·算法
新缸中之脑34 分钟前
微调BERT进行命名实体识别
人工智能·深度学习·bert
用户20187928316736 分钟前
故事:小白的“无限循环”噩梦与大师的 /loop 魔法
人工智能
段小二36 分钟前
Token 费用失控、VIP 用户体验一样烂:Context Engineering 才是关键
人工智能·后端
用户20187928316738 分钟前
/branch 你点了一份代码,Cli 帮你分成了两碗
人工智能