Skip to main content
Version: v1alpha2
Status: Draft
Last Updated: 2026-01-24
Authors: Eduardo Arango ([email protected])
This is the current version of the AIP specification. For the previous version, see v1alpha1.

Abstract

The Agent Identity Protocol (AIP) defines a standard for policy-based authorization of AI agent tool calls. AIP enables runtime environments to enforce fine-grained access control over Model Context Protocol (MCP) tool invocations, providing a security boundary between AI agents and external resources. This specification defines:
  1. The policy document schema (AgentPolicy)
  2. Evaluation semantics for authorization decisions
  3. Agent identity and session management (new in v1alpha2)
  4. Server-side validation endpoints (new in v1alpha2)
  5. Error codes for denied requests
  6. Audit log format for compliance

What’s New in v1alpha2

Agent Identity

Token-based session management with cryptographic binding to policy and process context. Automatic token rotation and replay prevention.

Server-Side Validation

Optional HTTP endpoints for distributed policy enforcement. Supports remote validation, token verification, and centralized audit.

Policy Signing

Cryptographic integrity verification using Ed25519 signatures. Prevents unauthorized policy modifications.

MCP Authorization Alignment

Complementary to MCP’s OAuth 2.1 authorization layer (MCP 2025-06-18). Can be used together for defense in depth.

Formal Specification

Download Formal Specification

View the complete formal specification document on GitHub

Introduction

Motivation

AI agents operating through the Model Context Protocol (MCP) have access to powerful tools: file systems, databases, APIs, and cloud infrastructure. Without a policy layer, agents operate with unrestricted access to any tool the MCP server exposes. AIP v1alpha2 addresses this gap by introducing:
  • Capability declaration: Explicit allowlists of permitted tools
  • Argument validation: Regex-based constraints on tool parameters
  • Human-in-the-loop: Interactive approval for sensitive operations
  • Audit trail: Immutable logging of all authorization decisions
  • Agent identity: Cryptographic binding of policies to agent sessions (new)
  • Server-side validation: Optional HTTP endpoints for distributed policy enforcement (new)

Goals

  1. Interoperability: Any MCP runtime can implement AIP
  2. Simplicity: YAML-based policies readable by security teams
  3. Defense in depth: Multiple layers (method, tool, argument, identity)
  4. Fail-closed: Unknown tools are denied by default
  5. Zero-trust ready: Support for token-based identity verification (new)

Relationship to MCP

┌─────────┐     ┌─────────────┐     ┌─────────────┐
│  Agent  │────▶│ AIP Policy  │────▶│ MCP Server  │
│         │◀────│   Engine    │◀────│             │
└─────────┘     └─────────────┘     └─────────────┘


              ┌─────────────┐
              │ AIP Server  │  (optional, v1alpha2)
              │  Endpoint   │
              └─────────────┘

Policy Document Schema

apiVersion: aip.io/v1alpha2
kind: AgentPolicy
metadata:
  name: <string>
  version: <string>           # OPTIONAL
  owner: <string>             # OPTIONAL
  signature: <string>         # OPTIONAL (v1alpha2)
spec:
  mode: <string>              # OPTIONAL, default: "enforce"
  allowed_tools: [<string>]   # OPTIONAL
  allowed_methods: [<string>] # OPTIONAL
  denied_methods: [<string>]  # OPTIONAL
  tool_rules: [<ToolRule>]    # OPTIONAL
  protected_paths: [<string>] # OPTIONAL
  strict_args_default: <bool> # OPTIONAL, default: false
  dlp: <DLPConfig>            # OPTIONAL
  identity: <IdentityConfig>  # OPTIONAL (v1alpha2)
  server: <ServerConfig>      # OPTIONAL (v1alpha2)

Required Fields

apiVersion
string
required
MUST be aip.io/v1alpha2
kind
string
required
MUST be AgentPolicy
metadata.name
string
required
Unique identifier for this policy. Must be a valid DNS-1123 subdomain (lowercase alphanumeric + hyphens).

New in v1alpha2: Policy Signature

metadata.signature
string
Cryptographic signature for policy integrity verification.Format: <algorithm>:<base64-encoded-signature>Supported algorithms:
  • ed25519 - Ed25519 signature (RECOMMENDED)
Example:
metadata:
  name: production-agent
  signature: "ed25519:YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo..."
