跳转到内容

MCP 运行 Python

MCP Run Python 包是一个 MCP 服务器,允许智能体在安全的沙盒环境中执行 Python 代码。它使用 Pyodide 在带有 Deno 的 JavaScript 环境中运行 Python 代码,将执行与主机系统隔离。

特性

  • 安全执行:在沙盒化的 WebAssembly 环境中运行 Python 代码
  • 包管理:自动检测并安装所需的依赖项
  • 完整结果:捕获标准输出、标准错误和返回值
  • 异步支持:正确运行异步代码
  • 错误处理:提供详细的错误报告以供调试

安装

从 npx 切换到 deno

我们之前将 mcp-run-python 作为 npm 包分发,以便通过 npx 使用。我们现在推荐使用 deno,因为它提供了更好的沙盒化和安全性。

MCP Run Python 服务器作为一个 JSR 包 分发,可以直接使用 deno run 运行。

终端
deno run \
  -N -R=node_modules -W=node_modules --node-modules-dir=auto \
  jsr:@pydantic/mcp-run-python [stdio|streamable_http|sse|warmup]

其中

  • -N -R=node_modules -W=node_modules (--allow-net --allow-read=node_modules --allow-write=node_modules 的别名) 允许网络访问以及对 ./node_modules 的读写权限。这些是必需的,以便 Pyodide 可以下载和缓存 Python 标准库和包。
  • --node-modules-dir=auto 告诉 deno 使用本地的 node_modules 目录
  • stdio 使用 Stdio MCP 传输协议 运行服务器 — 适合作为本地子进程运行
  • streamable_http 使用 Streamable HTTP MCP 传输协议 运行服务器 — 将服务器作为 HTTP 服务器运行,以便在本地或远程连接。这支持有状态的请求,但不需要客户端像 SSE 那样保持有状态的连接。
  • sse 使用 SSE MCP 传输协议 运行服务器 — 将服务器作为 HTTP 服务器运行,以便在本地或远程连接
  • warmup 将运行一个最小的 Python 脚本来下载和缓存 Python 标准库。这也用于检查服务器是否正常运行。

客户端文档中描述了如何将 jsr:@pydantic/mcp-run-python 与 Pydantic AI 一起使用。

直接使用

除了将此服务器与 Pydantic AI 一起使用外,它还可以连接到其他 MCP 客户端。为清楚起见,在此示例中,我们使用 Python MCP 客户端直接连接。

mcp_run_python.py
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client

code = """
import numpy
a = numpy.array([1, 2, 3])
print(a)
a
"""
server_params = StdioServerParameters(
    command='deno',
    args=[
        'run',
        '-N',
        '-R=node_modules',
        '-W=node_modules',
        '--node-modules-dir=auto',
        'jsr:@pydantic/mcp-run-python',
        'stdio',
    ],
)


async def main():
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            tools = await session.list_tools()
            print(len(tools.tools))
            #> 1
            print(repr(tools.tools[0].name))
            #> 'run_python_code'
            print(repr(tools.tools[0].inputSchema))
            """
            {'type': 'object', 'properties': {'python_code': {'type': 'string', 'description': 'Python code to run'}}, 'required': ['python_code'], 'additionalProperties': False, '$schema': 'https://json-schema.fullstack.org.cn/draft-07/schema#'}
            """
            result = await session.call_tool('run_python_code', {'python_code': code})
            print(result.content[0].text)
            """
            <status>success</status>
            <dependencies>["numpy"]</dependencies>
            <output>
            [1 2 3]
            </output>
            <return_value>
            [
              1,
              2,
              3
            ]
            </return_value>
            """

如果发生异常,status 将是 install-errorrun-error,并且 return_value 将被替换为 error,其中将包含回溯和异常消息。

依赖项

依赖项在代码运行时安装。

依赖项可以通过以下两种方式之一来定义

从导入中推断

如果没有元数据,依赖项会从代码中的导入语句中推断出来,如上文示例所示。

内联脚本元数据

如 PEP 723 中所引入,此处有解释,并由 uv 推广——依赖项可以在文件顶部的注释中定义。

这允许使用代码中未导入的依赖项,并且更加明确。

inline_script_metadata.py
from mcp import ClientSession
from mcp.client.stdio import stdio_client

# using `server_params` from the above example.
from mcp_run_python import server_params

code = """\
# /// script
# dependencies = ["pydantic", "email-validator"]
# ///
import pydantic

class Model(pydantic.BaseModel):
    email: pydantic.EmailStr

print(Model(email='hello@pydantic.dev'))
"""


async def main():
    async with stdio_client(server_params) as (read, write):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool('run_python_code', {'python_code': code})
            print(result.content[0].text)
            """
            <status>success</status>
            <dependencies>["pydantic","email-validator"]</dependencies>
            <output>
            email='hello@pydantic.dev'
            </output>
            """

它还允许为非二进制包固定版本(Pyodide 对其支持的二进制包,如 pydanticnumpy,只支持单一版本)。

例如,您可以将依赖项设置为

# /// script
# dependencies = ["rich<13"]
# ///

日志记录

MCP Run Python 支持将 Python 执行过程中的 stdout 和 stderr 作为 MCP 日志消息 发出。

要发出日志,您必须在连接到服务器时设置日志级别。默认情况下,日志级别设置为最高级别 emergency

目前,由于 Python MCP 客户端存在一个 bug,无法演示此功能,请参阅 modelcontextprotocol/python-sdk#201