Agent Identities in the Enterprise: Service Accounts for Autonomous Tool Calls
How enterprises are implementing identity and access management for AI agents that make autonomous tool calls, with practical patterns using MCP and service accounts.
Published on • September 7, 2026
AI Assistant

When AI agents operate in enterprise environments, they need more than just API keys. They need proper identities — service accounts with scoped permissions, audit trails, and the ability to prove which agent performed which action. This is not a future concern; it is a present-day requirement for any organization deploying agents that interact with production systems.
Why This Matters
Consider a typical enterprise agent scenario: an AI agent needs to read data from a database, update records in a CRM, send notifications through Slack, and file reports in a document management system. Each of these actions needs to be:
- Authenticated — verified as coming from a legitimate, authorized agent
- Authorized — scoped to only the permissions the agent needs
- Auditable — traceable to the specific agent and invocation context
- Revocable — deletable without affecting other agents or human users
Without proper identity management, organizations face security risks, compliance violations, and debugging nightmares. The Model Context Protocol (MCP) provides a foundational layer for this, but enterprise deployments need additional patterns on top.
The Problem with Shared API Keys
Most teams start by sharing a single API key across all agent instances. This is dangerous:
# BAD: Shared credentials across all agents
import os
# Same key used by dev, staging, and production agents
DATABASE_KEY = os.environ["MASTER_DB_KEY"]
CRM_API_KEY = os.environ["CRM_API_KEY"]
# No way to distinguish which agent made which call
# No way to revoke access for one agent without affecting others
# No audit trail per agent
This approach violates the principle of least privilege and makes incident response nearly impossible. If an agent is compromised, you have to rotate keys for everything.
Implementing Agent Service Accounts
The solution is treating agents like employees: each gets its own identity, its own credentials, and its own permission scope.
Step 1: Define Agent Identity Schema
from dataclasses import dataclass, field
from datetime import datetime
from enum import Enum
class PermissionLevel(Enum):
READ_ONLY = "read_only"
READ_WRITE = "read_write"
ADMIN = "admin"
@dataclass
class AgentIdentity:
agent_id: str
agent_name: str
owner_team: str
permissions: dict[str, PermissionLevel]
created_at: datetime = field(default_factory=datetime.utcnow)
max_tokens_per_hour: int = 100000
max_cost_per_hour_usd: float = 5.00
allowed_tools: list[str] = field(default_factory=list)
blocked_tools: list[str] = field(default_factory=list)
# Example: A customer support agent with limited permissions
support_agent = AgentIdentity(
agent_id="agent-support-001",
agent_name="Customer Support Agent",
owner_team="customer-success",
permissions={
"crm:read": PermissionLevel.READ_ONLY,
"crm:write": PermissionLevel.READ_WRITE,
"database:read": PermissionLevel.READ_ONLY,
"slack:write": PermissionLevel.READ_WRITE,
},
allowed_tools=["lookup_customer", "update_ticket", "send_notification"],
blocked_tools=["delete_record", "export_bulk", "modify_schema"],
)
Step 2: MCP Server with Agent Identity Verification
from mcp.server.fastmcp import FastMCP
from functools import wraps
mcp = FastMCP("enterprise-tools")
def require_agent_identity(required_permission: PermissionLevel):
"""Decorator that verifies agent identity and permissions."""
def decorator(func):
@wraps(func)
async def wrapper(*args, **kwargs):
agent_id = kwargs.get("agent_id") or args[0] if args else None
if not agent_id:
raise PermissionError("Agent identity required")
identity = await get_agent_identity(agent_id)
resource = func.__name__
if resource not in identity.allowed_tools:
raise PermissionError(
f"Agent {agent_id} not authorized for {resource}"
)
permission = identity.permissions.get(f"{resource}:write",
PermissionLevel.READ_ONLY)
if required_permission == PermissionLevel.READ_WRITE and \
permission == PermissionLevel.READ_ONLY:
raise PermissionError(
f"Agent {agent_id} has read-only access to {resource}"
)
# Log the action for audit trail
await log_agent_action(
agent_id=agent_id,
action=resource,
args=args,
timestamp=datetime.utcnow()
)
return await func(*args, **kwargs)
return wrapper
return decorator
@mcp.tool()
@require_agent_identity(PermissionLevel.READ_ONLY)
async def lookup_customer(customer_id: str, agent_id: str) -> dict:
"""Look up customer information. Requires agent identity."""
customer = await crm_client.get_customer(customer_id)
return {
"id": customer.id,
"name": customer.name,
"email": customer.email,
"status": customer.status
}
@mcp.tool()
@require_agent_identity(PermissionLevel.READ_WRITE)
async def update_ticket(
ticket_id: str,
status: str,
note: str,
agent_id: str
) -> dict:
"""Update a support ticket. Requires read-write permissions."""
ticket = await crm_client.update_ticket(
ticket_id=ticket_id,
status=status,
note=note,
updated_by=agent_id # Audit trail
)
return {"ticket_id": ticket.id, "status": ticket.status}
Step 3: Agent Authentication Middleware
import jwt
import hashlib
from datetime import timedelta
class AgentAuthenticator:
def __init__(self, secret_key: str):
self.secret_key = secret_key
def create_agent_token(
self,
identity: AgentIdentity,
ttl_minutes: int = 60
) -> str:
"""Create a short-lived JWT for an agent session."""
payload = {
"agent_id": identity.agent_id,
"agent_name": identity.agent_name,
"team": identity.owner_team,
"permissions": {
k: v.value for k, v in identity.permissions.items()
},
"allowed_tools": identity.allowed_tools,
"exp": datetime.utcnow() + timedelta(minutes=ttl_minutes),
"iat": datetime.utcnow(),
"jti": hashlib.sha256(
f"{identity.agent_id}:{datetime.utcnow().isoformat()}"
.encode()
).hexdigest()[:16],
}
return jwt.encode(payload, self.secret_key, algorithm="HS256")
def verify_agent_token(self, token: str) -> dict:
"""Verify and decode an agent token."""
try:
payload = jwt.decode(
token, self.secret_key, algorithms=["HS256"]
)
return payload
except jwt.ExpiredSignatureError:
raise PermissionError("Agent token expired")
except jwt.InvalidTokenError:
raise PermissionError("Invalid agent token")
# Usage in your MCP server
auth = AgentAuthenticator(secret_key="your-secret-key")
@app.middleware("http")
async def agent_auth_middleware(request, call_next):
agent_token = request.headers.get("X-Agent-Token")
if agent_token:
identity = auth.verify_agent_token(agent_token)
request.state.agent_id = identity["agent_id"]
request.state.agent_permissions = identity["permissions"]
response = await call_next(request)
return response
Step 4: Audit Trail Implementation
from sqlalchemy import Column, String, DateTime, JSON
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class AgentAuditLog(Base):
__tablename__ = "agent_audit_log"
id = Column(String, primary_key=True)
agent_id = Column(String, index=True)
agent_name = Column(String)
action = Column(String)
resource = Column(String)
arguments = Column(JSON)
result_status = Column(String) # success, failure, denied
timestamp = Column(DateTime)
session_id = Column(String)
ip_address = Column(String)
async def log_agent_action(
agent_id: str,
action: str,
args: tuple,
result_status: str = "success",
session_id: str = None
):
"""Log every agent action for audit and compliance."""
log_entry = AgentAuditLog(
id=str(uuid4()),
agent_id=agent_id,
action=action,
resource=action,
arguments={"args": str(args)},
result_status=result_status,
timestamp=datetime.utcnow(),
session_id=session_id,
)
await database.insert(log_entry)
Best Practices
-
One identity per agent instance: Do not share identities between agent instances, even if they perform the same function.
-
Short-lived tokens: Agent tokens should expire within an hour. Agents can refresh their own tokens using longer-lived refresh tokens stored securely.
-
Principle of least privilege: Give each agent only the permissions it needs. A read-only reporting agent should not have write access to any system.
-
Separate human and agent credentials: Never reuse human service accounts for agents. This makes auditing impossible and violates security policies.
-
Rotate credentials automatically: Use a secrets manager and rotate agent credentials on a regular schedule, not just when incidents occur.
Common Pitfalls
- Hardcoding agent credentials: Always inject credentials through environment variables or secrets managers. Never commit them to source control.
- Ignoring token expiration: Expired tokens cause silent failures. Implement proper error handling and automatic token refresh.
- Missing audit logs: If you cannot trace which agent performed an action, you cannot investigate incidents or pass compliance audits.
- Overly broad permissions: Start with read-only access and grant write permissions only when justified by specific use cases.
Getting Started
Here is a practical checklist for implementing agent identities in your enterprise:
- Create a service account schema for agents in your identity provider
- Implement token-based authentication for your MCP servers
- Add agent identity verification to every tool that performs write operations
- Set up audit logging for all agent actions
- Define permission scopes for each type of agent in your system
- Implement automatic credential rotation using your secrets manager
- Create dashboards to monitor agent identity usage and anomalies
Conclusion
Agent identity management is not optional in enterprise environments. The same security principles that apply to human users — authentication, authorization, audit logging, and credential management — apply equally to AI agents. The Model Context Protocol provides the foundation, but enterprises need to build identity layers on top.
Treat your agents like employees. Give them IDs, give them permissions, and watch what they do. The organizations that get this right will deploy agents confidently. The ones that do not will face security incidents and compliance failures.
Next steps:
- Audit your current agent deployments for shared credentials
- Implement agent service accounts in your identity provider
- Add identity verification to your MCP servers using the patterns above
- Set up audit logging and review it weekly