mcpField
M
Modal MCP

Modal MCP

本地服务
github.com/george-bobby云与基础设施47 周前更新

关于 Modal MCP

Modal MCP 是通过本地 Modal CLI 管理 Modal 应用、容器、卷和密钥的 MCP 服务,也可部署和运行应用。适用于希望从 Claude Code 等 MCP 客户端操作 Modal 的开发者。

主要功能

  1. 01查看资源与应用历史
  2. 02获取和搜索应用日志
  3. 03部署应用并运行任务
  4. 04管理应用状态与回滚
  5. 05检查成本与密钥

适用场景

  1. 01排查应用日志中的错误
  2. 02部署可共享的应用端点
  3. 03运行一次性或分离任务

MCP 相关

向 MCP 客户端提供 12 种 Modal 管理工具。工具通过本地 `modal` CLI 执行,并使用本机配置的 Modal 配置文件和凭据。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"modal": {
"command": "uvx",
"args": [
"mcp-modal"
]
}
}
}
启动命令uvx mcp-modal

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypimcp-modal0.5.0

工具

12

收录的工具列表 · 更新于 2 周前

参数类型必填说明
envany否
actionstring是
versionany否
app_identifierstring是

详细介绍

MCP Modal 服务

mcp-modal MCP server

PyPI

一个用于管理 Modal 的 MCP 服务,涵盖应用、容器、卷和密钥;还可直接从 Claude Code 和其他 MCP 客户端部署和运行 Modal 应用。

每个工具都会调用本地的 modal CLI,因此会使用你机器上配置的 Modal 配置文件和凭据。无需管理额外令牌。

安装

此服务已作为 mcp-modal 发布到 PyPI。无需手动安装——推荐使用 uvx 运行,它会按需获取并启动服务。只需将 MCP 客户端指向以下命令即可(请参阅配置)。

每个版本也会打上标签并发布到 Releases 页面,附带发行说明以及 PyPI 上相同的 .whl / .tar.gz 文件,可用于固定版本、在隔离网络环境中 安装,或查看两个版本之间的更改。

登录 Modal

此服务使用你的本地 Modal 凭据。如果你还没有完成身份验证,请运行:

modal setup

这会打开浏览器供你登录,并将令牌存储在 ~/.modal.toml 中。如果你已在其他地方登录,可运行 modal profile current 检查。

配置

使用 claude mcp CLI 将服务添加到 Claude Code:

claude mcp add mcp-modal -- uvx mcp-modal@latest

或者将其添加到项目根目录下的 .mcp.json 文件中。这是更适合团队的方式 ——任何打开此仓库的人都会使用相同的配置:

{
  "mcpServers": {
    "mcp-modal": {
      "command": "uvx",
      "args": ["mcp-modal@latest"]
    }
  }
}
为什么使用 @latest,以及何时固定版本

uvx 会缓存首次运行时构建的环境,之后不会再次检查 PyPI:

“uvx 会在首次调用时使用所请求工具的最新可用版本。 此后,除非指定其他版本、清理缓存或刷新缓存,否则 uvx 会使用缓存的工具版本。” — uv 文档

因此,直接运行 uvx mcp-modal 意味着安装时使用最新版本,此后永远固定不变——重启 客户端或重启电脑都不会改变版本,因为缓存保存在磁盘上。不同的人可能会因为首次运行时间不同而使用不同版本,而且不会收到任何提示。

  • mcp-modal@latest 会在每次启动时重新解析版本,因此重启后即可获取新版本。 代价是启动时需要进行一次网络往返。工具功能仍在频繁变动时请使用此方式。
  • [email protected](指定具体版本)可确保运行结果可复现,升级也会变成 有意为之的单行更改。需要稳定性或面向更多用户时请使用此方式。

对于已经被旧缓存版本困住的机器,只需切换为上述任一种形式即可——请求指定版本会使缓存失效。否则,运行 uv cache clean mcp-modal 可强制刷新缓存。

要求

  • Python 3.11 或更高版本
  • uv(提供 uvx)
  • Modal CLI 1.5 或更高版本,并已配置有效凭据(modal setup)——1.5 引入了 modal billing summary/rates,并将账单报告切换为 snake_case 列名;费用工具可读取两种写法,但这两个视图需要 1.5 版本
  • 如需支持 Modal deploy 和 run:
    • 要部署/运行的项目必须使用 uv 管理依赖
    • 必须在该项目的虚拟环境中安装 modal

