Skip to content

MCP Server

Glasstrace exposes five debugging tools to AI coding agents via the Model Context Protocol (MCP). Your agent connects once, then queries traces, errors, and root cause analysis directly from your development session.

SettingValue
Endpointhttps://api.glasstrace.dev/mcp
ProtocolStreamable HTTP
AuthAuthorization: Bearer <your-api-key>

The bearer token is either your anonymous key (from .glasstrace/anon_key, generated automatically by the SDK) or your developer key (GLASSTRACE_API_KEY environment variable).

Test connectivity with curl:

Terminal window
curl -X POST https://api.glasstrace.dev/mcp \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}},"id":1}'

A successful response returns a JSON-RPC result with the server’s capabilities and tool list.

Glasstrace registers five tools with the MCP server. Each tool returns a ToolResponseWrapper envelope:

// Success
{ success: true, data: { /* tool-specific response */ } }
// Failure
{ success: false, diagnostic: { reason: string, message: string, upgradeUrl?: string, dataPreserved?: boolean } }

Returns the most recent error trace in your session, including the full span tree. This is the tool your agent should call first when something breaks.

None. This tool operates on the current session automatically.

interface GetLatestErrorResponse {
summary: TraceSummary;
spans: SpanSummary[];
}

Available on all tiers (Anonymous, Free Trial, Pro).

Request:

{}

Response:

{
"success": true,
"data": {
"summary": {
"traceId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"route": "POST /api/polls/create",
"statusCode": 500,
"error": "PrismaClientKnownRequestError: Unique constraint failed on the fields: (`slug`)",
"errorCategory": "foreign-key-violation",
"affectedComponent": "prisma",
"duration": 142,
"timestamp": 1712534400000,
"enrichmentStatus": "completed"
},
"spans": [
{
"name": "POST /api/polls/create",
"layer": "server",
"duration": 142,
"status": "ERROR",
"error": "PrismaClientKnownRequestError",
"children": [
{
"name": "prisma:client:operation polls.create",
"layer": "database",
"duration": 38,
"status": "ERROR",
"error": "Unique constraint failed on the fields: (`slug`)"
}
]
}
]
}
}
{
"success": false,
"diagnostic": {
"reason": "no_traces_found",
"message": "No error traces found in the current session. This could mean no errors have occurred, or traces have expired."
}
}

Search for traces by URL, HTTP method, status code, time window, or correlation ID. Results are paginated (default 20 per page, max 100).

NameTypeDefaultDescription
urlstringFilter by request URL (exact match on route)
methodstringFilter by HTTP method (GET, POST, etc.)
statusCodenumberFilter by HTTP status code
timeWindow{ start: number, end: number }Filter by timestamp range (milliseconds since epoch)
correlationIdstringFilter by browser extension correlation ID
cursorstringPagination cursor from a previous response
limitnumber20Number of results per page (max 100)

All parameters are optional.

interface GetTraceResponse {
items: Array<{
summary: TraceSummary;
spans: SpanSummary[];
}>;
cursor?: string;
hasMore: boolean;
}

Available on all tiers (Anonymous, Free Trial, Pro).

Request:

{
"url": "/api/polls",
"method": "POST",
"statusCode": 500,
"limit": 5
}

Response:

{
"success": true,
"data": {
"items": [
{
"summary": {
"traceId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"route": "POST /api/polls/create",
"statusCode": 500,
"error": "Unique constraint failed on the fields: (`slug`)",
"duration": 142,
"timestamp": 1712534400000
},
"spans": [
{
"name": "POST /api/polls/create",
"layer": "server",
"duration": 142,
"status": "ERROR",
"children": []
}
]
}
],
"cursor": "eyJ0IjoxNzEyNTM0NDAwMDAwLCJpIjoiYWJjMTIzIn0",
"hasMore": true
}
}
{
"success": false,
"diagnostic": {
"reason": "no_traces_found",
"message": "No traces match your filters. Try broadening the time window or removing filters."
}
}

Returns AI-powered root cause analysis for a specific trace. The enrichment pipeline runs asynchronously after trace ingestion. This tool returns immediately with whatever data is available — it never blocks on an LLM call.

NameTypeDefaultDescription
traceIdstringRequired. The trace ID to analyze.

The response is a discriminated union based on status:

// status: "completed" — enrichment finished successfully
interface GetRootCauseCompleted {
status: "completed";
rootCause: string;
affectedComponent: string;
errorCategory: string;
suggestedFix: string;
confidence: number; // 0 to 1
relatedContext?: string;
codeLocation?: { file: string; line: number; column?: number };
}
// status: "pending" — enrichment is still running
interface GetRootCausePending {
status: "pending";
message: string;
estimatedWaitMs?: number;
}
// status: "failed" — enrichment failed
interface GetRootCauseFailed {
status: "failed";
reason: string;
message: string;
}
// status: "unavailable" — anonymous tier (no enrichment)
interface GetRootCauseUnavailable {
status: "unavailable";
summary: TraceSummary;
spans: SpanSummary[];
message: string;
upgradeUrl?: string;
}
  • Anonymous: Returns status: "unavailable" with raw trace data (TraceSummary and span tree included). No AI analysis.
  • Free Trial / Pro: Returns enrichment result (completed, pending, or failed).

