MCPWorks

Per-Agent Access Control: Least Privilege for AI Agents

Simon Carr

Every agent in a MCPWorks namespace could previously call any function and read any state key. That works for single-agent setups, but the moment you run multiple agents with different responsibilities — a content bot, a billing bot, a moderation bot — unrestricted access becomes a liability. Today we shipped per-agent access control.

What is per-agent access control?

Access rules let namespace owners restrict which functions and state keys each agent can use. Rules are defined using fnmatch glob patterns and follow a simple precedent: deny rules always win.

There are four function rule types and two state rule types:

Rule Type Scope Example Pattern
allow_services Entire services social, content
deny_services Entire services billing, admin
allow_functions Specific functions social.post_*
deny_functions Specific functions admin.delete_*
allow_keys State keys content.*, cache.*
deny_keys State keys secrets.*

An agent with no rules configured retains full access — the feature is backwards compatible.

How does deny-takes-precedence work?

If an agent has both an allow rule for the "admin" service and a deny rule for admin.delete_*, the deny wins. The agent can call admin.list_users but not admin.delete_user. This means you can grant broad access and carve out exceptions without worrying about rule ordering.

The evaluation order is:

  1. Check deny rules for services
  2. Check deny rules for specific functions
  3. Check allow rules for services (if any exist, unlisted services are blocked)
  4. Check allow rules for specific functions (if any exist, unlisted functions are blocked)

If no rules match, access is allowed.

How do you configure it?

Three new MCP tools handle access management:

configure_agent_access(
  agent_name="content-bot",
  rule={
    "type": "allow_services",
    "patterns": ["social", "content"]
  }
)

This restricts content-bot to only call functions within the "social" and "content" services. Any attempt to call a function in another service — "billing", "admin", or anything else — returns an access denied error.

To block specific dangerous functions while keeping the rest of a service open:

configure_agent_access(
  agent_name="admin-bot",
  rule={
    "type": "deny_functions",
    "patterns": ["admin.delete_*", "admin.drop_*"]
  }
)

To view and remove rules:

list_agent_access_rules(agent_name="content-bot")
remove_agent_access_rule(agent_name="content-bot", rule_id="rule_abc123")

What about state keys?

State access follows the same pattern. A content agent that only needs content.* and cache.* keys can be restricted so it cannot read secrets.* or billing.*:

configure_agent_access(
  agent_name="content-bot",
  rule={
    "type": "deny_keys",
    "patterns": ["secrets.*", "billing.*"]
  }
)

When an agent lists state keys, restricted keys are filtered from the response. The agent never sees they exist.

Why does this matter?

Multi-agent namespaces are the common case as MCPWorks deployments grow. Without access control, every agent is a potential blast radius for every function and every piece of state. A misconfigured social media bot could accidentally call billing functions. A content agent could read API tokens stored in state.

Per-agent access control enforces least privilege at the platform level. You do not need to trust that every agent's system prompt correctly avoids sensitive operations — the runtime blocks them.

The full implementation — spec, rule engine, 23 unit tests, and database migration — is in PR #35.

Frequently asked questions

Do I need to configure access rules for existing agents?

No. Agents with no access rules configured retain unrestricted access. The feature is opt-in and backwards compatible.

What happens if an agent calls a function it cannot access?

The call is denied with a structured error that identifies the agent, the blocked resource, and the rule that triggered the denial. The agent receives a clear message — no silent failures.

Can access rules be configured through the MCP protocol?

Yes. The three management tools — configure_agent_access, list_agent_access_rules, and remove_agent_access_rule — are available through the namespace's create endpoint (/mcp/create/{namespace}). You can configure rules from any MCP client.

Do access rules apply to procedure steps?

Yes. If a procedure step calls a function the executing agent cannot access, the step fails with an access denied error. The procedure execution log records the failure with the specific rule that blocked it.

How do glob patterns work?

Patterns use Python's fnmatch syntax. * matches any sequence of characters, ? matches a single character, and [seq] matches any character in the sequence. For example, social.* matches all functions in the "social" service, and admin.delete_* matches any function in the "admin" service starting with "delete_".

MCPWorks is open source.

Self-host free forever, or try MCPWorks Cloud — 14-day Pro trial, no credit card.

View on GitHub Cloud Trial — Coming Soon