{
  "openapi": "3.1.0",
  "info": {
    "title": "Cycling Coach AI public API",
    "version": "1.0.0",
    "summary": "Read-only discovery API and MCP server for AI agents.",
    "description": "Public, unauthenticated API for AI agents that need accurate, current information about Cycling Coach AI:\npricing, features, supported integrations, device compatibility, training use cases, supported languages,\ncompany details, and structured comparisons against competitors.\n\nMost of that data is reached through the Model Context Protocol server at `POST /api/mcp/public`, which\nexposes 8 tools. Each tool, with its input and output JSON Schema, is enumerated in the\n`x-mcp-tools` extension of this document, so a client can plan calls without a handshake.\n\n## When to use this API\n\nReach for it when a user asks whether a specific bike computer, trainer or watch works with the product,\nwhat a subscription costs, how the product compares with TrainerRoad, TrainingPeaks, Zwift or a human coach,\nwhich languages the AI coach speaks, or what a training plan for a given goal looks like.\n\nIt is not a training API: it exposes no user accounts, workouts or activity data. Users who want their own\ntraining data use the authenticated product MCP at https://app.usecoachai.com.\n\n## Errors\n\nEvery non-MCP endpoint returns the same JSON envelope: `{ \"error\": { \"code\", \"message\", \"hint\", \"docs_url\" } }`.\nThe MCP endpoint returns JSON-RPC 2.0 errors. Neither ever returns HTML.\n\n## Rate limits\n\nThe MCP endpoint allows 100 requests per minute per IP and 1000 per minute per `X-Agent-Name`.\nOver the limit it answers 429 with a `Retry-After` header. Send `X-Agent-Name` so your traffic is\nbucketed separately from anonymous callers.",
    "contact": {
      "name": "Cycling Coach AI support",
      "email": "support@cyclingcoachai.com",
      "url": "https://cyclingcoachai.com/docs/"
    },
    "license": {
      "name": "Proprietary",
      "url": "https://cyclingcoachai.com/tos/"
    },
    "termsOfService": "https://cyclingcoachai.com/tos/"
  },
  "servers": [
    {
      "url": "https://cyclingcoachai.com",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Agent integration guide",
    "url": "https://cyclingcoachai.com/agents/"
  },
  "tags": [
    {
      "name": "Discovery",
      "description": "Entry points that describe the rest of the API."
    },
    {
      "name": "MCP",
      "description": "Model Context Protocol server. Preferred surface for agents."
    },
    {
      "name": "Site",
      "description": "Endpoints backing the public website."
    }
  ],
  "paths": {
    "/api": {
      "get": {
        "operationId": "getApiIndex",
        "summary": "API index",
        "description": "Machine-readable index of every public endpoint, the MCP server location, and the error format. Start here if you are discovering the API without reading this document.",
        "tags": [
          "Discovery"
        ],
        "responses": {
          "200": {
            "description": "The API index.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "name",
                    "documentation",
                    "openapi",
                    "mcp",
                    "endpoints"
                  ],
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "API name."
                    },
                    "description": {
                      "type": "string",
                      "description": "What this API is for."
                    },
                    "documentation": {
                      "type": "string",
                      "format": "uri",
                      "description": "Human-readable docs."
                    },
                    "openapi": {
                      "type": "string",
                      "format": "uri",
                      "description": "This document."
                    },
                    "llms_txt": {
                      "type": "string",
                      "format": "uri",
                      "description": "llms.txt with product summary and when-to-use guidance."
                    },
                    "mcp": {
                      "type": "object",
                      "description": "How to reach the MCP server.",
                      "properties": {
                        "endpoint": {
                          "type": "string",
                          "format": "uri",
                          "description": "JSON-RPC endpoint."
                        },
                        "manifest": {
                          "type": "string",
                          "format": "uri",
                          "description": "MCP manifest."
                        },
                        "transport": {
                          "const": "streamable-http"
                        },
                        "protocol_version": {
                          "type": "string",
                          "description": "Default MCP protocol version."
                        },
                        "tools": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Tool names."
                        },
                        "authentication": {
                          "const": "none"
                        }
                      }
                    },
                    "endpoints": {
                      "type": "array",
                      "description": "Every public endpoint with its method.",
                      "items": {
                        "type": "object",
                        "properties": {
                          "method": {
                            "type": "string",
                            "description": "HTTP method."
                          },
                          "path": {
                            "type": "string",
                            "description": "Path."
                          },
                          "description": {
                            "type": "string",
                            "description": "What it returns."
                          }
                        }
                      }
                    },
                    "errors": {
                      "type": "object",
                      "description": "Error envelope format and the list of stable codes."
                    },
                    "contact": {
                      "type": "string",
                      "description": "Support email."
                    }
                  }
                }
              }
            }
          },
          "406": {
            "description": "The client does not accept application/json.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp/public": {
      "get": {
        "operationId": "getMcpServerInfo",
        "summary": "MCP server info",
        "description": "Returns the MCP server name, version, supported protocol versions, transport and tool count. Responds 405 to Accept: text/event-stream because this server never initiates streams.",
        "tags": [
          "MCP"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/McpProtocolVersion"
          }
        ],
        "responses": {
          "200": {
            "description": "Server descriptor.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "server",
                    "version",
                    "protocol_version",
                    "tools_count"
                  ],
                  "properties": {
                    "server": {
                      "type": "string",
                      "description": "MCP server name."
                    },
                    "version": {
                      "type": "string",
                      "description": "Server version."
                    },
                    "protocol_version": {
                      "type": "string",
                      "description": "Default MCP protocol version."
                    },
                    "supported_protocol_versions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Every protocol version accepted in the MCP-Protocol-Version header."
                    },
                    "transport": {
                      "const": "streamable-http"
                    },
                    "authentication": {
                      "const": "none"
                    },
                    "tools_count": {
                      "type": "integer",
                      "description": "Number of tools exposed."
                    },
                    "manifest": {
                      "type": "string",
                      "format": "uri",
                      "description": "MCP manifest URL."
                    },
                    "openapi": {
                      "type": "string",
                      "format": "uri",
                      "description": "This document."
                    },
                    "docs": {
                      "type": "string",
                      "format": "uri",
                      "description": "Agent integration docs."
                    },
                    "message": {
                      "type": "string",
                      "description": "How to call the server."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Unsupported MCP-Protocol-Version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcError"
                }
              }
            }
          },
          "405": {
            "description": "Server-initiated SSE streams are not supported.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcError"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "callMcpJsonRpc",
        "summary": "MCP JSON-RPC 2.0 endpoint",
        "description": "Single entry point for the Model Context Protocol. Supported methods: initialize, notifications/initialized, tools/list and tools/call. The 8 callable tools, with their input and output schemas, are enumerated in the x-mcp-tools extension of this document.",
        "tags": [
          "MCP"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/McpProtocolVersion"
          },
          {
            "$ref": "#/components/parameters/AgentName"
          },
          {
            "$ref": "#/components/parameters/SessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result. For tools/call the payload is a ToolResult.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "jsonrpc",
                    "result"
                  ],
                  "properties": {
                    "jsonrpc": {
                      "const": "2.0"
                    },
                    "id": {
                      "$ref": "#/components/schemas/JsonRpcId"
                    },
                    "result": {
                      "$ref": "#/components/schemas/ToolResult"
                    }
                  }
                }
              }
            }
          },
          "204": {
            "description": "Acknowledgement of a notification (no response body)."
          },
          "400": {
            "description": "Parse error, invalid request, or unsupported protocol version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcError"
                }
              }
            }
          },
          "406": {
            "description": "The client accepts neither application/json nor text/event-stream.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Retry after the number of seconds in Retry-After.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the limit resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcError"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp/public/health": {
      "get": {
        "operationId": "getMcpHealth",
        "summary": "MCP liveness probe",
        "description": "Returns ok plus uptime and tool count. Use it to check the server is reachable before starting a session.",
        "tags": [
          "MCP"
        ],
        "responses": {
          "200": {
            "description": "The server is healthy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "server",
                    "version",
                    "tools_count"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "server": {
                      "type": "string",
                      "description": "MCP server name."
                    },
                    "version": {
                      "type": "string",
                      "description": "Server version."
                    },
                    "protocol_version": {
                      "type": "string",
                      "description": "Default MCP protocol version."
                    },
                    "uptime_seconds": {
                      "type": "integer",
                      "description": "Seconds since this isolate started. Resets on cold start; not a global uptime."
                    },
                    "tools_count": {
                      "type": "integer",
                      "description": "Number of tools exposed."
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only GET is allowed on the health probe.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcError"
                }
              }
            }
          }
        }
      }
    },
    "/api/ab/status": {
      "get": {
        "operationId": "getAbTestStatus",
        "summary": "Current A/B test status",
        "description": "Reports whether a site-wide A/B test is running. Used by the edge middleware to decide whether to split traffic; public because it carries no user data.",
        "tags": [
          "Site"
        ],
        "responses": {
          "200": {
            "description": "The current test status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "active",
                    "test"
                  ],
                  "properties": {
                    "active": {
                      "type": "boolean",
                      "description": "True when a test is running."
                    },
                    "test": {
                      "description": "The running test, or null when none is active.",
                      "oneOf": [
                        {
                          "type": "object",
                          "required": [
                            "id",
                            "name"
                          ],
                          "properties": {
                            "id": {
                              "type": "integer",
                              "description": "Test id."
                            },
                            "name": {
                              "type": "string",
                              "description": "Test name."
                            }
                          }
                        },
                        {
                          "type": "null"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "405": {
            "description": "Only GET and HEAD are allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The status could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/strava-live": {
      "get": {
        "operationId": "getStravaLiveActivity",
        "summary": "Latest public Strava activity",
        "description": "Proxies the public activity feed shown by the homepage widget. Cached for 60 seconds. The response shape is owned by the upstream application API and is not part of this contract.",
        "tags": [
          "Site"
        ],
        "responses": {
          "200": {
            "description": "The upstream activity payload, passed through unchanged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Opaque upstream payload.",
                  "additionalProperties": true
                }
              }
            }
          },
          "405": {
            "description": "Only GET is allowed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "The upstream service is unreachable or failing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every error in this API uses this envelope. `code` is the stable contract; `message` and `hint` are human/agent readable and may be reworded.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "description": "The error detail. Always present on a failed request.",
            "required": [
              "code",
              "message",
              "hint",
              "docs_url"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable error code.",
                "enum": [
                  "bad_request",
                  "invalid_json",
                  "unauthorized",
                  "not_found",
                  "method_not_allowed",
                  "not_acceptable",
                  "unprocessable_entity",
                  "rate_limited",
                  "internal_error"
                ]
              },
              "message": {
                "type": "string",
                "description": "What went wrong, in one sentence."
              },
              "hint": {
                "type": "string",
                "description": "How to fix the request and retry."
              },
              "docs_url": {
                "type": "string",
                "format": "uri",
                "description": "Documentation covering this endpoint."
              }
            }
          }
        }
      },
      "JsonRpcId": {
        "description": "Correlation id echoed back in the response. Omit only for notifications.",
        "oneOf": [
          {
            "type": "string"
          },
          {
            "type": "integer"
          },
          {
            "type": "null"
          }
        ]
      },
      "JsonRpcRequest": {
        "description": "A JSON-RPC 2.0 request. The `method` determines the shape of `params`.",
        "oneOf": [
          {
            "title": "initialize",
            "description": "Handshake. Call this first; the response carries the protocol version and server capabilities.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0"
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "initialize"
              },
              "params": {
                "type": "object",
                "description": "Handshake parameters. All fields are optional for this server.",
                "properties": {
                  "protocolVersion": {
                    "type": "string",
                    "enum": [
                      "2025-06-18",
                      "2025-03-26",
                      "2024-11-05"
                    ],
                    "description": "MCP protocol version the client speaks."
                  },
                  "capabilities": {
                    "type": "object",
                    "description": "Client capabilities. This server ignores them."
                  },
                  "clientInfo": {
                    "type": "object",
                    "description": "Identifies the calling client.",
                    "properties": {
                      "name": {
                        "type": "string",
                        "description": "Client name."
                      },
                      "version": {
                        "type": "string",
                        "description": "Client version."
                      }
                    }
                  }
                }
              }
            }
          },
          {
            "title": "tools/list",
            "description": "Lists the 8 available tools with their JSON Schemas.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0"
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/list"
              }
            }
          },
          {
            "title": "tools/call → get_pricing",
            "description": "Returns current Cycling Coach AI plans, prices in USD, billing periods, free trial duration, and signup URL. Use this before recommending a signup.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "get_pricing"
                  },
                  "arguments": {
                    "description": "Arguments for get_pricing.",
                    "type": "object",
                    "properties": {},
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → get_features",
            "description": "Returns the structured Cycling Coach AI feature list grouped by category (AI & Planning, AI Coach, Health & Wellness, Performance Analytics, Integrations & Export, Social).",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "get_features"
                  },
                  "arguments": {
                    "description": "Arguments for get_features.",
                    "type": "object",
                    "properties": {
                      "category": {
                        "type": "string",
                        "description": "Optional category filter"
                      }
                    },
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → get_supported_integrations",
            "description": "Returns all platforms Cycling Coach AI integrates with (Strava, Garmin, Wahoo, Zwift, Rouvy, MyWhoosh, PDF), each with sync direction (in/out/bidirectional), capabilities, and setup links.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "get_supported_integrations"
                  },
                  "arguments": {
                    "description": "Arguments for get_supported_integrations.",
                    "type": "object",
                    "properties": {},
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → check_device_compatibility",
            "description": "Checks if a specific cycling device (e.g. \"Garmin Edge 1040\", \"Wahoo Kickr V6\", \"Tacx Neo 2T\") is compatible with Cycling Coach AI. Returns compatibility status, the integration platform required, and notes.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "check_device_compatibility"
                  },
                  "arguments": {
                    "description": "Arguments for check_device_compatibility.",
                    "type": "object",
                    "properties": {
                      "device_name": {
                        "type": "string",
                        "description": "Name of the device, e.g. \"Garmin Edge 1040\""
                      },
                      "device_type": {
                        "type": "string",
                        "description": "Optional category: head_unit, watch, smart_trainer"
                      }
                    },
                    "required": [
                      "device_name"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → compare_with_alternatives",
            "description": "Returns a structured attribute comparison of Cycling Coach AI against a named competitor (e.g. \"TrainerRoad\", \"TrainingPeaks\", \"Zwift\", \"Xert\", \"human-coach\"). Includes per-attribute \"advantage\" field.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "compare_with_alternatives"
                  },
                  "arguments": {
                    "description": "Arguments for compare_with_alternatives.",
                    "type": "object",
                    "properties": {
                      "competitor": {
                        "type": "string",
                        "description": "Competitor name (e.g. \"TrainerRoad\")"
                      }
                    },
                    "required": [
                      "competitor"
                    ],
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → get_use_cases",
            "description": "Returns Cycling Coach AI training use cases (FTP improvement, gran fondo, climbing, weight loss, return to cycling, criterium, gravel/MTB, maintenance) with target audience, typical duration in weeks, and recommended hours per week.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "get_use_cases"
                  },
                  "arguments": {
                    "description": "Arguments for get_use_cases.",
                    "type": "object",
                    "properties": {},
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → get_languages_supported",
            "description": "Returns the 10 languages supported in Cycling Coach AI UI and AI coach: English, Spanish, French, German, Portuguese, Italian, Hungarian, Polish, Dutch, Chinese.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "get_languages_supported"
                  },
                  "arguments": {
                    "description": "Arguments for get_languages_supported.",
                    "type": "object",
                    "properties": {},
                    "additionalProperties": false
                  }
                }
              }
            }
          },
          {
            "title": "tools/call → get_company_info",
            "description": "Returns Cycling Coach AI company information: name, founded year, country, founders, contact email, social links, and press kit URL if available.",
            "type": "object",
            "required": [
              "jsonrpc",
              "method",
              "params"
            ],
            "properties": {
              "jsonrpc": {
                "const": "2.0",
                "description": "JSON-RPC version. Always \"2.0\"."
              },
              "id": {
                "$ref": "#/components/schemas/JsonRpcId"
              },
              "method": {
                "const": "tools/call"
              },
              "params": {
                "type": "object",
                "description": "Names the tool to invoke and carries its arguments.",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "const": "get_company_info"
                  },
                  "arguments": {
                    "description": "Arguments for get_company_info.",
                    "type": "object",
                    "properties": {},
                    "additionalProperties": false
                  }
                }
              }
            }
          }
        ]
      },
      "JsonRpcError": {
        "type": "object",
        "description": "JSON-RPC 2.0 error response. Transport-level failures use the HTTP status; protocol failures use this body.",
        "required": [
          "jsonrpc",
          "error"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "$ref": "#/components/schemas/JsonRpcId"
          },
          "error": {
            "type": "object",
            "description": "The JSON-RPC error detail.",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer",
                "description": "JSON-RPC error code. -32700 parse error, -32600 invalid request, -32601 method/tool not found, -32000 rate limited or unsupported transport."
              },
              "message": {
                "type": "string",
                "description": "Human readable error."
              },
              "data": {
                "description": "Optional structured detail, e.g. the list of supported protocol versions."
              }
            }
          }
        }
      },
      "ToolResult": {
        "type": "object",
        "description": "Result of tools/call. `structuredContent` is the typed payload; `content` is the same data serialised for models that only read text.",
        "required": [
          "content",
          "structuredContent"
        ],
        "properties": {
          "content": {
            "type": "array",
            "description": "Text rendering of the result.",
            "items": {
              "type": "object",
              "required": [
                "type",
                "text"
              ],
              "properties": {
                "type": {
                  "const": "text"
                },
                "text": {
                  "type": "string",
                  "description": "The result serialised as pretty-printed JSON."
                }
              }
            }
          },
          "structuredContent": {
            "description": "The typed result. Its schema is the outputSchema of the called tool, listed under x-mcp-tools.",
            "oneOf": [
              {
                "title": "get_pricing",
                "type": "object",
                "description": "Full price list for the three tiers, each in monthly and yearly billing.",
                "properties": {
                  "plans": {
                    "type": "array",
                    "description": "Six entries: three tiers times two billing periods.",
                    "items": {
                      "type": "object",
                      "description": "One purchasable plan/billing-period combination.",
                      "properties": {
                        "name": {
                          "type": "string",
                          "description": "Display name including billing period, e.g. \"Pro (annual)\"."
                        },
                        "plan": {
                          "type": "string",
                          "enum": [
                            "base",
                            "pro",
                            "elite"
                          ],
                          "description": "Plan tier identifier."
                        },
                        "billing_period": {
                          "type": "string",
                          "enum": [
                            "monthly",
                            "yearly"
                          ],
                          "description": "How often the subscription is charged."
                        },
                        "price_per_month": {
                          "type": "number",
                          "description": "Monthly price. Present only when billing_period is \"monthly\"."
                        },
                        "price_per_month_equivalent": {
                          "type": "number",
                          "description": "Yearly price divided by 12. Present only when billing_period is \"yearly\"."
                        },
                        "price_total": {
                          "type": "number",
                          "description": "Total amount charged per billing period. Present only when billing_period is \"yearly\"."
                        },
                        "currency": {
                          "type": "string",
                          "enum": [
                            "USD"
                          ],
                          "description": "ISO 4217 currency code. Always USD."
                        },
                        "most_popular": {
                          "type": "boolean",
                          "description": "True for the tier highlighted as most popular on the pricing page."
                        },
                        "notes": {
                          "type": "string",
                          "description": "What the tier includes, in prose."
                        }
                      },
                      "required": [
                        "name",
                        "plan",
                        "billing_period",
                        "currency",
                        "most_popular",
                        "notes"
                      ]
                    }
                  },
                  "free_trial_days": {
                    "type": "integer",
                    "description": "Length of the free trial in days. No credit card required."
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "USD"
                    ],
                    "description": "ISO 4217 currency code for every price in the response."
                  },
                  "signup_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Pricing page with UTM attribution for the calling agent."
                  },
                  "cancel_anytime": {
                    "type": "boolean",
                    "description": "True when the subscription can be cancelled at any time."
                  }
                },
                "required": [
                  "plans",
                  "free_trial_days",
                  "currency",
                  "signup_url",
                  "cancel_anytime"
                ]
              },
              {
                "title": "get_features",
                "type": "object",
                "description": "Features grouped by product category.",
                "properties": {
                  "categories": {
                    "type": "array",
                    "description": "One entry per category, filtered when the category argument is supplied.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "category": {
                          "type": "string",
                          "description": "Category name."
                        },
                        "features": {
                          "type": "array",
                          "description": "Features belonging to this category.",
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "description": "Stable feature slug, also the URL segment under /features/."
                              },
                              "name": {
                                "type": "string",
                                "description": "Feature display name."
                              },
                              "description": {
                                "type": "string",
                                "description": "One-paragraph explanation of the feature."
                              }
                            },
                            "required": [
                              "key",
                              "name",
                              "description"
                            ]
                          }
                        }
                      },
                      "required": [
                        "category",
                        "features"
                      ]
                    }
                  },
                  "total": {
                    "type": "integer",
                    "description": "Number of features across all returned categories."
                  }
                },
                "required": [
                  "categories",
                  "total"
                ]
              },
              {
                "title": "get_supported_integrations",
                "type": "object",
                "description": "Every supported third-party platform and what it syncs.",
                "properties": {
                  "integrations": {
                    "type": "array",
                    "description": "One entry per supported platform.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "description": "Stable integration slug."
                        },
                        "name": {
                          "type": "string",
                          "description": "Platform display name."
                        },
                        "type": {
                          "type": "string",
                          "description": "Integration family, e.g. \"platform\" or \"export\"."
                        },
                        "sync_direction": {
                          "type": "string",
                          "enum": [
                            "in",
                            "out",
                            "bidirectional"
                          ],
                          "description": "Overall direction of data flow."
                        },
                        "capabilities": {
                          "type": "array",
                          "description": "Individual capabilities of this integration.",
                          "items": {
                            "type": "object",
                            "description": "One thing the integration can do.",
                            "properties": {
                              "name": {
                                "type": "string",
                                "description": "Short capability name."
                              },
                              "description": {
                                "type": "string",
                                "description": "What the capability does."
                              },
                              "direction": {
                                "type": "string",
                                "enum": [
                                  "in",
                                  "out"
                                ],
                                "description": "\"in\" imports data into Cycling Coach AI, \"out\" pushes data to the external platform."
                              }
                            },
                            "required": [
                              "name",
                              "description",
                              "direction"
                            ]
                          }
                        },
                        "official_url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Homepage of the third-party platform."
                        },
                        "setup_url": {
                          "type": "string",
                          "format": "uri",
                          "description": "Where the user connects the integration, with UTM attribution for the calling agent."
                        }
                      },
                      "required": [
                        "key",
                        "name",
                        "sync_direction",
                        "capabilities"
                      ]
                    }
                  }
                },
                "required": [
                  "integrations"
                ]
              },
              {
                "title": "check_device_compatibility",
                "type": "object",
                "description": "Compatibility verdict for the requested device. matched=false means the device is not in the database, not that it is incompatible.",
                "properties": {
                  "device_key": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Normalized key of the matched device, null when no match."
                  },
                  "device_name": {
                    "type": "string",
                    "description": "Device name as supplied by the caller."
                  },
                  "matched": {
                    "type": "boolean",
                    "description": "True when the device was found in the compatibility database."
                  },
                  "compatible": {
                    "type": "boolean",
                    "description": "True when workouts can be sent to, or data imported from, the device."
                  },
                  "compatible_via": {
                    "type": "array",
                    "description": "Integration keys that enable compatibility.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "notes": {
                    "type": "string",
                    "description": "Human-readable detail about how compatibility works, or what to do when unmatched."
                  },
                  "setup_url": {
                    "description": "Where to connect the required integration, or null when the device is unmatched.",
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uri",
                        "description": "Integration setup page."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "multiple_matches": {
                    "type": "array",
                    "description": "Present only when the name matched more than one device. Ask the user to disambiguate.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "error": {
                    "type": "string",
                    "description": "Present only when device_name was missing or not a string."
                  }
                },
                "required": [
                  "device_name",
                  "matched",
                  "compatible"
                ]
              },
              {
                "title": "compare_with_alternatives",
                "type": "object",
                "description": "Attribute-by-attribute comparison. When matched is false, message lists the competitors that do have a comparison.",
                "properties": {
                  "matched": {
                    "type": "boolean",
                    "description": "True when a structured comparison exists for the requested competitor."
                  },
                  "competitor": {
                    "type": "string",
                    "description": "Competitor name as supplied, echoed only when matched is false."
                  },
                  "message": {
                    "type": "string",
                    "description": "Present only when matched is false. Lists the available competitors."
                  },
                  "competitor_name": {
                    "type": "string",
                    "description": "Canonical competitor name."
                  },
                  "competitor_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Competitor homepage."
                  },
                  "tldr": {
                    "type": "string",
                    "description": "Two-sentence summary of the comparison."
                  },
                  "attributes": {
                    "type": "array",
                    "description": "Side-by-side attribute rows.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "label": {
                          "type": "string",
                          "description": "What is being compared, e.g. \"Plan adaptation\"."
                        },
                        "ourValue": {
                          "type": "string",
                          "description": "Cycling Coach AI value for this attribute."
                        },
                        "competitorValue": {
                          "type": "string",
                          "description": "Competitor value for this attribute."
                        },
                        "advantage": {
                          "type": "string",
                          "enum": [
                            "ours",
                            "theirs",
                            "neutral"
                          ],
                          "description": "Which product wins this row."
                        }
                      },
                      "required": [
                        "label",
                        "ourValue",
                        "competitorValue",
                        "advantage"
                      ]
                    }
                  },
                  "when_to_choose_ours": {
                    "type": "array",
                    "description": "Situations where Cycling Coach AI is the better recommendation.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "when_to_choose_theirs": {
                    "type": "array",
                    "description": "Situations where the competitor is the better recommendation. Use this to stay honest.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "full_comparison_url": {
                    "description": "Full comparison page with UTM attribution, or null when no public page exists for this competitor.",
                    "anyOf": [
                      {
                        "type": "string",
                        "format": "uri",
                        "description": "Comparison page."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "error": {
                    "type": "string",
                    "description": "Present only when the competitor argument was missing or not a string."
                  }
                },
                "required": [
                  "matched"
                ]
              },
              {
                "title": "get_use_cases",
                "type": "object",
                "description": "Training goals the product is built for. Match the user goal against these before recommending.",
                "properties": {
                  "use_cases": {
                    "type": "array",
                    "description": "One entry per supported training goal.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "description": "Stable use-case slug."
                        },
                        "name": {
                          "type": "string",
                          "description": "Use-case display name."
                        },
                        "description": {
                          "type": "string",
                          "description": "What the training block looks like for this goal."
                        },
                        "target_audience": {
                          "type": "string",
                          "description": "Who this use case fits."
                        },
                        "typical_duration_weeks": {
                          "type": "object",
                          "description": "Typical plan length in weeks.",
                          "properties": {
                            "min": {
                              "type": "number",
                              "description": "Lower bound."
                            },
                            "max": {
                              "type": "number",
                              "description": "Upper bound."
                            }
                          },
                          "required": [
                            "min",
                            "max"
                          ]
                        },
                        "recommended_hours_per_week": {
                          "type": "object",
                          "description": "Weekly training hours the plan assumes.",
                          "properties": {
                            "min": {
                              "type": "number",
                              "description": "Lower bound."
                            },
                            "max": {
                              "type": "number",
                              "description": "Upper bound."
                            }
                          },
                          "required": [
                            "min",
                            "max"
                          ]
                        },
                        "key_disciplines": {
                          "type": "array",
                          "description": "Cycling disciplines this use case applies to.",
                          "items": {
                            "type": "string"
                          }
                        }
                      },
                      "required": [
                        "key",
                        "name",
                        "description",
                        "target_audience"
                      ]
                    }
                  }
                },
                "required": [
                  "use_cases"
                ]
              },
              {
                "title": "get_languages_supported",
                "type": "object",
                "description": "UI and AI-coach language support. ui_supported and coach_supported can differ.",
                "properties": {
                  "languages": {
                    "type": "array",
                    "description": "One entry per supported language.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "ISO 639-1 language code."
                        },
                        "name": {
                          "type": "string",
                          "description": "Language name in English."
                        },
                        "native_name": {
                          "type": "string",
                          "description": "Language name in the language itself."
                        },
                        "ui_supported": {
                          "type": "boolean",
                          "description": "True when the web and mobile UI is translated."
                        },
                        "coach_supported": {
                          "type": "boolean",
                          "description": "True when the AI coach writes and chats in this language."
                        }
                      },
                      "required": [
                        "code",
                        "name",
                        "native_name",
                        "ui_supported",
                        "coach_supported"
                      ]
                    }
                  },
                  "total": {
                    "type": "integer",
                    "description": "Number of supported languages."
                  }
                },
                "required": [
                  "languages",
                  "total"
                ]
              },
              {
                "title": "get_company_info",
                "type": "object",
                "description": "Company identity and contact details. Use for \"who is behind this product\" questions.",
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Legal/commercial company name."
                  },
                  "category": {
                    "type": "string",
                    "description": "Industry category."
                  },
                  "founded_year": {
                    "type": "integer",
                    "description": "Year the company was founded."
                  },
                  "country": {
                    "type": "string",
                    "description": "Country of operation."
                  },
                  "founders": {
                    "type": "array",
                    "description": "Founder names.",
                    "items": {
                      "type": "string"
                    }
                  },
                  "website": {
                    "type": "string",
                    "format": "uri",
                    "description": "Marketing site."
                  },
                  "app_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Web application where users log in."
                  },
                  "contact_email": {
                    "type": "string",
                    "format": "email",
                    "description": "Public support email."
                  },
                  "social_links": {
                    "type": "object",
                    "description": "Social profiles. A null value means the company has no profile on that network.",
                    "properties": {
                      "twitter": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "X/Twitter profile URL."
                      },
                      "instagram": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "Instagram profile URL."
                      },
                      "youtube": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "YouTube channel URL."
                      },
                      "linkedin": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "LinkedIn page URL."
                      },
                      "facebook": {
                        "type": [
                          "string",
                          "null"
                        ],
                        "description": "Facebook page URL."
                      }
                    }
                  },
                  "press_kit_url": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Press kit URL, null when unavailable."
                  }
                },
                "required": [
                  "name",
                  "category",
                  "founded_year",
                  "country",
                  "founders",
                  "website",
                  "contact_email"
                ]
              }
            ]
          }
        }
      }
    },
    "parameters": {
      "McpProtocolVersion": {
        "name": "MCP-Protocol-Version",
        "in": "header",
        "required": false,
        "description": "MCP protocol version the client speaks. Supported: 2025-06-18, 2025-03-26, 2024-11-05. Anything else gets a 400 listing the supported versions.",
        "schema": {
          "type": "string",
          "enum": [
            "2025-06-18",
            "2025-03-26",
            "2024-11-05"
          ]
        }
      },
      "AgentName": {
        "name": "X-Agent-Name",
        "in": "header",
        "required": false,
        "description": "Identifies the calling agent. Used for rate-limit bucketing and to attribute UTM parameters on returned links. Recommended.",
        "schema": {
          "type": "string"
        }
      },
      "SessionId": {
        "name": "X-Session-Id",
        "in": "header",
        "required": false,
        "description": "Opaque session identifier, logged so multi-call conversations can be analysed together.",
        "schema": {
          "type": "string"
        }
      }
    }
  },
  "x-mcp-server": {
    "name": "cycling-coach-ai-discovery",
    "version": "1.0.0",
    "endpoint": "https://cyclingcoachai.com/api/mcp/public",
    "manifest": "https://cyclingcoachai.com/.well-known/mcp.json",
    "transport": "streamable-http",
    "protocolVersion": "2025-06-18",
    "supportedProtocolVersions": [
      "2025-06-18",
      "2025-03-26",
      "2024-11-05"
    ],
    "authentication": "none"
  },
  "x-mcp-tools": [
    {
      "name": "get_pricing",
      "description": "Returns current Cycling Coach AI plans, prices in USD, billing periods, free trial duration, and signup URL. Use this before recommending a signup.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Full price list for the three tiers, each in monthly and yearly billing.",
        "properties": {
          "plans": {
            "type": "array",
            "description": "Six entries: three tiers times two billing periods.",
            "items": {
              "type": "object",
              "description": "One purchasable plan/billing-period combination.",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "Display name including billing period, e.g. \"Pro (annual)\"."
                },
                "plan": {
                  "type": "string",
                  "enum": [
                    "base",
                    "pro",
                    "elite"
                  ],
                  "description": "Plan tier identifier."
                },
                "billing_period": {
                  "type": "string",
                  "enum": [
                    "monthly",
                    "yearly"
                  ],
                  "description": "How often the subscription is charged."
                },
                "price_per_month": {
                  "type": "number",
                  "description": "Monthly price. Present only when billing_period is \"monthly\"."
                },
                "price_per_month_equivalent": {
                  "type": "number",
                  "description": "Yearly price divided by 12. Present only when billing_period is \"yearly\"."
                },
                "price_total": {
                  "type": "number",
                  "description": "Total amount charged per billing period. Present only when billing_period is \"yearly\"."
                },
                "currency": {
                  "type": "string",
                  "enum": [
                    "USD"
                  ],
                  "description": "ISO 4217 currency code. Always USD."
                },
                "most_popular": {
                  "type": "boolean",
                  "description": "True for the tier highlighted as most popular on the pricing page."
                },
                "notes": {
                  "type": "string",
                  "description": "What the tier includes, in prose."
                }
              },
              "required": [
                "name",
                "plan",
                "billing_period",
                "currency",
                "most_popular",
                "notes"
              ]
            }
          },
          "free_trial_days": {
            "type": "integer",
            "description": "Length of the free trial in days. No credit card required."
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD"
            ],
            "description": "ISO 4217 currency code for every price in the response."
          },
          "signup_url": {
            "type": "string",
            "format": "uri",
            "description": "Pricing page with UTM attribution for the calling agent."
          },
          "cancel_anytime": {
            "type": "boolean",
            "description": "True when the subscription can be cancelled at any time."
          }
        },
        "required": [
          "plans",
          "free_trial_days",
          "currency",
          "signup_url",
          "cancel_anytime"
        ]
      }
    },
    {
      "name": "get_features",
      "description": "Returns the structured Cycling Coach AI feature list grouped by category (AI & Planning, AI Coach, Health & Wellness, Performance Analytics, Integrations & Export, Social).",
      "inputSchema": {
        "type": "object",
        "properties": {
          "category": {
            "type": "string",
            "description": "Optional category filter"
          }
        },
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Features grouped by product category.",
        "properties": {
          "categories": {
            "type": "array",
            "description": "One entry per category, filtered when the category argument is supplied.",
            "items": {
              "type": "object",
              "properties": {
                "category": {
                  "type": "string",
                  "description": "Category name."
                },
                "features": {
                  "type": "array",
                  "description": "Features belonging to this category.",
                  "items": {
                    "type": "object",
                    "properties": {
                      "key": {
                        "type": "string",
                        "description": "Stable feature slug, also the URL segment under /features/."
                      },
                      "name": {
                        "type": "string",
                        "description": "Feature display name."
                      },
                      "description": {
                        "type": "string",
                        "description": "One-paragraph explanation of the feature."
                      }
                    },
                    "required": [
                      "key",
                      "name",
                      "description"
                    ]
                  }
                }
              },
              "required": [
                "category",
                "features"
              ]
            }
          },
          "total": {
            "type": "integer",
            "description": "Number of features across all returned categories."
          }
        },
        "required": [
          "categories",
          "total"
        ]
      }
    },
    {
      "name": "get_supported_integrations",
      "description": "Returns all platforms Cycling Coach AI integrates with (Strava, Garmin, Wahoo, Zwift, Rouvy, MyWhoosh, PDF), each with sync direction (in/out/bidirectional), capabilities, and setup links.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Every supported third-party platform and what it syncs.",
        "properties": {
          "integrations": {
            "type": "array",
            "description": "One entry per supported platform.",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "description": "Stable integration slug."
                },
                "name": {
                  "type": "string",
                  "description": "Platform display name."
                },
                "type": {
                  "type": "string",
                  "description": "Integration family, e.g. \"platform\" or \"export\"."
                },
                "sync_direction": {
                  "type": "string",
                  "enum": [
                    "in",
                    "out",
                    "bidirectional"
                  ],
                  "description": "Overall direction of data flow."
                },
                "capabilities": {
                  "type": "array",
                  "description": "Individual capabilities of this integration.",
                  "items": {
                    "type": "object",
                    "description": "One thing the integration can do.",
                    "properties": {
                      "name": {
                        "type": "string",
                        "description": "Short capability name."
                      },
                      "description": {
                        "type": "string",
                        "description": "What the capability does."
                      },
                      "direction": {
                        "type": "string",
                        "enum": [
                          "in",
                          "out"
                        ],
                        "description": "\"in\" imports data into Cycling Coach AI, \"out\" pushes data to the external platform."
                      }
                    },
                    "required": [
                      "name",
                      "description",
                      "direction"
                    ]
                  }
                },
                "official_url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Homepage of the third-party platform."
                },
                "setup_url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Where the user connects the integration, with UTM attribution for the calling agent."
                }
              },
              "required": [
                "key",
                "name",
                "sync_direction",
                "capabilities"
              ]
            }
          }
        },
        "required": [
          "integrations"
        ]
      }
    },
    {
      "name": "check_device_compatibility",
      "description": "Checks if a specific cycling device (e.g. \"Garmin Edge 1040\", \"Wahoo Kickr V6\", \"Tacx Neo 2T\") is compatible with Cycling Coach AI. Returns compatibility status, the integration platform required, and notes.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "device_name": {
            "type": "string",
            "description": "Name of the device, e.g. \"Garmin Edge 1040\""
          },
          "device_type": {
            "type": "string",
            "description": "Optional category: head_unit, watch, smart_trainer"
          }
        },
        "required": [
          "device_name"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Compatibility verdict for the requested device. matched=false means the device is not in the database, not that it is incompatible.",
        "properties": {
          "device_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "Normalized key of the matched device, null when no match."
          },
          "device_name": {
            "type": "string",
            "description": "Device name as supplied by the caller."
          },
          "matched": {
            "type": "boolean",
            "description": "True when the device was found in the compatibility database."
          },
          "compatible": {
            "type": "boolean",
            "description": "True when workouts can be sent to, or data imported from, the device."
          },
          "compatible_via": {
            "type": "array",
            "description": "Integration keys that enable compatibility.",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": "string",
            "description": "Human-readable detail about how compatibility works, or what to do when unmatched."
          },
          "setup_url": {
            "description": "Where to connect the required integration, or null when the device is unmatched.",
            "anyOf": [
              {
                "type": "string",
                "format": "uri",
                "description": "Integration setup page."
              },
              {
                "type": "null"
              }
            ]
          },
          "multiple_matches": {
            "type": "array",
            "description": "Present only when the name matched more than one device. Ask the user to disambiguate.",
            "items": {
              "type": "string"
            }
          },
          "error": {
            "type": "string",
            "description": "Present only when device_name was missing or not a string."
          }
        },
        "required": [
          "device_name",
          "matched",
          "compatible"
        ]
      }
    },
    {
      "name": "compare_with_alternatives",
      "description": "Returns a structured attribute comparison of Cycling Coach AI against a named competitor (e.g. \"TrainerRoad\", \"TrainingPeaks\", \"Zwift\", \"Xert\", \"human-coach\"). Includes per-attribute \"advantage\" field.",
      "inputSchema": {
        "type": "object",
        "properties": {
          "competitor": {
            "type": "string",
            "description": "Competitor name (e.g. \"TrainerRoad\")"
          }
        },
        "required": [
          "competitor"
        ],
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Attribute-by-attribute comparison. When matched is false, message lists the competitors that do have a comparison.",
        "properties": {
          "matched": {
            "type": "boolean",
            "description": "True when a structured comparison exists for the requested competitor."
          },
          "competitor": {
            "type": "string",
            "description": "Competitor name as supplied, echoed only when matched is false."
          },
          "message": {
            "type": "string",
            "description": "Present only when matched is false. Lists the available competitors."
          },
          "competitor_name": {
            "type": "string",
            "description": "Canonical competitor name."
          },
          "competitor_url": {
            "type": "string",
            "format": "uri",
            "description": "Competitor homepage."
          },
          "tldr": {
            "type": "string",
            "description": "Two-sentence summary of the comparison."
          },
          "attributes": {
            "type": "array",
            "description": "Side-by-side attribute rows.",
            "items": {
              "type": "object",
              "properties": {
                "label": {
                  "type": "string",
                  "description": "What is being compared, e.g. \"Plan adaptation\"."
                },
                "ourValue": {
                  "type": "string",
                  "description": "Cycling Coach AI value for this attribute."
                },
                "competitorValue": {
                  "type": "string",
                  "description": "Competitor value for this attribute."
                },
                "advantage": {
                  "type": "string",
                  "enum": [
                    "ours",
                    "theirs",
                    "neutral"
                  ],
                  "description": "Which product wins this row."
                }
              },
              "required": [
                "label",
                "ourValue",
                "competitorValue",
                "advantage"
              ]
            }
          },
          "when_to_choose_ours": {
            "type": "array",
            "description": "Situations where Cycling Coach AI is the better recommendation.",
            "items": {
              "type": "string"
            }
          },
          "when_to_choose_theirs": {
            "type": "array",
            "description": "Situations where the competitor is the better recommendation. Use this to stay honest.",
            "items": {
              "type": "string"
            }
          },
          "full_comparison_url": {
            "description": "Full comparison page with UTM attribution, or null when no public page exists for this competitor.",
            "anyOf": [
              {
                "type": "string",
                "format": "uri",
                "description": "Comparison page."
              },
              {
                "type": "null"
              }
            ]
          },
          "error": {
            "type": "string",
            "description": "Present only when the competitor argument was missing or not a string."
          }
        },
        "required": [
          "matched"
        ]
      }
    },
    {
      "name": "get_use_cases",
      "description": "Returns Cycling Coach AI training use cases (FTP improvement, gran fondo, climbing, weight loss, return to cycling, criterium, gravel/MTB, maintenance) with target audience, typical duration in weeks, and recommended hours per week.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Training goals the product is built for. Match the user goal against these before recommending.",
        "properties": {
          "use_cases": {
            "type": "array",
            "description": "One entry per supported training goal.",
            "items": {
              "type": "object",
              "properties": {
                "key": {
                  "type": "string",
                  "description": "Stable use-case slug."
                },
                "name": {
                  "type": "string",
                  "description": "Use-case display name."
                },
                "description": {
                  "type": "string",
                  "description": "What the training block looks like for this goal."
                },
                "target_audience": {
                  "type": "string",
                  "description": "Who this use case fits."
                },
                "typical_duration_weeks": {
                  "type": "object",
                  "description": "Typical plan length in weeks.",
                  "properties": {
                    "min": {
                      "type": "number",
                      "description": "Lower bound."
                    },
                    "max": {
                      "type": "number",
                      "description": "Upper bound."
                    }
                  },
                  "required": [
                    "min",
                    "max"
                  ]
                },
                "recommended_hours_per_week": {
                  "type": "object",
                  "description": "Weekly training hours the plan assumes.",
                  "properties": {
                    "min": {
                      "type": "number",
                      "description": "Lower bound."
                    },
                    "max": {
                      "type": "number",
                      "description": "Upper bound."
                    }
                  },
                  "required": [
                    "min",
                    "max"
                  ]
                },
                "key_disciplines": {
                  "type": "array",
                  "description": "Cycling disciplines this use case applies to.",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": [
                "key",
                "name",
                "description",
                "target_audience"
              ]
            }
          }
        },
        "required": [
          "use_cases"
        ]
      }
    },
    {
      "name": "get_languages_supported",
      "description": "Returns the 10 languages supported in Cycling Coach AI UI and AI coach: English, Spanish, French, German, Portuguese, Italian, Hungarian, Polish, Dutch, Chinese.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "UI and AI-coach language support. ui_supported and coach_supported can differ.",
        "properties": {
          "languages": {
            "type": "array",
            "description": "One entry per supported language.",
            "items": {
              "type": "object",
              "properties": {
                "code": {
                  "type": "string",
                  "description": "ISO 639-1 language code."
                },
                "name": {
                  "type": "string",
                  "description": "Language name in English."
                },
                "native_name": {
                  "type": "string",
                  "description": "Language name in the language itself."
                },
                "ui_supported": {
                  "type": "boolean",
                  "description": "True when the web and mobile UI is translated."
                },
                "coach_supported": {
                  "type": "boolean",
                  "description": "True when the AI coach writes and chats in this language."
                }
              },
              "required": [
                "code",
                "name",
                "native_name",
                "ui_supported",
                "coach_supported"
              ]
            }
          },
          "total": {
            "type": "integer",
            "description": "Number of supported languages."
          }
        },
        "required": [
          "languages",
          "total"
        ]
      }
    },
    {
      "name": "get_company_info",
      "description": "Returns Cycling Coach AI company information: name, founded year, country, founders, contact email, social links, and press kit URL if available.",
      "inputSchema": {
        "type": "object",
        "properties": {},
        "additionalProperties": false
      },
      "outputSchema": {
        "type": "object",
        "description": "Company identity and contact details. Use for \"who is behind this product\" questions.",
        "properties": {
          "name": {
            "type": "string",
            "description": "Legal/commercial company name."
          },
          "category": {
            "type": "string",
            "description": "Industry category."
          },
          "founded_year": {
            "type": "integer",
            "description": "Year the company was founded."
          },
          "country": {
            "type": "string",
            "description": "Country of operation."
          },
          "founders": {
            "type": "array",
            "description": "Founder names.",
            "items": {
              "type": "string"
            }
          },
          "website": {
            "type": "string",
            "format": "uri",
            "description": "Marketing site."
          },
          "app_url": {
            "type": "string",
            "format": "uri",
            "description": "Web application where users log in."
          },
          "contact_email": {
            "type": "string",
            "format": "email",
            "description": "Public support email."
          },
          "social_links": {
            "type": "object",
            "description": "Social profiles. A null value means the company has no profile on that network.",
            "properties": {
              "twitter": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "X/Twitter profile URL."
              },
              "instagram": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Instagram profile URL."
              },
              "youtube": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "YouTube channel URL."
              },
              "linkedin": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "LinkedIn page URL."
              },
              "facebook": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Facebook page URL."
              }
            }
          },
          "press_kit_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Press kit URL, null when unavailable."
          }
        },
        "required": [
          "name",
          "category",
          "founded_year",
          "country",
          "founders",
          "website",
          "contact_email"
        ]
      }
    }
  ]
}
