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

相关推荐
键盘侠伍十七1 分钟前
Gandalf Lakera AI Prompt Injection 靶场深度教程:从 Level 1 到 Level 8 全面攻防解析
人工智能·prompt·ai安全
调试优选官1 分钟前
2026年上海GEO优化公司全景透视:技术路线、选型逻辑与实施路径
人工智能·技术分享·geo·上海
li-xun3 分钟前
2026年6月9日博客精选
人工智能·每日阅读
黑马师兄6 分钟前
RAG混合检索深度解析:让AI真正找到你要的内容
java·人工智能·ai·agent·rag·ai-native
哈伦20196 分钟前
第十二章 深度学习基础 案例:MLP实现银行单据手写数字识别
人工智能·深度学习·图像识别
右耳朵猫AI10 分钟前
GitHub周趋势2026W22 | AI编程工具、知识图谱、自托管、AI代理、代码智能
人工智能·github·ai编程
Black蜡笔小新23 分钟前
企业AI算力工作站DLTM深度学习推理工作站零代码私有化重塑企业AI落地新模式
人工智能·深度学习
IT知识分享30 分钟前
从零开发在线简繁转换工具:OpenCC 实战、避坑经验与方案选型
javascript·python
2601_9594801534 分钟前
Moneta Markets亿汇:“比特币反弹走势仍脆弱”
人工智能
lunzi_082635 分钟前
【学习笔记】《Python编程 从入门到实践》第8章:函数定义、参数传递与模块导入
笔记·python·学习