Appearance
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
Airlock exposes a single MCP HTTP endpoint per organization. Both URLs below are served by the same handler; agents can use either:
POST https://mcp.air-lock.ai/org/{slug}
POST https://mcp.air-lock.ai/The endpoint provides access to all servers in your organization through meta-tools:
| Meta-Tool | Description |
|---|---|
list_services | List all available servers in the organization |
search_tools | Search for tools across all servers by keyword |
describe_tools | Get detailed descriptions of specific tools |
execute_tool | Execute a tool on a specific server |
activate_skill | Activate a skill to get its instructions and tool references |
Used by Claude Desktop, Claude Code, Augment, and other MCP clients.
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:
- Discover metadata:
GET /.well-known/oauth-authorization-server - Register client:
POST /register - Authorize: Redirect to
/mcp/authorizewith PKCE parameters - Token exchange:
POST /tokenwithgrant_type=authorization_code - Token refresh:
POST /tokenwithgrant_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"
}| Parameter | Lifetime | Notes |
|---|---|---|
| Access token | 8 hours | JWT, used in Authorization: Bearer header |
| Refresh token | 30 days | Opaque token, use to obtain new access tokens |
| ID token | 8 hours | JWT 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.
Skill catalog visibility depends on the client
The skills catalog is delivered in result.instructions and result._airlock.skills, but only clients that forward initialize.result.instructions to the model as system context surface it to the agent. Claude Code and claude.ai do this; the Anthropic Managed Agents runtime does not (verified 2026-04-21). For runtimes that drop result.instructions, instruct the agent in its system prompt to call airlock-management/list_skills (via execute_tool) before activate_skill. See the Skills guide for the workaround and a copy-paste prompt fragment.
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 pollIntervalSeconds. Approvers are notified by email; the agent observes the decision by polling the status URL or, if the client implements SEP-1686 tasks, by polling tasks/get with the returned taskId. Clients that implement SEP-1036 elicitation can prompt the human user to open the approval URL directly.
Tool Mapping
OpenAPI operations map to MCP tools:
| OpenAPI | MCP Tool |
|---|---|
operationId: list_users | Tool name: list_users |
summary: List all users | Tool description |
| Request body schema | Tool inputSchema |
| Path parameters | Added to inputSchema.properties |
| Query parameters | Added 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
| Code | Meaning |
|---|---|
| -32700 | Parse error |
| -32600 | Invalid request |
| -32601 | Method not found |
| -32602 | Invalid params |
| -32603 | Internal error |
Rate Limiting
Organizations have monthly request limits. When exceeded:
json
{
"jsonrpc": "2.0",
"id": 3,
"error": {
"code": -32603,
"message": "Rate limit exceeded"
}
}