fix(extension): 向MCP命令传递插件设置
This commit is contained in:
@@ -633,6 +633,7 @@ class PluginRuntime:
|
|||||||
"command_id": _spec.command_id,
|
"command_id": _spec.command_id,
|
||||||
"arguments": arguments,
|
"arguments": arguments,
|
||||||
"context": context,
|
"context": context,
|
||||||
|
"settings": settings,
|
||||||
"secrets": secret_values,
|
"secrets": secret_values,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -71,8 +71,10 @@ def call_tool(request_id: int, params: dict[str, Any]) -> None:
|
|||||||
envelope = arguments.get("_notesagent") or {}
|
envelope = arguments.get("_notesagent") or {}
|
||||||
command_arguments = envelope.get("arguments") or {}
|
command_arguments = envelope.get("arguments") or {}
|
||||||
context = envelope.get("context") or {}
|
context = envelope.get("context") or {}
|
||||||
|
settings = envelope.get("settings") or {}
|
||||||
secrets = envelope.get("secrets") or {}
|
secrets = envelope.get("secrets") or {}
|
||||||
message = command_arguments.get("message") or context.get("selection") or ""
|
message = command_arguments.get("message") or context.get("selection") or ""
|
||||||
|
message = f"{settings.get('message_prefix', '')}{message}"
|
||||||
respond(
|
respond(
|
||||||
request_id,
|
request_id,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
section_id: mcp-fixture.general
|
section_id: mcp-fixture.general
|
||||||
schema_version: 1
|
schema_version: 1
|
||||||
fields:
|
fields:
|
||||||
|
- key: message_prefix
|
||||||
|
label: Message Prefix
|
||||||
|
type: string
|
||||||
|
default: ""
|
||||||
- key: api_key
|
- key: api_key
|
||||||
label: Fixture API Key
|
label: Fixture API Key
|
||||||
type: secret
|
type: secret
|
||||||
|
|||||||
@@ -415,6 +415,9 @@ def test_mcp_command_target_receives_scoped_context_and_declared_secret(
|
|||||||
mcp_container.plugins.put_setting_secret(
|
mcp_container.plugins.put_setting_secret(
|
||||||
"mcp-fixture", "api_key", "mcp-command-secret"
|
"mcp-fixture", "api_key", "mcp-command-secret"
|
||||||
)
|
)
|
||||||
|
mcp_container.plugins.update_settings(
|
||||||
|
"mcp-fixture", 1, {"message_prefix": "Fixture: "}
|
||||||
|
)
|
||||||
result = await mcp_container.plugins.execute_command(
|
result = await mcp_container.plugins.execute_command(
|
||||||
"mcp-fixture.notify",
|
"mcp-fixture.notify",
|
||||||
{},
|
{},
|
||||||
@@ -427,7 +430,7 @@ def test_mcp_command_target_receives_scoped_context_and_declared_secret(
|
|||||||
assert result.effect.type == "notification"
|
assert result.effect.type == "notification"
|
||||||
assert result.effect.payload == {
|
assert result.effect.payload == {
|
||||||
"level": "success",
|
"level": "success",
|
||||||
"message": "来自选区",
|
"message": "Fixture: 来自选区",
|
||||||
"secret_configured": True,
|
"secret_configured": True,
|
||||||
}
|
}
|
||||||
assert "mcp-command-secret" not in repr(
|
assert "mcp-command-secret" not in repr(
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ error
|
|||||||
|
|
||||||
需要 Secret 的 Command 必须在 `commands.yaml` 的内部 `secrets` 数组中声明对应 Setting Key,并在 Plugin Manifest 声明 `secrets.use` 权限。安装时宿主校验该字段确实属于当前 Plugin Settings Schema 的 `secret` 类型;只有权限已授予并启用后,运行时才向受控 handler 或 MCP Command Target 提供声明过的 Secret。未声明字段返回 `PLUGIN_SECRET_ACCESS_DENIED`,必填 Secret 未配置返回 `PLUGIN_SECRET_REQUIRED`。`secrets` 不属于前端 `PluginCommand` DTO,Secret 明文也不会并入普通 Settings 字典。
|
需要 Secret 的 Command 必须在 `commands.yaml` 的内部 `secrets` 数组中声明对应 Setting Key,并在 Plugin Manifest 声明 `secrets.use` 权限。安装时宿主校验该字段确实属于当前 Plugin Settings Schema 的 `secret` 类型;只有权限已授予并启用后,运行时才向受控 handler 或 MCP Command Target 提供声明过的 Secret。未声明字段返回 `PLUGIN_SECRET_ACCESS_DENIED`,必填 Secret 未配置返回 `PLUGIN_SECRET_REQUIRED`。`secrets` 不属于前端 `PluginCommand` DTO,Secret 明文也不会并入普通 Settings 字典。
|
||||||
|
|
||||||
`commands.yaml` 中的执行目标必须在宿主白名单 `handler` 与当前 Plugin 命名空间的 `mcp_tool` 之间二选一。MCP Command Target 不注册为 Agent Tool;宿主用 `_notesagent` 保留包装传入 Command ID、参数、裁剪后的 Context 和声明过的 Secret,并将 MCP structured result 再校验为白名单 effect。Command 与 Tool Schema 仅允许 `#...` 文档内引用,任何通过 `$ref` 或 `$dynamicRef` 指向文件、HTTP 或其他外部资源的 Schema 都会在注册前被拒绝。文档内引用遵循 Draft 2020-12 的嵌套 `$id` 与 Anchor 资源作用域,不能解析的引用不得进入运行时。
|
`commands.yaml` 中的执行目标必须在宿主白名单 `handler` 与当前 Plugin 命名空间的 `mcp_tool` 之间二选一。MCP Command Target 不注册为 Agent Tool;宿主用 `_notesagent` 保留包装传入 Command ID、参数、裁剪后的 Context、已校验的非敏感 Settings 和声明过的 Secret,并将 MCP structured result 再校验为白名单 effect。Command 与 Tool Schema 仅允许 `#...` 文档内引用,任何通过 `$ref` 或 `$dynamicRef` 指向文件、HTTP 或其他外部资源的 Schema 都会在注册前被拒绝。文档内引用遵循 Draft 2020-12 的嵌套 `$id` 与 Anchor 资源作用域,不能解析的引用不得进入运行时。
|
||||||
|
|
||||||
### 7.5 Settings Schema
|
### 7.5 Settings Schema
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ Plugin 在 `plugin.yaml` 的 `contributes.commands` 与 `contributes.settings_se
|
|||||||
|
|
||||||
Command 执行器通过受控 Resolver 按需读取 `commands.yaml` 已声明且确实属于当前 Plugin Schema 的 Secret;使用 Secret 的 Plugin 还必须声明并获授 `secrets.use` 权限。读取未声明字段返回 `PLUGIN_SECRET_ACCESS_DENIED`,必填 Secret 未配置则返回 `PLUGIN_SECRET_REQUIRED`。Secret 不会并入普通 Settings 字典。Command 审计使用 500 条有界内存队列,仅保留 `command_id`、`plugin_id`、成功/失败状态、耗时、错误码和时间。arguments、正文选区、文件路径、effect 与 Secret 均不进入审计事件。
|
Command 执行器通过受控 Resolver 按需读取 `commands.yaml` 已声明且确实属于当前 Plugin Schema 的 Secret;使用 Secret 的 Plugin 还必须声明并获授 `secrets.use` 权限。读取未声明字段返回 `PLUGIN_SECRET_ACCESS_DENIED`,必填 Secret 未配置则返回 `PLUGIN_SECRET_REQUIRED`。Secret 不会并入普通 Settings 字典。Command 审计使用 500 条有界内存队列,仅保留 `command_id`、`plugin_id`、成功/失败状态、耗时、错误码和时间。arguments、正文选区、文件路径、effect 与 Secret 均不进入审计事件。
|
||||||
|
|
||||||
MCP Command Target 是专用执行目标,不注册进 Agent `ToolRegistry`,因此模型无法绕过 Command 权限与 Context 裁剪直接调用。宿主通过 `_notesagent` 保留包装传入 `command_id`、已校验 arguments、已裁剪 Context 和声明过的 Secret;MCP Server 必须返回结构化的白名单 effect。远程原始错误不直接透传给 HTTP 调用方。插件仍不能把模块路径或 Shell 字符串作为执行器。
|
MCP Command Target 是专用执行目标,不注册进 Agent `ToolRegistry`,因此模型无法绕过 Command 权限与 Context 裁剪直接调用。宿主通过 `_notesagent` 保留包装传入 `command_id`、已校验 arguments、已裁剪 Context、已校验的非敏感 Settings 和声明过的 Secret;MCP Server 必须返回结构化的白名单 effect。远程原始错误不直接透传给 HTTP 调用方。插件仍不能把模块路径或 Shell 字符串作为执行器。
|
||||||
|
|
||||||
Command 与 Tool 的 JSON Schema 只允许当前文档内的 Fragment 引用(`#...`);宿主在注册前递归拒绝 `$ref` / `$dynamicRef` 指向的文件、HTTP 或其他外部资源,避免 Schema 校验触发未授权 I/O。文档内引用使用 Draft 2020-12 Resource Resolver 预检,嵌套 `$id` 创建的新资源及其 Anchor 按各自作用域解析,无法解析的引用在注册阶段返回稳定错误。
|
Command 与 Tool 的 JSON Schema 只允许当前文档内的 Fragment 引用(`#...`);宿主在注册前递归拒绝 `$ref` / `$dynamicRef` 指向的文件、HTTP 或其他外部资源,避免 Schema 校验触发未授权 I/O。文档内引用使用 Draft 2020-12 Resource Resolver 预检,嵌套 `$id` 创建的新资源及其 Anchor 按各自作用域解析,无法解析的引用在注册阶段返回稳定错误。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user