{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://labs.lubbee.net/mcp-landscape/schema/1.0.0/server.schema.json",
  "title": "MCP Server Landscape 2026 — dataset row",
  "description": "One row = one MCP server. Frozen 2026-08-24. Prose definitions and the computation rules for the 8 computed fields live in SCHEMA.md, which is normative where this file is ambiguous.",
  "type": "object",
  "additionalProperties": false,
  "required": [
    "id",
    "name",
    "description",
    "category",
    "repo_url",
    "homepage_url",
    "registry_name",
    "transport",
    "package_registry",
    "package_name",
    "install_method",
    "latest_version",
    "latest_release_at",
    "stars",
    "archived",
    "last_commit_at",
    "maintenance_status",
    "alive",
    "license_spdx",
    "commercial_use_ok",
    "auth_required",
    "tool_count",
    "tool_names",
    "dedup_group",
    "source_urls",
    "retrieved_at",
    "liveness_reason"
  ],
  "properties": {
    "id": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:[-.]{1,2}[a-z0-9]+)*$",
      "maxLength": 160,
      "description": "Stable unique slug, {owner}--{repo} lowercased, or registry--{name}. Stable across monthly refreshes."
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120,
      "description": "Human-facing server name: registry title > registry name > repo name."
    },
    "description": {
      "type": "string",
      "minLength": 10,
      "maxLength": 200,
      "pattern": "^[^\\n\\r]+$",
      "description": "Our own one-sentence description. Never an upstream README excerpt verbatim."
    },
    "category": {
      "type": "string",
      "description": "Computed. Exactly one term of the frozen 18-term taxonomy.",
      "enum": [
        "dev-tools",
        "version-control",
        "databases",
        "cloud-infra",
        "observability",
        "ci-cd",
        "file-storage",
        "web-search",
        "browser-automation",
        "communication",
        "productivity",
        "crm-sales",
        "finance-payments",
        "data-analytics",
        "ai-ml",
        "security",
        "media-design",
        "other"
      ]
    },
    "repo_url": {
      "type": ["string", "null"],
      "format": "uri",
      "pattern": "^https://",
      "description": "Normalized canonical source repo URL: lowercase host, no www., no .git, no trailing slash, redirects resolved."
    },
    "homepage_url": {
      "type": ["string", "null"],
      "format": "uri",
      "pattern": "^https?://"
    },
    "registry_name": {
      "type": ["string", "null"],
      "description": "Exact server.name in the official MCP registry; null when absent from it."
    },
    "transport": {
      "type": "string",
      "enum": ["stdio", "streamable-http", "sse", "mixed", "unknown"]
    },
    "package_registry": {
      "type": "string",
      "enum": ["npm", "pypi", "oci", "nuget", "none"]
    },
    "package_name": {
      "type": ["string", "null"],
      "description": "Registry-exact identifier. Null if and only if package_registry = none."
    },
    "install_method": {
      "type": "string",
      "description": "Computed. Fastest documented path to a first tool call; ordered rule set in SCHEMA.md 2.11.",
      "enum": ["npx", "uvx", "docker", "remote", "manual", "unknown"]
    },
    "latest_version": {
      "type": ["string", "null"],
      "maxLength": 64
    },
    "latest_release_at": {
      "type": ["string", "null"],
      "format": "date-time",
      "description": "Publish time of latest_version on its package registry. Null when package_registry = none."
    },
    "stars": {
      "type": ["integer", "null"],
      "minimum": 0
    },
    "archived": {
      "type": ["boolean", "null"]
    },
    "last_commit_at": {
      "type": ["string", "null"],
      "format": "date-time",
      "description": "GitHub pushed_at on the default branch."
    },
    "maintenance_status": {
      "type": "string",
      "description": "Computed from last_commit_days and archived, against snapshot_date. abandoned: archived OR >365d. dormant: 181-365d. slow: 31-180d. active: <=30d. unknown: last_commit_at null.",
      "enum": ["active", "slow", "dormant", "abandoned", "unknown"]
    },
    "alive": {
      "type": "boolean",
      "description": "Computed. True iff (1) the canonical source resolves 200, AND (2) last_commit_days <= 183 and archived = false, AND (3) the package is installable (npm/pypi/oci manifest resolves 200 with a usable latest release) or, for package_registry = none, a declared remote endpoint completes DNS+TCP+TLS and returns any HTTP status. Any unevaluable condition re-queues the row instead of marking it dead."
    },
    "license_spdx": {
      "type": ["string", "null"],
      "maxLength": 128,
      "description": "SPDX identifier or expression, verbatim. NOASSERTION and free-text licence strings map to null, never to a guess."
    },
    "commercial_use_ok": {
      "type": ["boolean", "null"],
      "description": "Computed by frozen allow/deny mapping of license_spdx. Null = licence unknown or answer depends on the buyer's deployment (GPL/AGPL/LGPL/EUPL family). Mechanical mapping of a declared identifier, not legal advice."
    },
    "auth_required": {
      "type": "string",
      "description": "Computed from declarative config only. oauth > api_key > none > unknown; absence of evidence yields unknown, never none.",
      "enum": ["none", "api_key", "oauth", "unknown"]
    },
    "tool_count": {
      "type": ["integer", "null"],
      "minimum": 0,
      "description": "Computed. Distinct declared MCP tools, from declarative sources only. Null when not declarable or registered dynamically. Never estimated."
    },
    "tool_names": {
      "type": ["array", "null"],
      "items": { "type": "string", "maxLength": 128 },
      "uniqueItems": true,
      "description": "Sorted, de-duplicated tool names. Names only, no descriptions or schemas. Null iff tool_count is null."
    },
    "dedup_group": {
      "type": "string",
      "pattern": "^[a-z0-9]+(?:[-.]{1,2}[a-z0-9]+)*$",
      "description": "Computed. The id of the canonical member of this fork/mirror cluster; equals id for a canonical row. Deduplicated counts filter on id = dedup_group."
    },
    "source_urls": {
      "type": "array",
      "minItems": 1,
      "items": { "type": "string", "format": "uri" },
      "description": "Every API endpoint that contributed a fact to this row."
    },
    "retrieved_at": {
      "type": "string",
      "format": "date-time"
    },
    "liveness_reason": {
      "type": ["string", "null"],
      "description": "Null when alive = true; otherwise which condition failed.",
      "enum": ["unreachable", "stale", "archived", "package_missing", "endpoint_dead", null]
    }
  },
  "allOf": [
    {
      "$comment": "package_name is null iff package_registry = none",
      "if": { "properties": { "package_registry": { "const": "none" } } },
      "then": { "properties": { "package_name": { "type": "null" }, "latest_release_at": { "type": "null" } } },
      "else": { "properties": { "package_name": { "type": "string", "minLength": 1 } } }
    },
    {
      "$comment": "alive rows are never dormant/abandoned/unknown, and carry no liveness_reason",
      "if": { "properties": { "alive": { "const": true } } },
      "then": {
        "properties": {
          "maintenance_status": { "enum": ["active", "slow"] },
          "liveness_reason": { "type": "null" }
        }
      },
      "else": { "properties": { "liveness_reason": { "type": "string" } } }
    },
    {
      "$comment": "tool_names is null iff tool_count is null",
      "if": { "properties": { "tool_count": { "type": "null" } } },
      "then": { "properties": { "tool_names": { "type": "null" } } },
      "else": { "properties": { "tool_names": { "type": "array" } } }
    },
    {
      "$comment": "commercial_use_ok requires a known licence",
      "if": { "properties": { "license_spdx": { "type": "null" } } },
      "then": { "properties": { "commercial_use_ok": { "type": "null" } } }
    }
  ]
}
