diff --git a/README.md b/README.md
index e40a4ae1f..eb999fc8f 100644
--- a/README.md
+++ b/README.md
@@ -20,6 +20,8 @@
+
+
Docs ·
Install ·
@@ -238,6 +240,7 @@ shows an **Output Tokens Saved** card next to input compression, labelled
Any OpenAI-compatible client works via `headroom proxy`. MCP-native: `headroom mcp install`.
Undo durable wrapping with `headroom unwrap ` (supports: `claude`, `copilot`, `codex`, `opencode`, `openclaw`).
+Registry authors can use the canonical [`server.json`](server.json) in the repo root instead of reconstructing the `headroom mcp serve` contract from prose.
### GitHub Copilot CLI subscription mode
diff --git a/docs/content/docs/mcp.mdx b/docs/content/docs/mcp.mdx
index 82bc5e597..bd6978fd2 100644
--- a/docs/content/docs/mcp.mdx
+++ b/docs/content/docs/mcp.mdx
@@ -121,6 +121,8 @@ headroom mcp serve --debug
For MCP hosts that let you configure a local stdio server, point them at `headroom mcp serve`. If you also run the proxy, pass the proxy URL explicitly so retrieval and stats come from the intended proxy instance.
+If you are publishing or consuming Headroom through an MCP registry, use the canonical descriptor at `https://github.com/headroomlabs-ai/headroom/blob/main/server.json`. It captures the package form for `headroom-ai[mcp]` and the current `headroom mcp serve` launch contract in one file.
+
```json
{
"mcpServers": {
diff --git a/headroom/mcp_registry/__init__.py b/headroom/mcp_registry/__init__.py
index 7fbcf7f3d..e812359f2 100644
--- a/headroom/mcp_registry/__init__.py
+++ b/headroom/mcp_registry/__init__.py
@@ -26,6 +26,7 @@ from .install import (
install_everywhere,
)
from .opencode import OpencodeRegistrar
+from .server_json import build_server_json, render_server_json
__all__ = [
"DEFAULT_PROXY_URL",
@@ -39,9 +40,11 @@ __all__ = [
"any_succeeded",
"build_headroom_spec",
"build_serena_spec",
+ "build_server_json",
"build_tokensave_spec",
"format_result",
"format_results",
"get_all_registrars",
"install_everywhere",
+ "render_server_json",
]
diff --git a/headroom/mcp_registry/server_json.py b/headroom/mcp_registry/server_json.py
new file mode 100644
index 000000000..0fa90b598
--- /dev/null
+++ b/headroom/mcp_registry/server_json.py
@@ -0,0 +1,128 @@
+"""Canonical MCP publication metadata for the Headroom server."""
+
+from __future__ import annotations
+
+import json
+from dataclasses import dataclass
+from pathlib import Path
+
+try:
+ import tomllib
+except ModuleNotFoundError: # pragma: no cover
+ import tomli as tomllib # type: ignore[no-redef]
+
+from .install import build_headroom_spec
+
+SCHEMA_URL = "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json"
+SERVER_NAME = "io.github.headroomlabs-ai/headroom"
+SERVER_TITLE = "Headroom"
+SERVER_DESCRIPTION = (
+ "Headroom MCP server for compression, retrieval, and stats in MCP-compatible hosts."
+)
+PYPI_OWNERSHIP_MARKER = f""
+WEBSITE_URL = "https://headroomlabs-ai.github.io/headroom/"
+REPOSITORY_URL = "https://github.com/headroomlabs-ai/headroom"
+REPOSITORY_ID = "1129940957"
+PYPI_REGISTRY_URL = "https://pypi.org"
+
+
+@dataclass(frozen=True)
+class ProjectMetadata:
+ """Package metadata needed for the published MCP descriptor."""
+
+ package_name: str
+ version: str
+
+
+def _project_root() -> Path:
+ return Path(__file__).resolve().parents[2]
+
+
+def load_project_metadata(pyproject_path: Path | None = None) -> ProjectMetadata:
+ """Load the publishable package metadata from ``pyproject.toml``."""
+
+ path = pyproject_path or (_project_root() / "pyproject.toml")
+ data = tomllib.loads(path.read_text(encoding="utf-8"))
+ project = data["project"]
+ return ProjectMetadata(
+ package_name=project["name"],
+ version=project["version"],
+ )
+
+
+def _build_runtime_contract() -> tuple[str, tuple[str, str]]:
+ """Return the canonical CLI entrypoint plus the MCP subcommand tail."""
+
+ spec = build_headroom_spec()
+ if spec.name != "headroom":
+ raise ValueError(f"unexpected MCP server name: {spec.name}")
+ runtime_tail = spec.args[-2:]
+ if runtime_tail != ("mcp", "serve"):
+ raise ValueError(f"unexpected MCP launch tail: {spec.args}")
+ return spec.name, (runtime_tail[0], runtime_tail[1])
+
+
+def _build_mcp_package_spec(metadata: ProjectMetadata) -> str:
+ """Return the PyPI requirement needed to launch ``headroom mcp serve``."""
+
+ return f"{metadata.package_name}[mcp]"
+
+
+def build_server_json(metadata: ProjectMetadata | None = None) -> dict[str, object]:
+ """Build the canonical ``server.json`` payload for Headroom."""
+
+ metadata = metadata or load_project_metadata()
+ command_name, runtime_tail = _build_runtime_contract()
+ package_spec = _build_mcp_package_spec(metadata)
+ return {
+ "$schema": SCHEMA_URL,
+ "name": SERVER_NAME,
+ "description": SERVER_DESCRIPTION,
+ "title": SERVER_TITLE,
+ "websiteUrl": WEBSITE_URL,
+ "repository": {
+ "url": REPOSITORY_URL,
+ "source": "github",
+ "id": REPOSITORY_ID,
+ },
+ "version": metadata.version,
+ "packages": [
+ {
+ "registryType": "pypi",
+ "registryBaseUrl": PYPI_REGISTRY_URL,
+ "identifier": metadata.package_name,
+ "version": metadata.version,
+ "runtimeHint": "uvx",
+ # Current uvx needs --from when the package name and script name differ.
+ "runtimeArguments": [
+ {
+ "type": "named",
+ "name": "--from",
+ "value": package_spec,
+ }
+ ],
+ "transport": {
+ "type": "stdio",
+ },
+ "packageArguments": [
+ {
+ "type": "positional",
+ "value": command_name,
+ },
+ *(
+ {
+ "type": "positional",
+ "value": value,
+ }
+ for value in runtime_tail
+ ),
+ ],
+ }
+ ],
+ }
+
+
+def render_server_json(metadata: ProjectMetadata | None = None) -> str:
+ """Render the canonical ``server.json`` payload with stable formatting."""
+
+ return json.dumps(build_server_json(metadata), indent=2) + "\n"
diff --git a/server.json b/server.json
new file mode 100644
index 000000000..c660bf2fe
--- /dev/null
+++ b/server.json
@@ -0,0 +1,46 @@
+{
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
+ "name": "io.github.headroomlabs-ai/headroom",
+ "description": "Headroom MCP server for compression, retrieval, and stats in MCP-compatible hosts.",
+ "title": "Headroom",
+ "websiteUrl": "https://headroomlabs-ai.github.io/headroom/",
+ "repository": {
+ "url": "https://github.com/headroomlabs-ai/headroom",
+ "source": "github",
+ "id": "1129940957"
+ },
+ "version": "0.27.0",
+ "packages": [
+ {
+ "registryType": "pypi",
+ "registryBaseUrl": "https://pypi.org",
+ "identifier": "headroom-ai",
+ "version": "0.27.0",
+ "runtimeHint": "uvx",
+ "runtimeArguments": [
+ {
+ "type": "named",
+ "name": "--from",
+ "value": "headroom-ai[mcp]"
+ }
+ ],
+ "transport": {
+ "type": "stdio"
+ },
+ "packageArguments": [
+ {
+ "type": "positional",
+ "value": "headroom"
+ },
+ {
+ "type": "positional",
+ "value": "mcp"
+ },
+ {
+ "type": "positional",
+ "value": "serve"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/test_mcp_registry/test_server_json.py b/tests/test_mcp_registry/test_server_json.py
new file mode 100644
index 000000000..04f255eb6
--- /dev/null
+++ b/tests/test_mcp_registry/test_server_json.py
@@ -0,0 +1,86 @@
+"""Tests for the canonical MCP server.json descriptor."""
+
+from __future__ import annotations
+
+import json
+from pathlib import Path
+
+from headroom.mcp_registry import build_server_json, render_server_json
+from headroom.mcp_registry.install import build_headroom_spec
+from headroom.mcp_registry.server_json import (
+ PYPI_OWNERSHIP_MARKER,
+ REPOSITORY_ID,
+ REPOSITORY_URL,
+ SCHEMA_URL,
+ SERVER_DESCRIPTION,
+ SERVER_NAME,
+ WEBSITE_URL,
+ _build_mcp_package_spec,
+ load_project_metadata,
+)
+
+PROJECT_ROOT = Path(__file__).resolve().parents[2]
+
+
+def test_build_server_json_uses_project_metadata() -> None:
+ metadata = load_project_metadata()
+ descriptor = build_server_json(metadata)
+
+ assert descriptor["$schema"] == SCHEMA_URL
+ assert descriptor["name"] == SERVER_NAME
+ assert descriptor["description"] == SERVER_DESCRIPTION
+ assert descriptor["version"] == metadata.version
+ assert descriptor["websiteUrl"] == WEBSITE_URL
+ assert descriptor["repository"] == {
+ "url": REPOSITORY_URL,
+ "source": "github",
+ "id": REPOSITORY_ID,
+ }
+
+ package = descriptor["packages"][0]
+ assert package["registryType"] == "pypi"
+ assert package["registryBaseUrl"] == "https://pypi.org"
+ assert package["identifier"] == metadata.package_name
+ assert package["version"] == metadata.version
+ assert package["runtimeArguments"] == [
+ {
+ "type": "named",
+ "name": "--from",
+ "value": _build_mcp_package_spec(metadata),
+ }
+ ]
+
+
+def test_build_server_json_matches_runtime_contract() -> None:
+ descriptor = build_server_json()
+ runtime = build_headroom_spec()
+ package = descriptor["packages"][0]
+
+ assert package["runtimeHint"] == "uvx"
+ assert package["runtimeArguments"] == [
+ {
+ "type": "named",
+ "name": "--from",
+ "value": _build_mcp_package_spec(load_project_metadata()),
+ }
+ ]
+ assert [arg["value"] for arg in package["packageArguments"]] == [
+ runtime.name,
+ *runtime.args[-2:],
+ ]
+ assert package["transport"] == {"type": "stdio"}
+
+
+def test_root_server_json_matches_builder() -> None:
+ artifact = PROJECT_ROOT / "server.json"
+ assert artifact.read_text(encoding="utf-8") == render_server_json()
+ assert json.loads(artifact.read_text(encoding="utf-8")) == build_server_json()
+
+
+def test_docs_point_to_canonical_server_json() -> None:
+ readme = (PROJECT_ROOT / "README.md").read_text(encoding="utf-8")
+ mcp_docs = (PROJECT_ROOT / "docs/content/docs/mcp.mdx").read_text(encoding="utf-8")
+
+ assert PYPI_OWNERSHIP_MARKER in readme
+ assert "`server.json`" in readme
+ assert "https://github.com/headroomlabs-ai/headroom/blob/main/server.json" in mcp_docs