cnvs.app Discovery API

Service-level discovery documents for AI agents and MCP clients.

GitHub OpenAPI

Operations 5

1 of 5 operations are conformant: apis.io called them with no credentials and the responses matched this contract; 3 more answered but could not be checked against a schema. Checked 2026-11-12. how this works · status file

GET /mcp MCP server discovery observed #
GET /.well-known/mcp.json MCP `.well-known` document observed #
GET /llms.txt llms.txt (LLM-facing site guide) #
GET /quotas.json Machine-readable limits manifest conformant #
GET /openapi.json This OpenAPI spec observed #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/cnvs-app:cnvs-app-discovery-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

cnvs-app-discovery-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Cnvs App Discovery API
  version: 1.0.0
  contact:
    name: cnvs.app
    url: https://cnvs.app/about/
  license:
    name: Public service — no account required
    url: https://cnvs.app/about/
  x-accessLock:
    modes:
    - write
    - all
    keyFormat: 8 chars [a-z0-9] (6-char legacy keys also accepted)
    channel:
      rest: X-Board-Key header
      mcp: X-Board-Key header OR `access_key` tool argument
      ws: Sec-WebSocket-Protocol subprotocol `cnvs-key.<code>` (server echoes it back in the 101 response). `?key=<code>` query parameter is accepted as a deprecated fallback but leaks the key into access logs.
    endpoints:
      lock: POST /api/boards/{id}/lock
      unlock: POST /api/boards/{id}/unlock
      verify: POST /api/boards/{id}/verify-key
    rejection:
      rest:
        status: 401
        body:
          code: board_locked
          lockMode: write|all
      mcp:
        jsonRpcCode: -32001
        data:
          code: board_locked
          lockMode: write|all
      ws:
        status: 401
        note: Upgrade rejected for read-locked boards; write-locked allows the upgrade but server drops mutation frames with type=error code=board_locked.
    note: By default boards are open (anyone with the ID can read + write). When locked, mode `write` only requires the key for mutations; `all` requires it for both reads and writes. There is no recovery — losing the key loses the board.
  x-boardImportLimits:
    maxItems: 2550
    maxBatchStatements: 320
    maxBoundParamsPerStatement: 100
    countedCollections:
    - texts
    - lines
    - images
    - columns
    - tasks
    - lanes
    maxLaneTitles: 10
    laneTitleRule: Each lane title must reference a lane used by a column created in the same request.
    infrastructureToken: X-Import-Token is server-to-server. A valid token selects the infrastructure REST/MCP and board-create rate tiers; it never bypasses hard caps, validation, storage, board access locks, or Cloudflare platform limits.
  x-cors:
    allowOrigin: '*'
    allowMethods:
    - GET
    - POST
    - DELETE
    - OPTIONS
    allowHeaders:
    - Content-Type
    - Mcp-Session-Id
    - If-None-Match
    - X-Board-Key
    note: 'Every public endpoint (/api/boards/..., /json/..., /svg-preview/..., /mcp) returns permissive CORS headers and handles OPTIONS preflight. The board ID is the access credential when the board is unlocked; locked boards additionally require the X-Board-Key header. X-Import-Token is intentionally absent: it is a server-to-server credential, so browser clients cannot send it and belong on the standard per-IP rate tier.'
  x-fieldLimits:
    maxAuthorChars: 80
    maxThumbnailBytes: 8000
    textWidth:
      min: 160
      max: 4096
    columnWidth:
      min: 200
      max: 480
      default: 280
    maxLaneTitleChars: 200
    maxColumnTitleChars: 200
    maxTaskNameChars: 500
    maxAssigneeChars: 200
  x-operationLimits:
    maxRecolorItems: 500
    maxBatchOps: 500
    wsContinuation:
      maxFrames: 500
      idleMs: 500
  x-quotasManifest:
    url: /quotas.json
    note: Machine-readable single source of truth for limits. Cache ≤ 5 min.
  x-rateLimits:
    standard:
      restMcpPerBoard:
        requests: 60
        windowSeconds: 10
        per: boardId
      boardCreate:
        requests: 5
        windowSeconds: 60
        per: clientIp
        enforcement: Cloudflare Rate Limiting binding; permissive and eventually consistent per edge location
    infrastructure:
      credential: valid X-Import-Token (server-to-server only)
      restMcpPerBoard:
        requests: 600
        windowSeconds: 10
        per: boardId
      boardCreate:
        requests: 50
        windowSeconds: 60
        per: infrastructureToken
        perNote: Keyed by a one-way digest of the token VALUE (the credential never enters limiter keys or telemetry). There is a single import-token secret, so all trusted callers share this one bucket — it is not a per-integration allowance.
        enforcement: Cloudflare Rate Limiting binding; permissive and eventually consistent per edge location
    webSocket:
      requests: 60
      windowSeconds: 10
      per: boardId
      infrastructureTokenChangesTier: false
    security:
      lockUnlockVerify:
        requests: 5
        windowSeconds: 60
        per: clientIp
        infrastructureTokenChangesTier: false
    scope: Browser WebSocket frames are rate-limited inside the per-board BoardServer Durable Object — single-writer and strong. REST and MCP are rate-limited in whichever Worker isolate serves the request; because Cloudflare routes traffic across many isolates (regions, colos, warm/cold starts), a caller distributing load effectively gets N × the advertised cap. Treat REST/MCP as a soft per-isolate ceiling, not a strong global guarantee. X-Import-Token raises only the REST/MCP and board-create tiers; it does not bypass hard caps or board access locks.
    response:
      rest:
        status: 429
        headers:
          Retry-After: <seconds>
        body:
          code: rate_limited
          retryAfterSeconds: 10
      mcp:
        jsonRpcCode: -32000
        data:
          code: rate_limited
          retryAfterSeconds: 10
      ws:
        body:
          type: error
          code: rate_limited
          retryAfterSeconds: 10
    note: Strong for browser WS (DO-enforced), soft for REST/MCP (isolate-local; bypassable via distribution). Cloudflare's platform-level limits remain the hard wall. Live values in /quotas.json.
  x-requestBodyLimit:
    bytes: 5242880
    note: Single-request body cap (5 MiB) enforced via Content-Length AND during the streamed body read. Chunked / header-less clients cannot bypass the cap. HTTP 413 (REST) / JSON-RPC -32000 code:payload_too_large (MCP).
  x-webSocketErrors:
    note: 'Every WebSocket error frame is `{type: "error", code, message, originType, originId}` and is sent ONLY to the socket whose mutation failed — never broadcast. `originType`/`originId` echo the frame that caused it.'
    codes:
      rate_limited: Rejection — per-board WS budget exceeded (see x-rateLimits). Nothing was written.
      board_locked: Rejection — board is write-locked and this socket has no valid key (see x-accessLock). Nothing was written.
      quota_exceeded: Rejection — a per-board quota would be exceeded; carries `kind`. Nothing was written.
      invalid_payload: Rejection — the frame failed validation; carries `field`. Nothing was written.
      server_error: 'NOT a rejection — the mutation threw server-side (e.g. a D1 storage reset mid-write). The throw may occur before, during or after the write commits, so the outcome is unknown: the change may be fully stored, partly stored, or absent. Re-read the board (GET /json/{id}) and reconcile; do not assume local state is correct, and do not blindly undo the change.'
  description: 'Operations tagged Discovery across 2 of this provider''s published API definitions: cnvs-app-openapi.json, cnvs-app-openapi.yml. Each path carries the servers of the definition it was published in.'
