sse mcp flask 开放mcp服务到内网

python 复制代码
# e:\code\my_python_server\sse\sse_server.py
from mcp import ClientSession
from mcp.client.sse import sse_client
import asyncio
from flask import Flask, request, jsonify

app = Flask(__name__)

async def read_excel_data(filepath, sheet_name=None):
    """通过 SSE 连接到 MCP 服务器并读取 Excel 数据"""
    url = "http://localhost:8017/sse"
    
    async with sse_client(url) as (read, write):
        async with ClientSession(read, write) as session:
            # 初始化连接
            await session.initialize()
            print("已连接到 MCP 服务器")
            
            # 处理 sheet_name 参数
            # 如果没有提供 sheet_name,则使用默认值 "Sheet1"
            if sheet_name is None:
                sheet_name = "Sheet1"
            
            # 读取数据
            result = await session.call_tool(
                "read_data_from_excel",
                arguments={
                    "filepath": filepath,
                    "sheet_name": sheet_name,
                    "start_cell": "A1",
                    "preview_only": True
                }
            )
            print("已读取数据:", result)
            # 将结果转换为可序列化的格式
            return convert_result_to_serializable(result)

def convert_result_to_serializable(result):
    """将 CallToolResult 转换为可序列化的字典格式,并避免重复内容"""
    if hasattr(result, '__dict__'):
        # 如果结果对象有 __dict__ 属性,尝试转换其属性
        serializable = {}
        for key, value in result.__dict__.items():
            if isinstance(value, (str, int, float, bool, type(None))):
                serializable[key] = value
            elif isinstance(value, (list, tuple)):
                serializable[key] = [convert_result_to_serializable(item) if hasattr(item, '__dict__') else item for item in value]
            elif isinstance(value, dict):
                serializable[key] = {k: convert_result_to_serializable(v) if hasattr(v, '__dict__') else v for k, v in value.items()}
            else:
                # 对于其他对象,转换为字符串表示
                serializable[key] = str(value)
        
        # 特殊处理 content 和 structuredContent 字段,避免重复数据
        if 'content' in serializable and 'structuredContent' in serializable:
            # 如果 structuredContent 中的 result 与 content 的 text 相同,则移除其中一个
            if (isinstance(serializable['content'], list) and 
                len(serializable['content']) > 0 and
                isinstance(serializable['content'][0], dict) and
                'text' in serializable['content'][0] and
                isinstance(serializable['structuredContent'], dict) and
                'result' in serializable['structuredContent']):
                
                # 比较内容是否重复
                if serializable['content'][0]['text'] == serializable['structuredContent']['result']:
                    # 移除重复的 structuredContent,只保留 content
                    del serializable['structuredContent']
        
        return serializable
    else:
        return str(result)

async def list_available_tools():
    """通过 SSE 连接到 MCP 服务器并列出所有可用工具"""
    url = "http://localhost:8017/sse"
    
    async with sse_client(url) as (read, write):
        async with ClientSession(read, write) as session:
            # 初始化连接
            await session.initialize()
            print("已连接到 MCP 服务器")
            
            # 列出所有可用工具
            tools = await session.list_tools()
            return [{"name": tool.name, "description": tool.description} for tool in tools.tools]

@app.route('/read_excel', methods=['GET'])
def read_excel_endpoint():
    """Flask 路由,接受 filepath 和可选的 sheet_name 参数并返回读取结果"""
    filepath = request.args.get('filepath')
    sheet_name = request.args.get('sheet_name')
    
    if not filepath:
        return jsonify({"error": "缺少 filepath 参数"}), 400
    
    try:
        # 在异步环境中运行
        result = asyncio.run(read_excel_data(filepath, sheet_name))
        return jsonify({"result": result})
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route('/list_tools', methods=['GET'])
def list_tools_endpoint():
    """Flask 路由,列出所有可用的 MCP 工具"""
    try:
        # 在异步环境中运行
        tools = asyncio.run(list_available_tools())
        return jsonify({"tools": tools})
    except Exception as e:
        return jsonify({"error": str(e)}), 500

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)
相关推荐
我不会起名字3227 分钟前
一天一道算法题(34):回溯法的经典例题(子集)
java·数据结构·python·算法·golang·深度优先·力扣
ThornArmor43 分钟前
重铸1996|肉体渲染:关节的裂缝:分段模型积木拼装与未成熟的 RSP 矩阵骨骼动画形变
c语言·汇编·c++·python·硬件架构·游戏机
毕业设计7031 小时前
(免费领源码)基于Python的博物馆研学活动管理系统的设计与实现22724- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
python·mysql·随机森林·pycharm·django·flask·推荐算法
苏三说技术1 小时前
为什么越来越多人用OpenWiki?
后端
kyrie_sakura1 小时前
python学习笔记15 -- Anaconda,Jupyter,numpy
python·学习·jupyter·numpy
IT_陈寒1 小时前
Java里用Stream.parallel()翻车实录,这性能还不如单线程
前端·人工智能·后端
Bs_MoneyMagnet1 小时前
基于springboot+vue的生态果园采摘预约系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·毕业设计·计算机毕业设计
测试老哥1 小时前
接口测试的测试用例应该怎么写?
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·接口测试
Zenova EdgeOS2 小时前
Python 工业边缘 redis-py 异步实战
开发语言·redis·python
码事漫谈2 小时前
FDE 的起源、形态与真实边界
后端