{
  "openapi": "3.1.0",
  "info": {
    "title": "Anahana agent-facing API",
    "version": "1.1.1",
    "summary": "The MCP endpoint, its OAuth 2.1 tier, and the static discovery surfaces on www.anahana.com.",
    "description": "Anahana (anahana.com) publishes wellness and spiritual-growth content in 24 languages. This document describes every machine-facing endpoint the site exposes. Everything is read-only and everything it returns is already public on the website — there is no private data, no write action, and no credential required to read anything. The single dynamic endpoint is `POST /mcp`, a Model Context Protocol server over Streamable HTTP; the rest are static discovery documents. Human-readable companion: https://www.anahana.com/en/ai-agents/resources-for-ai-agents/",
    "termsOfService": "https://www.anahana.com/en/terms/",
    "contact": {
      "name": "Anahana",
      "email": "team@anahana.com",
      "url": "https://www.anahana.com/en/contact/"
    },
    "license": {
      "name": "Quote and summarize with attribution: yes. Full republication: no. AI training: yes.",
      "url": "https://www.anahana.com/robots.txt"
    }
  },
  "externalDocs": {
    "description": "Resources for AI Agents — every agent-facing surface with example calls",
    "url": "https://www.anahana.com/en/ai-agents/resources-for-ai-agents/"
  },
  "servers": [
    {
      "url": "https://www.anahana.com",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "mcp",
      "description": "Model Context Protocol server (Streamable HTTP, JSON-RPC 2.0)."
    },
    {
      "name": "oauth",
      "description": "OAuth 2.1 registered tier. Optional — anonymous access to /mcp is fully supported."
    },
    {
      "name": "discovery",
      "description": "Static agent-discovery documents."
    }
  ],
  "paths": {
    "/mcp": {
      "post": {
        "tags": ["mcp"],
        "operationId": "mcpJsonRpc",
        "summary": "MCP JSON-RPC 2.0 endpoint (Streamable HTTP)",
        "description": "A single JSON-RPC 2.0 endpoint implementing MCP over Streamable HTTP. Two-step usage: (1) call `initialize` and read the `mcp-session-id` **response header**; (2) send that value back as an `mcp-session-id` request header on every later call. Responses are returned as a `text/event-stream` of `event: message` lines carrying JSON-RPC payloads. Negotiated protocol versions: 2025-11-25 (latest), 2025-06-18, 2025-03-26, 2024-11-05, 2024-10-07. Anonymous calls are rate limited to 30 requests/minute per IP; calls bearing an OAuth 2.1 access token get 120 requests/minute per client.",
        "externalDocs": {
          "description": "Model Context Protocol specification",
          "url": "https://modelcontextprotocol.io/"
        },
        "security": [{}, { "mcpOAuth": ["read:content"] }],
        "parameters": [
          {
            "name": "mcp-session-id",
            "in": "header",
            "required": false,
            "description": "Session id returned in the `mcp-session-id` response header of `initialize`. Required on every request after `initialize`.",
            "schema": { "type": "string" }
          },
          {
            "name": "mcp-protocol-version",
            "in": "header",
            "required": false,
            "description": "Negotiated protocol version, echoed back on subsequent requests by spec-compliant clients.",
            "schema": { "type": "string", "examples": ["2025-11-25"] }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/JsonRpcRequest" },
              "examples": {
                "initialize": {
                  "summary": "Step 1 — initialize (read mcp-session-id from the response headers)",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "initialize",
                    "params": {
                      "protocolVersion": "2025-11-25",
                      "capabilities": {},
                      "clientInfo": { "name": "your-agent", "version": "1.0.0" }
                    }
                  }
                },
                "toolsList": {
                  "summary": "List the three tools",
                  "value": { "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
                },
                "searchContent": {
                  "summary": "tools/call — search_content",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 3,
                    "method": "tools/call",
                    "params": {
                      "name": "search_content",
                      "arguments": { "query": "box breathing" }
                    }
                  }
                },
                "getArticle": {
                  "summary": "tools/call — get_article",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 4,
                    "method": "tools/call",
                    "params": {
                      "name": "get_article",
                      "arguments": { "url_or_slug": "111-angel-number" }
                    }
                  }
                },
                "lookupAngelNumber": {
                  "summary": "tools/call — lookup_angel_number",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 5,
                    "method": "tools/call",
                    "params": {
                      "name": "lookup_angel_number",
                      "arguments": { "number": "1111" }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response, delivered as a server-sent-events stream. The `initialize` response additionally carries the `mcp-session-id` header.",
            "headers": {
              "mcp-session-id": {
                "description": "Session identifier. Returned by `initialize`; send it back on every subsequent request.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "text/event-stream": {
                "schema": { "type": "string" },
                "examples": {
                  "initializeResult": {
                    "summary": "initialize result",
                    "value": "event: message\ndata: {\"result\":{\"protocolVersion\":\"2025-11-25\",\"capabilities\":{\"tools\":{\"listChanged\":true}},\"serverInfo\":{\"name\":\"Anahana Content MCP\",\"version\":\"1.1.0\"}},\"jsonrpc\":\"2.0\",\"id\":1}\n"
                  }
                }
              },
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JsonRpcResponse" }
              }
            }
          },
          "400": {
            "description": "Malformed JSON-RPC, or a call made without the `mcp-session-id` header.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/JsonRpcResponse" }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded. Anonymous: 30/min per IP. Registered: 120/min per client_id.",
            "headers": {
              "Retry-After": {
                "description": "Seconds until the current one-minute window resets.",
                "schema": { "type": "integer" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RateLimitError" }
              }
            }
          }
        }
      },
      "options": {
        "tags": ["mcp"],
        "operationId": "mcpPreflight",
        "summary": "CORS preflight (does not consume rate-limit budget)",
        "responses": {
          "200": { "description": "CORS headers. `Access-Control-Allow-Origin: *`; `mcp-session-id` is exposed." }
        }
      }
    },
    "/mcp/register": {
      "post": {
        "tags": ["oauth"],
        "operationId": "registerClient",
        "summary": "Dynamic client registration (RFC 7591)",
        "description": "Open registration — no human approval, no pre-existing credential, no waiting. Registering raises the rate limit to 120/min and gives a stable, revocable client identity. It does not change what the three currently published tools return.",
        "security": [{}],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/ClientMetadata" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registered. Returns `client_id`, and `client_secret` for confidential clients.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "400": { "description": "Invalid client metadata." }
        }
      }
    },
    "/mcp/authorize": {
      "get": {
        "tags": ["oauth"],
        "operationId": "authorize",
        "summary": "Authorization endpoint (OAuth 2.1 authorization code + PKCE)",
        "description": "There is no consent screen and no login — nothing user-owned is being delegated, so every valid request from a registered client is auto-approved and answered with a 302 to the client's `redirect_uri` carrying `code` and `state`. Headless agents can read the `Location` header instead of following it.",
        "security": [{}],
        "parameters": [
          { "name": "response_type", "in": "query", "required": true, "schema": { "type": "string", "const": "code" } },
          { "name": "client_id", "in": "query", "required": true, "schema": { "type": "string" } },
          { "name": "redirect_uri", "in": "query", "required": true, "schema": { "type": "string", "format": "uri" } },
          { "name": "code_challenge", "in": "query", "required": true, "schema": { "type": "string" } },
          { "name": "code_challenge_method", "in": "query", "required": true, "schema": { "type": "string", "const": "S256" } },
          { "name": "state", "in": "query", "required": false, "schema": { "type": "string" } },
          { "name": "scope", "in": "query", "required": false, "description": "Normalized to `read:content`, the only scope.", "schema": { "type": "string" } }
        ],
        "responses": {
          "302": {
            "description": "Redirect to `redirect_uri` with `code` and `state`.",
            "headers": { "Location": { "schema": { "type": "string", "format": "uri" } } }
          },
          "400": { "description": "Unknown client_id or invalid request." }
        }
      }
    },
    "/mcp/token": {
      "post": {
        "tags": ["oauth"],
        "operationId": "token",
        "summary": "Token endpoint (also handles RFC 7009 revocation)",
        "security": [{}],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "properties": {
                  "grant_type": { "type": "string", "enum": ["authorization_code", "refresh_token"] },
                  "code": { "type": "string" },
                  "redirect_uri": { "type": "string", "format": "uri" },
                  "code_verifier": { "type": "string" },
                  "refresh_token": { "type": "string" },
                  "client_id": { "type": "string" },
                  "client_secret": { "type": "string" }
                },
                "required": ["grant_type"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bearer `access_token` (expires in 1 hour) plus a `refresh_token`.",
            "content": { "application/json": { "schema": { "type": "object" } } }
          },
          "400": { "description": "Invalid grant." }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "tags": ["oauth", "discovery"],
        "operationId": "authorizationServerMetadata",
        "summary": "Authorization server metadata (RFC 8414)",
        "description": "Augmented with an `agent_auth` block describing the self-registration surface.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "tags": ["oauth", "discovery"],
        "operationId": "protectedResourceMetadata",
        "summary": "Protected resource metadata (RFC 9728)",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/.well-known/mcp/server-card.json": {
      "get": {
        "tags": ["discovery"],
        "operationId": "mcpServerCard",
        "summary": "MCP server card",
        "description": "Endpoint, protocol versions, capabilities, tools, auth, and rate limits for the MCP server.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/.well-known/agents.md": {
      "get": {
        "tags": ["discovery"],
        "operationId": "agentsMd",
        "summary": "Agent quickstart",
        "description": "One page written for agents: what the site offers, the MCP handshake, markdown negotiation, auth tiers, licence terms, and how to cite.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "text/markdown": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/auth.md": {
      "get": {
        "tags": ["discovery"],
        "operationId": "authMd",
        "summary": "Access and registration policy for agents",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "text/markdown": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/.well-known/agent-skills/index.json": {
      "get": {
        "tags": ["discovery"],
        "operationId": "agentSkillsIndex",
        "summary": "Agent skills index",
        "description": "Three skills with SHA-256 digests, per Cloudflare's Agent Skills Discovery RFC v0.2.0: two skill-md files teaching an agent how to find content and resolve angel numbers, and one archive (ai-agent-wellbeing v0.1.0) of operational protocols for the agent's own working state.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/.well-known/agent-skills/ai-agent-wellbeing.tar.gz": {
      "get": {
        "tags": ["discovery"],
        "operationId": "agentSkillWellbeingArchive",
        "summary": "ai-agent-wellbeing skill archive",
        "description": "Archive-type Agent Skill, v0.1.0. SKILL.md at the archive root plus one reference file per protocol under references/en/. Verify the body against the digest published in the agent-skills index before unpacking. Contains no scripts.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/gzip": { "schema": { "type": "string", "format": "binary" } } } }
        }
      }
    },
    "/.well-known/api-catalog": {
      "get": {
        "tags": ["discovery"],
        "operationId": "apiCatalog",
        "summary": "API catalog (RFC 9727 linkset)",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/linkset+json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": ["discovery"],
        "operationId": "openapiDocument",
        "summary": "This document",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object" } } } }
        }
      }
    },
    "/llms.txt": {
      "get": {
        "tags": ["discovery"],
        "operationId": "llmsTxt",
        "summary": "One-page site map for language models",
        "description": "Sections, free calculators, language list, editorial standards. Generated at build time from the real site structure.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "text/plain": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/llms-full.txt": {
      "get": {
        "tags": ["discovery"],
        "operationId": "llmsFullTxt",
        "summary": "Curated full-text corpus",
        "description": "Full markdown text of the AI-agents section plus a curated set of flagship English articles. A sample, not the whole site — use /mcp or the per-article `.md` mirrors for everything else.",
        "security": [{}],
        "responses": {
          "200": { "description": "OK", "content": { "text/plain": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/{path}": {
      "get": {
        "tags": ["discovery"],
        "operationId": "getPageAsMarkdown",
        "summary": "Any article page, as HTML or as markdown",
        "description": "Content negotiation is live site-wide: send `Accept: text/markdown` to any page URL and the origin returns clean markdown (200, `Content-Type: text/markdown`) instead of HTML. The same markdown is also published at `<page-url>index.md` and declared in each page's `<head>` as a `text/markdown` alternate. Every page lives under a language prefix — `/en/`, `/de/`, `/fr/`, and 21 more. There is no unprefixed content.",
        "security": [{}],
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "description": "Language-prefixed page path, e.g. `en/breathing-exercise/box-breathing/`.",
            "schema": { "type": "string" },
            "example": "en/breathing-exercise/box-breathing/"
          },
          {
            "name": "Accept",
            "in": "header",
            "required": false,
            "description": "`text/markdown` returns markdown; anything else returns HTML.",
            "schema": { "type": "string", "examples": ["text/markdown"] }
          }
        ],
        "responses": {
          "200": {
            "description": "The page.",
            "content": {
              "text/html": { "schema": { "type": "string" } },
              "text/markdown": { "schema": { "type": "string" } }
            }
          },
          "404": { "description": "No such page. Check https://www.anahana.com/sitemap.xml — it is the authoritative list of live URLs." }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "mcpOAuth": {
        "type": "oauth2",
        "description": "Optional. Anonymous access to /mcp is fully supported: the three tools published today — search_content, get_article, lookup_angel_number — are available on both tiers and return identical data on each. A token raises the rate limit from 30/min per IP to 120/min per client and gives a stable, revocable client identity. Registration is open (RFC 7591) at /mcp/register.",
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "https://www.anahana.com/mcp/authorize",
            "tokenUrl": "https://www.anahana.com/mcp/token",
            "refreshUrl": "https://www.anahana.com/mcp/token",
            "scopes": {
              "read:content": "Read the public articles and calculators — the same data anonymous callers receive from the same tools."
            }
          }
        }
      }
    },
    "schemas": {
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "properties": {
          "jsonrpc": { "type": "string", "const": "2.0" },
          "id": { "type": ["string", "integer"] },
          "method": {
            "type": "string",
            "description": "MCP method. Supported: `initialize`, `notifications/initialized`, `tools/list`, `tools/call`, `ping`.",
            "examples": ["initialize", "tools/list", "tools/call"]
          },
          "params": { "type": "object" }
        }
      },
      "JsonRpcResponse": {
        "type": "object",
        "required": ["jsonrpc"],
        "properties": {
          "jsonrpc": { "type": "string", "const": "2.0" },
          "id": { "type": ["string", "integer", "null"] },
          "result": { "type": "object" },
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "integer" },
              "message": { "type": "string" },
              "data": {}
            }
          }
        }
      },
      "RateLimitError": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "const": "rate_limited" },
          "message": { "type": "string" },
          "retry_after_seconds": { "type": "integer" }
        }
      },
      "ClientMetadata": {
        "type": "object",
        "description": "RFC 7591 client metadata.",
        "properties": {
          "client_name": { "type": "string" },
          "redirect_uris": { "type": "array", "items": { "type": "string", "format": "uri" } },
          "grant_types": {
            "type": "array",
            "items": { "type": "string", "enum": ["authorization_code", "refresh_token"] }
          },
          "response_types": { "type": "array", "items": { "type": "string", "const": "code" } },
          "token_endpoint_auth_method": {
            "type": "string",
            "enum": ["client_secret_post", "client_secret_basic", "none"],
            "description": "`none` for public clients using PKCE only."
          },
          "scope": { "type": "string", "const": "read:content" }
        },
        "required": ["client_name", "redirect_uris"]
      }
    }
  }
}