When present, implementations MUST verify the signature before applying the policy. Signature verification failure MUST result in policy rejection.
The signature is computed over the canonical form of the policy document (see Agent Identity section).

Core Spec Fields (from v1alpha1)

For core fields like mode, allowed_tools, allowed_methods, denied_methods, protected_paths, and tool_rules, see the v1alpha1 specification.

New in v1alpha2: Tool Schema Hashing

tool_rules[].schema_hash
string
Cryptographic verification of tool definitions to prevent tool poisoning attacks.Format: <algorithm>:<hex-digest>Supported algorithms:
  • sha256 (RECOMMENDED)
  • sha384
  • sha512
Example:
tool_rules:
  - tool: read_file
    action: allow
    schema_hash: "sha256:a3c7f2e8d9b4f1e2c8a7d6f3e9b2c4f1a8e7d3c2b5f4e9a7c3d8f2b6e1a9c4f7"
    allow_args:
      path: "^/home/.*"
Hash computation: The schema hash is computed over the canonical form of the tool’s MCP schema:
TOOL_SCHEMA_HASH(tool):
  schema = {
    "name": tool.name,
    "description": tool.description,
    "inputSchema": tool.inputSchema  # JSON Schema for arguments
  }
  canonical = JSON_CANONICALIZE(schema)  # RFC 8785
  hash = SHA256(canonical)
  RETURN "sha256:" + hex_encode(hash)
Behavior:
ConditionBehavior
schema_hash absentNo schema verification (backward compatible)
Hash matchesTool allowed (proceed to argument validation)
Hash mismatchTool BLOCKED with error -32013
Tool not foundTool BLOCKED with error -32001
Use cases:
  1. Tool poisoning prevention: Detect when an MCP server changes a tool’s behavior after policy approval
  2. Compliance auditing: Prove that approved tools haven’t been modified
  3. Supply chain security: Pin specific tool versions in policy

Enhanced DLP Configuration (v1alpha2)

dlp:
  enabled: <bool>             # OPTIONAL, default: true when dlp block present
  scan_requests: <bool>       # OPTIONAL, default: false (v1alpha2)
  scan_responses: <bool>      # OPTIONAL, default: true
  detect_encoding: <bool>     # OPTIONAL, default: false
  filter_stderr: <bool>       # OPTIONAL, default: false
  max_scan_size: <string>     # OPTIONAL, default: "1MB" (v1alpha2)
  on_request_match: <string>  # OPTIONAL, default: "block" (v1alpha2)
  patterns:
    - name: <string>          # REQUIRED - Rule identifier
      regex: <string>         # REQUIRED - Detection pattern
      scope: <string>         # OPTIONAL, default: "all" (request|response|all)
dlp.scan_requests
boolean
default:"false"
When true, DLP patterns are applied to tool arguments before the request is forwarded.Use case: Prevents data exfiltration via arguments (e.g., embedding secrets in API queries).
dlp.max_scan_size
string
default:"1MB"
Maximum size of content to scan per request/response.Format: Size string (e.g., "1MB", "512KB", "10MB")Purpose: Prevents ReDoS and memory exhaustion on large payloads.
dlp.on_request_match
enum
default:"block"
Action when DLP pattern matches in a request:
  • block: Reject the request with error -32001 (default)
  • redact: Replace matched content and forward
  • warn: Log warning and forward unchanged
dlp.patterns[].scope
enum
default:"all"
Where the pattern should be applied:
  • all: Scan both requests and responses
  • request: Only scan requests (detect exfiltration attempts)
  • response: Only scan responses (PII protection)
Example:
dlp:
  scan_requests: true
  on_request_match: "block"
  patterns:
    - name: "AWS Key"
      regex: "AKIA[0-9A-Z]{16}"
      scope: "all"
    
    - name: "SQL Injection"
      regex: "(?i)(DROP|DELETE|TRUNCATE)\s+TABLE"
      scope: "request"
    
    - name: "SSN"
      regex: "\d{3}-\d{2}-\d{4}"
      scope: "response"

Agent Identity (v1alpha2)

Overview

Agent identity provides:
  1. Session binding: Cryptographic proof that requests belong to the same session
  2. Policy integrity: Verification that the policy hasn’t changed mid-session
  3. Replay prevention: Nonces prevent token reuse across sessions
  4. Audit correlation: Session IDs link related audit events

