Streamable HTTP MCP实践

目录结构

mcp-http/
├── client-http.py # 客户端
├── mymcp-http.py # 服务端
├── servers_config.json # 客户端服务配置文件
└── .env # 环境变量配置文件

在这里插入图片描述

脚本


#### 初始化:
#### 为我们的项目创建一个新 directory
uv init mcp-http
cd mcp-http
#### 创建 virtual environment 并激活它
uv venv
.venv\Scripts\activate
#### 安装 dependencies
uv add mcp[cli]
uv add mcp[cli] httpx
uv add requests
uv add pymongo

uv add fastapi uvicorn jinja2 python-dotenv openai mcp httpx


cd mcp-http
.venv\Scripts\activate
uv run mymcp-http.py


cd mcp-http
.venv\Scripts\activate
uv run client-http.py

服务端 mymcp-http.py

from mcp.server.fastmcp import FastMCP
from pymongo import MongoClient
from dotenv import load_dotenv
from typing import Optional
import logging
import platform  # 用于识别操作系统类型
import subprocess  # 用于执行外部命令
import requests
import os

# 加载 .env 文件中的环境变量
load_dotenv()

# 动态获取环境变量中的配置
devops_cookie = os.getenv('DEVOPS_COOKIE')
api_url_base = os.getenv('API_URL_BASE')
jenkins_cookies = {
   
   
    "http://xx.xx.xx": os.getenv('JENKINS_COOKIE_1'),
    "http://xx.xx.xx": os.getenv('JENKINS_COOKIE_2'),
}
mongo_client_url = os.getenv('MONGO_CLIENT_URL')

# 设置日志级别为DEBUG,以便捕捉详细信息
logging.basicConfig(level=logging.DEBUG)

# 初始化 FastMCP 实例
mcp = FastMCP(
    name="SimpleServer",
    port=5050,
    stateless_http=False,
    json_response=False,
    streamable_http_path="/mcp"
)


# 测试联通
@mcp.tool()
def hello() -> str:
    """
    测试联通
    返回:
        hello world 字符串
    """
    return "hello world"


# 定义 ping 工具
@mcp.tool()
def ping(host: str) -> dict:
    """
    使用系统的 ping 命令来检查指定主机是否可达。
    参数:
        host (str): 要 ping 的 IP 地址或主机名
    返回:
        dict: 包含 'reachable'(是否可达)和 'output'(命令输出)的字典
    """
    # 根据不同的操作系统调整 ping 命令参数
    param = '-n' if platform.system().lower() == 'windows' else '-c'
    command = ['ping', param, '1', host]
    try:
        # 执行 ping 命令并捕获输出
        output = subprocess.run(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
        # 判断是否成功到达目标主机
        reachable = output.returncode == 0
        return {
   
   
            'reachable': reachable,
            'output': output.stdout if reachable else output.stderr
        }
    except Exception as e:
        return {
   
   
            'reachable': False,
            'output': str(e)
        }


# 定义 queryDataBase 工具
@mcp.tool()
def queryDataBase(database: str, collection: str, query: dict = None) -> list:
    """
    连接 MongoDB,查询指定数据库和集合的数据。
    参数:
        database (str): 数据库名称
        collection (str): 集合名称
        query (dict): 查询条件,默认为空,表示返回所有数据
    返回:
        list: 查询结果列表
    """
    if query is None:
        query = {
   
   }

    # MongoDB 连接 URI
    client = MongoClient(mongo_client_url)
    try:
        # 连接数据库和集合
        db = client[database]
        col = db[collection]
        # 执行查询并打印查询语句
        results = list(col.find(query))
        # 将 ObjectId 转换为字符串以便序列化
        for result in results:
            if '_id' in result:
                result['_id'] = str(result['_id'])
        return results
    except Exception as e:
        logging.error(f"Error querying database: {
     
     e}")
        return []
    finally:
        client.close()


# 新建构建
@mcp.tool()
def runBuild(appId: int, branch: str) -> dict:
    """
    根据 appId 和 branch 查询 commit 信息,提取 shortId 并触发构建任务。
    参数:
        appId (int): 应用 ID
        branch (str): 分支名称
    返回:
        dict: 包含构建结果或错误信息
    """
    # Step 1: 查询 commit 接口获取 shortId
    commits_url = f"{
     
     api_url_base}/api/v1/apps/{
     
     appId}/commits"
    headers = {
   
   
        "Cookie": devops_cookie
    }
    params = {
   
   
        "current": 1,
        "pageSize": 10,
        "branch": branch
    }

    try:
        logging.info(f"Fetching commit info from {
     
     commits_url} with branch={
     
     branch}")
        response = requests.get(commits_url, headers=headers, params=params)
        response.raise_for_status()
        data = response.json()

        if not data.get("list"):
            return {
   
   "error": "No commits found for the given appId and branch"}

        first_commit = data["list"][0]
        short_id = first_commit.get("shortId")

        if not short_id:
            return {
   
   "error": "shortId not found in the first commit record"}

        logging.info(f"Found shortId: {
     
     short_id}")

    except requests.RequestException as e:
        logging.error(f"Failed to fetch commit info: {
     
     e}")
        return {
   
   "error": str(e)}

    # Step 2: 调用构建接口
    build_url = f"{
     
     api_url_base}/api/v1/apps/{
     
     appId}/builds"
    build_payload = {
   
   
        "appId": appId,
        "branch": branch,
        "commit": short_id,
        "buildFile": "build.sh",
        "isPackage": "full",
        "isSonar": "no",
        "gitBranch": branch,
        "gitCommit": short_id
    }

    try:
        logging.info(f"Triggering build at {
     
     build_url}")
        build_response = requests.post(build_url, headers=headers, json
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值