Skip to content
BotServBotServ
MCPPermissionsAccess ControlSecurityTool Permissions

MCP Permissions: Access Control for Tools

MCP permissions for AI agents. Access control, security, tool permissions and best practices.

S

schutzgeist

5 min read
MCP Permissions: Access Control for Tools

MCP Permissions: Access Control for Tools

What This Article Covers

  • How MCP permissions work for AI agents.
  • Implementing access control for MCP tools.
  • Granting agents only the permissions they need.
  • Practical examples for filesystem, database, and API permissions.
  • Security best practices and the principle of least privilege.

Introduction: Understanding MCP Permissions

MCP (Model Context Protocol) connects agents to tools. Permissions determine which tools an agent can use and what it can do with them. Not “all tools for everyone,” but rather “only necessary tools, only necessary actions.”

This article is for anyone configuring MCP permissions for agents. For foundational concepts, see MCP and Tool Permissions.

Why Do You Need MCP Permissions?

Imagine your agent has access to the filesystem. Without permissions, it can read, write, and delete all files. With permissions, it can only read from /data, cannot write, and cannot delete. That’s least privilege in action: only the permissions needed for the job.

MCP Permissions Explained

MCP tools have permissions: read, write, execute, delete. An agent receives only the permissions necessary for its task. A research agent needs read access but not write. An admin agent needs write access, but only to specific paths.

The core principle is simple: least privilege, only necessary permissions.

Who Is This Article For?

  • Security-conscious teams who want to lock down their agents.
  • Developers building MCP tools with permission controls.
  • System administrators implementing access control.
  • DevOps engineers deploying agents safely.

Key Terms

  • MCP - Model Context Protocol. Use when: integrating tools.
  • Tool Permissions - Access control. Use when: securing your system.
  • Least Privilege - Minimal permissions. Use when: hardening security.
  • Prompt Injection - Attack vectors. Use when: assessing risks.

Permission Model

# Define MCP tool permissions
tools = {
    "filesystem": {
        "permissions": ["read", "write"],
        "allowed_paths": ["/data", "/tmp"],
        "denied_paths": ["/etc", "/var", "/root"]
    },
    "database": {
        "permissions": ["read", "insert"],
        "allowed_tables": ["users", "logs"],
        "denied_tables": ["admin", "secrets"]
    },
    "api": {
        "permissions": ["get", "post"],
        "allowed_endpoints": ["/api/data", "/api/status"],
        "rate_limit": 100  # Requests per hour
    }
}

Example 1: Filesystem Permissions

class FileSystemTool:
    """Filesystem tool with permissions"""

    def __init__(self):
        self.permissions = {
            "read": True,
            "write": True,
            "delete": False,  # No delete permission
            "allowed_paths": ["/data", "/tmp"],
            "denied_paths": ["/etc", "/var", "/root", "/home"]
        }

    def check_permission(self, action, path):
        """Check permission for an action"""
        # Is the action allowed?
        if not self.permissions.get(action, False):
            raise PermissionError(f"Action '{action}' not allowed")

        # Is the path allowed?
        if not any(path.startswith(p) for p in self.permissions["allowed_paths"]):
            raise PermissionError(f"Path '{path}' not allowed")

        # Is the path denied?
        if any(path.startswith(p) for p in self.permissions["denied_paths"]):
            raise PermissionError(f"Path '{path}' is denied")

        return True

    def read_file(self, path):
        """Read a file (with permission check)"""
        self.check_permission("read", path)
        with open(path) as f:
            return f.read()

    def write_file(self, path, content):
        """Write a file (with permission check)"""
        self.check_permission("write", path)
        with open(path, "w") as f:
            f.write(content)

Example 2: Database Permissions

class DatabaseTool:
    """Database tool with permissions"""

    def __init__(self):
        self.permissions = {
            "read": True,
            "insert": True,
            "update": False,  # No update permission
            "delete": False,  # No delete permission
            "allowed_tables": ["users", "logs", "events"],
            "denied_tables": ["admin", "secrets", "credentials"]
        }

    def query(self, table, filters):
        """Query with permission check"""
        # Is the table denied?
        if table in self.permissions["denied_tables"]:
            raise PermissionError(f"Table '{table}' is denied")

        # Is the table allowed?
        if table not in self.permissions["allowed_tables"]:
            raise PermissionError(f"Table '{table}' not allowed")

        # Execute query
        return self.db.query(table, filters)

