From b9550bea0a7547f1c9dce655c115154cf000b085 Mon Sep 17 00:00:00 2001 From: vaaraio <267591518+vaaraio@users.noreply.github.com> Date: Wed, 20 May 2026 12:47:16 +0300 Subject: [PATCH] release(v0.22.0): MCP proxy operator allowlist/denylist for tools/list and tools/call MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps version 0.21.0 → 0.22.0 across pyproject.toml and clients/ts/package.json. Promotes the [Unreleased] CHANGELOG entry to [0.22.0] - 2026-05-20 with explicit Added / Verified / Use case subsections. Updates README MCP proxy section with a paragraph on the new --allow-tool / --deny-tool flags. Extends the mcp_proxy.py module docstring to note the optional filtering behaviour. --- CHANGELOG.md | 51 ++++++++++++++++++++++------- README.md | 2 ++ clients/ts/package.json | 2 +- pyproject.toml | 2 +- src/vaara/integrations/mcp_proxy.py | 5 +++ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ca0be1c..4da8213 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,19 +6,46 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht ## [Unreleased] +## [0.22.0] - 2026-05-20 + +**Theme: MCP proxy operator-side tool filtering.** Adds two repeatable +CLI flags to the MCP proxy that let an operator shape the upstream +tool surface visible to the AI client: `--allow-tool NAME` (if any are +given, only those tools pass through) and `--deny-tool NAME` (those +tools are filtered, wins on overlap with allowlist). Filtered tools +are dropped from `tools/list` responses before the client sees them, +and any `tools/call` to a filtered tool is rejected at the proxy +perimeter with an MCP `isError: true` payload (`decision: "FILTERED"`, +`reason: "Tool filtered by operator policy"`) without forwarding to +the upstream or invoking the risk pipeline. + ### Added -- MCP proxy: operator-side tool filtering at the perimeter. - `python -m vaara.integrations.mcp_proxy` now accepts repeatable - `--allow-tool NAME` and `--deny-tool NAME` flags. Filtered tools are - dropped from `tools/list` responses before the client sees them, and - any `tools/call` to a filtered tool is rejected at the proxy with an - MCP `isError: true` payload (`decision: "FILTERED"`, - `reason: "Tool filtered by operator policy"`) without forwarding - upstream or invoking the risk pipeline. Denylist wins on overlap with - allowlist. Backward compatible: no flags = current passthrough - behavior. Use case: hide write/delete tools (e.g. `delete_repository`, - `create_branch`) from an MCP client when the upstream server exposes - more capability than the deployment policy allows. +- `src/vaara/integrations/mcp_proxy.py`: `VaaraMCPProxy.__init__` + accepts `allowlist: Optional[set[str]]` and `denylist: + Optional[set[str]]`. New `_tool_filtered(name)` helper applied to + both `tools/list` (filters the `result.tools` array) and + `tools/call` (returns a `FILTERED` block payload before the + pipeline runs). +- CLI: `--allow-tool NAME` and `--deny-tool NAME`, both repeatable. + Backward compatible: no flags = passthrough. +- `tests/test_integrations_mcp_proxy.py`: eight new tests covering + denylist drops, allowlist restricts, denylist-wins-on-overlap, + no-policy passthrough, filtered tools/call returns block, and + allowlisted tools/call still routes through the pipeline. + +### Verified +- End-to-end smoke against `github/github-mcp-server` (42 real tools): + `--deny-tool` drops named entries from `tools/list` and rejects + matching `tools/call`; `--allow-tool` restricts `tools/list` to the + allowlist and routes allowlisted calls through the pipeline as + before; no-flag run is identical to v0.21.0 behaviour. + +### Use case +Hide write/delete tools (e.g. `delete_file`, `merge_pull_request`) +when the upstream MCP server exposes more capability than the +deployment policy allows. The LLM client never learns the tool +exists, which is materially different from instructing the model +not to call it. ## [0.21.0] - 2026-05-19 diff --git a/README.md b/README.md index 1f49845..a0759a6 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,8 @@ python -m vaara.integrations.mcp_proxy \ Point your MCP client at the proxy instead of the upstream. The audit chain captures every tool call without changing client or upstream behavior. Distinct from `mcp_server`, which exposes Vaara itself as an MCP server for agents that consult Vaara as a tool. +**Operator-side tool filtering** (since v0.22.0). The proxy accepts repeatable `--allow-tool NAME` and `--deny-tool NAME` flags. Filtered tools are dropped from `tools/list` responses before the client sees them and any matching `tools/call` is rejected at the proxy perimeter without contacting the upstream. Use this to hide write/delete tools (e.g. `delete_file`, `merge_pull_request`) when the upstream server exposes more capability than the deployment policy allows. Denylist wins on overlap with allowlist. No flags = passthrough. + Worked examples with real upstream servers: - [`examples/github-mcp-proxy-demo/`](examples/github-mcp-proxy-demo/). Vaara in front of [`github/github-mcp-server`](https://github.com/github/github-mcp-server) (GitHub's official MCP server, MIT-licensed). End-to-end verified: real subprocess, 42 tools advertised, hash-chained audit trail recorded. diff --git a/clients/ts/package.json b/clients/ts/package.json index fae1c02..404a9c6 100644 --- a/clients/ts/package.json +++ b/clients/ts/package.json @@ -1,6 +1,6 @@ { "name": "@vaara/client", - "version": "0.21.0", + "version": "0.22.0", "description": "TypeScript client for the Vaara HTTP API. Conformal risk scoring, hash-chained audit, policy reload, named detectors.", "main": "dist/index.js", "types": "dist/index.d.ts", diff --git a/pyproject.toml b/pyproject.toml index 9de9544..96985d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "vaara" -version = "0.21.0" +version = "0.22.0" description = "Adaptive AI Agent Execution Layer for risk scoring, audit trails, and regulatory compliance" requires-python = ">=3.10" license = "Apache-2.0" diff --git a/src/vaara/integrations/mcp_proxy.py b/src/vaara/integrations/mcp_proxy.py index 71288f0..f3006c1 100644 --- a/src/vaara/integrations/mcp_proxy.py +++ b/src/vaara/integrations/mcp_proxy.py @@ -5,6 +5,11 @@ community-built MCP server). Forwards every request to the upstream, but routes ``tools/call`` through Vaara's interception pipeline first. Allowed calls flow through transparently. Blocked calls return an MCP tool error. + +Optional operator-side filtering (``--allow-tool``/``--deny-tool``): when set, +the proxy filters the upstream's ``tools/list`` response before the client +sees it, and rejects ``tools/call`` to a filtered tool at the perimeter with +a ``FILTERED`` block payload, without contacting the upstream. """ from __future__ import annotations