构建MCP服务,配置到bisheng服务

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

一、导读

环境:kylin v10 sp1、Python 3.10 、bisheng 2.2.0

背景:希望实现一个镜像,通过挂载代码的方式实现扩展mcp工具

时间:20260106

说明:最终实现compose.yml配置实现多工具并行

二、功能实现

1、代码实现

        使用fastmcp实现stream流式工具样例

# tools/mcp_test.py

from fastmcp import FastMCP
from typing import Annotated
from pydantic import Field

mcp = FastMCP("数据类型验证")


@mcp.tool(
    name="greet",
    description="验证字符串功能"
)
def greet(name: Annotated[str, "需要打招呼的用户名字"]) -> str:
    # 字符串验证
    return f"Hello, {name}!"


@mcp.tool(
    name="add",
    description="整数验证"
)
def add(
    a: Annotated[int, Field(default=3, description="数字1", ge=1, le=20)],
    b: Annotated[int, Field(default=2, description="数字2", ge=1, le=20)],
) -> int:
    # 标注mcp中默认值、参数描述、参数控制说明
    return a + b


@mcp.tool(
    name="subtract",
    description="字典、整数验证",
)
def subtract(a: dict, b: int) -> dict:
    a.update({"subtract": b})
    return a


@mcp.tool(
    name="multiply",
    description="集合、布尔值验证",
)
def multiply(a: set, b: bool) -> str:
    a.add(b)
    return str(a)


@mcp.tool(
    name="divide",
    description="列表、浮点数验证",
)
def divide(a: list, b: float) -> str:
    a.append(b)
    return str(a)


if __name__ == "__main__":
    mcp.run(
        transport="http",
        host="0.0.0.0",
        port=8001,
        log_level="DEBUG",
    )

2、脚本执行

python mcp_test.py

3、bisheng测试

 我在本地搭建了bisheng的项目,网络本身是互通的。
        

        正常情况,MCP服务配置后,点击刷新,可出现下列工具

三、构建镜像

1、拉取镜像

docker pull docker.1ms.run/library/python:3.10-slim

2、编辑Dockerfile文件

利用dockerfile构建新的镜像

# Dockerfile

# 使用指定基础镜像
FROM docker.1ms.run/library/python:3.10-slim

# 设置时区和编码(可选但推荐)
ENV TZ=Asia/Shanghai \
    LANG=C.UTF-8 \
    LC_ALL=C.UTF-8

# 配置 pip 使用阿里云镜像源(构建时生效)
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && \
    pip config set install.trusted-host mirrors.aliyun.com

# 安装依赖(此时需有网络)
RUN pip install --no-cache-dir --disable-pip-version-check fastmcp==2.14.2

# 清理 pip 缓存(减小镜像体积)
RUN rm -rf /root/.cache

# 设置工作目录
WORKDIR /app

# 复制mcp的工具文件
COPY tools/ tools/

EXPOSE 8000

# 默认启动命令可留空,由 compose 覆盖
CMD ["python", "tools/mcp_test.py"]

3、目录结构

[xxxxxxxxxxx ~]$tree fastmcp-offline-image/
fastmcp-offline-image/
├── Dockerfile                # dockerfile文件
└── tools                     # 所有的工具种类目录
    └── mcp_test.py           # 某一个测试工具

1 directory, 2 files

4、构建镜像

docker build -t py_mcp_tools:v0.0.1 .

其中,py_mcp_tools为镜像名称,v0.0.1为标签


5、查询是否构建成功

查询如下即成功了

[xxxxxx ~]$docker images | grep py_m
py_mcp_tools                 v0.0.1                           e77d3daa0e9a   2 hours ago     214MB

6、运行测试

docker run -d --name mcp-test -p 8001:8001 py_mcp_tools:v0.0.1

查看日志

[xxxxxxxxx ~]$docker logs -f mcp-test


╭──────────────────────────────────────────────────────────────────────────────╮
│                                                                              │
│                                                                              │
│                         ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█                        │
│                         █▀  █▀█ ▄▄█  █  █ ▀ █ █▄▄ █▀▀                        │
│                                                                              │
│                                                                              │
│                                FastMCP 2.14.2                                │
│                            https://gofastmcp.com                             │
│                                                                              │
│                    🖥  Server:      数据类型验证                              │
│                    🚀 Deploy free: https://fastmcp.cloud                     │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────╮
│                          ✨ FastMCP 3.0 is coming!                           │
│         Pin fastmcp<3 in production, then upgrade when you're ready.         │
╰──────────────────────────────────────────────────────────────────────────────╯


[01/06/26 13:42:43] INFO     Starting MCP server '数据类型验证'   server.py:2582
                             with transport 'http' on                           
                             http://0.0.0.0:8000/mcp                            
INFO:     Started server process [1]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8001 (Press CTRL+C to quit)

7、bisheng添加测试

日志变化

​​[xxxxxxx ~]$docker logs -f mcp-test


╭──────────────────────────────────────────────────────────────────────────────╮
│                                                                              │
│                                                                              │
│                         ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█                        │
│                         █▀  █▀█ ▄▄█  █  █ ▀ █ █▄▄ █▀▀                        │
│                                                                              │
│                                                                              │
│                                FastMCP 2.14.2                                │
│                            https://gofastmcp.com                             │
│                                                                              │
│                    🖥  Server:      数据类型验证                              │
│                    🚀 Deploy free: https://fastmcp.cloud                     │
│                                                                              │
╰──────────────────────────────────────────────────────────────────────────────╯
╭──────────────────────────────────────────────────────────────────────────────╮
│                          ✨ FastMCP 3.0 is coming!                           │
│         Pin fastmcp<3 in production, then upgrade when you're ready.         │
╰──────────────────────────────────────────────────────────────────────────────╯


[01/06/26 13:42:43] INFO     Starting MCP server '数据类型验证'   server.py:2582
                             with transport 'http' on                           
                             http://0.0.0.0:8000/mcp                            
INFO:     Started server process [1]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
INFO:     10.62.79.13:58838 - "POST /mcp HTTP/1.1" 200 OK
INFO:     10.62.79.13:58864 - "GET /mcp HTTP/1.1" 200 OK
INFO:     10.62.79.13:58852 - "POST /mcp HTTP/1.1" 202 Accepted
INFO:     10.62.79.13:58874 - "POST /mcp HTTP/1.1" 200 OK

四、compose配置多工具


再配置一个MySQL工具,占用8002端口,实现docker compose启动多个工具

1、MySQL工具集

# tools/mcp_mysql.py

import pymysql
from fastmcp import FastMCP
from typing import Dict, List, Any, Optional

# 创建 FastMCP 实例
mcp = FastMCP("MySQL Management Tool")

# 数据库连接配置 (这些是默认值,实际连接时会使用用户提供的参数)
DB_CONFIG = {
    'host': 'localhost',
    'port': 3306,
    'user': 'your_username',
    'password': 'your_password',
    'database': 'your_database',
    'charset': 'utf8mb4',  # 推荐使用 utf8mb4 支持完整的 UTF-8
}


@mcp.tool(
    name="test_connection",
    description="测试与 MySQL 数据库的连接。需要提供主机、端口、用户名和密码。"
)
def test_connection(host: str, port: int, username: str, password: str, database: Optional[str] = None) -> Dict[str, Any]:
    """
    测试数据库连接。
    """
    try:
        config = {
            'host': host,
            'port': port,
            'user': username,
            'password': password,
            'charset': 'utf8mb4',
        }
        # 如果提供了数据库名,则加入配置,用于测试连接到特定数据库
        if database:
            config['database'] = database

        connection = pymysql.connect(**config)
        connection.close()
        return {
            "status": "success",
            "message": f"连接到数据库 {host}:{port} (database: {database or 'not specified'}) 成功!"
        }
    except Exception as e:
        return {
            "status": "error",
            "message": f"连接失败: {str(e)}"
        }


