Skip to content

fix(mcp): enforce read-only policy and session scope on plugin tool dispatch - #10537

Merged
t8y2 merged 1 commit into
t8y2:mainfrom
jinpy666:up/mcp-plugin-tool-policy
Sep 29, 2026
Merged

t8y2 merged 1 commit into
t8y2:mainfrom
jinpy666:up/mcp-plugin-tool-policy

Conversation

@jinpy666

Copy link
Copy Markdown
Contributor

Problem

The plugin-tool surface introduced by the flat/lazy meta tools is gated by the flat tool allowlist, but it skips the rest of the execution policy stack that every native dbx_* tool enforces:

  • Under a read-only execution policy, plugin tools still run. Plugin-provided annotations.readOnlyHint is displayed (tools/list) but never enforced, so a tool such as dbx_kafka__kafka_topics_delete executes writes in a deployment the operator configured as read-only.
  • In a scoped session (DBX_MCP_SCOPE_*), the flat tools/list filters out plugins without in-scope connections, but the lazy/meta surface still lets callers enumerate every installed plugin (dbx_plugin_list, dbx_plugin_tools with full argument schemas) and call their connection-less tools.
  • dbx_plugin_tools answers "all tools hidden" differently from "plugin does not exist", which lets a client fingerprint installed plugin ids.

Fix

  • New shared ensure_plugin_tool_policy check on both call paths (dbx_<prefix>__<tool> dispatch and dbx_plugin_call), before the backend is reached:
    • under read_only, reject tools the plugin does not declare readOnlyHint with MCP_READ_ONLY;
    • with a scope active, reject plugins that own no in-scope connection with PLUGIN_OUT_OF_SCOPE.
  • dbx_plugin_list/catalog skip scope-hidden plugins entirely (no row, no hidden-count disclosure); dbx_plugin_tools answers a scoped-out plugin with the same out-of-scope error and no tool schema.
  • dbx_plugin_tools now answers a nonexistent plugin and an all-allowlist-hidden one identically.

Credentials stay bound to the owning plugin as before; this only closes the policy gap.

Testing

  • plugin_tools_enforce_read_only_policy: undeclared write rejected on both dispatch paths, backend never reached; declared read-only tool still runs.
  • plugin_tools_enforce_session_scope: out-of-scope plugin rejected, disappears from dbx_plugin_list/dbx_plugin_tools, in-scope plugin keeps working.
  • plugin_tool_wildcards_match_only_the_plugin_namespace (companion PR) and the existing allowlist tests still pass; full cargo test -p dbx-mcp --lib (186 tests) green on my fork's CI run of the equivalent branch.

…ispatch

Plugin tool calls were gated only by the flat tool allowlist and the
connection binding: the read-only execution policy, and the scoped-session
connection boundary that the flat tools/list enforces, both stopped at the
lazy/meta surface. A read_only deployment could be bypassed through any
installed plugin tool that does not declare readOnlyHint (e.g. a topic
delete), and a scoped session could call and enumerate plugins whose
connections are entirely out of scope.

- shared ensure_plugin_tool_policy check on both call paths
  (dbx_<prefix>__<tool> dispatch and dbx_plugin_call): rejects undeclared
  writes under a read-only policy (MCP_READ_ONLY) and out-of-scope plugins
  (PLUGIN_OUT_OF_SCOPE), before the backend is reached
- dbx_plugin_list/catalog skips scope-hidden plugins entirely (no row, no
  allowlist-hidden count); dbx_plugin_tools answers a scoped-out plugin
  with the same out-of-scope error and no tool schema
- dbx_plugin_tools now answers a nonexistent plugin and an
  all-allowlist-hidden one identically so the meta tool cannot fingerprint
  installed plugin ids
@github-actions github-actions Bot added area/mcp MCP server or packages bug Something isn't working labels Sep 28, 2026
@t8y2
t8y2 merged commit 1b6b003 into t8y2:main Sep 29, 2026
26 checks passed
@t8y2

t8y2 commented Sep 29, 2026

Copy link
Copy Markdown
Owner

Thanks for the contribution! Merged in 1b6b003, will be released in the next version.

@jinpy666
jinpy666 deleted the up/mcp-plugin-tool-policy branch September 30, 2026 12:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/mcp MCP server or packages bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants