{
  "openapi": "3.1.0",
  "info": {
    "title": "tokyo.how Public HTTP API",
    "version": "1.0.0",
    "description": "Public access to practical Tokyo guides through MCP, editorial article requests, and application liveness. No registration, API key, or OAuth token is required. MCP tool input schemas are discovered with tools/list; the language values currently supported by those tools are en and ja. Article submissions have side effects and should be sent only when the user asks.",
    "contact": {
      "name": "tokyo.how",
      "url": "https://tokyo.how/contact"
    },
    "termsOfService": "https://tokyo.how/ja/terms"
  },
  "servers": [
    {
      "url": "https://tokyo.how"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "Quickstart, tool documentation, and access model",
    "url": "https://tokyo.how/developers"
  },
  "paths": {
    "/mcp": {
      "post": {
        "operationId": "sendMcpMessage",
        "summary": "Send an MCP JSON-RPC message",
        "description": "Use an MCP client with the Streamable HTTP transport. Send Content-Type: application/json and Accept: application/json, text/event-stream. Initialize the connection and use tools/list to discover the current tools and their input schemas. Send the negotiated MCP-Protocol-Version header on subsequent requests. The endpoint is stateless and does not issue an MCP session ID. Read-only tools are search_guides, get_guide, list_guides, list_categories, get_related_guides, and get_latest_guides. The request_article tool submits an editorial request and can notify the operator; call it only when the user has asked to submit one.",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "description": "The protocol version negotiated during MCP initialization; send on subsequent requests.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpMessage"
              },
              "examples": {
                "listTools": {
                  "summary": "Discover current tools without an editorial submission",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 1,
                    "method": "tools/list",
                    "params": {}
                  }
                },
                "searchGuides": {
                  "summary": "Search guides in English",
                  "value": {
                    "jsonrpc": "2.0",
                    "id": 2,
                    "method": "tools/call",
                    "params": {
                      "name": "search_guides",
                      "arguments": {
                        "query": "suica card",
                        "lang": "en",
                        "limit": 5
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC result or error. Tool results can report isError even when the HTTP response is 200.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpResponse"
                }
              }
            }
          },
          "202": {
            "description": "Notification accepted; no response body."
          },
          "400": {
            "description": "Invalid JSON or invalid MCP message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpResponse"
                }
              }
            }
          },
          "406": {
            "description": "Accept must support application/json and text/event-stream."
          },
          "415": {
            "description": "Content-Type must be application/json."
          },
          "500": {
            "description": "Application runtime or data unavailable."
          }
        }
      },
      "get": {
        "operationId": "mcpGetNotSupported",
        "summary": "GET is not supported by this stateless MCP endpoint",
        "responses": {
          "405": {
            "description": "Method Not Allowed. Use POST for MCP requests."
          }
        }
      }
    },
    "/api/article-request": {
      "post": {
        "operationId": "submitArticleRequest",
        "summary": "Submit an editorial article request or report",
        "description": "This creates an editorial submission and can send a notification to the site operator. Call only when the user asks to submit a request or report. Supply an email address only if the user provided it for a reply. A 200 response acknowledges receipt; it does not guarantee email delivery, publication, or a response.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ArticleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The request was accepted. Editorial notification delivery is not confirmed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid JSON, or a missing type or blank description.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "500": {
            "description": "Unexpected application error."
          }
        }
      }
    },
    "/api/health": {
      "get": {
        "operationId": "checkApplicationLiveness",
        "summary": "Check application liveness",
        "description": "Reports that the application can answer this request. This does not exercise MCP tool execution, search data, editorial email delivery, or external dependencies and is not a complete readiness check.",
        "responses": {
          "200": {
            "description": "Application is responding.",
            "headers": {
              "Cache-Control": {
                "description": "The liveness response is not cached.",
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                }
              }
            }
          }
        }
      },
      "head": {
        "operationId": "checkApplicationLivenessHeaders",
        "summary": "Check application liveness without a response body",
        "responses": {
          "200": {
            "description": "Application is responding; no response body.",
            "headers": {
              "Cache-Control": {
                "description": "The liveness response is not cached.",
                "schema": {
                  "type": "string",
                  "const": "no-store"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "McpMessage": {
        "type": "object",
        "required": [
          "jsonrpc",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer"
            ],
            "description": "Omit only for a JSON-RPC notification."
          },
          "method": {
            "type": "string",
            "description": "An MCP method, such as initialize, notifications/initialized, tools/list, or tools/call."
          },
          "params": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "McpResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "const": "2.0"
          },
          "id": {
            "type": [
              "string",
              "integer",
              "null"
            ]
          },
          "result": {
            "type": "object",
            "additionalProperties": true
          },
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              },
              "data": {}
            }
          }
        },
        "oneOf": [
          {
            "required": [
              "result"
            ],
            "not": {
              "required": [
                "error"
              ]
            }
          },
          {
            "required": [
              "error"
            ],
            "not": {
              "required": [
                "result"
              ]
            }
          }
        ]
      },
      "ArticleRequest": {
        "type": "object",
        "required": [
          "type",
          "description"
        ],
        "properties": {
          "type": {
            "type": "string",
            "minLength": 1,
            "description": "Use new_article, missing_info, or other. The REST handler requires a nonempty value; the MCP tool validates these three values.",
            "examples": [
              "new_article",
              "missing_info",
              "other"
            ]
          },
          "description": {
            "type": "string",
            "minLength": 1,
            "pattern": "\\S",
            "description": "Describe the requested article or missing information. Whitespace-only descriptions are rejected. The MCP request_article tool requires at least 10 characters."
          },
          "url": {
            "type": "string",
            "description": "Existing article URL, if relevant."
          },
          "email": {
            "type": "string",
            "description": "Optional reply email supplied by the user for this submission. It is not an authentication credential."
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "Health": {
        "type": "object",
        "required": [
          "status",
          "service",
          "discovery",
          "mcp"
        ],
        "properties": {
          "status": {
            "type": "string",
            "const": "ok"
          },
          "service": {
            "type": "string",
            "const": "tokyo.how"
          },
          "discovery": {
            "type": "string",
            "const": "public"
          },
          "mcp": {
            "type": "string",
            "const": "/mcp"
          }
        }
      }
    }
  }
}