@mcp.tool(
    name="list_tables",
    description="查询当前数据库下的所有表名。"
)
def list_tables(host: str, port: int, username: str, password: str, database: str) -> Dict[str, Any]:
    """
    查询数据库中的所有表。
    """
    try:
        config = {**DB_CONFIG, 'host': host, 'port': port,
                  'user': username, 'password': password, 'database': database}
        connection = pymysql.connect(**config)
        cursor = connection.cursor()

        cursor.execute("SHOW TABLES;")
        tables = [row[0]
                  for row in cursor.fetchall()]  # row[0] 因为SHOW TABLES返回单列

        cursor.close()
        connection.close()

        return {
            "status": "success",
            "database": database,
            "tables": tables
        }
    except Exception as e:
        return {
            "status": "error",
            "message": f"查询表列表失败: {str(e)}"
        }


@mcp.tool(
    name="describe_table",
    description="查询指定表的结构(列信息)。"
)
def describe_table(host: str, port: int, username: str, password: str, database: str, table_name: str) -> Dict[str, Any]:
    """
    查询表结构。
    """
    try:
        config = {**DB_CONFIG, 'host': host, 'port': port,
                  'user': username, 'password': password, 'database': database}
        connection = pymysql.connect(**config)
        cursor = connection.cursor()

        # 使用 DESCRIBE 语句获取表结构
        cursor.execute(f"DESCRIBE `{table_name}`;")
        # 或者使用 SHOW COLUMNS 语句,结果类似
        # cursor.execute(f"SHOW COLUMNS FROM `{table_name}`;")
        columns_info = cursor.fetchall()

        # 将结果转换为更易读的字典列表格式
        column_descriptions = []
        for col in columns_info:
            # DESCRIBE 返回的每一行是一个元组 (Field, Type, Null, Key, Default, Extra)
            column_descriptions.append({
                "Field": col[0],
                "Type": col[1],
                "Null": col[2],
                "Key": col[3],
                "Default": col[4],
                "Extra": col[5]
            })

        cursor.close()
        connection.close()

        return {
            "status": "success",
            "database": database,
            "table": table_name,
            "structure": column_descriptions
        }
    except Exception as e:
        return {
            "status": "error",
            "message": f"查询表 {table_name} 结构失败: {str(e)}"
        }


@mcp.tool(
    name="fetch_all_data",
    description="查询指定表的所有数据。"
)
def fetch_all_data(host: str, port: int, username: str, password: str, database: str, table_name: str) -> Dict[str, Any]:
    """
    查询表的所有数据。
    """
    try:
        config = {**DB_CONFIG, 'host': host, 'port': port,
                  'user': username, 'password': password, 'database': database}
        connection = pymysql.connect(**config)
        cursor = connection.cursor(
            pymysql.cursors.DictCursor)  # 使用字典游标,返回结果为字典格式

        # 构建并执行查询语句
        query = f"SELECT * FROM `{table_name}`;"
        cursor.execute(query)
        rows = cursor.fetchall()

        cursor.close()
        connection.close()

        return {
            "status": "success",
            "database": database,
            "table": table_name,
            "data": rows
        }
    except Exception as e:
        return {
            "status": "error",
            "message": f"查询表 {table_name} 数据失败: {str(e)}"
        }


@mcp.tool(
    name="show_user_privileges",
    description="查看当前登录用户的权限。"
)
def show_user_privileges(host: str, port: int, username: str, password: str, database: str) -> Dict[str, Any]:
    """
    查看用户权限。
    """
    try:
        config = {**DB_CONFIG, 'host': host, 'port': port,
                  'user': username, 'password': password, 'database': database}
        connection = pymysql.connect(**config)
        cursor = connection.cursor()

        # 执行 SHOW GRANTS 语句
        cursor.execute("SHOW GRANTS;")
        grants = [row[0]
                  for row in cursor.fetchall()]  # row[0] 因为SHOW GRANTS返回单列

        cursor.close()
        connection.close()

        return {
            "status": "success",
            "user": username,
            "grants": grants
        }
    except Exception as e:
        return {
            "status": "error",
            "message": f"查询用户 {username} 权限失败: {str(e)}"
        }


