Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
53 changes: 53 additions & 0 deletions axonflow/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,53 @@ 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.

Expand All @@ -191,6 +238,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):
Expand Down