安全

此服务会使用 ~/.modal.toml 中的凭据调用本地 modal CLI。一些工具本身具有强大的能力——如果驱动此服务的 MCP 客户端遭到提示词注入(例如,通过其获取的日志中的恶意文本),以下路径可能导致权限提升,因此应保留在客户端的工具审批提示之后,而非自动批准:

  • deploy_modal_app / run_modal_app — 在主机上执行任意本地 Python(modal deploy 会导入应用文件;uv run 会解析并安装目标项目的依赖项)。
  • modal_volume_files,且 action="put" — 可读取任意本地文件(例如 ~/.ssh/id_rsa、~/.modal.toml),并将其上传到云卷(可用于数据外传)。
  • modal_volume_files,且 action="get" 和 force=True — 可覆盖任意本地路径(例如 ~/.zshrc 或 shell 配置文件,可用于持久化)。
  • manage_modal_container,且 action="exec" — 按设计会在容器内运行任意命令。

每个工具都声明了 MCP 工具注解,因此客户端可以区分 4 个只读工具(list_modal_resources、get_modal_logs、search_modal_logs、analyze_modal_costs——它们的 readOnlyHint: true)与会更改远程状态或启动计算的 8 个工具。其中 6 个标记为 destructiveHint: true;例外是 run_modal_app 和 inspect_modal_secret,它们会启动计算,但不会删除或覆盖任何内容。读取操作可自动批准;其余操作应保留在审批提示之后。

可选的本地路径允许列表

为限制两个会操作文件系统的卷工具,请将 MCP_MODAL_ALLOWED_LOCAL_PATHS 环境变量设为以 os.pathsep 分隔的目录列表(macOS/Linux 上为 :)。设置后,除非解析路径(展开 ~ 并折叠 .. 和符号链接后)位于其中某个根目录内,否则 modal_volume_files 会拒绝操作任何本地路径——action="put" 时的 local_path,以及 action="get" 时的目标路径。下载目标 "-"(返回内容而不是写入文件)不受此限制,因为不会向磁盘写入内容。

未设置此变量时(默认情况),不设任何限制,因此现有配置不受影响。请在 MCP 客户端中配置,例如:

{
  "mcpServers": {
    "mcp-modal": {
      "command": "uvx",
      "args": ["mcp-modal"],
      "env": { "MCP_MODAL_ALLOWED_LOCAL_PATHS": "/Users/me/modal-workspace:/tmp/modal" }
    }
  }
}

所有工具还会在 -- 选项结束分隔符之后传递用户提供的名称/路径,因此以 - 开头的值始终会被视为数据,而不是 modal CLI 标志。传递给 manage_modal_secret 的密钥值会从回显的命令、日志和任何错误输出中删除。

支持的工具

共 12 个工具。相关操作通过 action/resource 参数分组,而不是按 CLI 子命令拆分为每个子命令一个工具:每个工具的架构在整个会话期间都会加载到模型的上下文中,因此较小的工具集合能为实际工作留出更多空间(也能减少模型需要选择的近似工具)。

用于操作环境范围资源的工具可以接收可选的 env 参数,以指定目标 Modal 环境;若省略,则使用配置文件的默认环境(或 MODAL_ENVIRONMENT)。例外是 manage_modal_container 和容器日志——容器 ID 全局唯一,且 CLI 不接受环境参数。