if __name__ == "__main__":
    mcp.run(
        transport="http",
        host="0.0.0.0",  # 绑定到所有网络接口
        port=8002,       # 指定端口
        log_level="INFO",  # 设置日志级别
    )

该代码已测试,此处不再复现。可按照第一个进行复测

2、构建新镜像

dockerfile内容需要增加安装pymysql的内容,如下:

# Dockerfile

# 安装依赖(此时需有网络)
RUN pip install --no-cache-dir --disable-pip-version-check fastmcp==2.14.2 pymysql==1.1.2

按照上述构建镜像的方法构建新镜像,命令如下:

docker build -t py_mcp_tools:v0.0.2 .

3、构建compose文件

通过在compose中实现两个(多个)服务,同时启动

# compose.yml

version: '3.10'

x-service-template: &service-template
  image: 10.64.7.121:30085/agentops/py_mcp_tools:v0.0.3
  volumes:
    - ./tools:/app/tools
  working_dir: /app/tools
  restart: unless-stopped

services:

  mcp-test:
    <<: *service-template
    container_name: mcp-test
    command: python mcp_test.py
    ports:
      - "8001:8001"

  mcp-mysql:
    <<: *service-template
    container_name: mcp-mysql
    command: python mcp_mysql.py
    ports:
      - "8002:8002"

4、目录结构

[xxxxxxxxxx fastmcp-offline-image]$tree
.
├── compose.yml
├── Dockerfile
├── readme.md
└── tools
    ├── mcp_mysql.py
    └── mcp_test.py

1 directory, 5 files

5、启动

在dockerfile同级目录下执行:

[xxxxxxxx fastmcp-offline-image]$docker-compose up -d

6、日志查看