Request:

{
"traceId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}

Response:

{
"success": true,
"data": {
"status": "completed",
"rootCause": "The slug generation does not check for existing slugs before inserting. When two polls have the same title, the derived slug collides.",
"affectedComponent": "prisma",
"errorCategory": "foreign-key-violation",
"suggestedFix": "Add a uniqueness check or append a random suffix to the slug before inserting.",
"confidence": 0.92,
"codeLocation": {
"file": "src/app/api/polls/create/route.ts",
"line": 24
}
}
}
{
"success": true,
"data": {
"status": "pending",
"message": "Root cause analysis is in progress. Call again in a few seconds.",
"estimatedWaitMs": 3000
}
}
{
"success": true,
"data": {
"status": "unavailable",
"summary": {
"traceId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d",
"route": "POST /api/polls/create",
"statusCode": 500,
"error": "Unique constraint failed on the fields: (`slug`)",
"duration": 142,
"timestamp": 1712534400000
},
"spans": [
{
"name": "POST /api/polls/create",
"layer": "server",
"duration": 142,
"status": "ERROR",
"children": []
}
],
"message": "AI root cause analysis requires a trial or pro account. Raw trace data is included above.",
"upgradeUrl": "https://glasstrace.dev/signup"
}
}

Enrichment failed:

{
"success": false,
"diagnostic": {
"reason": "enrichment_failed",
"message": "Automated analysis was inconclusive. Please try again or investigate manually."
}
}

Returns regression test ideas based on trace data and (optionally) the import graph. The response has three parts:

  • Part 1 — Coverage map (paid tier only): Shows which code paths are tested and untested, derived from the import graph. Requires coverageMapEnabled on your tier (Free Trial or Pro). Enable import graph capture by setting GLASSTRACE_COVERAGE_MAP=true in your project.
  • Part 2 — Regression tests: Specific test cases to catch the error that occurred.
  • Part 3 — Prevention tests: Broader test ideas to prevent similar errors.

Parts 2 and 3 are available on all tiers. Anonymous users receive Parts 2 and 3 only — the coverage map field will contain empty arrays.

NameTypeDefaultDescription
traceIdstringRequired. The trace ID to generate test suggestions for.
interface GetTestSuggestionsResponse {
coverage: {
testedPaths: string[];
untestedPaths: string[];
coveragePercent: number; // 0 to 100
};
regressionTests: Array<{
name: string;
description: string;
targetPath: string;
}>;
preventionTests: Array<{
name: string;
description: string;
targetPath: string;
}>;
}
  • Anonymous: Parts 2 and 3 only (regression and prevention tests). Coverage map fields return empty arrays and coveragePercent: 0.
  • Free Trial / Pro: All three parts, including coverage map. Requires coverageMapEnabled feature flag (true for Free Trial and Pro).

Request:

{
"traceId": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d"
}

Response (paid tier, with coverage map):

{
"success": true,
"data": {
"coverage": {
"testedPaths": ["src/app/api/polls/create/route.ts"],
"untestedPaths": ["src/app/api/polls/[id]/route.ts", "src/lib/slug.ts"],
"coveragePercent": 33
},
"regressionTests": [
{
"name": "duplicate slug collision",
"description": "Create two polls with identical titles and verify the second receives a unique slug.",
"targetPath": "src/app/api/polls/create/route.ts"
}
],
"preventionTests": [
{
"name": "slug uniqueness validation",
"description": "Verify that the slug generation function appends a suffix when a collision is detected.",
"targetPath": "src/lib/slug.ts"
}
]
}
}

The handler always returns success: true. When the coverage map is unavailable (anonymous tier or no import graph), the coverage fields contain empty arrays and coveragePercent: 0. Regression and prevention tests are always generated from trace data.

{
"success": false,
"diagnostic": {
"reason": "no_traces_found",
"message": "No trace found with ID a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5d."
}
}

Returns a chronological timeline of traces in a session (default 200, max 500). When results are truncated, hasMore is true so the caller knows additional pages exist. Use this to understand the sequence of requests your application handled.

NameTypeDefaultDescription
sessionIdstringFilter by session ID. If omitted, uses the current session.
interface GetSessionTimelineResponse {
items: TraceSummary[];
cursor?: string;
hasMore: boolean;
}

Available on all tiers (Anonymous, Free Trial, Pro).

Request:

{
"sessionId": "abcdef1234567890"
}

Response:

{
"success": true,
"data": {
"items": [
{
"traceId": "11111111-1111-4111-8111-111111111111",
"route": "GET /api/polls",
"statusCode": 200,
"duration": 45,
"timestamp": 1712534400000
},
{
"traceId": "22222222-2222-4222-8222-222222222222",
"route": "POST /api/polls/create",
"statusCode": 500,
"error": "Unique constraint failed",
"duration": 142,
"timestamp": 1712534460000
},
{
"traceId": "33333333-3333-4333-8333-333333333333",
"route": "GET /api/polls",
"statusCode": 200,
"duration": 38,
"timestamp": 1712534520000
}
],
"hasMore": false
}
}
{
"success": false,
"diagnostic": {
"reason": "no_traces_found",
"message": "No traces found for this session. The session may have expired or no requests have been captured yet."
}
}

Every tool that returns trace data uses the TraceSummary type:

interface TraceSummary {
traceId: string;
clientAction?: string;
route: string;
statusCode: number;
error?: string;
errorCode?: string;
errorCategory?: "foreign-key-violation" | "auth-failure" | "timeout" | "not-found" | "validation-error" | "connection-error" | "unknown";
affectedComponent?: string;
duration: number; // milliseconds
timestamp: number; // milliseconds since epoch
correlationConfidence?: "high" | "medium" | "low";
sourceLocation?: { file: string; line: number; mapped: boolean };
enrichmentStatus?: "pending" | "processing" | "completed" | "failed";
}

Span trees represent the request lifecycle:

interface SpanSummary {
name: string;
layer: "server" | "database" | "external";
duration: number; // milliseconds
status: string;
error?: string;
children?: SpanSummary[];
}

Error and empty-state responses use the ToolDiagnostic type:

interface ToolDiagnostic {
reason: "no_traces_found" | "ttl_expired" | "subscription_required" | "enrichment_pending" | "enrichment_failed" | "database_unreachable" | "tier_insufficient" | "data_not_available" | "invalid_input" | "internal_error";
message: string;
upgradeUrl?: string;
dataPreserved?: boolean;
}

Every MCP tool response is wrapped in this envelope:

// Success
{ success: true, data: { /* tool-specific response */ } }
// Failure
{ success: false, diagnostic: ToolDiagnostic }
FeatureAnonymousFree TrialPro
get_latest_errorAll dataAll dataAll data
get_traceAll dataAll dataAll data
get_session_timelineAll dataAll dataAll data
get_root_cause — raw traceYesYesYes
get_root_cause — AI analysisNoYesYes
get_test_suggestions — regression tests (Part 2)YesYesYes
get_test_suggestions — prevention tests (Part 3)YesYesYes
get_test_suggestions — coverage map (Part 1)NoYesYes
LimitAnonymousFree TrialPro
Traces per minute1005002,000
Storage TTL48 hours7 days90 days
Max trace size500 KB1 MB2 MB
Concurrent sessions1 (advisory)1 (advisory)10

Anonymous mode does not include LLM enrichment. Free Trial and Pro both use the best enrichment model (Anthropic).

Concurrent session limits are advisory, not enforced. If you exceed your tier’s limit, traces from all sessions are still accepted. The dashboard shows a nudge suggesting an upgrade.

Anonymous mode is free, requires no account, and never expires. Sign up for a Free Trial to enable AI-powered root cause analysis and the coverage map.

If you ran npx @glasstrace/sdk init, your agent’s MCP configuration was generated automatically. The instructions below are for manual setup or verification.

Manual fallback for any agent:

Terminal window
npx @glasstrace/sdk mcp add

Config file: .mcp.json (project root)

{
"mcpServers": {
"glasstrace": {
"type": "http",
"url": "https://api.glasstrace.dev/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}

Or register via CLI:

Terminal window
claude mcp add-json glasstrace '{"type":"http","url":"https://api.glasstrace.dev/mcp","headers":{"Authorization":"Bearer <your-api-key>"}}' --scope project

Config file: .codex/config.toml (project) or ~/.codex/config.toml (global)

[mcp_servers.glasstrace]
url = "https://api.glasstrace.dev/mcp"
bearer_token_env_var = "GLASSTRACE_API_KEY"

Set the environment variable in .env.local or export it in your shell:

Terminal window
export GLASSTRACE_API_KEY="<your-api-key>"

Or register via CLI:

Terminal window
codex mcp add glasstrace --url https://api.glasstrace.dev/mcp

Config file: .gemini/settings.json (project) or ~/.gemini/settings.json (global)

{
"mcpServers": {
"glasstrace": {
"httpUrl": "https://api.glasstrace.dev/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}

Or register via CLI:

Terminal window
gemini mcp add --transport http --header "Authorization: Bearer <your-api-key>" glasstrace https://api.glasstrace.dev/mcp

Config file: .cursor/mcp.json (project) or ~/.cursor/mcp.json (global). Requires Cursor v0.48.0+.

{
"mcpServers": {
"glasstrace": {
"url": "https://api.glasstrace.dev/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}

Cursor does not have a CLI registration command. Create the config file directly.

Config file: ~/.codeium/windsurf/mcp_config.json (global only — no project-scoped config).

{
"mcpServers": {
"glasstrace": {
"serverUrl": "https://api.glasstrace.dev/mcp",
"headers": {
"Authorization": "Bearer <your-api-key>"
}
}
}
}

Windsurf also supports environment variable interpolation:

{
"mcpServers": {
"glasstrace": {
"serverUrl": "https://api.glasstrace.dev/mcp",
"headers": {
"Authorization": "Bearer ${env:GLASSTRACE_API_KEY}"
}
}
}
}

Windsurf does not have a CLI registration command. Create the config file directly.