只读
  1. 列出 Modal 资源(list_modal_resources)——一次查询即可获取整个账户的信息。

    • 参数:resource(必填)、name、path(默认为 /)、env
    • resource 的取值:
      value返回内容name 表示
      apps已部署、正在运行或最近停止的应用—
      app_history某个应用的部署版本(用于回滚)应用名称/ID
      containers正在运行的容器(ta-...)用于筛选的应用 ID
      volumes命名卷—
      volume_files卷中的文件(使用 path)卷名称
      secrets密钥名称(不会公开密钥值)—
      environments此工作区有效的 env 取值—
      profile当前配置及所有配置—
    • 如果 volume_files 确实没有列出任何内容,则会设置 empty: true 并附上说明,以便区分空目录和错误路径。
    • 列表超过 200 项时会截断,并通过 omitted_items 给出省略的项目数。
  2. 获取 Modal 日志(get_modal_logs)——获取或流式传输应用或容器的日志。

    • 参数:identifier(必填)、target(auto/app/container,默认为 auto——以 ta- 开头的标识符均视为容器)、timeout_seconds(默认为 30)、 env、since、until、tail、source(stdout/stderr/system)、timestamps、 follow
    • 不带 tail 的 since 会获取时间范围内的所有条目;同时传入 until 可限制日志量(最大 范围为 35 天,tail 上限为 20,000),避免繁忙应用的输出过多。
    • 设置 follow=True 后,日志会持续流式传输,直到应用/容器停止或达到 timeout_seconds,然后返回包含 truncated: true 的快照。
    • 此工具仅涵盖 stdout/stderr/system 流;某些故障(例如报告为 “... exited with ...” 的崩溃)属于 Modal 控制面板事件,不是日志行,因此不会显示在此处。
  3. 搜索 Modal 日志(search_modal_logs)——搜索日志,并获取每个命中项及其周围的日志行,专为“问题出在哪里?”这类调试场景设计。日志只获取一次,然后在本地搜索,因此可以提供上下文、正则表达式、大小写控制和精确的匹配数。

    • 参数:identifier(必填)、pattern(必填)、target(默认为 auto)、 regex、case_sensitive、context_lines(默认为 3)、max_matches(默认为 50)、 since、until、tail(默认为最近 1000 条)、source、 exclude(搜索前排除噪声行,例如 "queue put failed")、 prefilter、timestamps(默认为 true)、timeout_seconds、env
    • 繁忙应用请限制时间窗口。 单独使用 since 会获取从该时间点到现在的所有日志——对于日志频繁的应用,每小时可能有数百 KB;30 秒的获取限制会导致日志被截断(logs_truncated: true),输出也会受到预算限制。解决方法是同时设置 since 和 until,将时间范围限定在你关注的那一分钟,通常只需几 KB。
    • 设置 prefilter=True 会将 pattern 作为服务端子字符串筛选条件传给 Modal(modal app logs --search),因此不会获取不匹配的行——这是处理日志量大到无法完整拉取时的有效方法。此功能要求 regex=False,此时上下文行也只会显示其他匹配项,因此可先用它定位时间窗口,再通过 prefilter=False 重新查询该窗口。
    • 返回 match_count 和 matches:带时间戳、行号的上下文块,匹配行前缀为 >,例如 > 8: 2026-06-04T... ValueError: bad input。始终会搜索获取到的全部日志,因此即使返回的上下文块较少,match_count 仍然精确。returned 表示返回的匹配项数量(相邻匹配项会合并为一个块,并由 returned_blocks 统计)。使用 exclude 时会报告 excluded_lines。
    • 如果 CLI 拒绝某个时间窗口(时间范围颠倒、超过 35 天或 tail 超过 20,000),工具会返回 success: false 和 Modal 提供的错误信息,而不是单独的退出码。
    • 与 get_modal_logs 一样,此工具仅涵盖 stdout/stderr/system 流。
部署与运行
  1. 部署 Modal 应用(deploy_modal_app)

    • 部署 Modal 应用(modal deploy)。已部署的 Web 端点会持续有效,因此输出中的链接均可访问并可分享(通过 urls 返回)。
    • 参数:absolute_path_to_app(必需)、env、name、tag、 strategy(rolling/recreate)、stream_logs
    • 应用目录必须使用 uv,并在其虚拟环境中安装 modal。
  2. 运行 Modal 应用(run_modal_app)

    • 一次性运行函数或本地入口点并收集其输出(modal run)。
    • 参数:absolute_path_to_app(必需)、function_name、env、detach、 timeout_seconds(默认值为 120)
    • 如果运行在超时时仍未结束,则返回包含 truncated: true 的快照。 传入 detach=True,即可让长时间运行的任务在 Modal 上超时后继续运行。

为什么没有 modal serve 工具? modal serve 只会在阻塞进程运行期间保持其端点有效——返回结果的 MCP 工具会立即终止该进程,从而拆除端点,返回一个失效的 URL。请使用 deploy_modal_app 来创建持久且可分享的端点。