Identity Configuration

spec:
  identity:
    enabled: <bool>           # OPTIONAL, default: false
    token_ttl: <duration>     # OPTIONAL, default: "5m"
    rotation_interval: <duration>  # OPTIONAL, default: "4m"
    require_token: <bool>     # OPTIONAL, default: false
    session_binding: <string> # OPTIONAL, default: "process"
    nonce_window: <duration>  # OPTIONAL, default: equals token_ttl
    policy_transition_grace: <duration>  # OPTIONAL, default: "0s"
    audience: <string>        # OPTIONAL, default: metadata.name
    nonce_storage: <NonceStorageConfig>  # OPTIONAL
    keys: <KeyConfig>         # OPTIONAL
identity.enabled
boolean
default:"false"
When true, the AIP engine generates and manages identity tokens for the session.
identity.token_ttl
duration
default:"5m"
The time-to-live for identity tokens.Format: Go duration string (e.g., "5m", "1h", "300s")Implementations SHOULD use short TTLs (5-15 minutes) to limit token theft window.
identity.rotation_interval
duration
default:"4m"
How often to rotate tokens before expiry.Constraint: MUST be less than token_ttl.
identity.require_token
boolean
default:"false"
When true, all tool calls MUST include a valid identity token. Calls without tokens are rejected with error code -32008.This enables gradual rollout: start with require_token: false to generate tokens without enforcement, then enable enforcement.
identity.session_binding
enum
default:"process"
Determines what context is bound to the session identity:
  • process: Session bound to process ID (default)
  • policy: Session bound to policy hash
  • strict: Session bound to process + policy + hostname
identity.audience
string
The intended audience for identity tokens. This value is included in the token’s aud claim and MUST be validated by recipients.Default: Value of metadata.namePurpose: Prevents tokens issued for one MCP server from being accepted by another.

Identity Token Structure

An AIP Identity Token is a JWT-like structure with the following fields:
{
  "version": "aip/v1alpha2",
  "aud": "<audience-uri>",
  "policy_hash": "<64-char-hex>",
  "session_id": "<uuid>",
  "agent_id": "<policy-metadata-name>",
  "issued_at": "<ISO-8601>",
  "expires_at": "<ISO-8601>",
  "nonce": "<random-hex>",
  "binding": {
    "process_id": <int>,
    "policy_path": "<string>",
    "hostname": "<string>"
  }
}
version
string
required
Token format version (aip/v1alpha2)
aud
string
required
Intended audience (from identity.audience or metadata.name)
policy_hash
string
required
SHA-256 hash of canonical policy
session_id
string
required
UUID identifying this session
nonce
string
required
Random value for replay prevention

Token Encoding

Implementations MUST encode tokens using one of the following formats:
When server.enabled: true, tokens MUST be encoded as RFC 7519 JWTs.JWT Header:
{
  "alg": "ES256",
  "typ": "aip+jwt"
}
Supported signing algorithms (in order of preference):
  1. ES256 (ECDSA with P-256 and SHA-256) - RECOMMENDED for production
  2. EdDSA (Ed25519) - RECOMMENDED for performance
  3. HS256 (HMAC-SHA256) - MAY be used only when server.enabled: false
HS256 requires a shared secret, which is unsuitable for distributed validation. Implementations MUST reject HS256 tokens on server endpoints.

Token Lifecycle

┌──────────────┐
│   Session    │
│    Start     │
└──────┬───────┘


┌──────────────┐     ┌──────────────┐
│    Issue     │────▶│   Active     │
│    Token     │     │    Token     │
└──────────────┘     └──────┬───────┘

       ┌────────────────────┼────────────────────┐
       │                    │                    │
       ▼                    ▼                    ▼
┌──────────────┐     ┌──────────────┐     ┌──────────────┐
│   Rotation   │     │   Expired    │     │   Session    │
│   (new token)│     │   (reject)   │     │     End      │
└──────────────┘     └──────────────┘     └──────────────┘

Token Validation

