# Generated from openapi/ by scripts/bundle-openapi.mjs. Do not edit.
openapi: 3.1.0
info:
  title: MCP Studio API
  version: 1.0.0
  description: Create, configure, and monitor MCP servers programmatically. Every operation from the per-resource references at https://docs.appatools.com/api, in one document.
  contact:
    name: MCP Studio support
    email: zair@appatools.com
servers:
  - url: https://appatools.com/mcp-studio
    description: Production
security:
  - apiKey: []
tags:
  - name: Servers
    description: An MCP server is one live endpoint that AI clients connect to, built from one or more sources.
  - name: Sources
    description: A source is anything a server reads before answering, such as a docs site, a repository, a PDF, or another MCP server.
  - name: Tools
    description: The actions an AI client can call on a server, such as `search_docs` or `ask_question`.
  - name: Custom tools
    description: Tools you describe in plain English, built once and attachable to any of your servers.
  - name: Retrieval rules
    description: Plain-English instructions about when a server should use a source.
  - name: Analytics
    description: Usage of one server by the AI clients connected to it.
  - name: Account
    description: Plan, usage, and entitlements for the account that owns the key.
  - name: MCP endpoint
    description: The endpoint AI clients connect to.
paths:
  /api/mcp/create:
    post:
      tags:
        - Servers
      operationId: createServer
      summary: Create a server
      description: |
        Creates a server from one or more sources, queues them for indexing,
        and returns the live endpoint URL plus a ready-to-paste client config.

        Requires an account-wide key; a scoped key is refused with `key_scoped`.
        Invalid tool names are dropped before the count is checked, so at least
        3 valid tools must remain.
      x-codeSamples:
        - lang: shell
          label: curl
          source: |
            curl -X POST https://appatools.com/mcp-studio/api/mcp/create \
              -H "Authorization: Bearer $MCP_STUDIO_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "name": "Engineering Context",
                "sources": [{ "url": "https://docs.example.com" }],
                "tools": ["search_docs", "get_code_examples", "ask_question"]
              }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateServerRequest"
            examples:
              docs:
                summary: A documentation site
                value:
                  name: Engineering Context
                  description: Our API docs and the main repository
                  sources:
                    - url: https://docs.example.com
                      label: Product docs
                    - url: https://github.com/example/api
                  tools:
                    - search_docs
                    - get_code_examples
                    - ask_question
                    - find_api_reference
              private:
                summary: A private server federating another MCP server
                value:
                  name: Support Context
                  visibility: private
                  sources:
                    - url: https://mcp.example.com/mcp
                      type: mcp
                      auth:
                        headerName: Authorization
                        secret: Bearer sk_live_example
                  tools:
                    - search_docs
                    - ask_question
                    - query_source
      responses:
        "200":
          description: The server was created and its sources are queued for indexing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreatedServer"
        "400":
          description: The request is incomplete or invalid.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                name:
                  value:
                    error: Name is required
                sources:
                  value:
                    error: At least 1 source is required
                tools:
                  value:
                    error: Select between 3 and 10 tools
                validTools:
                  value:
                    error: At least 3 valid tools required
                urls:
                  value:
                    error: At least one valid source URL is required
                internal:
                  value:
                    error: "These URLs point to private or internal network addresses and cannot be indexed: http://10.0.0.5/"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "402":
          description: More sources than your plan includes on one server.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LimitError"
        "403":
          description: |
            The key is scoped to specific servers (`key_scoped`), or the account
            is at its server limit (`enterprise_limit`).
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LimitError"
              examples:
                scoped:
                  value:
                    error: key_scoped
                    message: This API key is limited to specific servers, so it cannot create new ones. Use an account-wide key to create servers, or create the server in the dashboard and add it to this key.
                serverLimit:
                  value:
                    error: enterprise_limit
                    message: You have reached the 3 MCP server limit. Contact zair@appatools.com for an Enterprise plan with custom options.
                    upgradeUrl: https://appatools.com/mcp-studio/account/billing
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          description: A source carries a credential but credential storage is unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: credentials_unavailable
                message: Authenticated MCP sources are unavailable because this deployment has no credential encryption key configured. Add the source without a key, or contact support.
      security:
        - apiKey: []
  /api/mcp/list:
    get:
      tags:
        - Servers
      operationId: listServers
      summary: List servers
      description: |
        Returns every server on the account, including servers
        deleted within the last 7 days (`status: deleted`) so they can still be
        found while they are restorable. A scoped key sees only its own servers.
      responses:
        "200":
          description: The servers this key can see.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ServerSummary"
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - apiKey: []
  /api/mcp/{id}:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    get:
      tags:
        - Servers
      operationId: getServer
      summary: Get a server
      description: |
        Returns a server with per-source indexing progress, its endpoint URL,
        and its client config snippet. For a private server the snippet carries
        a placeholder token, because access tokens are shown only once.
      responses:
        "200":
          description: The server.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ServerDetail"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
    delete:
      tags:
        - Servers
      operationId: deleteServer
      summary: Delete a server
      description: |
        Soft-deletes a server. It stops answering MCP clients immediately and
        stops counting toward your server limit. It can be restored from the
        dashboard for 7 days; after that its content is permanently deleted.
      responses:
        "200":
          description: The server was deleted.
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - retentionDays
                  - deletedAt
                  - purgeAt
                properties:
                  ok:
                    type: boolean
                    const: true
                  retentionDays:
                    type: integer
                    example: 7
                  deletedAt:
                    type: string
                    format: date-time
                  purgeAt:
                    type: string
                    format: date-time
                    description: When the server and its content are permanently deleted.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
    post:
      tags:
        - MCP endpoint
      operationId: mcpRequest
      summary: Send an MCP request
      description: |
        Send one JSON-RPC message. A request (a message with an `id`) gets a
        JSON-RPC response. A notification (no `id` member at all, such as
        `notifications/initialized`) is acknowledged with `202` and an empty
        body.

        A public server needs no credentials. A private server needs an
        access token on every request, including `initialize`.
      x-codeSamples:
        - lang: shell
          label: curl
          source: |
            curl -X POST https://appatools.com/mcp-studio/api/mcp/engineering-context-a1b2 \
              -H "Content-Type: application/json" \
              -H "Accept: application/json, text/event-stream" \
              -d '{
                "jsonrpc": "2.0",
                "id": 1,
                "method": "tools/call",
                "params": {
                  "name": "ask_question",
                  "arguments": { "question": "How do I rotate an API key?" }
                }
              }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/JsonRpcRequest"
            examples:
              initialize:
                summary: initialize
                value:
                  jsonrpc: "2.0"
                  id: 0
                  method: initialize
                  params:
                    protocolVersion: 2025-06-18
                    capabilities: {}
                    clientInfo:
                      name: my-script
                      version: 1.0.0
              listTools:
                summary: tools/list
                value:
                  jsonrpc: "2.0"
                  id: 1
                  method: tools/list
              callTool:
                summary: tools/call
                value:
                  jsonrpc: "2.0"
                  id: 2
                  method: tools/call
                  params:
                    name: ask_question
                    arguments:
                      question: How do I rotate an API key?
              initialized:
                summary: notifications/initialized
                value:
                  jsonrpc: "2.0"
                  method: notifications/initialized
      responses:
        "200":
          description: A JSON-RPC response. Tool failures and unknown methods are reported in `error` with HTTP `200`.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JsonRpcResponse"
              examples:
                initialize:
                  summary: initialize
                  value:
                    jsonrpc: "2.0"
                    id: 0
                    result:
                      protocolVersion: 2025-06-18
                      serverInfo:
                        name: Engineering Context
                        version: 1.0.0
                      capabilities:
                        tools: {}
                      instructions: Engineering Context answers from documentation indexed by MCP Studio...
                listTools:
                  summary: tools/list
                  value:
                    jsonrpc: "2.0"
                    id: 1
                    result:
                      tools:
                        - name: ask_question
                          description: Ask a natural language question and get an answer synthesized from all connected sources.
                          inputSchema:
                            type: object
                            properties:
                              question:
                                type: string
                            required:
                              - question
                callTool:
                  summary: tools/call
                  value:
                    jsonrpc: "2.0"
                    id: 2
                    result:
                      content:
                        - type: text
                          text: |-
                            To rotate a key, open Account > API Keys...

                            Source: https://docs.example.com/keys
        "202":
          description: A notification was received. The body is empty.
        "401":
          description: The server is private and the request carried no valid access token.
          headers:
            WWW-Authenticate:
              schema:
                type: string
                example: Bearer realm="MCP Studio", error="invalid_token"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JsonRpcResponse"
              example:
                jsonrpc: "2.0"
                id: null
                error:
                  code: -32001
                  message: "This MCP server is private. Add an access token to your client config as an Authorization: Bearer header. See https://docs.appatools.com/mcp-studio/guides/private-mcp-servers"
                  data:
                    reason: missing_token
                    docsUrl: https://docs.appatools.com/mcp-studio/guides/private-mcp-servers
        "404":
          description: No active server with that ID or slug.
        "429":
          $ref: "#/components/responses/RateLimited"
      security:
        - {}
        - accessToken: []
  /api/mcp/crawl:
    post:
      tags:
        - Servers
      operationId: refreshServer
      summary: Refresh a server
      description: |
        Queues a re-index so the server picks up changed content, for every
        source or for one. Returns once the work is queued; poll the progress
        endpoint to follow it.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - serverId
              properties:
                serverId:
                  type: string
                  description: The server's ID or slug.
                  example: engineering-context-a1b2
                sourceId:
                  type: string
                  description: Re-index only this source. It must belong to the server.
      responses:
        "200":
          description: The re-index is queued.
          content:
            application/json:
              schema:
                allOf:
                  - type: object
                    required:
                      - started
                      - queued
                    properties:
                      started:
                        type: boolean
                        const: true
                      queued:
                        type: integer
                        description: How many sources were queued.
                        example: 2
                  - $ref: "#/components/schemas/IndexProgress"
        "400":
          description: "`serverId` is missing."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: serverId is required
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: Unknown server, or a `sourceId` that is not on it.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                server:
                  value:
                    error: Server not found
                source:
                  value:
                    error: Source not found
      security:
        - apiKey: []
  /api/mcp/{id}/crawl-next:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    get:
      tags:
        - Servers
      operationId: getIndexProgress
      summary: Get indexing progress
      description: |
        A lightweight progress read for polling. It needs no credentials and
        reports only queue state, never content. Keep polling while `status`
        is `crawling`; any other value means the queue is drained.
      security: []
      responses:
        "200":
          description: Current indexing progress.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IndexProgress"
        "404":
          $ref: "#/components/responses/ServerNotFound"
  /api/mcp/{id}/visibility:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    patch:
      tags:
        - Servers
      operationId: setServerVisibility
      summary: Make a server public or private
      description: |
        Switches a server between public and private. Making a server private
        for the first time issues an access token and returns it **once** in
        `issuedToken.plaintext`; every MCP client then needs it as an
        `Authorization: Bearer` header.

        A server that indexes a private GitHub repository or reaches an MCP
        source with your credential cannot be made public until that source is
        removed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                visibility:
                  $ref: "#/components/schemas/Visibility"
            example:
              visibility: private
      responses:
        "200":
          description: The visibility now in effect.
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - visibility
                properties:
                  ok:
                    type: boolean
                    const: true
                  visibility:
                    $ref: "#/components/schemas/Visibility"
                  unchanged:
                    type: boolean
                    description: Present and `true` when the server already had this visibility.
                  maxTokens:
                    type: integer
                    example: 10
                  issuedToken:
                    oneOf:
                      - $ref: "#/components/schemas/IssuedAccessToken"
                      - type: "null"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
        "409":
          description: A private source keeps this server private.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: private_source_present
                message: This server indexes a private GitHub repo, so it cannot be made public. Disconnect the private source first — doing so also deletes everything indexed from it.
      security:
        - apiKey: []
  /api/mcp/{id}/sources:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    post:
      tags:
        - Sources
      operationId: addSource
      summary: Add a source
      description: |
        Adds a source to an existing server and queues it for indexing.

        Adding a private GitHub repository needs a GitHub account linked once
        in the dashboard; without it the request returns `422 auth_required`.
        A private repository or a credentialed MCP source makes the server
        private, and if it had no access token yet, one is issued and returned
        once in `issuedToken.plaintext`.
      x-codeSamples:
        - lang: shell
          label: curl
          source: |
            curl -X POST https://appatools.com/mcp-studio/api/mcp/engineering-context-a1b2/sources \
              -H "Authorization: Bearer $MCP_STUDIO_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{ "url": "https://github.com/example/api", "label": "API repository" }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
              properties:
                url:
                  type: string
                  format: uri
                  example: https://github.com/example/api
                type:
                  type: string
                  maxLength: 20
                  enum:
                    - website
                    - docs
                    - github
                    - api
                    - mcp
                    - pdf
                  description: Omit to detect it from the URL. Only `mcp` sources accept `auth`.
                label:
                  type: string
                  example: API repository
                auth:
                  type: object
                  description: A credential sent to a remote MCP server. Stored encrypted and never returned.
                  properties:
                    headerName:
                      type: string
                      enum:
                        - Authorization
                        - X-API-Key
                      default: Authorization
                    secret:
                      type: string
                      maxLength: 4096
                      writeOnly: true
      responses:
        "200":
          description: The source was added and queued for indexing.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AddedSource"
        "400":
          description: Invalid URL or credential.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                url:
                  value:
                    error: Valid URL required
                internal:
                  value:
                    error: That URL points to a private or internal network address
                    which cannot be indexed.: null
                header:
                  value:
                    error: Unsupported authentication header. Use Authorization or X-API-Key.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "402":
          description: |
            The server has used its included sources (`source_limit_reached`,
            `source_credit_required`) or its total source size
            (`source_size_limit_reached`). `purchaseUrl` buys one more source.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/LimitError"
                  - type: object
                    properties:
                      used:
                        type: integer
                      paidCredits:
                        type: integer
                      canUpgrade:
                        type: boolean
              example:
                error: source_limit_reached
                message: This server already uses 2 included sources. After that, each additional source is $3.
                used: 2
                limit: 2
                paidCredits: 0
                purchaseUrl: https://buy.stripe.com/example
        "404":
          $ref: "#/components/responses/ServerNotFound"
        "409":
          description: That URL is already on this server.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: Source already exists
        "422":
          description: A GitHub repository that cannot be read with the account's GitHub link.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    enum:
                      - auth_required
                      - not_found_or_no_access
                      - github_access_failed
                  message:
                    type: string
                  owner:
                    type: string
                  repo:
                    type: string
                  hasGithubLink:
                    type: boolean
                  isPrivate:
                    type: boolean
              example:
                error: auth_required
                message: This looks like a private GitHub repo. Link your GitHub account so we can verify ownership.
                owner: example
                repo: internal-api
                hasGithubLink: false
                isPrivate: true
        "503":
          description: The source carries a credential but credential storage is unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
      security:
        - apiKey: []
    patch:
      tags:
        - Sources
      operationId: updateSourceCredential
      summary: Rotate or remove an MCP source credential
      description: |
        Sets, replaces, or removes the credential MCP Studio sends to a remote
        MCP server, without removing the source (which would spend a source
        slot to re-add it). A new credential is tested by listing the remote
        server's tools before it is saved.

        Removing a credential does not make the server public.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - sourceId
              properties:
                sourceId:
                  type: string
                secret:
                  type: string
                  maxLength: 4096
                  writeOnly: true
                  description: The new header value. Send this or `remove`.
                headerName:
                  type: string
                  enum:
                    - Authorization
                    - X-API-Key
                  default: Authorization
                remove:
                  type: boolean
                  const: true
                  description: Send `true` to delete the stored credential.
            examples:
              rotate:
                value:
                  sourceId: cm1src000001
                  secret: Bearer sk_live_new
              remove:
                value:
                  sourceId: cm1src000001
                  remove: true
      responses:
        "200":
          description: The credential was saved or removed.
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - hasCredential
                properties:
                  ok:
                    type: boolean
                    const: true
                  hasCredential:
                    type: boolean
                  tools:
                    type: array
                    description: Tools the remote server listed with the new credential.
                    items:
                      type: string
        "400":
          description: Missing fields, or the source is not an MCP source.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                sourceId:
                  value:
                    error: sourceId is required
                notMcp:
                  value:
                    error: Only MCP sources can carry credentials.
                nothing:
                  value:
                    error: "Provide a credential, or remove: true."
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: Unknown server or source.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "422":
          description: The remote MCP server refused the credential.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: credential_rejected
                message: That MCP server rejected this credential.
      security:
        - apiKey: []
    delete:
      tags:
        - Sources
      operationId: removeSource
      summary: Remove a source
      description: |
        Removes a source by ID or by URL and deletes its indexed content.
        Removing a source that is not on the server succeeds with
        `removed: 0`, so a workflow can run this repeatedly.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Send `sourceId`, `url`, or both.
              properties:
                sourceId:
                  type: string
                url:
                  type: string
                  format: uri
            example:
              url: https://github.com/example/api
      responses:
        "200":
          description: The source and its content were removed.
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - removed
                properties:
                  ok:
                    type: boolean
                    const: true
                  removed:
                    type: integer
                    example: 1
                  purged:
                    type: object
                    description: What was deleted along with the source.
                    properties:
                      chunks:
                        type: integer
                        example: 1288
                      crawlUrls:
                        type: integer
                      indexJobs:
                        type: integer
                      callCitations:
                        type: integer
                  remainingPrivateSources:
                    type: integer
                    description: Private sources still on the server. While above zero, the server stays private.
        "400":
          description: Neither `sourceId` nor `url` was sent.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: sourceId or url required
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
  /api/mcp/{id}/tools:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    get:
      tags:
        - Tools
      operationId: getServerTools
      summary: List a server's tools
      description: |
        Returns the tools the server exposes now, the full built-in catalog,
        and the custom tools on your account that can be attached.
      responses:
        "200":
          description: The server's tools and what can be added.
          content:
            application/json:
              schema:
                type: object
                properties:
                  serverId:
                    type: string
                  slug:
                    type: string
                    example: engineering-context-a1b2
                  tools:
                    type: array
                    description: What the server exposes now.
                    items:
                      $ref: "#/components/schemas/ToolName"
                    example:
                      - search_docs
                      - get_code_examples
                      - ask_question
                  available:
                    type: array
                    description: Every built-in tool.
                    items:
                      $ref: "#/components/schemas/BuiltInTool"
                  customTools:
                    type: array
                    description: Your custom tools. Attach one as `custom:<id>`.
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        displayName:
                          type: string
                        description:
                          type: string
                        status:
                          type: string
                          enum:
                            - building
                            - ready
                            - failed
                  minTools:
                    type: integer
                    example: 3
                  maxTools:
                    type: integer
                    example: 10
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
    patch:
      tags:
        - Tools
      operationId: updateServerTools
      summary: Change a server's tools
      description: |
        Send `tools` to replace the whole selection, or `add` and `remove` to
        change it. Each accepts an array or a comma-separated string, which
        makes it easy to drive from a spreadsheet or a form field. When `tools`
        is present, `add` and `remove` are ignored.

        A change that leaves fewer than 3 or more than 10 tools is refused and
        nothing is saved. A change that alters nothing returns `200` with empty
        `added` and `removed`.
      x-codeSamples:
        - lang: shell
          label: curl
          source: |
            curl -X PATCH https://appatools.com/mcp-studio/api/mcp/engineering-context-a1b2/tools \
              -H "Authorization: Bearer $MCP_STUDIO_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{ "add": ["find_api_reference"], "remove": ["get_changelog"] }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                tools:
                  description: Replace the selection with exactly these tools.
                  oneOf:
                    - type: array
                      items:
                        $ref: "#/components/schemas/ToolName"
                    - type: string
                      description: Comma-separated tool names.
                add:
                  description: Tools to add.
                  oneOf:
                    - type: array
                      items:
                        $ref: "#/components/schemas/ToolName"
                    - type: string
                remove:
                  description: Tools to remove.
                  oneOf:
                    - type: array
                      items:
                        $ref: "#/components/schemas/ToolName"
                    - type: string
            examples:
              change:
                summary: Add and remove
                value:
                  add:
                    - find_api_reference
                  remove:
                    - get_changelog
              replace:
                summary: Replace the selection
                value:
                  tools:
                    - search_docs
                    - ask_question
                    - get_quickstart
                    - custom:cm1tool0001
              csv:
                summary: Comma-separated
                value:
                  add: extract_schema, search_issues
      responses:
        "200":
          description: The selection now in effect.
          content:
            application/json:
              schema:
                type: object
                properties:
                  serverId:
                    type: string
                  slug:
                    type: string
                  tools:
                    type: array
                    items:
                      $ref: "#/components/schemas/ToolName"
                  added:
                    type: array
                    items:
                      type: string
                    example:
                      - find_api_reference
                  removed:
                    type: array
                    items:
                      type: string
                    example:
                      - get_changelog
        "400":
          description: An unknown tool, or a selection outside 3 to 10. Nothing was saved.
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  unknown:
                    type: array
                    items:
                      type: string
                  validTools:
                    type: array
                    items:
                      type: string
                  tools:
                    type: array
                    description: The unchanged selection.
                    items:
                      type: string
              examples:
                unknown:
                  value:
                    error: Unknown tool name
                    unknown:
                      - search_everything
                    validTools:
                      - search_docs
                      - query_source
                      - get_code_examples
                      - summarize_content
                      - find_api_reference
                      - get_changelog
                      - search_issues
                      - get_quickstart
                      - extract_schema
                      - ask_question
                tooFew:
                  value:
                    error: An MCP server needs at least 3 tools. That change would leave 2.
                    tools:
                      - search_docs
                      - ask_question
                      - get_quickstart
                tooMany:
                  value:
                    error: An MCP server can expose at most 10 tools.
                empty:
                  value:
                    error: Provide "tools" to replace the selection, or "add" and/or "remove" to change it
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
  /api/custom-tools:
    get:
      tags:
        - Custom tools
      operationId: listCustomTools
      summary: List custom tools
      responses:
        "200":
          description: Every custom tool on the account.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tools:
                    type: array
                    items:
                      $ref: "#/components/schemas/CustomTool"
                  limit:
                    type: integer
                    description: How many custom tools an account can hold.
                    example: 5
                  available:
                    type: boolean
                    description: Whether building new tools is available.
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - apiKey: []
    post:
      tags:
        - Custom tools
      operationId: buildCustomTool
      summary: Build a custom tool
      description: |
        Builds a tool from a description. Building takes several seconds, so
        the response is a stream of [newline-delimited JSON](https://github.com/ndjson/ndjson-spec):
        one object per line, `progress` while it works, then exactly one
        `tool` with the finished tool or one `error`.

        A build that fails reports it in the stream with HTTP `200`, because
        the status is sent before the build starts. Read the last line.
        Limited to 15 builds per hour.
      x-codeSamples:
        - lang: shell
          label: curl
          source: |
            curl -N -X POST https://appatools.com/mcp-studio/api/custom-tools \
              -H "Authorization: Bearer $MCP_STUDIO_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{ "prompt": "Find every breaking change between two versions and the migration steps for each" }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - prompt
              properties:
                prompt:
                  type: string
                  minLength: 20
                  maxLength: 1000
                  description: What the tool should do, in plain English.
                  example: Find every breaking change between two versions and the migration steps for each
                sources:
                  type: array
                  maxItems: 8
                  description: Optional sources to design the tool around. Helps it pick the right retrieval behavior.
                  items:
                    type: object
                    properties:
                      url:
                        type: string
                        maxLength: 500
                      type:
                        type: string
                        maxLength: 20
                        default: website
                      label:
                        type:
                          - string
                          - "null"
                        maxLength: 100
      responses:
        "200":
          description: A stream of build events, one JSON object per line.
          content:
            application/x-ndjson:
              schema:
                oneOf:
                  - type: object
                    title: progress
                    properties:
                      type:
                        const: progress
                      stage:
                        type: string
                        enum:
                          - reading
                          - designing
                          - validating
                      message:
                        type: string
                  - type: object
                    title: tool
                    properties:
                      type:
                        const: tool
                      tool:
                        $ref: "#/components/schemas/CustomTool"
                  - type: object
                    title: error
                    properties:
                      type:
                        const: error
                      message:
                        type: string
              example: |
                {"type":"progress","stage":"reading","message":"Reading your description…"}
                {"type":"progress","stage":"designing","message":"Designing the tool against your indexed sources…"}
                {"type":"progress","stage":"validating","message":"Validating \"Find Breaking Changes\" and wiring it to your MCP server…"}
                {"type":"tool","tool":{"id":"cm1tool0001","name":"find_breaking_changes","displayName":"Find Breaking Changes","status":"ready"}}
        "400":
          description: The description is too short, or the body is not JSON.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: prompt_too_short
                message: Describe the tool in at least 20 characters so there is something to build from.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "409":
          description: The account already holds the maximum number of custom tools.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/LimitError"
              example:
                error: custom_tool_limit
                message: You can hold 5 custom tools. Delete one to build another.
                limit: 5
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          description: Building custom tools is unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: not_configured
                message: Custom tool building is not available on this deployment yet.
      security:
        - apiKey: []
  /api/custom-tools/{toolId}:
    parameters:
      - name: toolId
        in: path
        required: true
        description: The custom tool's ID (without the `custom:` prefix).
        schema:
          type: string
    get:
      tags:
        - Custom tools
      operationId: getCustomTool
      summary: Get a custom tool
      responses:
        "200":
          description: The tool.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CustomTool"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ToolNotFound"
      security:
        - apiKey: []
    delete:
      tags:
        - Custom tools
      operationId: deleteCustomTool
      summary: Delete a custom tool
      description: |
        Deletes the tool and detaches it from every server that uses it. The
        response lists those servers and how many tools each has left, so you
        can top up any that dropped below what you want.

        Because this changes servers across the whole account, it needs an
        account-wide key; a key scoped to specific servers gets `403 key_scoped`.
      responses:
        "200":
          description: The tool was deleted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    const: true
                  detachedFrom:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        slug:
                          type: string
                        remainingTools:
                          type: integer
                          example: 4
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: The key is scoped to specific servers.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: key_scoped
                message: This API key is limited to specific servers, so it cannot change resources shared across the whole account. Use an account-wide key.
        "404":
          $ref: "#/components/responses/ToolNotFound"
      security:
        - apiKey: []
  /api/retrieval-rules:
    get:
      tags:
        - Retrieval rules
      operationId: listRetrievalRules
      summary: List a server's retrieval rules
      parameters:
        - name: serverId
          in: query
          required: true
          description: The server's ID (`serverId` from create, or `id` from list). Slugs are not accepted here.
          schema:
            type: string
          example: cm1x2y3z40001abcd
      responses:
        "200":
          description: The server's rules.
          content:
            application/json:
              schema:
                type: object
                properties:
                  rules:
                    type: array
                    items:
                      $ref: "#/components/schemas/RetrievalRule"
                  limit:
                    type: integer
                    example: 10
                  available:
                    type: boolean
                    description: Whether new rules can be created.
                  example:
                    type: string
                    description: A sample rule sentence.
        "400":
          description: "`serverId` is missing."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: serverId is required.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/RuleServerNotFound"
      security:
        - apiKey: []
    post:
      tags:
        - Retrieval rules
      operationId: createRetrievalRule
      summary: Create a retrieval rule
      description: |
        Turns a sentence into a rule and returns it with its `effects`. If parts
        of the sentence asked for something a rule cannot do, they are dropped
        and listed in `removed`. Limited to 25 per hour.
      x-codeSamples:
        - lang: shell
          label: curl
          source: |
            curl -X POST https://appatools.com/mcp-studio/api/retrieval-rules \
              -H "Authorization: Bearer $MCP_STUDIO_API_KEY" \
              -H "Content-Type: application/json" \
              -d '{
                "serverId": "cm1x2y3z40001abcd",
                "sourceId": "cm1src000003",
                "naturalLanguage": "This is our email brand kit. For anything customer-facing, use it and follow its logo placement and color palette."
              }'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - serverId
                - naturalLanguage
              properties:
                serverId:
                  type: string
                  description: The server's ID. Slugs are not accepted here.
                  example: cm1x2y3z40001abcd
                sourceId:
                  type:
                    - string
                    - "null"
                  description: The source the rule is about. It must be on the server.
                naturalLanguage:
                  type: string
                  minLength: 20
                  maxLength: 600
                  example: This is our email brand kit. For anything customer-facing, use it and follow its logo placement and color palette.
      responses:
        "200":
          description: The rule is active.
          content:
            application/json:
              schema:
                type: object
                properties:
                  rule:
                    $ref: "#/components/schemas/RetrievalRule"
                  removed:
                    type: array
                    description: Parts of the sentence a rule cannot carry out.
                    items:
                      type: string
        "400":
          description: The sentence is the wrong length, the server has no sources, or it asks for something a rule cannot do.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                short:
                  value:
                    error: Describe the rule in at least 20 characters.
                long:
                  value:
                    error: Keep the rule under 600 characters.
                noSources:
                  value:
                    error: Add a source before writing a retrieval rule.
                scope:
                  value:
                    error: A retrieval rule can say which sources to prefer and how to use them. It cannot change how answers are grounded, cited, or how uncertainty is reported.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          description: Unknown server, or a source that is not on it.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              examples:
                server:
                  value:
                    error: Server not found.
                source:
                  value:
                    error: Source not found on this server.
        "409":
          description: The server already has the maximum number of rules.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: This server already has 10 retrieval rules. Delete one to add another.
        "422":
          description: The sentence could not be turned into a rule. Rephrase it and try again.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: Could not compile the rule.
        "429":
          $ref: "#/components/responses/RateLimited"
        "503":
          description: Retrieval rules are unavailable.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: Retrieval rules are unavailable on this deployment.
      security:
        - apiKey: []
  /api/retrieval-rules/{ruleId}:
    parameters:
      - name: ruleId
        in: path
        required: true
        schema:
          type: string
    patch:
      tags:
        - Retrieval rules
      operationId: updateRetrievalRule
      summary: Pause, resume, or reorder a rule
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Send at least one field.
              properties:
                enabled:
                  type: boolean
                priority:
                  type: integer
                  minimum: -100
                  maximum: 100
                  description: Higher runs first. Values outside the range are clamped.
            example:
              enabled: false
      responses:
        "200":
          description: The rule was updated.
          content:
            application/json:
              schema:
                type: object
                properties:
                  rule:
                    type: object
                    properties:
                      id:
                        type: string
                      enabled:
                        type: boolean
                      priority:
                        type: integer
        "400":
          description: Nothing to update.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: Nothing to update.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/RuleNotFound"
      security:
        - apiKey: []
    delete:
      tags:
        - Retrieval rules
      operationId: deleteRetrievalRule
      summary: Delete a rule
      responses:
        "200":
          description: The rule was deleted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    const: true
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/RuleNotFound"
      security:
        - apiKey: []
  /api/analytics/{id}/summary:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    get:
      tags:
        - Analytics
      operationId: getAnalyticsSummary
      summary: Get a usage summary
      description: |
        Headline metrics for a server, available on every plan. The deeper
        analytics tiers are in the dashboard; `upgradeUrl` links there.
      responses:
        "200":
          description: The server's usage summary.
          content:
            application/json:
              schema:
                type: object
                properties:
                  serverId:
                    type: string
                  slug:
                    type: string
                  name:
                    type: string
                  status:
                    type: string
                  generatedAt:
                    type: string
                    format: date-time
                  totalCalls:
                    type: integer
                    example: 42
                  failedCalls:
                    type: integer
                    example: 3
                  successRate:
                    type: number
                    description: Percent of calls that succeeded, from 0 to 100.
                    example: 92.86
                  avgDurationMs:
                    type: number
                    example: 180
                  activeSources:
                    type: integer
                    example: 2
                  citedSources:
                    type: integer
                    description: Sources that appeared in at least one answer.
                    example: 1
                  toolUsage:
                    type: array
                    items:
                      type: object
                      properties:
                        name:
                          type: string
                          example: ask_question
                        calls:
                          type: integer
                        successRate:
                          type: number
                  sourceUsage:
                    type: array
                    items:
                      type: object
                      properties:
                        url:
                          type: string
                        label:
                          type:
                            - string
                            - "null"
                        calls:
                          type: integer
                  clientUsage:
                    type: array
                    items:
                      type: object
                      properties:
                        client:
                          type: string
                          example: cursor
                        calls:
                          type: integer
                  callsOverTime:
                    type: array
                    description: Daily totals for the last 30 days that had calls.
                    items:
                      type: object
                      properties:
                        date:
                          type: string
                          format: date
                        calls:
                          type: integer
                        errors:
                          type: integer
                  tier:
                    type: string
                    const: free
                  upgradeUrl:
                    type: string
                    format: uri
                    example: https://appatools.com/mcp-studio/account/billing
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
  /api/analytics/{id}/calls:
    parameters:
      - $ref: "#/components/parameters/ServerId"
    get:
      tags:
        - Analytics
      operationId: listCalls
      summary: List requests
      description: |
        The request log: one entry per MCP request, newest first, 20 per page.
        Requires Core Analytics or higher (included during the free trial).
      parameters:
        - name: range
          in: query
          schema:
            type: string
            enum:
              - 7d
              - 30d
              - 90d
              - 1y
              - all
            default: all
        - name: tool
          in: query
          description: Only calls to this tool.
          schema:
            type: string
          example: ask_question
        - name: client
          in: query
          description: Only calls from this client. `Unknown` matches calls with no client name.
          schema:
            type: string
          example: cursor
        - name: status
          in: query
          schema:
            type: string
            enum:
              - ok
              - error
        - name: page
          in: query
          schema:
            type: integer
            minimum: 1
            default: 1
      responses:
        "200":
          description: One page of requests.
          content:
            application/json:
              schema:
                type: object
                properties:
                  calls:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        toolName:
                          type: string
                          example: ask_question
                        sourceUrl:
                          type:
                            - string
                            - "null"
                        sourceUrls:
                          type: array
                          items:
                            type: string
                        sources:
                          type: array
                          items:
                            type: object
                            properties:
                              label:
                                type: string
                              pages:
                                type: array
                                items:
                                  type: string
                        duration:
                          type: integer
                          description: Milliseconds.
                          example: 210
                        success:
                          type: boolean
                        createdAt:
                          type: string
                          format: date-time
                        input:
                          type: object
                          description: The arguments the client sent.
                          example:
                            question: How do I rotate an API key?
                        client:
                          type:
                            - string
                            - "null"
                          example: cursor
                  page:
                    type: integer
                  pageSize:
                    type: integer
                    example: 20
                  total:
                    type: integer
                  totalPages:
                    type: integer
                  failures:
                    type: integer
                  range:
                    type: string
                  filters:
                    type: object
                    description: Values available for the `tool` and `client` filters, across all time.
                    properties:
                      tools:
                        type: array
                        items:
                          type: object
                          properties:
                            value:
                              type: string
                            count:
                              type: integer
                      clients:
                        type: array
                        items:
                          type: object
                          properties:
                            value:
                              type: string
                            count:
                              type: integer
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: The request log needs Core Analytics.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
              example:
                error: request_log_locked
                message: The request log is part of Core Analytics.
        "404":
          $ref: "#/components/responses/ServerNotFound"
      security:
        - apiKey: []
  /api/billing/usage:
    get:
      tags:
        - Account
      operationId: getUsage
      summary: Get usage and limits
      responses:
        "200":
          description: Usage for the current period and the limits that apply.
          content:
            application/json:
              schema:
                type: object
                properties:
                  plan:
                    type: string
                    enum:
                      - free
                      - credits
                      - enterprise
                  mcpCallsUsed:
                    type: integer
                    description: MCP requests this period, across all of the account's servers.
                    example: 12
                  mcpCallsLimit:
                    type: integer
                    example: 50
                  mcpCallsPackage:
                    type: string
                    enum:
                      - none
                      - calls_100
                      - calls_1000
                      - calls_unlimited
                      - enterprise
                  callsExpiresAt:
                    type:
                      - string
                      - "null"
                    format: date-time
                  creditsActive:
                    type: boolean
                  serversUsed:
                    type: integer
                    example: 1
                  serversLimit:
                    type: integer
                    example: 3
                  sourcesLimitPerServer:
                    type: integer
                    example: 2
                  extraSources:
                    type: integer
                  sourcesActive:
                    type: boolean
                  usageOverageEnabled:
                    type: boolean
                  overageBillingReady:
                    type: boolean
                  overageBillingStatus:
                    type: string
                    example: not_configured
                  usageOverageBudgetUsd:
                    type: number
                  usageOverageSpendUsd:
                    type: number
                  previousMonthOverageSpendUsd:
                    type: number
                  withinLimits:
                    type: boolean
                  totalCallsAllTime:
                    type: integer
                  upgradeUrl:
                    type: string
                    format: uri
                    example: https://appatools.com/mcp-studio/account/billing
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - apiKey: []
  /api/account/entitlements:
    get:
      tags:
        - Account
      operationId: getEntitlements
      summary: Get entitlements
      description: Which analytics tier and limits apply to the account, including the free trial.
      responses:
        "200":
          description: The account's entitlements.
          content:
            application/json:
              schema:
                type: object
                properties:
                  tier:
                    type: string
                    enum:
                      - none
                      - core
                      - action
                      - predictive
                    description: The analytics tier in effect, including a trial.
                  paidTier:
                    type: string
                    enum:
                      - none
                      - core
                      - action
                      - predictive
                    description: The analytics tier you pay for.
                  source:
                    type: string
                    enum:
                      - free
                      - trial
                      - paid
                      - enterprise
                  requestLogEnabled:
                    type: boolean
                  actionEnabled:
                    type: boolean
                  predictiveEnabled:
                    type: boolean
                  coreChartsEnabled:
                    type: boolean
                  plan:
                    type: string
                    example: free
                  serversUsed:
                    type: integer
                  serversLimit:
                    type: integer
                  sourcesLimitPerServer:
                    type: integer
                  firstServerSourceLimit:
                    type: integer
                    description: Sources included on your first server. Five during the trial offer.
                    example: 5
                  perkServerId:
                    type:
                      - string
                      - "null"
                  perkAvailable:
                    type: boolean
                  trial:
                    type: object
                    properties:
                      status:
                        type: string
                        enum:
                          - none
                          - active
                          - converted
                          - expired
                      startedAt:
                        type:
                          - string
                          - "null"
                        format: date-time
                      endsAt:
                        type:
                          - string
                          - "null"
                        format: date-time
                      daysRemaining:
                        type:
                          - integer
                          - "null"
        "401":
          $ref: "#/components/responses/Unauthorized"
      security:
        - apiKey: []
