{
  "openapi": "3.1.0",
  "info": {
    "title": "Rune MCP",
    "version": "2.0.0",
    "description": "Rune over MCP at /api/mcp. MCP Streamable HTTP: JSON-RPC 2.0 over POST. initialize and ping are open so a client can complete the protocol handshake and read a proper error. Every other method needs a seat: an AuthKit JWT or a session bearer on this Forgespace. Seventeen reads run. Fourteen writes return an approval link and do not run. Nothing is sent.",
    "contact": { "name": "Forgeby", "url": "https://forgeby.com/integrations" },
    "termsOfService": "https://forgeby.com/terms.html"
  },
  "servers": [
    { "url": "https://forgeby.com", "description": "Forgeby, the Next app" }
  ],
  "security": [{ "bearerAuth": [] }],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "An AuthKit JWT or a forgeby.com session token for a seat on this Forgespace. There is no zone grant on this door. There is no 14-day window."
      }
    },
    "schemas": {
      "JsonRpcRequest": {
        "type": "object",
        "required": ["jsonrpc", "method"],
        "properties": {
          "jsonrpc": { "const": "2.0" },
          "id": { "oneOf": [{ "type": "string" }, { "type": "integer" }, { "type": "null" }] },
          "method": {
            "type": "string",
            "enum": ["initialize", "ping", "tools/list", "tools/call", "resources/list", "prompts/list"]
          },
          "params": { "type": "object" }
        }
      },
      "JsonRpcError": {
        "type": "object",
        "properties": {
          "jsonrpc": { "const": "2.0" },
          "id": {},
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "integer",
                "description": "-32001 signed out; -32601 unknown method; -32602 unknown tool"
              },
              "message": { "type": "string" }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/api/mcp": {
      "post": {
        "summary": "JSON-RPC 2.0 endpoint",
        "description": "All MCP methods. initialize and ping need no token. tools/list and tools/call require a seat, and return -32001 otherwise. resources/list and prompts/list return empty arrays. GET without a token returns 401 so a client can start OAuth.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/JsonRpcRequest" },
              "examples": {
                "initialize": {
                  "summary": "Handshake, no token needed",
                  "value": { "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-03-26", "capabilities": {} } }
                },
                "who_to_call": {
                  "summary": "Who to call today, seat required",
                  "value": { "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "who_to_call", "arguments": { "days": 14, "limit": 5 } } }
                },
                "enrich_contact": {
                  "summary": "A write that returns an approval link and does not run",
                  "value": { "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "enrich_contact", "arguments": { "contact_id": "c1", "want": "email" } } }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC result, or a JSON-RPC error object.",
            "content": {
              "application/json": {
                "schema": { "oneOf": [{ "type": "object" }, { "$ref": "#/components/schemas/JsonRpcError" }] }
              }
            }
          },
          "401": {
            "description": "signed out. WWW-Authenticate points at the protected-resource metadata."
          },
          "405": {
            "description": "GET with a seat is refused. POST and OPTIONS only."
          }
        }
      },
      "get": {
        "summary": "Discovery challenge",
        "description": "Without a token, returns 401 and WWW-Authenticate so a client can start OAuth. With a seat, returns 405.",
        "responses": {
          "401": {
            "description": "unauthorized. WWW-Authenticate points at the path-aware protected-resource metadata."
          },
          "405": {
            "description": "A seat presented a token. Use POST."
          }
        }
      }
    }
  },
  "x-forgeby": {
    "access": "a seat on this Forgespace",
    "open_methods": ["initialize", "ping"],
    "primitives": { "tools": 29, "resources": 0, "prompts": 0 },
    "tools": [
      "who_to_call",
      "whats_changed",
      "prep_meeting",
      "query_corpus",
      "account_contacts",
      "my_network",
      "due_draft",
      "account_context",
      "pipeline",
      "intent_watch",
      "can_contact",
      "champion_check",
      "found_revenue",
      "accounts_changed",
      "kvasir_learned",
      "desk_act",
      "network_campaign",
      "enrich_contact",
      "find_people",
      "reverse_email",
      "find_companies",
      "remember",
      "engagement_update",
      "book_meeting",
      "post_slack",
      "take_due",
      "set_never_list",
      "send_mail",
      "schedule"
    ],
    "reads": [
      "who_to_call",
      "whats_changed",
      "prep_meeting",
      "query_corpus",
      "account_contacts",
      "my_network",
      "due_draft",
      "account_context",
      "pipeline",
      "intent_watch",
      "can_contact",
      "champion_check",
      "found_revenue",
      "accounts_changed",
      "kvasir_learned"
    ],
    "writes": [
      "desk_act",
      "network_campaign",
      "enrich_contact",
      "find_people",
      "reverse_email",
      "find_companies",
      "remember",
      "engagement_update",
      "book_meeting",
      "post_slack",
      "take_due",
      "set_never_list",
      "send_mail",
      "schedule"
    ],
    "freshness": "official public signals already on file; news says no source until a feeder exists",
    "data_policy": "People already held on the book, the mailbox, and Connections.csv. LinkedIn is the URL we already hold. We do not fetch LinkedIn.com. A write returns an approval link and does not run. Nothing is sent.",
    "upgrade": "https://forgeby.com/waitlist"
  }
}