状态变更
  1. 管理 Modal 应用(manage_modal_app)——action 可设为 stop(关闭应用并终止其容器)或 rollback(重新部署先前版本)。

    • 参数:action(必需)、app_identifier(必需)、version(仅用于回滚——默认为紧邻的上一版本)、env
  2. 管理 Modal 容器(manage_modal_container)——action 可设为 exec(在运行中的容器内运行命令,使用 modal container exec --no-pty)或 stop(终止容器)。

    • 参数:action(必需)、container_id(必需)、command(仅用于 exec——参数列表,例如 ["python", "-c", "print('hi')"])、timeout_seconds(默认值为 60)
  3. 管理 Modal 卷(manage_modal_volume)——action 可设为 create、delete(删除卷及其所有数据,不可撤销)或 rename。

    • 参数:action(必需)、volume_name(必需)、new_name(仅用于重命名)、env
  4. Modal 卷文件(modal_volume_files)——对卷内文件执行写入操作: action 可设为 put(上传)、get(下载)、cp(在卷内复制)或 rm。

    • 参数:action(必需)、volume_name(必需)、local_path、remote_path、 paths(用于 cp:源路径在前,目标路径在后)、recursive、force、env
    • action="get" 且 local_path="-" 时,会返回文件内容而不是写入文件。
    • 如需列出卷的内容,请使用 list_modal_resources(resource="volume_files")。
  5. 管理 Modal 密钥(manage_modal_secret)——action 可设为 create 或 delete。

    • 参数:action(必需)、secret_name(必需)、key_values(字典)、 from_dotenv(路径)、from_json(路径)、force、env。创建时必须至少提供 key_values、from_dotenv 或 from_json 中的一项。
    • 返回的所有字段(包括错误输出)都会对密钥值进行脱敏。
    • 如需列出密钥名称,请使用 list_modal_resources(resource="secrets")。
成本
  1. 分析 Modal 成本(analyze_modal_costs)——只读。只获取一次 modal billing,然后在本地汇总,让你看到按金额排序的总额和 环比变化,而不是数百条原始记录。
    • 参数:view(默认 by_app)、period、start、end、resolution (d/h)、timezone、app、environment、top_n(默认 10)、tag_names
    • view 的取值:
      取值可回答的问题
      by_app“哪个应用的成本最高?”——按支出对应用排序,并显示占比
      timeline“为什么周一这么贵?”——显示每个时间区间的成本,以及一个 explanation,用于对比峰值区间和前一个区间,并列出增长最多的应用
      by_environment资金流向了哪个环境
      by_resourceCPU、GPU 类别、内存和存储的费用
      summary月度周期的计费成本与计量成本,以及抵扣额/套餐调整
      rates当前单价
    • total_cost 始终涵盖范围内的所有记录,即使 groups 被截断为 top_n 条也是如此——请直接引用该值,不要累加可见记录。
    • 计费范围是整个工作区(CLI 不接受 -e),因此此处报告的是所有 环境的费用;environment 会在之后筛选记录。
    • Modal 只报告完整时间区间,所以未结束当天的费用会显得较低。
Secret——检查
  1. 检查 Modal Secret(inspect_modal_secret)——列出 secret 中的键名, 绝不显示键值。
    • 参数:secret_name(必填)、env、image、timeout_seconds(默认 300)
    • Modal 有意不提供用于此操作的 API:CLI、SDK 和 gRPC 层都不行。查看 secret 定义了哪些键的唯一方法,是将其挂载到容器中 并列出环境变量。因此,此工具会运行 modal shell --secret <name>,并使用 compgen -e(bash 内置命令,只打印导出的变量名称——即使在容器内部也 绝不会打印任何值),然后减去镜像和 Modal 运行时本身设置的变量——23 个已知 名称,以及六个前缀(MODAL_、PYTHON、PIP_、NVIDIA_、 CUDA_、LD_LIBRARY_PATH)下的所有变量;这也涵盖了每个容器中都有的 MODAL_TOKEN_* 凭据。
    • 此调用会启动远程计算,因此会花费几美分并耗时数十秒(需要构建镜像时 会更久)。此服务中的其他读取操作都免费;使用 list_modal_resources(resource="secrets") 查看有哪些 secret,仅在需要了解 某个 secret 内部内容时才使用此工具。
    • 返回 keys,以及未经筛选的 all_env_names,这样看起来像运行时变量的键 也会显示出来,而不会被悄悄剔除。
    • 省略 image 可使用 Modal 默认镜像(构建时会与服务的 Python 版本匹配,是 最可靠的选择)。如果工作区的镜像构建器不接受该 Python 版本,可以传入镜像, 例如 python:3.12-slim。