servers:
- url: https://cnvs.app
  description: Production
tags:
- name: Discovery
  description: Service-level discovery documents for AI agents and MCP clients.
paths:
  /mcp:
    get:
      tags:
      - Discovery
      summary: MCP server discovery
      description: 'Returns a small JSON document describing the MCP endpoint (name, version, protocol). For actual MCP interaction, POST JSON-RPC 2.0 requests to this same URL, or open an SSE stream with `Accept: text/event-stream` plus the `Mcp-Session-Id` returned by `initialize` — a stream request without that header is rejected. Streams are recycled on an idle TTL (5 min) and a hard lifetime cap (15 min); reconnect with the same session id and your subscriptions carry over. Send `DELETE /mcp` with the session id when you are done. See `/llms.txt` for full tool reference.'
      operationId: mcpDiscovery
      responses:
        '200':
          description: MCP discovery document.
          content:
            application/json:
              schema:
                type: object
        '400':
          description: SSE stream requested without a valid `Mcp-Session-Id` header.
          content:
            application/json:
              schema:
                type: object
    servers:
    - url: https://cnvs.app
      description: Production
  /.well-known/mcp.json:
    get:
      tags:
      - Discovery
      summary: MCP `.well-known` document
      description: 'Service-level discovery per the `.well-known` convention: server URL, protocol version, tool list, resource URIs, capabilities. For AI agents that scan `.well-known/` for available integrations.'
      operationId: wellKnownMcp
      responses:
        '200':
          description: Discovery document.
          content:
            application/json:
              schema:
                type: object
    servers:
    - url: https://cnvs.app
      description: Production
  /llms.txt:
    get:
      tags:
      - Discovery
      summary: llms.txt (LLM-facing site guide)
      description: Human- and LLM-readable description of cnvs.app including the full MCP tool/resource reference, client config snippets for Claude Desktop / Claude Code, rate limits, and author tagging conventions.
      operationId: llmsTxt
      responses:
        '200':
          description: Plain text.
          content:
            text/plain:
              schema:
                type: string
    servers:
    - url: https://cnvs.app
      description: Production
  /quotas.json:
    get:
      tags:
      - Discovery
      summary: Machine-readable limits manifest
      description: 'Single source of truth for per-request body caps, per-board quotas, board-import limits and rate-limit windows. Values are emitted from server constants and active configuration. Response is `Cache-Control: public, max-age=300`.'
      operationId: quotasJson
      responses:
        '200':
          description: Quotas / limits manifest.
          content:
            application/json:
              schema:
                type: object
                properties:
                  perRequest:
                    type: object
                    properties:
                      maxBodyBytes:
                        type: integer
                  perBoard:
                    type: object
                    properties:
                      maxTexts:
                        type: integer
                      maxTextContentChars:
                        type: integer
                      maxImages:
                        type: integer
                      maxImageBytesTotal:
                        type: integer
                      maxStrokes:
                        type: integer
                      maxColumns:
                        type: integer
                      maxColumnsPerLane:
                        type: integer
                      maxLanes:
                        type: integer
                      maxTasks:
                        type: integer
                      maxTaskContentChars:
                        type: integer
                  boardImport:
                    type: object
                    properties:
                      maxItems:
                        type: integer
                        const: 2550
                      maxBatchStatements:
                        type: integer
                        const: 320
                      countedCollections:
                        type: array
                        items:
                          type: string
                      counting:
                        type: string
                      maxLaneTitles:
                        type: integer
                        const: 10
                      laneTitleRule:
                        type: string
                      infrastructureToken:
                        type: string
                  fieldLimits:
                    type: object
                    properties:
                      maxAuthorChars:
                        type: integer
                        const: 80
                      maxThumbnailBytes:
                        type: integer
                        const: 8000
                      textWidth:
                        type: object
                        properties:
                          min:
                            type: integer
                            const: 160
                          max:
                            type: integer
                            const: 4096
                      columnWidth:
                        type: object
                        properties:
                          min:
                            type: integer
                            const: 200
                          max:
                            type: integer
                            const: 480
                          default:
                            type: integer
                            const: 280
                      maxLaneTitleChars:
                        type: integer
                        const: 200
                      maxColumnTitleChars:
                        type: integer
                        const: 200
                      maxTaskNameChars:
                        type: integer
                        const: 500
                      maxAssigneeChars:
                        type: integer
                        const: 200
                  operationLimits:
                    type: object
                    properties:
                      maxRecolorItems:
                        type: integer
                        const: 500
                      maxBatchOps:
                        type: integer
                        const: 500
                      wsContinuation:
                        type: object
                        properties:
                          maxFrames:
                            type: integer
                            const: 500
                          idleMs:
                            type: integer
                            const: 500
                  rateLimits:
                    type: object
                    description: Standard and X-Import-Token infrastructure REST/MCP tiers, plus unchanged WebSocket and access-lock security limits.
                    properties:
                      standard:
                        type: object
                      infrastructure:
                        type: object
                      webSocket:
                        type: object
                      security:
                        type: object
                      tokenPolicy:
                        type: string
    servers:
    - url: https://cnvs.app
      description: Production
  /openapi.json:
    get:
      tags:
      - Discovery
      summary: This OpenAPI spec
      description: Self-reference. The OpenAPI 3.1 spec you're reading now.
      operationId: openapiJson
      responses:
        '200':
          description: OpenAPI document.
          content:
            application/json:
              schema:
                type: object
    servers:
    - url: https://cnvs.app
      description: Production
components:
  securitySchemes:
    BoardKey:
      type: apiKey
      in: header
      name: X-Board-Key
      description: 8-char [a-z0-9] access key (6-char legacy keys also accepted). Required for write operations on any locked board, and for ALL operations on a board locked with mode=all. Obtain via POST /api/boards/{id}/lock. Browsers carry the key in localStorage under `cnvs:board_key:<id>`.
externalDocs:
  description: cnvs.app / MCP reference
  url: https://cnvs.app/llms.txt
x-refined-from:
- cnvs-app-openapi.json
- cnvs-app-openapi.yml
x-mcp:
  endpoint: https://cnvs.app/mcp
  wellKnown: https://cnvs.app/.well-known/mcp.json
  transport: streamable-http
  note: This REST API covers reads and mutations one-to-one with MCP. MCP additionally provides live `notifications/resources/updated` subscriptions and the `wait_for_update` long-poll tool.