Example 3: API Permissions

class APITool:
    """API tool with permissions"""

    def __init__(self):
        self.permissions = {
            "get": True,
            "post": True,
            "put": False,
            "delete": False,
            "allowed_endpoints": [
                "/api/data",
                "/api/status",
                "/api/users"
            ],
            "rate_limit": 100  # Requests per hour
        }
        self.request_count = 0

    def call_api(self, method, endpoint, data=None):
        """Call API with permission check"""
        # Is the method allowed?
        if method.lower() not in self.permissions:
            raise PermissionError(f"Method '{method}' not allowed")

        if not self.permissions[method.lower()]:
            raise PermissionError(f"Method '{method}' is denied")

        # Is the endpoint allowed?
        if endpoint not in self.permissions["allowed_endpoints"]:
            raise PermissionError(f"Endpoint '{endpoint}' not allowed")

        # Check rate limit
        if self.request_count >= self.permissions["rate_limit"]:
            raise RateLimitError("Rate limit exceeded")

        self.request_count += 1
        return self.http_request(method, endpoint, data)

Permissions per Agent

# Different agents, different permissions
agents = {
    "research_agent": {
        "tools": {
            "filesystem": {"read": True, "write": False},
            "web_search": {"search": True},
            "database": {"read": True}
        }
    },
    "writer_agent": {
        "tools": {
            "filesystem": {"read": True, "write": True},
            "database": {"read": True, "insert": True}
        }
    },
    "admin_agent": {
        "tools": {
            "filesystem": {"read": True, "write": True, "delete": True},
            "database": {"read": True, "insert": True, "update": True, "delete": True},
            "system": {"execute": True}
        }
    }
}

Security Guidelines

  • Least Privilege: Only grant necessary permissions. See Tool Permissions.
  • Path Restrictions: For filesystem tools, restrict to allowed paths only, never root directories.
  • Rate Limiting: For APIs, enforce rate limits to prevent abuse.
  • Audit Logging: Log all permission violations. See Audit Logging.
  • Prompt Injection: Agents may attempt to bypass permissions. See Prompt Injection.

Common Pitfalls

  • Excessive permissions: Agents should not have unrestricted access. Apply the principle of least privilege.
  • No path restrictions: Agents should not be able to access all file paths.
  • Missing rate limits: Without rate limits, agents can overwhelm APIs.
  • Permissions not validated: Permissions must be checked before each action.
  • No audit trail: Permission violations should be logged.

Further Reading

Key Takeaways:

  • MCP permissions: least privilege for tools.
  • Filesystem: only allowed paths, no root access.
  • Database: only allowed tables, no admin tables.
  • API: rate limits and endpoint restrictions.
  • Audit: log all permission violations.

FAQ

What are MCP permissions?

Access control for MCP tools: which actions (read/write/delete), which paths/tables/endpoints, which rate limits. Least privilege for agents.

What is least privilege?

A security principle: grant only the permissions an agent needs. A research agent needs read access, not write. An admin agent requires broader access, but only for its assigned tasks.

How do I implement permissions?

In each tool, call check_permission() before every action. Define allowed actions, paths, tables, and endpoints. Validate permissions before execution.

What types of permissions exist?

Actions: read, write, delete, execute. Scopes: paths (filesystem), tables (database), endpoints (API). Limits: rate limits, quotas.

Can an agent bypass permissions?

No, if implemented correctly. Permissions are enforced server-side, not client-side. Prompt injection might attempt to bypass them, but should not succeed.

How do I log permissions?

Audit logging: track who used which permission and when. On violations: send alerts, block the action, and create a log entry.

Should different agents have different permissions?

Yes, each agent should have its own permission set. A research agent might be read-only. A writer agent gets read and write. An admin agent has broader access, but only what it needs.

What are default permissions?

For most agents: read and write in allowed scopes. No delete, no execute, no system permissions. For sensitive agents: require human approval.

Sources and Further Reading

Back to Blog
Share:

Related Posts