{"openapi": "3.1.0", "info": {"title": "Patchwork MCP API", "version": "1.0.0", "description": "API for Patchwork MCP application"}, "paths": {"/api/": {"get": {"operationId": "api_main_api_root", "summary": "API Root", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/APIRootResponse"}}}}}, "description": "API root endpoint with version information"}}, "/api/v1/health": {"get": {"operationId": "api_v1_router_health_check", "summary": "Health Check", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HealthResponse"}}}}}, "description": "Simple health check endpoint", "tags": ["v1"]}}, "/api/v1/feedback/": {"post": {"operationId": "api_v1_feedback_submit_feedback", "summary": "Submit Feedback", "parameters": [], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeedbackOut"}}}}}, "description": "Public endpoint that drop-in tools POST to.", "tags": ["Feedback"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/FeedbackIn"}}}, "required": true}, "security": [{"ServerKeyAuth": []}, {"ApiKeyAuth": []}]}}, "/api/v1/servers/": {"get": {"operationId": "api_v1_servers_list_servers", "summary": "List Servers", "parameters": [{"in": "query", "name": "mode", "schema": {"title": "Mode", "type": "string"}, "required": false}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ServerOut"}, "title": "Response", "type": "array"}}}}}, "description": "List all servers for the active team.", "tags": ["Servers"], "security": [{"SessionAuth": []}, {"ApiKeyAuth": []}]}, "post": {"operationId": "api_v1_servers_create_server", "summary": "Create Server", "parameters": [], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerOut"}}}}}, "description": "Create a new MCP server for the active team.", "tags": ["Servers"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerIn"}}}, "required": true}, "security": [{"SessionAuth": []}, {"ApiKeyAuth": []}]}}, "/api/v1/servers/{slug}/stats": {"get": {"operationId": "api_v1_servers_get_server_stats", "summary": "Get Server Stats", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ServerStatsOut"}}}}}, "description": "Get feedback statistics for a server.", "tags": ["Servers"], "security": [{"SessionAuth": []}, {"ApiKeyAuth": []}]}}, "/api/v1/servers/{slug}/tool-changes/": {"get": {"operationId": "api_v1_servers_get_tool_changes", "summary": "Get Tool Changes", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/ToolChangeOut"}, "title": "Response", "type": "array"}}}}}, "description": "Get recent tool change history for a server.", "tags": ["Servers"], "security": [{"SessionAuth": []}, {"ApiKeyAuth": []}]}}, "/api/v1/servers/{slug}/quality/": {"get": {"operationId": "api_v1_servers_get_tool_quality", "summary": "Get Tool Quality", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ToolQualityOut"}}}}}, "description": "Get per-tool quality scores for a server.", "tags": ["Servers"], "security": [{"SessionAuth": []}, {"ApiKeyAuth": []}]}}, "/api/v1/servers/{slug}/probe/": {"post": {"operationId": "api_v1_servers_trigger_probe", "summary": "Trigger Probe", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ProbeResultOut"}}}}}, "description": "Trigger an on-demand probe for a server. Returns immediately; probe runs async.", "tags": ["Servers"], "security": [{"SessionAuth": []}, {"ApiKeyAuth": []}]}}, "/api/v1/teams/": {"get": {"operationId": "api_v1_teams_list_teams", "summary": "List teams", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/TeamOut"}, "title": "Response", "type": "array"}}}}}, "description": "List teams for the authenticated API key.", "tags": ["Teams"], "security": [{"ApiKeyAuth": []}]}}, "/api/v1/teams/{slug}/": {"patch": {"operationId": "api_v1_teams_update_team", "summary": "Update team name", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TeamOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "tags": ["Teams"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/TeamUpdateIn"}}}, "required": true}, "security": [{"ApiKeyAuth": []}]}}, "/api/v1/teams/{slug}/api-keys/": {"get": {"operationId": "api_v1_team_api_keys_list_api_keys", "summary": "List API keys", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/APIKeyOut"}, "title": "Response", "type": "array"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "List active API keys for a team.", "tags": ["API Keys"], "security": [{"ApiKeyAuth": []}]}, "post": {"operationId": "api_v1_team_api_keys_create_api_key", "summary": "Create API key", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"201": {"description": "Created", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/APIKeyCreatedOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "Create a new API key for a team.", "tags": ["API Keys"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/APIKeyCreateIn"}}}, "required": true}, "security": [{"ApiKeyAuth": []}]}}, "/api/v1/teams/{slug}/api-keys/{key_uuid}/": {"delete": {"operationId": "api_v1_team_api_keys_revoke_api_key", "summary": "Revoke API key", "parameters": [{"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}, {"in": "path", "name": "key_uuid", "schema": {"title": "Key Uuid", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MessageOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "Revoke an API key (soft delete).", "tags": ["API Keys"], "security": [{"ApiKeyAuth": []}]}}, "/api/v1/admin/users/{email}/teams/": {"get": {"operationId": "api_v1_admin_api_list_user_teams", "summary": "List user's teams (superuser)", "parameters": [{"in": "path", "name": "email", "schema": {"title": "Email", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/UserTeamOut"}, "title": "Response", "type": "array"}}}}, "403": {"description": "Forbidden", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "List all teams for a user (superuser only).", "tags": ["Admin"], "security": [{"ApiKeyAuth": []}]}}, "/api/v1/admin/users/{email}/teams/{slug}/api-keys/": {"get": {"operationId": "api_v1_admin_api_list_user_team_api_keys", "summary": "List user's team API keys (superuser)", "parameters": [{"in": "path", "name": "email", "schema": {"title": "Email", "type": "string"}, "required": true}, {"in": "path", "name": "slug", "schema": {"title": "Slug", "type": "string"}, "required": true}], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"items": {"$ref": "#/components/schemas/APIKeyOut"}, "title": "Response", "type": "array"}}}}, "403": {"description": "Forbidden", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}, "404": {"description": "Not Found", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorOut"}}}}}, "description": "List API keys for a user's team (superuser only).", "tags": ["Admin"], "security": [{"ApiKeyAuth": []}]}}, "/api/v1/heartbeat/": {"post": {"operationId": "api_v1_heartbeat_heartbeat", "summary": "Heartbeat", "parameters": [], "responses": {"200": {"description": "OK", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/HeartbeatOut"}}}}}, "description": "Receive a heartbeat ping from an MCP server middleware.", "tags": ["Heartbeat"], "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/HeartbeatIn"}}}, "required": true}, "security": [{"ServerKeyAuth": []}, {"ApiKeyAuth": []}]}}}, "components": {"schemas": {"APIRootResponse": {"description": "API root response schema", "properties": {"message": {"description": "Welcome message", "title": "Message", "type": "string"}, "versions": {"additionalProperties": {"type": "string"}, "description": "Available API versions", "title": "Versions", "type": "object"}, "documentation": {"description": "Documentation URL", "title": "Documentation", "type": "string"}, "openapi_schema": {"description": "OpenAPI schema URL", "title": "Openapi Schema", "type": "string"}}, "required": ["message", "versions", "documentation", "openapi_schema"], "title": "APIRootResponse", "type": "object"}, "HealthResponse": {"description": "Health check response schema", "properties": {"status": {"description": "API health status", "title": "Status", "type": "string"}, "version": {"description": "API version", "title": "Version", "type": "string"}, "timestamp": {"description": "Current timestamp", "title": "Timestamp", "type": "string"}}, "required": ["status", "version", "timestamp"], "title": "HealthResponse", "type": "object"}, "FeedbackOut": {"properties": {"id": {"title": "Id", "type": "string"}, "status": {"title": "Status", "type": "string"}, "message": {"title": "Message", "type": "string"}, "guidance": {"default": "", "title": "Guidance", "type": "string"}, "filtered": {"default": false, "title": "Filtered", "type": "boolean"}, "filter_reason": {"default": "", "title": "Filter Reason", "type": "string"}}, "required": ["id", "status", "message"], "title": "FeedbackOut", "type": "object"}, "FeedbackIn": {"properties": {"server_slug": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Server Slug"}, "what_i_needed": {"title": "What I Needed", "type": "string"}, "what_i_tried": {"title": "What I Tried", "type": "string"}, "gap_type": {"default": "other", "title": "Gap Type", "type": "string"}, "suggestion": {"default": "", "title": "Suggestion", "type": "string"}, "user_goal": {"default": "", "title": "User Goal", "type": "string"}, "resolution": {"default": "", "title": "Resolution", "type": "string"}, "tools_available": {"default": [], "items": {"type": "string"}, "title": "Tools Available", "type": "array"}, "agent_model": {"default": "", "title": "Agent Model", "type": "string"}, "session_id": {"default": "", "title": "Session Id", "type": "string"}, "client_type": {"default": "", "title": "Client Type", "type": "string"}}, "required": ["what_i_needed", "what_i_tried"], "title": "FeedbackIn", "type": "object"}, "ServerOut": {"properties": {"id": {"title": "Id", "type": "string"}, "name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string"}, "description": {"title": "Description", "type": "string"}, "mode": {"title": "Mode", "type": "string"}, "github_repo": {"title": "Github Repo", "type": "string"}, "health_status": {"title": "Health Status", "type": "string"}, "uptime_24h": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Uptime 24H"}, "created_at": {"title": "Created At", "type": "string"}, "updated_at": {"title": "Updated At", "type": "string"}}, "required": ["id", "name", "slug", "description", "mode", "github_repo", "health_status", "created_at", "updated_at"], "title": "ServerOut", "type": "object"}, "ServerIn": {"properties": {"name": {"title": "Name", "type": "string"}, "description": {"default": "", "title": "Description", "type": "string"}, "default_branch": {"default": "main", "title": "Default Branch", "type": "string"}}, "required": ["name"], "title": "ServerIn", "type": "object"}, "ServerStatsOut": {"properties": {"server_id": {"title": "Server Id", "type": "string"}, "server_name": {"title": "Server Name", "type": "string"}, "mode": {"title": "Mode", "type": "string"}, "total_feedback": {"title": "Total Feedback", "type": "integer"}, "unreviewed": {"title": "Unreviewed", "type": "integer"}, "by_gap_type": {"additionalProperties": true, "title": "By Gap Type", "type": "object"}, "recent": {"items": {}, "title": "Recent", "type": "array"}}, "required": ["server_id", "server_name", "mode", "total_feedback", "unreviewed", "by_gap_type", "recent"], "title": "ServerStatsOut", "type": "object"}, "ToolChangeOut": {"properties": {"timestamp": {"title": "Timestamp", "type": "string"}, "added": {"items": {"type": "string"}, "title": "Added", "type": "array"}, "removed": {"items": {"type": "string"}, "title": "Removed", "type": "array"}, "tool_count_before": {"title": "Tool Count Before", "type": "integer"}, "tool_count_after": {"title": "Tool Count After", "type": "integer"}}, "required": ["timestamp", "added", "removed", "tool_count_before", "tool_count_after"], "title": "ToolChangeOut", "type": "object"}, "ToolQualityItemOut": {"properties": {"tool_name": {"title": "Tool Name", "type": "string"}, "quality_score": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Quality Score"}, "quality_issues": {"items": {}, "title": "Quality Issues", "type": "array"}, "last_analyzed_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Last Analyzed At"}}, "required": ["tool_name", "quality_score", "quality_issues", "last_analyzed_at"], "title": "ToolQualityItemOut", "type": "object"}, "ToolQualityOut": {"properties": {"server_slug": {"title": "Server Slug", "type": "string"}, "tool_count": {"title": "Tool Count", "type": "integer"}, "average_score": {"anyOf": [{"type": "number"}, {"type": "null"}], "title": "Average Score"}, "tools": {"items": {"$ref": "#/components/schemas/ToolQualityItemOut"}, "title": "Tools", "type": "array"}}, "required": ["server_slug", "tool_count", "average_score", "tools"], "title": "ToolQualityOut", "type": "object"}, "ProbeResultOut": {"properties": {"server_slug": {"title": "Server Slug", "type": "string"}, "status": {"title": "Status", "type": "string"}, "message": {"default": "", "title": "Message", "type": "string"}}, "required": ["server_slug", "status"], "title": "ProbeResultOut", "type": "object"}, "TeamOut": {"properties": {"name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string"}, "created_at": {"title": "Created At", "type": "string"}, "owner_email": {"title": "Owner Email", "type": "string"}}, "required": ["name", "slug", "created_at", "owner_email"], "title": "TeamOut", "type": "object"}, "ErrorOut": {"properties": {"detail": {"title": "Detail", "type": "string"}}, "required": ["detail"], "title": "ErrorOut", "type": "object"}, "TeamUpdateIn": {"properties": {"name": {"maxLength": 255, "minLength": 1, "title": "Name", "type": "string"}}, "required": ["name"], "title": "TeamUpdateIn", "type": "object"}, "APIKeyOut": {"properties": {"uuid": {"title": "Uuid", "type": "string"}, "description": {"title": "Description", "type": "string"}, "is_prod": {"title": "Is Prod", "type": "boolean"}, "created_at": {"title": "Created At", "type": "string"}}, "required": ["uuid", "description", "is_prod", "created_at"], "title": "APIKeyOut", "type": "object"}, "APIKeyCreatedOut": {"properties": {"uuid": {"title": "Uuid", "type": "string"}, "description": {"title": "Description", "type": "string"}, "is_prod": {"title": "Is Prod", "type": "boolean"}, "created_at": {"title": "Created At", "type": "string"}, "raw_key": {"title": "Raw Key", "type": "string"}}, "required": ["uuid", "description", "is_prod", "created_at", "raw_key"], "title": "APIKeyCreatedOut", "type": "object"}, "APIKeyCreateIn": {"properties": {"description": {"default": "", "title": "Description", "type": "string"}, "is_prod": {"default": false, "title": "Is Prod", "type": "boolean"}}, "title": "APIKeyCreateIn", "type": "object"}, "MessageOut": {"properties": {"uuid": {"title": "Uuid", "type": "string"}, "message": {"title": "Message", "type": "string"}}, "required": ["uuid", "message"], "title": "MessageOut", "type": "object"}, "UserTeamOut": {"properties": {"name": {"title": "Name", "type": "string"}, "slug": {"title": "Slug", "type": "string"}, "role": {"title": "Role", "type": "string"}, "created_at": {"title": "Created At", "type": "string"}}, "required": ["name", "slug", "role", "created_at"], "title": "UserTeamOut", "type": "object"}, "HeartbeatOut": {"properties": {"status": {"title": "Status", "type": "string"}, "server_slug": {"title": "Server Slug", "type": "string"}}, "required": ["status", "server_slug"], "title": "HeartbeatOut", "type": "object"}, "HeartbeatIn": {"properties": {"server_slug": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Server Slug"}, "tool_count": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Tool Count"}, "tool_names": {"default": [], "items": {"type": "string"}, "title": "Tool Names", "type": "array"}, "scan_results": {"default": [], "items": {"$ref": "#/components/schemas/ScanIssue"}, "title": "Scan Results", "type": "array"}, "last_error_type": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Last Error Type"}, "consecutive_failures": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Consecutive Failures"}, "sent_at": {"anyOf": [{"type": "string"}, {"type": "null"}], "title": "Sent At"}, "middleware_uptime_seconds": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Middleware Uptime Seconds"}, "heartbeats_sent": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Heartbeats Sent"}, "heartbeats_failed": {"anyOf": [{"type": "integer"}, {"type": "null"}], "title": "Heartbeats Failed"}}, "title": "HeartbeatIn", "type": "object"}, "ScanIssue": {"properties": {"tool": {"title": "Tool", "type": "string"}, "type": {"title": "Type", "type": "string"}, "severity": {"title": "Severity", "type": "string"}, "detail": {"default": "", "title": "Detail", "type": "string"}}, "required": ["tool", "type", "severity"], "title": "ScanIssue", "type": "object"}}, "securitySchemes": {"ServerKeyAuth": {"type": "http", "scheme": "bearer"}, "ApiKeyAuth": {"type": "http", "scheme": "bearer"}, "SessionAuth": {"type": "apiKey", "in": "cookie", "name": "pw_sessionid"}}}, "servers": []}