Token validation follows this algorithm:
VALIDATE_TOKEN(token):
  # Step 0: Check revocation FIRST
  revocation_result = CHECK_REVOCATION(token)
  IF revocation_result == REVOKED:
    RETURN (INVALID, revocation_result.reason)
  
  # Step 1: Check expiration
  IF now() > token.expires_at:
    RETURN (INVALID, "token_expired")
  
  # Step 2: Check audience
  expected_audience = identity.audience OR current_policy.metadata.name
  IF token.aud != expected_audience:
    RETURN (INVALID, "audience_mismatch")
  
  # Step 3: Check policy hash
  IF token.policy_hash != POLICY_HASH(current_policy):
    # Check if within grace period
    IF policy_transition_grace > 0:
      IF token.policy_hash IN recent_policy_hashes:
        CONTINUE
    RETURN (INVALID, "policy_changed")
  
  # Step 4: Check session binding
  IF identity.session_binding == "process":
    IF token.binding.process_id != current_process_id:
      RETURN (INVALID, "session_mismatch")
  
  IF identity.session_binding == "strict":
    IF token.binding != current_binding:
      RETURN (INVALID, "binding_mismatch")
  
  # Step 5: Check nonce (atomic operation required)
  IF NOT ATOMIC_CHECK_AND_RECORD_NONCE(token.nonce, identity.nonce_window):
    RETURN (INVALID, "replay_detected")
  
  RETURN (VALID, nil)

Server-Side Validation (v1alpha2)

Server Configuration

spec:
  server:
    enabled: <bool>           # OPTIONAL, default: false
    listen: <string>          # OPTIONAL, default: "127.0.0.1:9443"
    failover_mode: <string>   # OPTIONAL, default: "fail_closed"
    timeout: <duration>       # OPTIONAL, default: "5s"
    tls:                      # OPTIONAL
      cert: <string>          # Path to TLS certificate
      key: <string>           # Path to TLS private key
    endpoints:                # OPTIONAL
      validate: <string>      # Validation endpoint path (default: "/v1/validate")
      revoke: <string>        # Revocation endpoint path (default: "/v1/revoke")
      jwks: <string>          # JWKS endpoint path (default: "/v1/jwks")
      health: <string>        # Health check path (default: "/health")
      metrics: <string>       # Metrics endpoint path (default: "/metrics")
server.enabled
boolean
default:"false"
When true, the AIP engine starts an HTTP server for remote validation.
server.listen
string
default:"127.0.0.1:9443"
The address and port to bind the HTTP server.Format: <host>:<port> or :<port>
Binding to 0.0.0.0 exposes the validation endpoint to the network. Implementations MUST require TLS when listen address is not localhost.
server.failover_mode
enum
default:"fail_closed"
Behavior when the validation server is unreachable:
  • fail_closed: Deny all requests (RECOMMENDED for production)
  • fail_open: Allow all requests (NOT RECOMMENDED)
  • local_policy: Fall back to local policy evaluation (RECOMMENDED for hybrid deployments)
server.timeout
duration
default:"5s"
Maximum time to wait for validation server response.After timeout, the failover_mode behavior is triggered.

Validation Endpoints

EndpointDefaultDescription
validate/v1/validatePolicy validation endpoint
revoke/v1/revokeToken/session revocation
jwks/v1/jwksJSON Web Key Set for token verification
health/healthHealth check (for load balancers)
metrics/metricsPrometheus metrics (optional)

Error Codes (v1alpha2)

New error codes in v1alpha2:
-32008
Token Required
Missing identity token when identity.require_token: true
-32009
Token Invalid
Expired, malformed, or invalid token
-32010
Signature Invalid
Policy signature verification failed
-32013
Schema Mismatch
Tool schema hash does not match policy
-32014
DLP Redaction Failed
Request redaction produced invalid content
For complete error code reference including v1alpha1 codes, see v1alpha1 Error Codes.

Conformance Levels

Requirements: Method authorization, tool allowlist, error codesAPI Version: v1alpha1+

Migration from v1alpha1

1

Update apiVersion

Change apiVersion: aip.io/v1alpha1 to apiVersion: aip.io/v1alpha2
2

Add Identity (Optional)

If you want token-based identity:
spec:
  identity:
    enabled: true
    require_token: false  # Start with false for gradual rollout
3

Add Server (Optional)

If you want distributed validation:
spec:
  server:
    enabled: true
    listen: "127.0.0.1:9443"
4

Test in Monitor Mode

Before enforcing:
spec:
  mode: monitor
v1alpha1 policies continue to work in v1alpha2 implementations. Simply update the apiVersion to access new features.

References

See Also

Build docs developers (and LLMs) love