应用声明
当某个插件的 MCP 服务器作为桌面应用的前台时,它需要声明这是哪个应用,以及该服务器对它有何依赖。核心会在主机上评估该声明,并据此决定是否放行该服务器的工具,以及任何点名该应用的 skill。解析器只依赖标准库和 hermes_platform。
相关词汇定义位于 hermes_platform/declaration.py。一份声明是"数据加策略",从普通映射(已解码的 YAML、JSON、dict 字面量——解析器从不直接触碰文件)解析而来:
from hermes_platform import declaration
decl = declaration.parse_declaration(
"my-server",
raw_app={"linux": {"presence": "executable", "location": "/opt/my-app/server"}},
raw_requires={"app": True},
where="my-plugin/plugin.yaml", # 用于错误信息中的人类可读标签
)
declaration.register("my-server", decl)
register(server_name, decl) 以配置的服务器名,把一份声明存入进程内注册表。加载器集成是另一件事;核心不会自动读取插件 YAML。
未注册的 MCP 服务器保留其仅做连接检查的行为。显式点名未注册服务器的 skill 会被隐藏。clear() 会移除所有注册,它不是按插件卸载的操作。注册是进程级的,不按 profile 划分。
app — 如何在各操作系统上找到应用 {#app--how-to-find-the-application-on-each-os}
app:
win32:
presence: executable
location: "%ProgramFiles%/Vendor/Vendor App/McpServer/Server.exe"
version: { kind: uninstall_registry, display_name_prefix: "Vendor App" }
liveness:
kind: server_json
path: "%LOCALAPPDATA%/Vendor/Vendor App/McpServer/server.json"
pid_key: pid
url_key: http
token_key: token
endpoint_path: /mcp
darwin:
presence: bundle
location: /Applications/Vendor.app
version: { kind: plist }
| 字段 | 类型 | 规则 | 映射到 AppDef |
|---|---|---|---|
<os> | win32 | darwin | linux | 至少一个;未知键即报错 | AppDef.os_family |
presence | executable | bundle | 每个操作系统必填 | .presence |
location | str | 必填;Windows 上须为盘符根路径(C:\\...),或以 ~ / %VAR% / $VAR 开头;拒绝 UNC 路径,以确保存在性检查绝不触碰网络;不得含 .. 段或 URL scheme;在查找时展开 | .location |
version.kind | pe_resource | plist | uninstall_registry | none | 默认 none;pe_resource/uninstall_registry 仅用于 win32,plist 仅用于 darwin | .version_kind |
version.display_name_prefix | str | 当 uninstall_registry 时必填 | .version_arg |
liveness.kind | server_json | none | 默认 none | .liveness_kind |
liveness.path | str | 当 server_json 时必填 | .liveness_path |
liveness.pid_key / url_key / token_key | str | 默认 pid / http / token | .liveness_*_key |
liveness.endpoint_path | str | 默认 /mcp;用于 initialize 的路径,绝不是文件里那个路径 | .endpoint_path |
当 requires.app 为 true,而 app: 中缺少某操作系统时,得到 unsupported_os。
requires — 服务器在被提供之前需要什么 {#requires--what-the-server-needs-before-it-is-offered}
requires:
app: true
min_version: "2.3.0"
| 字段 | 类型 | 规则 |
|---|---|---|
app | bool | 为 true 时,必须存在 app: 块,且服务器的放行以应用存在为门槛 |
min_version | str | 要求 app: true;点分数字形式;每个适用的 app.<os> 都必须声明真实的 version.kind;按段逐段做数值比较,段内的非数字字符会被丢弃(2.3.0.12594 ≥ 2.3.0;预发布后缀不参与排序) |
requires.app: true 却没有 app: 块,属于 DeclarationError。
可用性:每个读取方共用的唯一评估 {#availability-the-one-evaluation-every-reader-uses}
hermes_platform/resolver/availability.py::availability(decl) -> Availability
Availability(
state: available | installed_not_running | missing_app | version_too_old
| unsupported_os | no_requirements,
version: str | None, # 检测到的版本(若存在)
path: str | None, # 应用被找到或被查找的位置
min_version: str | None, # 来自 requires
)
no_requirements:没有requires.app;应用门槛通过,但连接检查仍然适用。unsupported_os:有requires.app,但没有app.<当前操作系统>块。零 I/O。missing_app:locate在location处什么都没找到。version_too_old:版本低于最低要求,或无法读取。available:应用存在,版本可接受,或不要求版本。installed_not_running:保留词汇;本评估器永远不会产出它。
评估使用 locate 和可选的版本检测。它绝不探测服务器、启动应用或建立连接。工具注册表保留其现有的可用性缓存。
两道门槛 {#the-two-gates}
- MCP
check_fn(tools/mcp_tool_handlers.py::_make_check_fn):连接存活,并且(当为该服务器注册了带requires.app的声明时)availability(decl).offerable。返回普通bool,因为注册表缓存的是bool(fn())。 - Skill 的
requires_apps:frontmatter(agent/skill_utils.py::skill_matches_apps):每个名字都通过declaration.lookup解析;未知名字会隐藏该 skill(失败即关闭)。属于提供时过滤,与environments:类似。