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 配置

相关推荐
郑同学zxc13 小时前
机器学习18-tensorflow3
人工智能·机器学习
这张生成的图像能检测吗14 小时前
(论文速读)基于快速局域谱滤波的卷积神经网络
人工智能·神经网络·cnn·图神经网络·分类模型
wuxuand14 小时前
2026论文阅读——BayesAHDD:当贝叶斯决策规则遇上小样本单类分类
论文阅读·人工智能·分类·数据挖掘
wuxuand14 小时前
2026论文阅读——FedOCC:当单类分类遇上联邦学习——生成对抗+联邦蒸馏的新范式
人工智能·分类·数据挖掘
小陳参上16 小时前
用Python创建一个Discord聊天机器人
jvm·数据库·python
minstbe18 小时前
IC设计私有化AI助手实战:基于Docker+OpenCode+Ollama的数字前端综合增强方案(进阶版)
人工智能·python·语言模型·llama
mCell18 小时前
【短文】不是最强,是最适合
前端·aigc·deepseek
GinoInterpreter19 小时前
什么是翻译的去中心化?
人工智能·自然语言处理·去中心化·区块链·机器翻译·机器翻译模型·机器翻译引擎
zyq99101_119 小时前
优化二分查找:前缀和降复杂度
数据结构·python·蓝桥杯
qyzm19 小时前
天梯赛练习(3月13日)
开发语言·数据结构·python·算法·贪心算法