{
  "openapi": "3.1.0",
  "info": {
    "title": "Jinn gateway (MCP)",
    "version": "1.0.0",
    "summary": "The public Jinn MCP gateway: one bearer-authed JSON-RPC endpoint that serves an agent a brand's verified record.",
    "description": "The Jinn gateway is a single, read-only MCP endpoint. Point any MCP client at it with a bearer token and an agent can read a brand — voice, positioning, messaging, product, and design system — before it generates a word.\n\nIt speaks MCP over HTTP: JSON-RPC 2.0 to one URL, with three methods — `initialize`, `tools/list`, and `tools/call`. There is no REST resource tree; this document describes the transport, not a per-tool contract. Call `tools/list` for the exact tool set your token can reach: tier and brand allowlist resolve at request time, so the same bearer keeps working across trial, renewal, and upgrade.\n\nAuth is bearer-only. Tokens are self-serve, read-only, scoped to your own brands, and shown once at mint — see https://jinn.works/docs/mcp for the tool reference, auth model, and error taxonomy.\n\nRate limit: 120 requests per minute per token. Over the limit answers HTTP 429 with `Retry-After`.\n\nStatus-code shape: transport-level failures use real HTTP codes (401 for auth, 429 for rate limiting, 202 for accepted notifications, 405 for GET, which needs no token). Every other JSON-RPC error — parse, invalid request, method not found, invalid params, tool failure — rides an HTTP 200 response carrying a JSON-RPC error envelope, per JSON-RPC 2.0.",
    "termsOfService": "https://jinn.works/api-terms",
    "contact": {
      "name": "Jinn support",
      "url": "https://jinn.works/contact"
    }
  },
  "externalDocs": {
    "description": "Developer docs: tool reference, auth model, rate limits, error taxonomy.",
    "url": "https://jinn.works/docs/mcp"
  },
  "servers": [
    {
      "url": "https://app.jinn.works",
      "description": "Jinn gateway"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "MCP gateway",
      "description": "The single MCP endpoint. Transport is JSON-RPC 2.0 over HTTP POST.",
      "externalDocs": {
        "url": "https://jinn.works/docs/mcp"
      }
    }
  ],
  "paths": {
    "/api/mcp": {
      "post": {
        "tags": [
          "MCP gateway"
        ],
        "operationId": "mcpJsonRpc",
        "summary": "Call the MCP gateway (JSON-RPC 2.0)",
        "description": "Supported methods: `initialize` (protocol-version negotiation and server info), `tools/list` (the tools this token can call), and `tools/call` (invoke one).\n\nMCP notifications (`notifications/*`) are accepted and answered `202` with no body. An unknown method returns a JSON-RPC `method not found` error inside an HTTP 200.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/JsonRpcRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC 2.0 response envelope — `result` on success, `error` on any non-transport failure.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "202": {
            "description": "Notification accepted. No body."
          },
          "401": {
            "description": "Missing, malformed, invalid, revoked, or expired bearer token. The body is a JSON-RPC error envelope (code -32001).",
            "headers": {
              "WWW-Authenticate": {
                "description": "Bearer challenge (RFC 6750).",
                "schema": {
                  "type": "string",
                  "examples": [
                    "Bearer"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (120 requests per 60s per token). Back off and retry.",
            "headers": {
              "Retry-After": {
                "description": "Seconds to wait before retrying.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Limit": {
                "description": "Requests allowed in the window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer"
                }
              },
              "X-RateLimit-Reset": {
                "description": "Unix time (seconds) when the window resets.",
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "MCP gateway"
        ],
        "operationId": "mcpGetNotAllowed",
        "summary": "Not supported: use POST",
        "description": "The gateway offers no server-initiated SSE stream, so GET answers 405 with `Allow: POST` before any auth (MCP spec, Streamable HTTP transport). Every MCP method goes through POST.",
        "security": [],
        "responses": {
          "405": {
            "description": "GET is not supported on this endpoint.",
            "headers": {
              "Allow": {
                "description": "The supported method.",
                "schema": {
                  "type": "string",
                  "examples": [
                    "POST"
                  ]
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/JsonRpcResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "Opaque Jinn token (jmcp_ prefix)",
        "description": "Mint, rotate, and revoke tokens in the token panel at https://jinn.works/account/tokens. Secrets are shown once, at creation."
      }
    },
    "schemas": {
      "JsonRpcRequest": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "description": "Request id, echoed on the response. Omit for a notification (answered 202).",
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ]
          },
          "method": {
            "type": "string",
            "description": "One of `initialize`, `tools/list`, `tools/call`, or `notifications/*`."
          },
          "params": {
            "type": "object",
            "additionalProperties": true,
            "description": "Method-specific parameters. For `tools/call`: `name` plus an `arguments` object. The per-tool argument shape comes from `tools/list`, not from this document."
          }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true,
            "description": "Method-specific result. Present on success; mutually exclusive with `error`."
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer",
                "description": "JSON-RPC error code. Standard codes plus the gateway set: -32001 unauthorized, -32002 forbidden scope, -32003 rate limited, -32000 tool error."
              },
              "message": {
                "type": "string"
              },
              "data": {
                "type": "object",
                "additionalProperties": true,
                "description": "Machine-readable detail so an agent can branch without parsing prose. Auth failures carry a `code` (token_malformed, token_invalid, token_revoked, token_expired); an expired token also carries `renewal_url` and `tier`. Tool failures carry a `kind` and a `retryable` flag."
              }
            }
          }
        }
      }
    }
  }
}
