Skip to content

feat(mcp): add granular allow/deny policy configuration#776

Merged
joshrotenberg merged 2 commits intomainfrom
feat/mcp-policy-config
Mar 3, 2026
Merged

feat(mcp): add granular allow/deny policy configuration#776
joshrotenberg merged 2 commits intomainfrom
feat/mcp-policy-config

Conversation

@joshrotenberg
Copy link
Collaborator

Summary

Replaces the binary --read-only flag with a TOML-based policy system for granular tool access control. Closes #766.

  • Three safety tiers: read-only (default), read-write (reads + non-destructive writes), full (everything)
  • Per-toolset overrides: Cloud, Enterprise, Database, and App can each have their own tier
  • Explicit allow/deny lists: deny always wins, with category-level deny (e.g., deny_categories = ["destructive"])
  • Policy file resolution: --policy flag > REDISCTL_MCP_POLICY env > ~/.config/redisctl/mcp-policy.toml > built-in defaults
  • show_policy tool: agents can discover their own permissions at runtime
  • Fully backward compatible: no policy file + --read-only=true/false behaves identically to before

Example mcp-policy.toml

tier = "read-only"
deny_categories = ["destructive"]

[cloud]
tier = "read-write"

[database]
tier = "read-only"
allow = ["redis_set", "redis_expire"]

deny = ["flush_database", "delete_subscription"]

Key changes

Area Change
New policy.rs PolicyConfig (TOML schema), Policy (evaluator), SafetyTier enum, show_policy tool, 21 unit tests
main.rs --policy CLI arg, resolve_policy(), build_tool_toolset_mapping(), CapabilityFilter::new with Policy::is_tool_allowed
state.rs read_only: bool -> policy: Arc<Policy>, is_write_allowed() consults tier, new is_destructive_allowed()
Toolset modules TOOL_NAMES constants + tool_names() on all 4 toolset modules
29 destructive handlers is_write_allowed() -> is_destructive_allowed() for defense-in-depth at read-write tier

Test plan

  • cargo fmt --all -- --check
  • cargo clippy -p redisctl-mcp --all-features -- -D warnings
  • cargo test -p redisctl-mcp --all-features (all unit, integration, doc tests pass)
  • cargo check -p redisctl-mcp --no-default-features
  • cargo check -p redisctl-mcp --features cloud
  • cargo check -p redisctl-mcp --features enterprise
  • cargo check -p redisctl-mcp --features database
  • Manual: run server with a policy file and verify show_policy returns expected config

Replace the binary --read-only flag with a TOML-based policy system
that provides three safety tiers (read-only, read-write, full),
per-toolset overrides, and explicit allow/deny lists.

- Add policy.rs with PolicyConfig (TOML schema), Policy (resolved
  evaluator), SafetyTier enum, and show_policy MCP tool
- Policy file resolution: --policy flag > REDISCTL_MCP_POLICY env >
  ~/.config/redisctl/mcp-policy.toml > built-in defaults
- Replace CapabilityFilter::write_guard with CapabilityFilter::new
  using Policy::is_tool_allowed for per-tool evaluation
- Replace AppState read_only bool with Arc<Policy>, add
  is_destructive_allowed() for defense-in-depth in destructive handlers
- Add TOOL_NAMES constants to each toolset module for policy mapping
- Update 29 destructive handlers to use is_destructive_allowed()
- Fully backward compatible: no policy file + --read-only behaves
  identically to the previous binary model
@joshrotenberg joshrotenberg merged commit 380f60d into main Mar 3, 2026
19 checks passed
@joshrotenberg joshrotenberg deleted the feat/mcp-policy-config branch March 3, 2026 21:28
@joshrotenberg joshrotenberg mentioned this pull request Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(mcp): granular allow/deny policy configuration (redisctl-mcp.toml)

1 participant