提示词

该服务还提供四个 MCP 提示词——客户端可直接调用的多步骤工作流(在 Claude Code 中,它们显示为 /mcp__mcp-modal__<name>)。提示词按需获取,因此与工具不同,不会占用每个会话的上下文:

  • debug_modal_app(app_name,可选 symptom)——按顺序执行的排查流程:检查应用是否正常运行,在日志中搜索包含上下文的回溯信息;如果获取的日志被截断,则缩小时间窗口,而不是扩大窗口;改为查看日志末尾;检查同一时间窗口内是否有相关应用受到影响;检查容器;然后对照部署历史并考虑回滚。
  • deploy_and_verify(absolute_path_to_app,可选 env)——确认目标工作区,执行部署,报告线上 URL,然后验证应用是否正常运行,而不是想当然地认为它正常。
  • review_modal_account(可选 env)——只读清单,会标记空闲应用、原因不明的运行中容器以及孤立的卷/密钥,并指出清理各项所需的具体调用,但不会执行这些调用。
  • investigate_modal_costs(可选 period、app)——从每日时间线一路追查支出增长,直到峰值时段、资源类别,以及导致支出的部署或仍在运行的容器。

输出上限

日志、运行和执行输出在返回前都会受到长度限制,因此某个输出量大的应用不会占满你的上下文窗口。默认上限为每个文本字段 40,000 个字符(约 10k 个 token);字段被截断时,结果会设置 output_capped: true,文本中也会标明丢弃了多少内容。截断后的字段会保留开头和结尾,因此启动横幅和末尾的回溯信息都能保留下来。

搜索结果事先不会被截断:search_modal_logs 会在整个已获取的日志中进行 grep,只限制返回的上下文块数量,因此 match_count 始终准确。

对于被截断的日志搜索,提高 timeout_seconds 或输出上限很少是正确的做法——减少获取量才是。使用 since 和 until 限定时间窗口,使用 source/exclude 进行筛选,或设置 prefilter=True,以便在 Modal 内丢弃不匹配的行。

设置 MCP_MODAL_MAX_OUTPUT_CHARS 可提高或降低输出上限,设置为 0 则可完全禁用限制:

{
  "mcpServers": {
    "mcp-modal": {
      "command": "uvx",
      "args": ["mcp-modal"],
      "env": { "MCP_MODAL_MAX_OUTPUT_CHARS": "80000" }
    }
  }
}

响应格式

所有工具都以标准化格式返回响应,具体格式会根据操作类型略有不同:

# Lookups (list_modal_resources):
{
    "success": True,
    "apps": [...],          # or "containers", "volumes", "contents", "secrets", ...
    "omitted_items": 0      # present when the listing was capped at 200 entries
}

# Action operations (deploy, stop, rollback, create, delete, rename, cp, put, get, rm):
{
    "success": True,
    "message": "Operation successful message",
    "command": "executed command string",
    "stdout": "command output",  # if any
    "stderr": "error output"     # if any
}

# Log / run / exec operations (snapshot-based):
{
    "success": True,
    "logs": "...",          # or "output" for run/exec
    "truncated": False,     # True when cut off at timeout_seconds
    "output_capped": False, # True when text was trimmed to fit MCP_MODAL_MAX_OUTPUT_CHARS
    "command": "executed command string"
}

# Log search (search_modal_logs):
{
    "success": True,
    "match_count": 12,      # exact: the whole fetched log is searched
    "returned": 5,          # matches actually shown
    "returned_blocks": 2,   # adjacent matches merge into one context block
    "matches": ["> 8: ...", ...],
    "logs_truncated": False,  # True when the log fetch hit timeout_seconds
    "output_capped": False,
    "command": "executed command string"
}

# Error case (all operations):
{
    "success": False,
    "error": "Error message describing what went wrong",
    "command": "executed command string",
    "stdout": "command output",  # if available
    "stderr": "error output"     # if available
}

许可证

本项目采用 MIT 许可证授权,详情请参阅 LICENSE 文件。

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。