{ "openapi": "3.1.0", "info": { "title": "MCPJam API", "version": "1.0.0-preview", "description": "Programmatic access to MCP servers saved in your MCPJam projects — live diagnostics (validate, inspect, export) and operations: call tools, render prompts, run eval suites asynchronously and poll their results, and import OAuth tokens.\n\n**The API is in preview**: the surface may change while we finish the design. Error `code` values are stable; error `message` strings are not. Write clients that ignore unknown response fields.", "contact": { "name": "MCPJam", "url": "https://github.com/MCPJam/inspector/issues" } }, "servers": [ { "url": "https://app.mcpjam.com/api/v1", "description": "Hosted MCPJam" } ], "security": [{ "bearerAuth": [] }], "tags": [ { "name": "Server diagnostics", "description": "Connect-level health checks against a saved MCP server." }, { "name": "Primitives", "description": "The server's MCP primitives: tools, prompts, and resources." }, { "name": "Export", "description": "Full-server snapshots for diffing and CI." }, { "name": "Execution", "description": "Run the server's primitives: call tools, render prompts." }, { "name": "Eval runs", "description": "Asynchronous eval suite runs: create with 202, poll status, iterations, and traces." }, { "name": "OAuth", "description": "Bring-your-own OAuth: import externally obtained tokens for a server." } ], "paths": { "/projects/{projectId}/servers/{serverId}/validate": { "post": { "operationId": "validateServer", "tags": ["Server diagnostics"], "summary": "Validate a server", "description": "Connects to the server, initializes the MCP session, and returns a connection snapshot (server info, negotiated capabilities). The same check the hosted inspector runs when you connect a server.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/emptyBody" }, "responses": { "200": { "description": "Server connected and initialized.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidateResult" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/doctor": { "post": { "operationId": "runDoctor", "tags": ["Server diagnostics"], "summary": "Run the doctor", "description": "Runs the full doctor workflow — probe → connect → initialize → capabilities → primitives — and returns a step-by-step report. The richest signal for \"is this server healthy, and why not.\"", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/emptyBody" }, "responses": { "200": { "description": "Doctor report. `status` summarizes the outcome; per-step detail is in `checks`.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DoctorReport" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/check-oauth": { "post": { "operationId": "checkOAuth", "tags": ["Server diagnostics"], "summary": "Check OAuth requirement", "description": "Lightweight, no MCP connection: reports whether the server is configured to require an OAuth grant.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/emptyBody" }, "responses": { "200": { "description": "OAuth requirement for the server.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CheckOAuthResult" }, "example": { "useOAuth": true, "serverUrl": "https://mcp.example.com/mcp" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" } } } }, "/projects/{projectId}/servers/{serverId}/tools": { "post": { "operationId": "listTools", "tags": ["Primitives"], "summary": "List tools", "description": "Returns the server's tools as a collection page. Each item is the MCP tool definition (`name`, `description`, `inputSchema`, ...).", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/cursorBody" }, "responses": { "200": { "description": "One page of tools.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToolPage" }, "example": { "items": [ { "name": "create_issue", "description": "Create a new issue in the tracker", "inputSchema": { "type": "object", "properties": { "title": { "type": "string" } } } } ] } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/FeatureNotSupported" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/prompts": { "post": { "operationId": "listPrompts", "tags": ["Primitives"], "summary": "List prompts", "description": "Returns the server's prompts as a collection page.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/cursorBody" }, "responses": { "200": { "description": "One page of prompts.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PromptPage" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/FeatureNotSupported" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/resources": { "post": { "operationId": "listResources", "tags": ["Primitives"], "summary": "List resources", "description": "Returns the server's resources as a collection page.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/cursorBody" }, "responses": { "200": { "description": "One page of resources.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResourcePage" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/FeatureNotSupported" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/resources/read": { "post": { "operationId": "readResource", "tags": ["Primitives"], "summary": "Read a resource", "description": "Reads a single resource by URI and returns its contents.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["uri"], "properties": { "uri": { "type": "string", "description": "The resource URI, exactly as returned by the resources list.", "example": "file:///readme.md" } } } } } }, "responses": { "200": { "description": "The resource contents.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResourceContents" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/FeatureNotSupported" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/export": { "post": { "operationId": "exportServer", "tags": ["Export"], "summary": "Export a server snapshot", "description": "Lists tools, resources, and prompts in one call and returns a single JSON snapshot — handy for diffing a server's surface over time in CI.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "$ref": "#/components/requestBodies/emptyBody" }, "responses": { "200": { "description": "Full server snapshot.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExportSnapshot" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/tools/call": { "post": { "operationId": "callTool", "tags": ["Execution"], "summary": "Call a tool", "description": "Executes a tool on the server and returns the MCP `CallToolResult` directly. Tool-level failures (`isError: true` in the result) are **successful calls** — the server answered; only transport/auth errors use the error envelope.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["toolName"], "properties": { "toolName": { "type": "string", "description": "Tool name, exactly as returned by the tools list." }, "parameters": { "type": "object", "description": "Tool arguments matching the tool's `inputSchema`. Defaults to `{}`.", "additionalProperties": true } } }, "example": { "toolName": "create_issue", "parameters": { "title": "Bug: login fails" } } } } }, "responses": { "200": { "description": "The MCP `CallToolResult`. Check `isError` for tool-level failures.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CallToolResult" }, "example": { "content": [{ "type": "text", "text": "Issue created: #42" }] } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/FeatureNotSupported" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/servers/{serverId}/prompts/get": { "post": { "operationId": "getPrompt", "tags": ["Execution"], "summary": "Render a prompt", "description": "Renders a prompt with arguments and returns the MCP `GetPromptResult` directly (`description?`, `messages`).", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["promptName"], "properties": { "promptName": { "type": "string", "description": "Prompt name, exactly as returned by the prompts list." }, "arguments": { "type": "object", "description": "Prompt arguments. String, number, and boolean values.", "additionalProperties": { "type": ["string", "number", "boolean"] } } } }, "example": { "promptName": "summarize", "arguments": { "style": "bullet" } } } } }, "responses": { "200": { "description": "The MCP `GetPromptResult`.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GetPromptResult" } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/FeatureNotSupported" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/eval-runs": { "post": { "operationId": "createEvalRun", "tags": ["Eval runs"], "summary": "Create an eval run (async)", "description": "Creates a suite run from an existing `suiteId` (rerun) and/or inline `tests`, then **detaches execution and responds `202` immediately** with the `runId`. Validation and quota errors surface on this request; poll `GET /eval-runs/{runId}` for progress. The run appears live in the hosted UI Runs tab, tagged `source: \"api\"`.\n\nA bare `suiteId` with no inline tests reruns the suite as configured. Per-organization concurrency is capped (default 2 concurrent runs); exceeding it returns `429` with `details.reason: \"CONCURRENT_RUN_LIMIT\"`.", "parameters": [{ "$ref": "#/components/parameters/projectId" }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalRunCreateRequest" }, "example": { "suiteName": "smoke", "serverIds": ["srv_abc123"], "tests": [ { "title": "echo works", "query": "Use the echo tool to say hi", "runs": 1, "model": "claude-sonnet-4-6", "provider": "anthropic", "expectedToolCalls": [ { "toolName": "echo", "arguments": { "text": "hi" } } ] } ] } } } }, "responses": { "202": { "description": "Run created; execution continues in the background.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalRunCreated" }, "example": { "runId": "run_abc123", "suiteId": "suite_def456", "status": "running", "caseUpsert": { "committed": [{ "name": "echo works" }], "failed": [] } } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } }, "/projects/{projectId}/eval-runs/{runId}": { "get": { "operationId": "getEvalRun", "tags": ["Eval runs"], "summary": "Get run status", "description": "Run status, result, and summary. Poll until `status` is terminal (`completed`, `failed`, or `cancelled`).", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/runId" } ], "responses": { "200": { "description": "The run.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalRun" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" } } } }, "/projects/{projectId}/eval-runs/{runId}/iterations": { "get": { "operationId": "listEvalRunIterations", "tags": ["Eval runs"], "summary": "List run iterations", "description": "Per-iteration results: actual tool calls, structured token usage, and latency. Cursor-paginated.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/runId" }, { "name": "limit", "in": "query", "required": false, "description": "Page size, 1–200. Defaults to 50.", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 } }, { "name": "cursor", "in": "query", "required": false, "description": "Opaque cursor from a previous response's `nextCursor`.", "schema": { "type": "string" } } ], "responses": { "200": { "description": "One page of iterations.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalIterationPage" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" } } } }, "/projects/{projectId}/eval-runs/{runId}/iterations/{iterationId}/trace": { "get": { "operationId": "getEvalIterationTrace", "tags": ["Eval runs"], "summary": "Get an iteration trace", "description": "Full trace envelope for one iteration: conversation messages, expected-vs-actual tool call analysis, and spans. The shape is rich and may evolve — treat it as an open document. Returns `404` with `details.reason: \"TRACE_NOT_AVAILABLE\"` when the iteration finished without a stored trace.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/runId" }, { "$ref": "#/components/parameters/iterationId" } ], "responses": { "200": { "description": "The trace envelope.", "content": { "application/json": { "schema": { "type": "object", "description": "Trace document: `messages`, `prompts` (per-prompt expected/actual tool-call analysis), `spans`, and more.", "additionalProperties": true } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" } } } }, "/projects/{projectId}/eval-suites/{suiteId}/runs": { "get": { "operationId": "listEvalSuiteRuns", "tags": ["Eval runs"], "summary": "List a suite's runs", "description": "Recent runs for a suite, newest first.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/suiteId" }, { "name": "limit", "in": "query", "required": false, "description": "Maximum runs to return, 1–100. Defaults to 25.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } } ], "responses": { "200": { "description": "Recent runs, newest first.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EvalRunPage" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" } } } }, "/projects/{projectId}/servers/{serverId}/oauth/import-tokens": { "post": { "operationId": "importOAuthTokens", "tags": ["OAuth"], "summary": "Import OAuth tokens", "description": "Stores OAuth tokens you obtained yourself (e.g. via the SDK's `runOAuthLogin` — interactive loopback, headless, or client-credentials) for this server, scoped to your user, project, and server. Subsequent API calls against the server inject the stored access token automatically, and `401`s from the server trigger a server-side refresh — no further caller involvement.\n\nThis closes the loop after an `OAUTH_REQUIRED` error.", "parameters": [ { "$ref": "#/components/parameters/projectId" }, { "$ref": "#/components/parameters/serverId" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportTokensRequest" }, "example": { "serverUrl": "https://mcp.example.com/mcp", "clientInformation": { "clientId": "client_123" }, "tokens": { "access_token": "at_…", "refresh_token": "rt_…", "expires_in": 3600 } } } } }, "responses": { "200": { "description": "Tokens stored.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImportTokensResult" }, "example": { "imported": true, "expiresAt": 1781142000000 } } } }, "400": { "$ref": "#/components/responses/ValidationError" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" }, "500": { "$ref": "#/components/responses/InternalError" }, "502": { "$ref": "#/components/responses/ServerUnreachable" }, "504": { "$ref": "#/components/responses/Timeout" } } } } }, "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "MCPJam API key (`sk_…`). Create one at [Settings → API keys](https://app.mcpjam.com/settings/api-keys). Guest sessions cannot use the API, and API keys cannot manage other API keys." } }, "parameters": { "projectId": { "name": "projectId", "in": "path", "required": true, "description": "ID of the hosted project that contains the server.", "schema": { "type": "string" } }, "serverId": { "name": "serverId", "in": "path", "required": true, "description": "ID of the server inside the project.", "schema": { "type": "string" } }, "runId": { "name": "runId", "in": "path", "required": true, "description": "Eval run ID, as returned by `POST /eval-runs`.", "schema": { "type": "string" } }, "iterationId": { "name": "iterationId", "in": "path", "required": true, "description": "Iteration ID, as returned by the run's iterations list.", "schema": { "type": "string" } }, "suiteId": { "name": "suiteId", "in": "path", "required": true, "description": "Eval suite ID, as returned by `POST /eval-runs`.", "schema": { "type": "string" } } }, "requestBodies": { "emptyBody": { "required": false, "description": "Accepts an empty JSON object.", "content": { "application/json": { "schema": { "type": "object", "properties": {} }, "example": {} } } }, "cursorBody": { "required": false, "description": "Optional pagination cursor.", "content": { "application/json": { "schema": { "type": "object", "properties": { "cursor": { "type": "string", "description": "Opaque pagination cursor from a previous response's `nextCursor`. Don't parse it." } } }, "example": {} } } } }, "schemas": { "Error": { "type": "object", "required": ["code", "message"], "properties": { "code": { "type": "string", "description": "Stable, machine-readable error code. New codes may be added over time; treat unknown codes as non-retryable failures unless the HTTP status says otherwise.", "enum": [ "UNAUTHORIZED", "FORBIDDEN", "NOT_FOUND", "VALIDATION_ERROR", "RATE_LIMITED", "FEATURE_NOT_SUPPORTED", "SERVER_UNREACHABLE", "TIMEOUT", "OAUTH_REQUIRED", "INTERNAL_ERROR" ] }, "message": { "type": "string", "description": "Human-readable description. May change between releases — don't match on it." }, "details": { "type": "object", "description": "Optional, unstructured context bag.", "additionalProperties": true } } }, "ValidateResult": { "type": "object", "required": ["success", "status"], "properties": { "success": { "type": "boolean", "const": true }, "status": { "type": "string", "const": "connected" }, "initInfo": { "type": ["object", "null"], "description": "MCP initialization snapshot: server info, negotiated protocol version, and capabilities. `null` if the server connected but initialization data was unavailable.", "additionalProperties": true } } }, "DoctorReport": { "type": "object", "description": "Step-by-step health report from the probe → connect → initialize → capabilities workflow.", "required": ["generatedAt", "status", "connection", "checks"], "properties": { "generatedAt": { "type": "string", "format": "date-time", "description": "When the report was generated." }, "status": { "type": "string", "enum": ["ready", "oauth_required", "partial", "error"], "description": "Overall outcome. `partial` means the server connected but some primitive listings failed." }, "probe": { "type": ["object", "null"], "description": "Transport-level probe result (HTTP reachability, protocol hints), or `null` when skipped.", "additionalProperties": true }, "connection": { "type": "object", "required": ["status", "detail"], "properties": { "status": { "type": "string", "enum": ["connected", "error", "skipped"] }, "detail": { "type": "string" } } }, "initInfo": { "type": ["object", "null"], "additionalProperties": true }, "capabilities": { "type": ["object", "null"], "description": "The server's negotiated MCP capabilities.", "additionalProperties": true }, "tools": { "type": "array", "items": { "$ref": "#/components/schemas/Tool" } }, "resources": { "type": "array", "items": { "$ref": "#/components/schemas/Resource" } }, "resourceTemplates": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "prompts": { "type": "array", "items": { "$ref": "#/components/schemas/Prompt" } }, "checks": { "type": "object", "description": "Per-step status. Each check is `{ status: ok | error | skipped, detail }`.", "properties": { "probe": { "$ref": "#/components/schemas/DoctorCheck" }, "connection": { "$ref": "#/components/schemas/DoctorCheck" }, "initialization": { "$ref": "#/components/schemas/DoctorCheck" }, "capabilities": { "$ref": "#/components/schemas/DoctorCheck" }, "tools": { "$ref": "#/components/schemas/DoctorCheck" }, "resources": { "$ref": "#/components/schemas/DoctorCheck" }, "resourceTemplates": { "$ref": "#/components/schemas/DoctorCheck" }, "prompts": { "$ref": "#/components/schemas/DoctorCheck" } } }, "error": { "oneOf": [ { "type": "null" }, { "type": "object", "required": ["code", "message"], "properties": { "code": { "type": "string" }, "message": { "type": "string" }, "details": {} } } ], "description": "Terminal error, or `null` when the workflow completed." } }, "additionalProperties": true }, "DoctorCheck": { "type": "object", "required": ["status", "detail"], "properties": { "status": { "type": "string", "enum": ["ok", "error", "skipped"] }, "detail": { "type": "string" } } }, "CheckOAuthResult": { "type": "object", "required": ["useOAuth", "serverUrl"], "properties": { "useOAuth": { "type": "boolean", "description": "Whether the server is configured to require an OAuth grant." }, "serverUrl": { "type": ["string", "null"], "description": "The server's URL, or `null` for non-HTTP transports." } } }, "Tool": { "type": "object", "description": "MCP tool definition, as returned by the server.", "required": ["name"], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "inputSchema": { "type": "object", "description": "JSON Schema for the tool's arguments.", "additionalProperties": true }, "outputSchema": { "type": "object", "description": "JSON Schema for the tool's structured output, when declared.", "additionalProperties": true } }, "additionalProperties": true }, "Prompt": { "type": "object", "description": "MCP prompt definition, as returned by the server.", "required": ["name"], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "arguments": { "type": "array", "items": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "description": { "type": "string" }, "required": { "type": "boolean" } }, "additionalProperties": true } } }, "additionalProperties": true }, "Resource": { "type": "object", "description": "MCP resource descriptor, as returned by the server.", "required": ["uri"], "properties": { "uri": { "type": "string" }, "name": { "type": "string" }, "description": { "type": "string" }, "mimeType": { "type": "string" } }, "additionalProperties": true }, "ResourceContents": { "type": "object", "description": "MCP read-resource result.", "required": ["contents"], "properties": { "contents": { "type": "array", "items": { "type": "object", "required": ["uri"], "properties": { "uri": { "type": "string" }, "mimeType": { "type": "string" }, "text": { "type": "string", "description": "Present for text resources." }, "blob": { "type": "string", "description": "Base64-encoded payload, present for binary resources." } }, "additionalProperties": true } } }, "additionalProperties": true }, "ToolPage": { "type": "object", "required": ["items"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Tool" } }, "nextCursor": { "type": "string", "description": "Opaque cursor for the next page. Omitted on the last page." } } }, "PromptPage": { "type": "object", "required": ["items"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Prompt" } }, "nextCursor": { "type": "string", "description": "Opaque cursor for the next page. Omitted on the last page." } } }, "ResourcePage": { "type": "object", "required": ["items"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Resource" } }, "nextCursor": { "type": "string", "description": "Opaque cursor for the next page. Omitted on the last page." } } }, "CallToolResult": { "type": "object", "description": "MCP tool execution result, returned verbatim from the server.", "required": ["content"], "properties": { "content": { "type": "array", "description": "Content blocks (`text`, `image`, `resource`, ...).", "items": { "type": "object", "additionalProperties": true } }, "structuredContent": { "type": "object", "description": "Structured output matching the tool's `outputSchema`, when declared.", "additionalProperties": true }, "isError": { "type": "boolean", "description": "`true` when the **tool** reported a failure. The HTTP call still succeeds — the server answered." } }, "additionalProperties": true }, "GetPromptResult": { "type": "object", "description": "MCP prompt render result, returned verbatim from the server.", "required": ["messages"], "properties": { "description": { "type": "string" }, "messages": { "type": "array", "items": { "type": "object", "required": ["role", "content"], "properties": { "role": { "type": "string", "enum": ["user", "assistant"] }, "content": { "description": "MCP prompt message content block.", "additionalProperties": true } }, "additionalProperties": true } } }, "additionalProperties": true }, "EvalTestCase": { "type": "object", "description": "Inline eval test case. Same shape the hosted eval editor produces.", "required": ["title", "query", "runs", "model", "provider", "expectedToolCalls"], "properties": { "title": { "type": "string" }, "query": { "type": "string", "description": "The user prompt the model is given." }, "runs": { "type": "integer", "minimum": 1, "maximum": 10, "description": "Iterations to execute for this case." }, "model": { "type": "string", "description": "Model ID, e.g. `claude-sonnet-4-6`." }, "provider": { "type": "string", "description": "Model provider, e.g. `anthropic`, `openai`." }, "expectedToolCalls": { "type": "array", "description": "Tool calls the model is expected to make. Empty array for negative tests.", "items": { "type": "object", "required": ["toolName", "arguments"], "properties": { "toolName": { "type": "string" }, "arguments": { "type": "object", "additionalProperties": true } } } }, "isNegativeTest": { "type": "boolean", "description": "When `true`, the case passes if NO tools are called." }, "expectedOutput": { "type": "string" }, "advancedConfig": { "type": "object", "description": "Optional `system`, `temperature`, `toolChoice` overrides.", "additionalProperties": true } }, "additionalProperties": true }, "EvalRunCreateRequest": { "type": "object", "description": "Two valid shapes: `suiteId` (rerun an existing suite, optionally upserting inline `tests` into it), or `suiteName` + `tests` (create a new suite and run it). Inline `tests` alone — without a `suiteId` or a `suiteName` — are rejected with `VALIDATION_ERROR`.", "required": ["serverIds"], "anyOf": [ { "required": ["suiteId"] }, { "required": ["suiteName", "tests"], "properties": { "tests": { "minItems": 1 } } } ], "properties": { "suiteId": { "type": "string", "description": "Existing suite to rerun. A bare `suiteId` with no `tests` reruns the suite exactly as configured." }, "suiteName": { "type": "string", "description": "Name for a new suite. Required (non-empty) when no `suiteId` is given." }, "suiteDescription": { "type": "string" }, "tests": { "type": "array", "maxItems": 100, "description": "Inline test cases to upsert into the suite before running.", "items": { "$ref": "#/components/schemas/EvalTestCase" } }, "serverIds": { "type": "array", "minItems": 1, "description": "Servers (by ID) the run connects to.", "items": { "type": "string" } }, "modelApiKeys": { "type": "object", "description": "Optional per-provider model API keys (e.g. `{ \"anthropic\": \"sk-ant-…\" }`). Falls back to your organization's configured providers when omitted.", "additionalProperties": { "type": "string" } }, "notes": { "type": "string" }, "passCriteria": { "type": "object", "properties": { "minimumPassRate": { "type": "number" } } }, "iterationOverride": { "type": "integer", "minimum": 1, "maximum": 10, "description": "Override the per-case `runs` count for this run only." } }, "additionalProperties": true }, "EvalRunCreated": { "type": "object", "required": ["runId", "suiteId", "status", "caseUpsert"], "properties": { "runId": { "type": "string" }, "suiteId": { "type": "string" }, "status": { "type": "string", "const": "running" }, "caseUpsert": { "type": "object", "description": "Per-case upsert outcomes for inline `tests`. Partial failures don't abort the run.", "properties": { "committed": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" } } } }, "failed": { "type": "array", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "error": { "type": "string" } } } } } } } }, "EvalRun": { "type": "object", "required": ["id", "suiteId", "status", "source", "createdAt"], "properties": { "id": { "type": "string" }, "suiteId": { "type": "string" }, "runNumber": { "type": ["integer", "null"] }, "status": { "type": "string", "description": "Poll until terminal: `completed`, `failed`, or `cancelled`.", "enum": ["pending", "running", "completed", "failed", "cancelled"] }, "result": { "type": ["string", "null"], "description": "Pass/fail verdict once terminal.", "enum": ["passed", "failed", null] }, "summary": { "type": ["object", "null"], "properties": { "total": { "type": "integer" }, "passed": { "type": "integer" }, "failed": { "type": "integer" }, "passRate": { "type": "number" } } }, "source": { "type": "string", "description": "Run origin. API-created runs are `api`.", "enum": ["ui", "api", "sdk"] }, "notes": { "type": ["string", "null"] }, "createdAt": { "type": "number", "description": "Epoch milliseconds." }, "completedAt": { "type": ["number", "null"], "description": "Epoch milliseconds, `null` until terminal." } } }, "EvalRunPage": { "type": "object", "required": ["items"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/EvalRun" } } } }, "EvalIteration": { "type": "object", "required": ["id", "iterationNumber", "status"], "properties": { "id": { "type": "string" }, "testCaseId": { "type": ["string", "null"] }, "title": { "type": ["string", "null"] }, "iterationNumber": { "type": "integer" }, "status": { "type": "string", "enum": ["pending", "running", "completed", "failed", "cancelled"] }, "result": { "type": ["string", "null"], "enum": ["passed", "failed", null] }, "model": { "type": ["string", "null"] }, "provider": { "type": ["string", "null"] }, "startedAt": { "type": ["number", "null"], "description": "Epoch milliseconds." }, "durationMs": { "type": ["number", "null"], "description": "Wall-clock duration; `null` until terminal." }, "tokensUsed": { "type": ["number", "null"] }, "usage": { "type": ["object", "null"], "description": "Structured token usage (input/output/cached/reasoning) when available.", "additionalProperties": true }, "actualToolCalls": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "expectedToolCalls": { "type": "array", "items": { "type": "object", "additionalProperties": true } }, "error": { "type": ["string", "null"] } } }, "EvalIterationPage": { "type": "object", "required": ["items"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/EvalIteration" } }, "nextCursor": { "type": "string", "description": "Opaque cursor for the next page. Omitted on the last page." } } }, "ImportTokensRequest": { "type": "object", "required": ["serverUrl", "tokens"], "properties": { "serverUrl": { "type": "string", "description": "The MCP server URL the tokens were obtained for." }, "oauthResourceUrl": { "type": "string", "description": "OAuth protected-resource URL, when it differs from `serverUrl`." }, "clientInformation": { "type": "object", "description": "OAuth client used to obtain the tokens. Optional, but without it server-side refresh cannot run — always include it when you provide a `refresh_token`.", "required": ["clientId"], "properties": { "clientId": { "type": "string" }, "clientSecret": { "type": "string", "format": "password" } } }, "tokens": { "type": "object", "required": ["access_token"], "properties": { "access_token": { "type": "string", "format": "password" }, "refresh_token": { "type": "string", "format": "password" }, "expires_in": { "type": "number", "description": "Seconds until the access token expires." }, "token_type": { "type": "string" }, "scope": { "type": "string" }, "id_token": { "type": "string", "format": "password" } } } } }, "ImportTokensResult": { "type": "object", "required": ["imported"], "properties": { "imported": { "type": "boolean", "const": true }, "expiresAt": { "type": ["number", "null"], "description": "Epoch milliseconds when the stored access token expires, or `null` if unknown." } } }, "ExportSnapshot": { "type": "object", "required": ["serverId", "exportedAt", "tools", "resources", "prompts"], "properties": { "serverId": { "type": "string" }, "exportedAt": { "type": "string", "format": "date-time" }, "tools": { "type": "array", "items": { "$ref": "#/components/schemas/Tool" } }, "resources": { "type": "array", "items": { "$ref": "#/components/schemas/Resource" } }, "prompts": { "type": "array", "items": { "$ref": "#/components/schemas/Prompt" } } } } }, "responses": { "InternalError": { "description": "Something failed on MCPJam's side.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "INTERNAL_ERROR", "message": "Unexpected internal error" } } } }, "ValidationError": { "description": "Malformed body or parameters.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "VALIDATION_ERROR", "message": "Invalid JSON body" } } } }, "Unauthorized": { "description": "Missing, invalid, revoked, or orphaned key (`UNAUTHORIZED`) — or the **target MCP server** needs an OAuth grant (`OAUTH_REQUIRED`), which is a property of the server, not your key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "examples": { "badKey": { "summary": "Invalid or revoked key", "value": { "code": "UNAUTHORIZED", "message": "Invalid API key" } }, "oauthRequired": { "summary": "Target server needs an OAuth grant", "value": { "code": "OAUTH_REQUIRED", "message": "Server requires OAuth authorization" } } } } } }, "Forbidden": { "description": "Key is valid but not allowed to do this.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "FORBIDDEN", "message": "You do not have access to this project" } } } }, "NotFound": { "description": "Unknown project, server, or resource.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "NOT_FOUND", "message": "Server not found" } } } }, "FeatureNotSupported": { "description": "The target server doesn't support this MCP capability.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "FEATURE_NOT_SUPPORTED", "message": "Server does not support resources" } } } }, "RateLimited": { "description": "Per-key rate limit exceeded (60 requests/minute sustained, bursts up to 10). Honor `Retry-After` and back off with jitter.", "headers": { "Retry-After": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "RATE_LIMITED", "message": "API key rate limit exceeded. Slow down and retry." } } } }, "ServerUnreachable": { "description": "Could not connect to the target MCP server.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "SERVER_UNREACHABLE", "message": "Failed to connect to server" } } } }, "Timeout": { "description": "The target MCP server connected but didn't respond in time.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "code": "TIMEOUT", "message": "Request to server timed out" } } } } } } }