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:
    pricing, features, supported integrations, device compatibility, training use cases, supported languages,
    company details, and structured comparisons against competitors.

    Most of that data is reached through the Model Context Protocol server at `POST /api/mcp/public`, which
    exposes 8 tools. Each tool, with its input and output JSON Schema, is enumerated in the
    `x-mcp-tools` extension of this document, so a client can plan calls without a handshake.

    ## When to use this API

    Reach for it when a user asks whether a specific bike computer, trainer or watch works with the product,
    what a subscription costs, how the product compares with TrainerRoad, TrainingPeaks, Zwift or a human coach,
    which languages the AI coach speaks, or what a training plan for a given goal looks like.

    It is not a training API: it exposes no user accounts, workouts or activity data. Users who want their own
    training data use the authenticated product MCP at https://app.usecoachai.com.

    ## Errors

    Every non-MCP endpoint returns the same JSON envelope: `{ "error": { "code", "message", "hint", "docs_url" } }`.
    The MCP endpoint returns JSON-RPC 2.0 errors. Neither ever returns HTML.

    ## Rate limits

    The MCP endpoint allows 100 requests per minute per IP and 1000 per minute per `X-Agent-Name`.
    Over the limit it answers 429 with a `Retry-After` header. Send `X-Agent-Name` so your traffic is
    bucketed 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
