{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://xenmcp.com/xenmcp.schema.json",
  "title": "XenMCP server manifest (xenmcp.json)",
  "description": "Describes how XenMCP builds and runs an MCP server. Status: draft for the closed beta, schemaVersion 1. Guide: https://xenmcp.com/agents.md",
  "type": "object",
  "additionalProperties": false,
  "required": ["schemaVersion", "name", "source", "transport"],
  "properties": {
    "$schema": { "type": "string" },
    "schemaVersion": { "const": 1 },
    "name": { "type": "string", "pattern": "^[a-z0-9](?:[a-z0-9-]{1,38}[a-z0-9])$", "description": "Lowercase slug; becomes part of the address <name>-<org>.xenmcp.com." },
    "title": { "type": "string", "maxLength": 60 },
    "description": { "type": "string", "maxLength": 300, "description": "Plain text for people. No instructions to the model." },
    "source": {
      "oneOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["type", "package", "version"],
          "properties": {
            "type": { "const": "npm" },
            "package": { "type": "string" },
            "version": { "type": "string", "description": "Exact version, no ranges." }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["type", "image"],
          "properties": {
            "type": { "const": "docker" },
            "image": { "type": "string", "description": "Pinned by digest (…@sha256:…) or an immutable tag." }
          }
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["type", "repo", "ref"],
          "properties": {
            "type": { "const": "github" },
            "repo": { "type": "string", "pattern": "^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$" },
            "ref": { "type": "string", "description": "Tag or commit SHA; XenMCP builds exactly this version." },
            "dockerfile": { "type": "string", "default": "Dockerfile" }
          }
        }
      ]
    },
    "transport": {
      "oneOf": [
        { "type": "object", "additionalProperties": false, "required": ["type"], "properties": { "type": { "const": "stdio" } } },
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["type"],
          "properties": {
            "type": { "const": "http" },
            "port": { "type": "integer", "minimum": 1024, "maximum": 65535, "default": 8080 },
            "path": { "type": "string", "default": "/mcp" }
          }
        }
      ]
    },
    "command": { "type": "array", "items": { "type": "string" }, "minItems": 1, "description": "Start command, if the package or image does not define one." },
    "env": {
      "type": "array",
      "maxItems": 50,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["name"],
        "properties": {
          "name": { "type": "string", "pattern": "^[A-Z][A-Z0-9_]{0,63}$" },
          "description": { "type": "string", "maxLength": 200 },
          "secret": { "type": "boolean", "default": false, "description": "Stored encrypted, never shown again, never logged." },
          "required": { "type": "boolean", "default": false },
          "default": { "type": "string" }
        }
      }
    },
    "egress": {
      "type": "array",
      "maxItems": 50,
      "items": { "type": "string", "pattern": "^(\\*\\.)?[A-Za-z0-9.-]+(:[0-9]{1,5})?$" },
      "description": "Hosts (optionally host:port) the server may reach. Everything else is blocked."
    },
    "resources": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "memoryMb": { "type": "integer", "minimum": 64, "maximum": 2048, "default": 256 },
        "cpu": { "type": "number", "minimum": 0.1, "maximum": 2, "default": 0.5 }
      }
    }
  }
}
