From 860c120c2fbdc751e84345a1c56c18ad2bf0ded0 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 14 Jan 2026 14:39:39 +0100 Subject: [PATCH 1/2] feat: add exfiltration and dynamic policy fields to ConnectorPolicyInfo Add new response fields for MCP exfiltration detection and dynamic policies: - ExfiltrationCheckInfo: rows_returned, row_limit, bytes_returned, byte_limit, within_limits - DynamicPolicyInfo: policies_evaluated, matched_policies, orchestrator_reachable, processing_time_ms - DynamicPolicyMatch: policy_id, policy_name, policy_type, action, reason Update ConnectorPolicyInfo to include optional exfiltration_check and dynamic_policy_info fields. CHANGELOG.md updated for v1.4.0. --- CHANGELOG.md | 17 ++++++++++++++++ axonflow/types.py | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 230a924..d66090e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ All notable changes to the AxonFlow Python SDK will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.4.0] - 2026-01-14 + +### Added + +- **MCP Exfiltration Detection** (Issue #966): `ConnectorPolicyInfo` now includes `exfiltration_check` with row/volume limit information + - `ExfiltrationCheckInfo` type with `rows_returned`, `row_limit`, `bytes_returned`, `byte_limit`, `within_limits` fields + - Prevents large-scale data extraction via MCP queries + - Configurable via `MCP_MAX_ROWS_PER_QUERY` and `MCP_MAX_BYTES_PER_QUERY` environment variables + +- **MCP Dynamic Policies** (Issue #968): `ConnectorPolicyInfo` now includes `dynamic_policy_info` for Orchestrator-evaluated policies + - `DynamicPolicyInfo` type with `policies_evaluated`, `matched_policies`, `orchestrator_reachable`, `processing_time_ms` + - `DynamicPolicyMatch` type with `policy_id`, `policy_name`, `policy_type`, `action`, `reason` + - Supports rate limiting, budget controls, time-based access, and role-based access policies + - Optional feature - enable via `MCP_DYNAMIC_POLICIES_ENABLED=true` + +--- + ## [1.3.0] - 2026-01-09 ### Added diff --git a/axonflow/types.py b/axonflow/types.py index 7b92081..1194938 100644 --- a/axonflow/types.py +++ b/axonflow/types.py @@ -176,6 +176,51 @@ class PolicyMatchInfo(BaseModel): action: str = Field(..., description="Action taken") +class ExfiltrationCheckInfo(BaseModel): + """Information about exfiltration limit checks (Issue #966). + + Helps prevent large-scale data extraction via MCP queries. + """ + + rows_returned: int = Field(default=0, ge=0, description="Number of rows in the response") + row_limit: int = Field(default=0, ge=0, description="Configured max rows per query") + bytes_returned: int = Field(default=0, ge=0, description="Size of response data in bytes") + byte_limit: int = Field(default=0, ge=0, description="Configured max bytes per response") + within_limits: bool = Field(default=True, description="Whether response is within limits") + + +class DynamicPolicyMatch(BaseModel): + """Details about a matched dynamic policy.""" + + policy_id: str = Field(..., description="Unique policy identifier") + policy_name: str = Field(default="", description="Human-readable policy name") + policy_type: str = Field( + default="", + description="Type of policy (rate-limit, budget, time-access, role-access, mcp, connector)", + ) + action: str = Field(default="", description="Action taken (allow, block, log, etc.)") + reason: str | None = Field(default=None, description="Context for the policy match") + + +class DynamicPolicyInfo(BaseModel): + """Information about dynamic policy evaluation (Issue #968). + + Dynamic policies are evaluated by the Orchestrator and can include + rate limiting, budget controls, time-based access, and role-based access policies. + """ + + policies_evaluated: int = Field(default=0, ge=0, description="Number of dynamic policies checked") + matched_policies: list[DynamicPolicyMatch] = Field( + default_factory=list, description="Policies that matched" + ) + orchestrator_reachable: bool = Field( + default=True, description="Whether the Orchestrator was reachable" + ) + processing_time_ms: int = Field( + default=0, ge=0, description="Time taken for dynamic policy evaluation" + ) + + class ConnectorPolicyInfo(BaseModel): """Policy evaluation information included in MCP responses. @@ -191,6 +236,12 @@ class ConnectorPolicyInfo(BaseModel): matched_policies: list[PolicyMatchInfo] = Field( default_factory=list, description="Policies that matched" ) + exfiltration_check: ExfiltrationCheckInfo | None = Field( + default=None, description="Exfiltration check info (Issue #966)" + ) + dynamic_policy_info: DynamicPolicyInfo | None = Field( + default=None, description="Dynamic policy evaluation info (Issue #968)" + ) class ConnectorResponse(BaseModel): From 505550b160fa69c36df6bfb4b6594919100dfd34 Mon Sep 17 00:00:00 2001 From: Saurabh Jain Date: Wed, 14 Jan 2026 16:03:50 +0100 Subject: [PATCH 2/2] fix: lint error - line too long in types.py --- axonflow/types.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/axonflow/types.py b/axonflow/types.py index 1194938..08749ab 100644 --- a/axonflow/types.py +++ b/axonflow/types.py @@ -209,7 +209,9 @@ class DynamicPolicyInfo(BaseModel): rate limiting, budget controls, time-based access, and role-based access policies. """ - policies_evaluated: int = Field(default=0, ge=0, description="Number of dynamic policies checked") + policies_evaluated: int = Field( + default=0, ge=0, description="Number of dynamic policies checked" + ) matched_policies: list[DynamicPolicyMatch] = Field( default_factory=list, description="Policies that matched" )