components:
  schemas:
    SourceInput:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          description: An `http` or `https` URL. Addresses on private or internal networks are refused.
          example: https://docs.example.com
        type:
          type: string
          maxLength: 20
          enum:
            - website
            - docs
            - github
            - api
            - mcp
            - pdf
          description: |
            Omit to detect it from the URL. How a source is read always comes
            from the URL itself: a GitHub repository through the GitHub API, a
            `.pdf` as a document, anything else by crawling. Set `mcp` to
            connect a remote MCP server; only `mcp` sources accept `auth`.
        label:
          type: string
          maxLength: 100
          description: A human-readable name shown in the dashboard and in citations.
        auth:
          type: object
          description: A credential MCP Studio sends to a remote MCP server. Stored encrypted, never returned, and it makes the server private.
          properties:
            headerName:
              type: string
              enum:
                - Authorization
                - X-API-Key
              default: Authorization
            secret:
              type: string
              maxLength: 4096
              writeOnly: true
              description: The full header value, for example `Bearer sk_live_...`.
        retrievalRule:
          type: string
          minLength: 20
          maxLength: 600
          description: |
            Optional plain-English instruction about when to use this source,
            compiled into a retrieval rule after the server is created. Shorter
            than 20 characters is ignored. See the Retrieval rules reference.
    CreateServerRequest:
      type: object
      required:
        - name
        - sources
        - tools
      properties:
        name:
          type: string
          maxLength: 200
          description: Also used to derive the server's permanent slug.
          example: Engineering Context
        description:
          type: string
          maxLength: 1000
          description: Shown in the dashboard and to connecting AI clients.
        sources:
          type: array
          minItems: 1
          description: |
            What the server reads. The free plan includes 2 sources per server
            (5 on your first server during the trial); more returns `402`.
          items:
            $ref: "#/components/schemas/SourceInput"
        tools:
          type: array
          minItems: 3
          maxItems: 10
          description: The tools AI clients see. Change them later with the Tools endpoints.
          items:
            $ref: "#/components/schemas/ToolName"
          example:
            - search_docs
            - get_code_examples
            - ask_question
        visibility:
          $ref: "#/components/schemas/Visibility"
    CreatedServer:
      type: object
      required:
        - serverId
        - name
        - slug
        - url
        - configSnippet
        - visibility
        - createdAt
      properties:
        serverId:
          type: string
          example: cm1x2y3z40001abcd
        name:
          type: string
          example: Engineering Context
        slug:
          type: string
          example: engineering-context-a1b2
        url:
          type: string
          format: uri
          description: The MCP endpoint. Point any MCP client at it.
          example: https://appatools.com/mcp-studio/api/mcp/engineering-context-a1b2
        configSnippet:
          type: string
          description: A JSON client config (`mcpServers`) ready to paste into Cursor, Claude Desktop, or Windsurf.
          example: |-
            {
              "mcpServers": {
                "engineering-context-a1b2": {
                  "url": "https://appatools.com/mcp-studio/api/mcp/engineering-context-a1b2"
                }
              }
            }
        visibility:
          $ref: "#/components/schemas/Visibility"
        forcedPrivate:
          type: boolean
          description: "`true` when a private source (a private GitHub repository or a credentialed MCP source) made the server private."
        accessToken:
          type:
            - string
            - "null"
          description: For a private server, its first `mcps_live_` access token. Shown only here, so store it now.
          example: null
        createdAt:
          type: string
          format: date-time
    AnalyticsConfig:
      type: object
      properties:
        tier:
          type: string
          enum:
            - none
            - core
            - action
            - predictive
        selected:
          type: array
          items:
            type: string
        coreEnabled:
          type: boolean
        actionEnabled:
          type: boolean
        predictiveEnabled:
          type: boolean
        requestLogEnabled:
          type: boolean
    ServerSummary:
      type: object
      properties:
        id:
          type: string
          example: cm1x2y3z40001abcd
        name:
          type: string
          example: Engineering Context
        description:
          type:
            - string
            - "null"
        slug:
          type: string
          example: engineering-context-a1b2
        status:
          type: string
          description: "`indexing` while any source has work queued, then `active`, or `error` if no source could be indexed. `deleted` for a server in its 7-day restore window."
          example: active
        tools:
          type: array
          items:
            $ref: "#/components/schemas/ToolName"
        analyticsConfig:
          $ref: "#/components/schemas/AnalyticsConfig"
        sources:
          type: array
          items:
            type: object
            properties:
              url:
                type: string
              type:
                type: string
              label:
                type:
                  - string
                  - "null"
        visibility:
          $ref: "#/components/schemas/Visibility"
        totalCalls:
          type: integer
          example: 142
        createdAt:
          type: string
          format: date-time
        deletedAt:
          type:
            - string
            - "null"
          format: date-time
        purgeAt:
          type:
            - string
            - "null"
          format: date-time
          description: For a deleted server, when it is permanently deleted.
        retentionDays:
          type:
            - integer
            - "null"
    SourceDetail:
      type: object
      properties:
        id:
          type: string
        url:
          type: string
          example: https://docs.example.com
        type:
          type: string
          example: docs
        label:
          type:
            - string
            - "null"
        crawlStatus:
          type: string
          enum:
            - pending
            - crawling
            - complete
            - error
        crawlError:
          type:
            - string
            - "null"
          description: A reason code when `crawlStatus` is `error`, for example `auth_required` for a private GitHub repository with no linked GitHub account.
        isPrivate:
          type: boolean
        lastCrawled:
          type:
            - string
            - "null"
          format: date-time
        authHeaderName:
          type:
            - string
            - "null"
          description: The header a stored credential is sent in. The credential itself is never returned.
        hasCredential:
          type: boolean
        indexing:
          type:
            - object
            - "null"
          properties:
            pagesIndexed:
              type: integer
              example: 342
            chunksIndexed:
              type: integer
              example: 1288
            textChunks:
              type: integer
            codeChunks:
              type: integer
            headingChunks:
              type: integer
            embeddingsGenerated:
              type: integer
            embeddingCoveragePct:
              type: number
              example: 100
    AccessTokenSummary:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          example: Default access token
        prefix:
          type: string
          example: mcps_live_Ab12Cd
        lastUsedAt:
          type:
            - string
            - "null"
          format: date-time
        createdAt:
          type: string
          format: date-time
    IssuedAccessToken:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
          example: Default access token
        prefix:
          type: string
          example: mcps_live_Ab12Cd
        plaintext:
          type: string
          description: The full token. Shown once; only a hash is stored.
          example: mcps_live_Ab12Cd...
    ServerDetail:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        description:
          type:
            - string
            - "null"
        slug:
          type: string
        status:
          type: string
          example: indexing
        url:
          type: string
          format: uri
          example: https://appatools.com/mcp-studio/api/mcp/engineering-context-a1b2
        configSnippet:
          type: string
        visibility:
          $ref: "#/components/schemas/Visibility"
        visibilityLocked:
          type: boolean
          description: "`true` while a private source keeps the server private."
        visibilityLockedAt:
          type:
            - string
            - "null"
          format: date-time
        accessTokens:
          type: array
          description: Active access tokens for a private server. Prefixes only.
          items:
            $ref: "#/components/schemas/AccessTokenSummary"
        tools:
          type: array
          items:
            $ref: "#/components/schemas/ToolName"
        sources:
          type: array
          items:
            $ref: "#/components/schemas/SourceDetail"
        totalCalls:
          type: integer
        createdAt:
          type: string
          format: date-time
        paidSourceSlots:
          type: integer
        paidSourceCredits:
          type: integer
        bonusSourceSlots:
          type: integer
        freeSourceLimit:
          type: integer
          example: 2
        sourceLimit:
          type: integer
          description: How many sources this server may hold today.
          example: 2
        analyticsConfig:
          $ref: "#/components/schemas/AnalyticsConfig"
        sourceSize:
          type: object
          properties:
            atLimit:
              type: boolean
            nearLimit:
              type: boolean
            canUpgrade:
              type: boolean
    SourceProgress:
      type: object
      properties:
        sourceId:
          type: string
        url:
          type: string
        crawlStatus:
          type: string
          enum:
            - pending
            - crawling
            - complete
            - error
        crawlError:
          type:
            - string
            - "null"
        jobState:
          type:
            - string
            - "null"
          enum:
            - queued
            - discovering
            - fetching
            - finalizing
            - complete
            - failed
            - null
        attempts:
          type: integer
        urlsDiscovered:
          type: integer
          example: 812
        urlsProcessed:
          type: integer
          example: 340
        pagesIndexed:
          type: integer
          example: 338
        chunksIndexed:
          type: integer
          example: 2104
        percent:
          type:
            - integer
            - "null"
          example: 42
        startedAt:
          type:
            - string
            - "null"
          format: date-time
        heartbeatAt:
          type:
            - string
            - "null"
          format: date-time
        stalled:
          type: boolean
        message:
          type:
            - string
            - "null"
          example: Indexed 338 of 812 pages.
    IndexProgress:
      type: object
      properties:
        status:
          type: string
          description: "`crawling` while any source still has work queued. Anything else means the queue is drained."
          example: crawling
        currentSource:
          type:
            - string
            - "null"
          example: https://docs.example.com
        remaining:
          type: integer
          example: 1
        total:
          type: integer
          example: 2
        sources:
          type: array
          items:
            $ref: "#/components/schemas/SourceProgress"
    ToolName:
      type: string
      description: |
        A built-in tool name, or `custom:<id>` for a custom tool you built
        (see the Custom tools reference).
      example: search_docs
      anyOf:
        - enum:
            - search_docs
            - query_source
            - get_code_examples
            - summarize_content
            - find_api_reference
            - get_changelog
            - search_issues
            - get_quickstart
            - extract_schema
            - ask_question
        - pattern: ^custom:[A-Za-z0-9_-]+$
    Visibility:
      type: string
      enum:
        - public
        - private
      description: |
        `private` requires an `mcps_live_` access token (or the owner's API
        key) on every MCP request. Any value other than `private` is treated as
        `public`.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: A machine-readable code (for example `source_limit`) or a human-readable message.
          example: Server not found
        message:
          type: string
          description: A sentence you can show to a person. Present on coded errors.
    LimitError:
      type: object
      required:
        - error
        - message
      properties:
        error:
          type: string
          example: source_limit
        message:
          type: string
          example: Free tier includes 2 sources per server. After that, each additional source is $3.
        limit:
          type: integer
          example: 2
        upgradeUrl:
          type: string
          format: uri
          description: Absolute link to Billing, so an automation can include a working link in what it sends.
          example: https://appatools.com/mcp-studio/account/billing
        purchaseUrl:
          type: string
          format: uri
          description: Checkout link for one extra source, already tied to your account. Present on source limits.
    AddedSource:
      type: object
      properties:
        id:
          type: string
          example: cm1src000002
        url:
          type: string
          example: https://github.com/example/api
        type:
          type: string
          example: github
        label:
          type:
            - string
            - "null"
          example: API repository
        crawlStatus:
          type: string
          example: pending
        crawlError:
          type:
            - string
            - "null"
        isPrivate:
          type: boolean
        hasCredential:
          type: boolean
        authHeaderName:
          type:
            - string
            - "null"
        createdAt:
          type: string
          format: date-time
        autoPrivate:
          type: boolean
          description: "`true` when this source made the server private."
        issuedToken:
          description: The server's first access token, when this source made it private. Shown once.
          oneOf:
            - type: object
              properties:
                id:
                  type: string
                name:
                  type: string
                prefix:
                  type: string
                plaintext:
                  type: string
            - type: "null"
    BuiltInTool:
      type: object
      properties:
        name:
          type: string
          example: search_docs
        displayName:
          type: string
          example: Search Documentation
        description:
          type: string
          example: Full-text search across all connected documentation sources. Returns relevant passages and their source URLs.
        category:
          type: string
          example: search
    CustomTool:
      type: object
      properties:
        id:
          type: string
          example: cm1tool0001
        name:
          type: string
          description: The name AI clients call. Attach the tool as `custom:<id>`, not by this name.
          example: find_breaking_changes
        displayName:
          type: string
          example: Find Breaking Changes
        description:
          type: string
          example: Returns changelog entries and migration steps for changes that break compatibility between two versions.
        prompt:
          type: string
          description: The description the tool was built from.
        status:
          type: string
          enum:
            - building
            - ready
            - failed
          description: Only `ready` tools can be attached or appear to AI clients.
        buildError:
          type:
            - string
            - "null"
        retrieval:
          type:
            - string
            - "null"
          enum:
            - docs
            - code
            - schema
            - null
          description: What kind of content the tool searches.
        parameters:
          type: array
          description: The arguments AI clients pass when calling the tool.
          items:
            type: object
            properties:
              name:
                type: string
                example: from_version
              type:
                type: string
                enum:
                  - string
                  - number
                  - boolean
              description:
                type: string
              required:
                type: boolean
        createdAt:
          type: string
          format: date-time
    RetrievalRule:
      type: object
      properties:
        id:
          type: string
        sourceId:
          type:
            - string
            - "null"
        naturalLanguage:
          type: string
          description: The sentence as you wrote it.
        enabled:
          type: boolean
        priority:
          type: integer
          example: 0
        status:
          type: string
          enum:
            - compiling
            - ready
            - failed
        error:
          type:
            - string
            - "null"
        createdAt:
          type: string
          format: date-time
        effects:
          type: array
          description: What the rule does, in plain English. Check these rather than the sentence.
          items:
            type: string
          example:
            - "Trigger on requests mentioning: email, newsletter, landing page, brand kit"
            - Always include up to 1 passage from Brand kit
        valid:
          type: boolean
          description: "`false` if the rule no longer applies, for example because its source was removed. An invalid rule does nothing."
    JsonRpcRequest:
      type: object
      required:
        - jsonrpc
        - method
      properties:
        jsonrpc:
          const: "2.0"
        id:
          description: Omit entirely for a notification. `0` is a valid request id.
          oneOf:
            - type: string
            - type: integer
        method:
          type: string
          enum:
            - initialize
            - tools/list
            - tools/call
            - ping
            - notifications/initialized
        params:
          type: object
          description: For `tools/call`, `name` and `arguments`.
          properties:
            name:
              type: string
              example: ask_question
            arguments:
              type: object
              additionalProperties: true
            protocolVersion:
              type: string
              enum:
                - 2024-11-05
                - 2025-03-26
                - 2025-06-18
    JsonRpcResponse:
      type: object
      properties:
        jsonrpc:
          const: "2.0"
        id:
          oneOf:
            - type: string
            - type: integer
            - type: "null"
        result:
          type: object
          additionalProperties: true
        error:
          type: object
          properties:
            code:
              type: integer
            message:
              type: string
            data:
              type: object
              additionalProperties: true
  responses:
    ServerNotFound:
      description: |
        No server with that ID or slug on this account, a deleted server, or a
        server outside this key's scope.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Server not found
    Unauthorized:
      description: No API key, a malformed key, or a revoked key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Authentication required
    RateLimited:
      description: Too many requests. Wait for `Retry-After` seconds and try again.
      headers:
        Retry-After:
          description: Seconds until the limit resets.
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
            example: 0
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Too many requests. Please try again later.
    ToolNotFound:
      description: No custom tool with that ID on this account.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Tool not found
    RuleServerNotFound:
      description: No server with that ID or slug on this account, or a server outside this key's scope.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Server not found.
    RuleNotFound:
      description: No rule with that ID on a server this key can reach.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            error: Rule not found.
  parameters:
    ServerId:
      name: id
      in: path
      required: true
      description: The server's ID or its slug. Both are accepted everywhere.
      schema:
        type: string
      example: engineering-context-a1b2
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: msk_live_
      description: |
        An MCP Studio API key, sent as `Authorization: Bearer msk_live_...`.
        Create one under **Account > API Keys** in MCP Studio. A key is shown
        exactly once; only a hash is stored.

        A key can cover the whole account or be **scoped** to specific
        servers. A scoped key cannot create servers, and a server outside its
        scope returns `404`, exactly as a server on another account does.
    accessToken:
      type: http
      scheme: bearer
      bearerFormat: mcps_live_
      description: |
        Needed only for a private server. Send `Authorization: Bearer mcps_live_...`.
        Create access tokens on the server's page in the dashboard; one is
        also returned once when a server first becomes private. The owner's
        `msk_live_` API key is accepted too.
