{
  "openapi": "3.1.0",
  "info": {
    "title": "Agent Plugins Directory",
    "version": "1.0.0",
    "summary": "Every public plugin built on the Agent Plugins standard, as data.",
    "description": "A read-only directory of plugins for AI agents, indexed from public repositories.\n\nEverything here is open: no key, no account, and no operation that changes\nanything. The directory never executes plugin code and keeps no copy of a\npackage's files — every file it describes is linked at its source and pinned to a\ncommit.\n\nTwo conventions cover most of what an agent needs. Every page answers markdown under\n`Accept: text/markdown`, or at the same address with a `.md` suffix. And `/llms.txt`\nlists every indexed plugin in one fetch.\n\n## Versioning\n\n`/api/v1/*` is the versioned surface and the only one under a stability promise: a\nfield published there is not removed from v1, and an incompatible change becomes\n`/api/v2` rather than a quiet edit. Every response carries an `API-Version` header and\na `generation` field that changes whenever the indexed data does.\n\nEverything else is described here but not versioned. `/indexes/*.json` is the payload\nthis site's own browser code downloads — its one-letter keys exist to keep it small,\nand its shape has changed before. Read it if you like; build against `/api/v1` if the\nshape matters to you. A package's `mcp.json` is the author's own file, so its contents\nare theirs rather than ours to promise.",
    "license": {
      "name": "Open data",
      "url": "https://agent-plugins.directory/about"
    },
    "contact": {
      "name": "Agent Plugins Directory",
      "url": "https://agent-plugins.directory/contact"
    }
  },
  "servers": [
    {
      "url": "https://agent-plugins.directory",
      "description": "Production"
    }
  ],
  "security": [],
  "externalDocs": {
    "description": "What this site serves to agents, and how to fetch it",
    "url": "https://agent-plugins.directory/guides"
  },
  "tags": [
    {
      "name": "v1",
      "description": "The versioned read API. The only surface under a stability promise."
    },
    {
      "name": "Indexes",
      "description": "The whole corpus in one fetch, in a few shapes. Not versioned."
    },
    {
      "name": "Plugins",
      "description": "One plugin at a time."
    },
    {
      "name": "Topics",
      "description": "The subjects the corpus falls into."
    },
    {
      "name": "Site",
      "description": "Addresses that describe the site itself."
    }
  ],
  "paths": {
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "tags": [
          "Indexes"
        ],
        "summary": "Every indexed plugin, one line each",
        "description": "The whole corpus as plain text: what the directory is, what can be fetched from it, every topic, and every indexed plugin with its address and its author's description. The one fetch that answers 'what is in here'.",
        "responses": {
          "200": {
            "description": "The corpus as plain text.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "operationId": "getOpenApiDocument",
        "tags": [
          "Site"
        ],
        "summary": "This document",
        "description": "The OpenAPI description of every address listed here.",
        "responses": {
          "200": {
            "description": "This document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/sitemap.xml": {
      "get": {
        "operationId": "getSitemap",
        "tags": [
          "Site"
        ],
        "summary": "Every indexed URL, as a sitemap index",
        "description": "A sitemap index pointing at the parts. Written for search engines; an agent that wants the corpus should fetch /llms.txt instead, which carries the descriptions too.",
        "responses": {
          "200": {
            "description": "A sitemap index.",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/indexes/plugins.json": {
      "get": {
        "operationId": "getPluginsIndex",
        "tags": [
          "Indexes"
        ],
        "summary": "Every plugin: address and description",
        "description": "What the command palette searches. One row per indexed plugin, with the shortest fields that identify it. Field names are one letter because this file is shipped to every browser that opens the site.",
        "responses": {
          "200": {
            "description": "Every indexed plugin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginsIndex"
                }
              }
            }
          }
        }
      }
    },
    "/indexes/skills.json": {
      "get": {
        "operationId": "getSkillsIndex",
        "tags": [
          "Indexes"
        ],
        "summary": "Every skill declared by every plugin",
        "description": "One row per skill, carrying the plugin it belongs to, the author's description, and the keywords that filed it.",
        "responses": {
          "200": {
            "description": "Every indexed skill.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkillsIndex"
                }
              }
            }
          }
        }
      }
    },
    "/indexes/servers.json": {
      "get": {
        "operationId": "getServersIndex",
        "tags": [
          "Indexes"
        ],
        "summary": "Every MCP server declared by every plugin",
        "description": "One row per MCP server, carrying its transport, whether that transport is one the specification defines, and either the host that runs it or the command that starts it locally.",
        "responses": {
          "200": {
            "description": "Every indexed MCP server.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServersIndex"
                }
              }
            }
          }
        }
      }
    },
    "/indexes/keywords.json": {
      "get": {
        "operationId": "getKeywordsIndex",
        "tags": [
          "Indexes"
        ],
        "summary": "Every declared keyword and its reach",
        "description": "One row per keyword the authors themselves declared, with how many packages and how many distinct publishers use it.",
        "responses": {
          "200": {
            "description": "Every declared keyword.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordsIndex"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/plugins": {
      "get": {
        "operationId": "listPlugins",
        "tags": [
          "v1"
        ],
        "summary": "Every indexed plugin",
        "description": "Every plugin in the catalogue, with the address of its page, its markdown twin and its own API resource. The whole collection in one response — there is no pagination, because it is a static file behind a CDN.",
        "responses": {
          "200": {
            "description": "The whole collection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginCollection"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/skills": {
      "get": {
        "operationId": "listSkills",
        "tags": [
          "v1"
        ],
        "summary": "Every skill declared by every plugin",
        "description": "One entry per skill, with the plugin it belongs to, whether it ships more than a single instruction file, and the topic and keywords that filed it.",
        "responses": {
          "200": {
            "description": "The whole collection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SkillCollection"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/servers": {
      "get": {
        "operationId": "listServers",
        "tags": [
          "v1"
        ],
        "summary": "Every MCP server declared by every plugin",
        "description": "One entry per declared MCP server, with its transport, whether that transport is one the specification defines, and either the host that runs it or the command that starts it locally.",
        "responses": {
          "200": {
            "description": "The whole collection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServerCollection"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/keywords": {
      "get": {
        "operationId": "listKeywords",
        "tags": [
          "v1"
        ],
        "summary": "Every keyword the authors declared",
        "description": "One entry per declared keyword, with how many plugins and distinct publishers use it.",
        "responses": {
          "200": {
            "description": "The whole collection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KeywordCollection"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/topics": {
      "get": {
        "operationId": "listTopics",
        "tags": [
          "v1"
        ],
        "summary": "Every subject in the directory",
        "description": "The taxonomy, grouped from the keywords the authors themselves wrote, with the counts under each subject.",
        "responses": {
          "200": {
            "description": "The whole collection.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopicCollection"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/plugins/{owner}/{plugin}": {
      "get": {
        "operationId": "getPlugin",
        "tags": [
          "v1"
        ],
        "summary": "One plugin, with what it declares",
        "description": "A single plugin: its manifest facts, the commit it was read at, every skill it ships, and the MCP servers it declares. `mcpServers` is the author's own object, so v1 promises the field is present and nothing about what is inside it.",
        "parameters": [
          {
            "name": "owner",
            "in": "path",
            "required": true,
            "description": "The publisher's GitHub login, lowercased. The first segment of every plugin URL.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9-]*$",
              "examples": [
                "anthropics"
              ]
            }
          },
          {
            "name": "plugin",
            "in": "path",
            "required": true,
            "description": "The plugin name, taken from the name field of its manifest.",
            "schema": {
              "type": "string",
              "examples": [
                "claude-code"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The plugin.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginResource"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is published at this address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/{owner}/{plugin}.md": {
      "get": {
        "operationId": "getPluginMarkdown",
        "tags": [
          "Plugins"
        ],
        "summary": "One plugin as markdown",
        "description": "The plugin page as markdown: what it is, who published it, what it declares, and where every file of it lives. The same document is served at /{owner}/{plugin} to a request carrying `Accept: text/markdown`.",
        "parameters": [
          {
            "name": "owner",
            "in": "path",
            "required": true,
            "description": "The publisher's GitHub login, lowercased. The first segment of every plugin URL.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9-]*$",
              "examples": [
                "anthropics"
              ]
            }
          },
          {
            "name": "plugin",
            "in": "path",
            "required": true,
            "description": "The plugin name, taken from the name field of its manifest.",
            "schema": {
              "type": "string",
              "examples": [
                "claude-code"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The plugin, as markdown.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is published at this address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "406": {
            "description": "The request accepts none of the representations this address can be served as. Retry with Accept: text/markdown or Accept: text/html.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/{owner}/{plugin}/llms.txt": {
      "get": {
        "operationId": "getPluginLlmsTxt",
        "tags": [
          "Plugins"
        ],
        "summary": "One plugin's own index",
        "description": "Every address this directory answers for a single plugin: its skills, its servers, its versions, its changelog.",
        "parameters": [
          {
            "name": "owner",
            "in": "path",
            "required": true,
            "description": "The publisher's GitHub login, lowercased. The first segment of every plugin URL.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9-]*$",
              "examples": [
                "anthropics"
              ]
            }
          },
          {
            "name": "plugin",
            "in": "path",
            "required": true,
            "description": "The plugin name, taken from the name field of its manifest.",
            "schema": {
              "type": "string",
              "examples": [
                "claude-code"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The plugin's index, as plain text.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is published at this address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/{owner}/{plugin}/mcp.json": {
      "get": {
        "operationId": "getPluginMcpConfig",
        "tags": [
          "Plugins"
        ],
        "summary": "The MCP configuration a plugin declares",
        "description": "The `mcpServers` object exactly as the package declares it, parsed and validated by the indexer. Only published for a plugin that declares at least one server: an empty object would claim the plugin declares none, which is a different statement.",
        "parameters": [
          {
            "name": "owner",
            "in": "path",
            "required": true,
            "description": "The publisher's GitHub login, lowercased. The first segment of every plugin URL.",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9][A-Za-z0-9-]*$",
              "examples": [
                "anthropics"
              ]
            }
          },
          {
            "name": "plugin",
            "in": "path",
            "required": true,
            "description": "The plugin name, taken from the name field of its manifest.",
            "schema": {
              "type": "string",
              "examples": [
                "claude-code"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The plugin's MCP configuration.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpConfig"
                }
              }
            }
          },
          "404": {
            "description": "No such plugin, or the plugin declares no MCP servers.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/mcp.json": {
      "get": {
        "operationId": "getMcpManifest",
        "tags": [
          "Site"
        ],
        "summary": "Where the MCP server is, and what it offers",
        "description": "A discovery document naming the MCP endpoint, the protocol revisions it speaks, and its tools. The Model Context Protocol defines no such manifest — a client is normally handed the endpoint URL by whoever configured it — so this is a convention, published so the server can be found without reading prose first.",
        "responses": {
          "200": {
            "description": "The MCP discovery document.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/McpManifest"
                }
              }
            }
          }
        }
      }
    },
    "/api/mcp": {
      "post": {
        "operationId": "callMcpServer",
        "tags": [
          "Site"
        ],
        "summary": "The MCP server: one tool, checks a manifest",
        "description": "A Model Context Protocol server over Streamable HTTP. The body is JSON-RPC 2.0 rather than a REST payload, so the schemas below describe only the envelope; the methods, their parameters and their results are defined by the protocol, not by this document. Revision 2026-07-28 is served natively and 2025-era clients are served from the same endpoint. It exposes one tool, `validate`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "jsonrpc",
                  "method"
                ],
                "properties": {
                  "jsonrpc": {
                    "type": "string",
                    "const": "2.0"
                  },
                  "id": {
                    "description": "Absent on a notification, which is answered with 202 and no body.",
                    "type": [
                      "string",
                      "integer"
                    ]
                  },
                  "method": {
                    "type": "string",
                    "description": "A protocol method, such as tools/list or tools/call."
                  },
                  "params": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A JSON-RPC result, or an SSE stream carrying one.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "202": {
            "description": "A notification was accepted. No body."
          },
          "400": {
            "description": "A JSON-RPC error: unsupported protocol version, or headers that disagree with the body.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "405": {
            "description": "GET and DELETE are not part of this transport revision.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/topics.md": {
      "get": {
        "operationId": "getTopicsMarkdown",
        "tags": [
          "Topics"
        ],
        "summary": "Every subject, with counts",
        "description": "The whole taxonomy in one fetch: each subject, the sentence that defines it, and how many plugins and publishers are under it.",
        "responses": {
          "200": {
            "description": "Every topic, as markdown.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/topics/{topic}.md": {
      "get": {
        "operationId": "getTopicMarkdown",
        "tags": [
          "Topics"
        ],
        "summary": "One subject and the plugins under it",
        "parameters": [
          {
            "name": "topic",
            "in": "path",
            "required": true,
            "description": "The topic key, as listed in /topics.md.",
            "schema": {
              "type": "string",
              "examples": [
                "documentation"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The topic, as markdown.",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Nothing is published at this address.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "hint",
              "documentation"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "not_found",
                  "not_acceptable",
                  "method_not_allowed",
                  "invalid_request"
                ],
                "description": "The stable machine-readable reason. This is the only field to branch on; the others are for a person reading a log."
              },
              "message": {
                "type": "string",
                "description": "What went wrong, in one sentence."
              },
              "hint": {
                "type": "string",
                "description": "What to do about it, in the imperative."
              },
              "documentation": {
                "type": "string",
                "format": "uri",
                "description": "Where the contract for this address is written."
              }
            }
          }
        },
        "example": {
          "error": {
            "code": "not_found",
            "message": "No plugin is published at that address.",
            "hint": "Fetch /llms.txt for every address this directory answers.",
            "documentation": "https://agent-plugins.directory/guides"
          }
        }
      },
      "PluginsIndex": {
        "type": "object",
        "required": [
          "plugins"
        ],
        "properties": {
          "plugins": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PluginRow"
            }
          }
        }
      },
      "PluginRow": {
        "type": "object",
        "required": [
          "o",
          "n",
          "d"
        ],
        "properties": {
          "o": {
            "type": "string",
            "description": "Publisher login, lowercased."
          },
          "n": {
            "type": "string",
            "description": "Plugin name."
          },
          "d": {
            "type": "string",
            "description": "The author's description, cut at the index."
          }
        }
      },
      "SkillsIndex": {
        "type": "object",
        "required": [
          "order",
          "skills"
        ],
        "properties": {
          "order": {
            "type": "string",
            "description": "How the rows were ordered when written."
          },
          "skills": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillRow"
            }
          }
        }
      },
      "SkillRow": {
        "type": "object",
        "required": [
          "o",
          "p",
          "s",
          "d",
          "b",
          "m",
          "w"
        ],
        "properties": {
          "o": {
            "type": "string",
            "description": "Publisher login."
          },
          "p": {
            "type": "string",
            "description": "Package name."
          },
          "s": {
            "type": "string",
            "description": "Skill directory name."
          },
          "d": {
            "type": "string",
            "description": "The author's description, cut at the index."
          },
          "b": {
            "type": "boolean",
            "description": "True when the skill ships more than a single instruction file."
          },
          "m": {
            "type": "string",
            "description": "The topic its package was filed under, or \"\" for a package no topic reached."
          },
          "w": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to three keywords its author declared, in their own spelling."
          }
        }
      },
      "ServersIndex": {
        "type": "object",
        "required": [
          "order",
          "servers"
        ],
        "properties": {
          "order": {
            "type": "string",
            "description": "How the rows were ordered when written."
          },
          "servers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServerRow"
            }
          }
        }
      },
      "ServerRow": {
        "type": "object",
        "required": [
          "o",
          "p",
          "s",
          "y",
          "k",
          "h",
          "r",
          "m",
          "w",
          "d"
        ],
        "properties": {
          "o": {
            "type": "string",
            "description": "Publisher login."
          },
          "p": {
            "type": "string",
            "description": "Package name."
          },
          "s": {
            "type": "string",
            "description": "The key the package gives this server."
          },
          "y": {
            "type": "string",
            "description": "The transport the author declared, verbatim."
          },
          "k": {
            "type": "boolean",
            "description": "True when the transport is one the specification defines."
          },
          "h": {
            "type": [
              "string",
              "null"
            ],
            "description": "Host of the service, when somebody else runs the server."
          },
          "r": {
            "type": [
              "string",
              "null"
            ],
            "description": "The command, when the server runs on the reader's own machine."
          },
          "m": {
            "type": "string",
            "description": "The topic its package was filed under."
          },
          "w": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Up to three keywords."
          },
          "d": {
            "type": "string",
            "description": "Its package's opening sentence, cut. A server declares a transport and an address, never prose of its own."
          }
        }
      },
      "KeywordsIndex": {
        "type": "object",
        "required": [
          "order",
          "keywords"
        ],
        "properties": {
          "order": {
            "type": "string",
            "description": "How the rows were ordered when written."
          },
          "keywords": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordRow"
            }
          }
        }
      },
      "KeywordRow": {
        "type": "object",
        "required": [
          "g",
          "k",
          "p",
          "o"
        ],
        "properties": {
          "g": {
            "type": "string",
            "description": "The slug, which is also the URL segment of its page under /explore."
          },
          "k": {
            "type": "string",
            "description": "The display form, in the author's own spelling."
          },
          "p": {
            "type": "integer",
            "description": "Packages declaring it."
          },
          "o": {
            "type": "integer",
            "description": "Distinct publishers declaring it."
          }
        }
      },
      "PluginCollection": {
        "type": "object",
        "required": [
          "apiVersion",
          "generation",
          "count",
          "items"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "const": "1"
          },
          "generation": {
            "type": "string",
            "description": "Changes whenever the indexed data changes."
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PluginSummary"
            }
          }
        }
      },
      "SkillCollection": {
        "type": "object",
        "required": [
          "apiVersion",
          "generation",
          "count",
          "items"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "const": "1"
          },
          "generation": {
            "type": "string",
            "description": "Changes whenever the indexed data changes."
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SkillSummary"
            }
          }
        }
      },
      "ServerCollection": {
        "type": "object",
        "required": [
          "apiVersion",
          "generation",
          "count",
          "items"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "const": "1"
          },
          "generation": {
            "type": "string",
            "description": "Changes whenever the indexed data changes."
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ServerSummary"
            }
          }
        }
      },
      "KeywordCollection": {
        "type": "object",
        "required": [
          "apiVersion",
          "generation",
          "count",
          "items"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "const": "1"
          },
          "generation": {
            "type": "string",
            "description": "Changes whenever the indexed data changes."
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/KeywordSummary"
            }
          }
        }
      },
      "TopicCollection": {
        "type": "object",
        "required": [
          "apiVersion",
          "generation",
          "count",
          "items"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "const": "1"
          },
          "generation": {
            "type": "string",
            "description": "Changes whenever the indexed data changes."
          },
          "count": {
            "type": "integer"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TopicSummary"
            }
          }
        }
      },
      "PluginSummary": {
        "type": "object",
        "required": [
          "owner",
          "name",
          "description",
          "url",
          "markdown",
          "api"
        ],
        "properties": {
          "owner": {
            "type": "string",
            "description": "Publisher login, lowercased."
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "description": "The author's own sentence."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "The plugin page."
          },
          "markdown": {
            "type": "string",
            "format": "uri",
            "description": "The same page as markdown."
          },
          "api": {
            "type": "string",
            "format": "uri",
            "description": "This plugin's own resource."
          }
        }
      },
      "SkillSummary": {
        "type": "object",
        "required": [
          "owner",
          "plugin",
          "name",
          "description",
          "bundled",
          "topic",
          "keywords",
          "url"
        ],
        "properties": {
          "owner": {
            "type": "string"
          },
          "plugin": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "The skill directory name."
          },
          "description": {
            "type": "string"
          },
          "bundled": {
            "type": "boolean",
            "description": "Ships more than a single instruction file."
          },
          "topic": {
            "type": [
              "string",
              "null"
            ],
            "description": "Null when no topic reached it."
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "ServerSummary": {
        "type": "object",
        "required": [
          "owner",
          "plugin",
          "name",
          "transport",
          "standardTransport",
          "host",
          "command",
          "topic",
          "keywords",
          "description",
          "configuration"
        ],
        "properties": {
          "owner": {
            "type": "string"
          },
          "plugin": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "description": "The key the package gives this server."
          },
          "transport": {
            "type": "string",
            "description": "As the author declared it, verbatim."
          },
          "standardTransport": {
            "type": "boolean",
            "description": "The specification defines this transport."
          },
          "host": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set when somebody else runs the server."
          },
          "command": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set when it runs on the reader's machine."
          },
          "topic": {
            "type": [
              "string",
              "null"
            ]
          },
          "keywords": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "description": {
            "type": "string",
            "description": "Its package's sentence; a server declares no prose."
          },
          "configuration": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "KeywordSummary": {
        "type": "object",
        "required": [
          "slug",
          "keyword",
          "plugins",
          "publishers",
          "url"
        ],
        "properties": {
          "slug": {
            "type": "string",
            "description": "The URL segment under /explore."
          },
          "keyword": {
            "type": "string",
            "description": "The author's own spelling."
          },
          "plugins": {
            "type": "integer"
          },
          "publishers": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "TopicSummary": {
        "type": "object",
        "required": [
          "key",
          "label",
          "description",
          "plugins",
          "publishers",
          "url",
          "markdown"
        ],
        "properties": {
          "key": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "plugins": {
            "type": "integer"
          },
          "publishers": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "markdown": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "PluginResource": {
        "type": "object",
        "required": [
          "apiVersion",
          "generation",
          "plugin"
        ],
        "properties": {
          "apiVersion": {
            "type": "string",
            "const": "1"
          },
          "generation": {
            "type": "string",
            "description": "Identifies the view set this was built from."
          },
          "plugin": {
            "type": "object",
            "required": [
              "owner",
              "name",
              "description",
              "repository",
              "commit",
              "url",
              "markdown",
              "skills",
              "mcpServers"
            ],
            "properties": {
              "owner": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "version": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The manifest's version field, verbatim."
              },
              "license": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "keywords": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "repository": {
                "type": "string",
                "format": "uri"
              },
              "rootPath": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Null when the manifest sits at the repository root."
              },
              "commit": {
                "type": "string",
                "description": "The commit this revision is pinned to."
              },
              "indexedAt": {
                "type": "string",
                "format": "date-time"
              },
              "discoveredAt": {
                "type": "string",
                "format": "date-time"
              },
              "lastSeenAt": {
                "type": "string",
                "format": "date-time"
              },
              "url": {
                "type": "string",
                "format": "uri"
              },
              "markdown": {
                "type": "string",
                "format": "uri"
              },
              "skills": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "name",
                    "description",
                    "url"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              },
              "mcpServers": {
                "type": "object",
                "description": "The author's own object, unchanged. v1 promises the field, not its contents.",
                "additionalProperties": true
              },
              "mcpConfiguration": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      },
      "McpManifest": {
        "type": "object",
        "required": [
          "name",
          "endpoint",
          "transport",
          "protocolVersions",
          "tools"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "endpoint": {
            "type": "string",
            "format": "uri",
            "description": "Where to POST JSON-RPC."
          },
          "transport": {
            "type": "string",
            "enum": [
              "streamable-http"
            ]
          },
          "protocolVersions": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Protocol revisions the endpoint answers, newest first."
          },
          "authentication": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "none"
                ]
              }
            }
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "name",
                "description"
              ],
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                }
              }
            }
          },
          "documentation": {
            "type": "string",
            "format": "uri"
          }
        }
      },
      "McpConfig": {
        "type": "object",
        "required": [
          "mcpServers"
        ],
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri"
          },
          "mcpServers": {
            "type": "object",
            "description": "One entry per server, keyed by the name the package gives it.",
            "additionalProperties": {
              "type": "object"
            }
          }
        }
      }
    }
  }
}
