Skip to content

MCP Protocol

Airlock implements the Model Context Protocol (MCP) for AI agent communication.

Overview

MCP is a JSON-RPC based protocol that allows AI agents to discover and call tools. Airlock exposes your API operations as MCP tools.

Endpoints

Per-Server HTTP Transport

POST https://mcp.air-lock.ai/{projectId}

Used by Claude Desktop, Claude Code, Augment, and other MCP clients. Each server has its own MCP endpoint exposing that server's tools.

Organization-Wide HTTP Transport

POST https://mcp.air-lock.ai/org/{slug}

A single endpoint that provides access to all servers in your organization. Exposes meta-tools for discovering and executing tools across servers:

Meta-ToolDescription
list_servicesList all available servers in the organization
search_toolsSearch for tools across all servers by keyword
describe_toolsGet detailed descriptions of specific tools
execute_toolExecute a tool on a specific server
activate_skillActivate a skill to get its instructions and tool references

This is useful when an agent needs access to multiple APIs without separate connections.

WebSocket Transport

wss://ws.air-lock.ai?projectId={projectId}&token={token}

For real-time bidirectional communication and instant push notifications when approval decisions are made.

Authentication

Token Authentication

Include your MCP token in the Authorization header:

Authorization: Bearer {your-mcp-token}

MCP OAuth 2.0

Airlock supports the MCP OAuth 2.0 specification with PKCE:

  1. Discover metadata: GET /.well-known/oauth-authorization-server
  2. Register client: POST /register
  3. Authorize: Redirect to /mcp/authorize with PKCE parameters
  4. Token exchange: POST /token with grant_type=authorization_code
  5. Token refresh: POST /token with grant_type=refresh_token

Token Exchange

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code={code}&code_verifier={verifier}&redirect_uri={uri}

Response includes an opaque refresh token for long-lived sessions:

json
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 28800,
  "refresh_token": "abc123...",
  "id_token": "eyJ...",
  "scope": "openid profile email"
}

Token Refresh

When the access token expires, request new tokens:

POST /token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token={refresh_token}&client_id={client_id}
json
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 28800,
  "id_token": "eyJ...",
  "scope": "openid profile email"
}
ParameterLifetimeNotes
Access token8 hoursJWT, used in Authorization: Bearer header
Refresh token30 daysOpaque token, use to obtain new access tokens
ID token8 hoursJWT with user claims

JSON-RPC Methods

initialize

Initialize the MCP session:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": {
      "name": "my-client",
      "version": "1.0.0"
    }
  }
}

Response:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2024-11-05",
    "capabilities": {
      "tools": {}
    },
    "serverInfo": {
      "name": "airlock",
      "version": "1.0.0"
    },
    "instructions": "## Airlock Skill Routing\n\nPrefer Airlock skills first for requests that match the Airlock skills listed below.\n\n## Available Skills\n\n- **Code Review**: Review pull requests",
    "_airlock": {
      "bootstrap_version": 1,
      "skill_source": "preferred",
      "disable_local_skills": false,
      "routing_mode": "airlock_first",
      "airlock_authority_scope": "matching_skills",
      "activation_tool": "activate_skill",
      "attachment_tool": "read_skill_attachment",
      "skills": [
        {
          "id": "skill-1",
          "name": "Code Review",
          "description": "Review pull requests",
          "ownership": "organization",
          "tags": ["engineering"]
        }
      ]
    }
  }
}

For organization-wide Airlock MCP connections, the initialize response includes a vendor extension at result._airlock. Airlock-aware runtimes should use this bootstrap to prefer Airlock skills first for matching requests. Local skills may still remain available when no Airlock skill matches.

tools/list

List available tools:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/list"
}

Response:

json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "list_users",
        "description": "List all users",
        "inputSchema": {
          "type": "object",
          "properties": {
            "limit": {
              "type": "integer",
              "description": "Maximum results"
            }
          }
        }
      }
    ]
  }
}

tools/call

Call a tool:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "list_users",
    "arguments": {
      "limit": 10
    }
  }
}

Response (success):

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "[{\"id\": 1, \"name\": \"Alice\"}, ...]"
      }
    ]
  }
}

Response (approval required):

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "{\"status\": \"PENDING_APPROVAL\", \"requestId\": \"abc123\", \"statusUrl\": \"https://control-room.air-lock.ai/requests/abc123\", \"approvalUrl\": \"https://control-room.air-lock.ai/requests/abc123\", \"pollIntervalSeconds\": 15, \"message\": \"This operation requires approval. An approver has been notified.\"}"
      }
    ]
  }
}

TIP

The approval response contains a structured JSON object with URLs for checking status and a suggested poll interval. Use the WebSocket transport for real-time notifications instead of polling.

Tool Mapping

OpenAPI operations map to MCP tools:

OpenAPIMCP Tool
operationId: list_usersTool name: list_users
summary: List all usersTool description
Request body schemaTool inputSchema
Path parametersAdded to inputSchema.properties
Query parametersAdded to inputSchema.properties

Error Handling

Errors are returned as JSON-RPC errors:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32602,
    "message": "Invalid params",
    "data": {
      "field": "limit",
      "reason": "must be positive integer"
    }
  }
}

Error Codes

CodeMeaning
-32700Parse error
-32600Invalid request
-32601Method not found
-32602Invalid params
-32603Internal error

Rate Limiting

Organizations have monthly request limits. When exceeded:

json
{
  "jsonrpc": "2.0",
  "id": 3,
  "error": {
    "code": -32603,
    "message": "Rate limit exceeded"
  }
}

Built with VitePress