MCP Server
Model Context Protocol server reference for querying proxy logs with AI assistants.
Apoxy exposes an MCP server that lets AI assistants query your Envoy proxy access logs using PRQL. Any MCP-compatible client (Claude Code, Claude Desktop, Cursor, etc.) can connect and use the tools described below.
For Claude Code users, the Apoxy Claude plugin provides the MCP connection plus a skill that teaches Claude effective query patterns. See the integration guide for setup instructions.
Endpoint
https://api.apoxy.dev/mcpThe server uses the StreamableHTTP transport.
Authentication
All requests require a Bearer token in the Authorization header:
Authorization: Bearer <api-key>To create an API key, open the Apoxy console, click your avatar, go to Account Settings > API Keys, and create a new key. Keys are scoped to your project. You can have multiple active keys and set expiration dates.
Requests without a valid token receive 401 Unauthorized.
Tools
describe_schema
List all available log fields, their types, sources, and descriptions. Call this first to discover what you can query.
Parameters: None.
Response fields:
| Field | Type | Description |
|---|---|---|
name | string | Field name to use in PRQL queries (e.g., http.response.status_code). |
type | string | One of string, integer, float, uuid, timestamp. |
source | string | Where the field lives: LogAttributes, ResourceAttributes, or empty for top-level columns. |
description | string | Human-readable description. |
query
Execute a PRQL query against your proxy access logs.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
prql | string | Yes | PRQL query string. The table source is implicit — start with filter, select, derive, group, sort, or take. |
start_time | string | No | Start of time range (RFC 3339). Defaults to 24 hours ago. |
end_time | string | No | End of time range (RFC 3339). Defaults to now. |
cursor | string | No | Pagination cursor from a previous response. Both start_time and end_time are required when using a cursor. |
Queries without take default to 1000 rows. The maximum is 10000 rows. Use cursor pagination for larger result sets.
Response fields:
| Field | Type | Description |
|---|---|---|
rows | array | Result rows, each containing a fields map of column name to value. |
columns | array | Column metadata (name, type) for each column in the result. |
next_cursor | string | Pagination cursor. Empty if no more results. |
total_rows | integer | Number of rows returned in this page. |
compiled_sql | string | The SQL that was executed (useful for debugging). |
Log fields
The logs are Envoy access log entries collected via OpenTelemetry. Fields fall into three categories:
Top-level columns — Standard OpenTelemetry log fields:
| Field | Type | Description |
|---|---|---|
Timestamp | timestamp | Event timestamp (DateTime64). |
TimestampTime | timestamp | Truncated timestamp (DateTime), useful for grouping. |
Body | string | Log message body. |
ServiceName | string | Service name. |
SeverityText | string | Log severity text. |
SeverityNumber | integer | Log severity number (UInt8). |
TraceId | string | Trace correlation ID. |
SpanId | string | Span correlation ID. |
TraceFlags | integer | Trace flags (UInt8). |
EventName | string | Event name. |
LogAttributes — Envoy access log fields (use backtick-quoted names in PRQL):
| Field | Type | Description |
|---|---|---|
`http.request.method` | string | HTTP request method. |
`http.response.status_code` | integer | HTTP response status code. |
`url.path` | string | Request URL path. |
`client.address` | string | Client IP:port. |
`upstream.address` | string | Upstream host address. |
`upstream.cluster` | string | Envoy upstream cluster name. |
`http.request.duration_ms` | float | Request duration in milliseconds. |
`http.request.body.size` | integer | Request body bytes. |
`http.response.body.size` | integer | Response body bytes. |
`http.request.id` | uuid | Request UUID. |
`user_agent.original` | string | User-Agent header. |
`network.protocol.name` | string | Protocol (HTTP/1.1, HTTP/2). |
`url.host` | string | Request host header. |
`envoy.response_flags` | string | Envoy response flags. |
ResourceAttributes — Infrastructure metadata:
| Field | Type | Description |
|---|---|---|
`cluster_name` | string | Cluster identifier. |
`log_name` | string | Log source name. |
`project_id` | uuid | Project UUID. |
`node_name` | string | Node UUID. |
`service.name` | string | Service name. |
`zone_name` | string | Zone identifier. |
Additional fields may be discovered dynamically from the data. Use describe_schema to see the current full list.
How field rewriting works
Log attribute and resource attribute fields are stored as strings internally. The query engine automatically rewrites backtick-quoted field names to the appropriate storage-level access expressions and aliases them back to clean names in your results:
`url.path`→ accessed from log attributes, returned asurl.path`cluster_name`→ accessed from resource attributes, returned ascluster_name
Integer and float fields are automatically cast to their numeric types, so you can use numeric comparisons and aggregations directly. String literals in filter expressions (e.g., "/api/users") are left untouched.
The engine also injects WHERE conditions for project filtering and time range automatically — these appear in compiled_sql but don't need to be written in your query.
PRQL quick reference
Queries are pipelines of transforms. The table source is implicit — start directly with transforms.
# Filter 5xx errors in the last hour
filter `http.response.status_code` >= 500
select {Timestamp, `url.path`, `http.response.status_code`}
sort {-Timestamp}# Count requests by status code
group {`http.response.status_code`} (aggregate {count = count this})# Compute a derived column
derive {is_error = `http.response.status_code` >= 400}
select {Timestamp, `url.path`, is_error}# Limit results
sort {-Timestamp}
take 10See the PRQL language reference for the full syntax.
Rate limits
Rate limits apply per project. Contact support if you need higher limits.