[xxxxxxx fastmcp-offline-image]$docker-compose logs -f
mcp-mysql  | 
mcp-mysql  | 
mcp-mysql  | ╭──────────────────────────────────────────────────────────────────────────────╮
mcp-mysql  | │                                                                              │
mcp-mysql  | │                                                                              │
mcp-mysql  | │                         ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█                        │
mcp-mysql  | │                         █▀  █▀█ ▄▄█  █  █ ▀ █ █▄▄ █▀▀                        │
mcp-mysql  | │                                                                              │
mcp-mysql  | │                                                                              │
mcp-mysql  | │                                FastMCP 2.14.2                                │
mcp-mysql  | │                            https://gofastmcp.com                             │
mcp-mysql  | │                                                                              │
mcp-test   | 
mcp-test   | 
mcp-mysql  | │                    🖥  Server:      MySQL Management Tool                     │
mcp-mysql  | │                    🚀 Deploy free: https://fastmcp.cloud                     │
mcp-test   | ╭──────────────────────────────────────────────────────────────────────────────╮
mcp-test   | │                                                                              │
mcp-test   | │                                                                              │
mcp-mysql  | │                                                                              │
mcp-test   | │                         ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█                        │
mcp-test   | │                         █▀  █▀█ ▄▄█  █  █ ▀ █ █▄▄ █▀▀                        │
mcp-test   | │                                                                              │
mcp-test   | │                                                                              │
mcp-test   | │                                FastMCP 2.14.2                                │
mcp-test   | │                            https://gofastmcp.com                             │
mcp-test   | │                                                                              │
mcp-mysql  | ╰──────────────────────────────────────────────────────────────────────────────╯
mcp-mysql  | ╭──────────────────────────────────────────────────────────────────────────────╮
mcp-mysql  | │                          ✨ FastMCP 3.0 is coming!                           │
mcp-mysql  | │         Pin fastmcp<3 in production, then upgrade when you're ready.         │
mcp-mysql  | ╰──────────────────────────────────────────────────────────────────────────────╯
mcp-mysql  | 
mcp-mysql  | 
mcp-mysql  | [01/07/26 15:51:41] INFO     Starting MCP server 'MySQL           server.py:2582
mcp-mysql  |                              Management Tool' with transport                    
mcp-mysql  |                              'http' on http://0.0.0.0:8002/mcp                  
mcp-mysql  | INFO:     Started server process [1]
mcp-mysql  | INFO:     Waiting for application startup.
mcp-mysql  | INFO:     Application startup complete.
mcp-test   | │                    🖥  Server:      数据类型验证                              │
mcp-test   | │                    🚀 Deploy free: https://fastmcp.cloud                     │
mcp-test   | │                                                                              │
mcp-test   | ╰──────────────────────────────────────────────────────────────────────────────╯
mcp-test   | ╭──────────────────────────────────────────────────────────────────────────────╮
mcp-test   | │                          ✨ FastMCP 3.0 is coming!                           │
mcp-test   | │         Pin fastmcp<3 in production, then upgrade when you're ready.         │
mcp-test   | ╰──────────────────────────────────────────────────────────────────────────────╯
mcp-test   | 
mcp-test   | 
mcp-test   | [01/07/26 15:51:41] INFO     Starting MCP server '数据类型验证'   server.py:2582
mcp-test   |                              with transport 'http' on                           
mcp-test   |                              http://0.0.0.0:8001/mcp                            
mcp-test   | INFO:     Started server process [1]
mcp-mysql  | INFO:     Uvicorn running on http://0.0.0.0:8002 (Press CTRL+C to quit)
mcp-mysql  | INFO:     10.62.79.13:33960 - "POST /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:33980 - "GET /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:33972 - "POST /mcp HTTP/1.1" 202 Accepted
mcp-mysql  | INFO:     10.62.79.13:33982 - "POST /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:33990 - "DELETE /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:41548 - "POST /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:41572 - "GET /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:41556 - "POST /mcp HTTP/1.1" 202 Accepted
mcp-mysql  | INFO:     10.62.79.13:41580 - "POST /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:41588 - "DELETE /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:51588 - "POST /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:51600 - "GET /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:51594 - "POST /mcp HTTP/1.1" 202 Accepted
mcp-mysql  | INFO:     10.62.79.13:51614 - "POST /mcp HTTP/1.1" 200 OK
mcp-mysql  | INFO:     10.62.79.13:51620 - "DELETE /mcp HTTP/1.1" 200 OK
mcp-test   | INFO:     Waiting for application startup.
mcp-test   | INFO:     Application startup complete.
mcp-test   | INFO:     Uvicorn running on http://0.0.0.0:8001 (Press CTRL+C to quit)
mcp-test   | INFO:     10.62.79.13:54932 - "POST /mcp HTTP/1.1" 200 OK
mcp-test   | INFO:     10.62.79.13:54956 - "GET /mcp HTTP/1.1" 200 OK
mcp-test   | INFO:     10.62.79.13:54942 - "POST /mcp HTTP/1.1" 202 Accepted
mcp-test   | INFO:     10.62.79.13:54962 - "POST /mcp HTTP/1.1" 200 OK
mcp-test   | [01/07/26 15:53:54] DEBUG    [数据类型验证] Handler called:       server.py:1155
mcp-test   |                              list_tools                                         
mcp-test   | INFO:     10.62.79.13:54972 - "DELETE /mcp HTTP/1.1" 200 OK
mcp-test   | INFO:     10.62.79.13:49088 - "POST /mcp HTTP/1.1" 200 OK
mcp-test   | INFO:     10.62.79.13:49114 - "GET /mcp HTTP/1.1" 200 OK
mcp-test   | INFO:     10.62.79.13:49102 - "POST /mcp HTTP/1.1" 202 Accepted

7、bisheng验证

OK,到此结束

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值