Files
awoooi/apps/api/src/services/mcp_control_plane_service.py

617 lines
25 KiB
Python

"""Cross-product MCP control plane catalog and runtime readback.
The service deliberately separates committed desired/source inventory from live
runtime evidence. Marketplace directories are discovery inputs only; this code
never installs packages, resolves credentials, calls a tool, writes RAG data, or
promotes an external candidate.
"""
from __future__ import annotations
import asyncio
import json
from datetime import datetime
from pathlib import Path
from typing import Any
from zoneinfo import ZoneInfo
import structlog
from sqlalchemy import text
from src.db.base import get_db_context
from src.plugins.mcp.registry import get_provider_registry
from src.services.mcp_federation_service import collect_mcp_federation_readback
from src.services.mcp_tool_registry import get_mcp_tool_registry
from src.services.mcp_version_lifecycle_service import (
collect_mcp_version_lifecycle_readback,
)
from src.services.snapshot_paths import default_operations_dir
logger = structlog.get_logger(__name__)
SCHEMA_VERSION = "mcp_control_plane_overview_v1"
CATALOG_SCHEMA_VERSION = "mcp_control_plane_catalog_v1"
TZ_TAIPEI = ZoneInfo("Asia/Taipei")
_DEFAULT_OPERATIONS_DIR = default_operations_dir(Path(__file__))
_CATALOG_FILE = "mcp-control-plane-catalog.snapshot.json"
_EXPECTED_PRODUCT_IDS = {
"awoooi",
"ewoooc",
"2026fifa",
"agent-bounty-protocol",
"awooogo",
"stockplatform-v2",
"vibework",
"momo-pro-system",
"tsenyang-website",
"vtuber",
"bitan-pharmacy",
"clawbot-openclaw",
}
def load_mcp_control_plane_catalog(
operations_dir: Path | None = None,
) -> dict[str, Any]:
"""Load and validate the committed 12-product MCP catalog."""
directory = operations_dir or _DEFAULT_OPERATIONS_DIR
path = directory / _CATALOG_FILE
with path.open(encoding="utf-8") as handle:
payload = json.load(handle)
if not isinstance(payload, dict):
raise ValueError(f"{path}: expected JSON object")
_validate_catalog(payload, str(path))
return payload
def build_mcp_control_plane_overview(
*,
catalog: dict[str, Any],
product_matrix: dict[str, Any],
runtime: dict[str, Any] | None = None,
generated_at: str | None = None,
) -> dict[str, Any]:
"""Join catalog desired state with source-control and runtime truth."""
_validate_catalog(catalog, "catalog")
matrix_rows = {
str(row.get("product_id")): row
for row in _dict_rows(product_matrix.get("products"))
if row.get("product_id")
}
if set(matrix_rows) != _EXPECTED_PRODUCT_IDS:
raise ValueError(
"product governance matrix must contain the exact 12 governed products: "
f"missing={sorted(_EXPECTED_PRODUCT_IDS - set(matrix_rows))}, "
f"unexpected={sorted(set(matrix_rows) - _EXPECTED_PRODUCT_IDS)}"
)
capability_rows = _dict_rows(catalog.get("capabilities"))
capability_index = {str(row["capability_id"]): row for row in capability_rows}
products: list[dict[str, Any]] = []
for desired in _dict_rows(catalog.get("products")):
product_id = str(desired["product_id"])
source = matrix_rows[product_id]
existing_ids = _strings(desired.get("existing_capability_ids"))
recommended_ids = _strings(desired.get("recommended_capability_ids"))
rejected_ids = _strings(desired.get("rejected_capability_ids"))
products.append(
{
"product_id": product_id,
"canonical_repo": str(source.get("canonical_repo") or ""),
"source_control_status": str(
source.get("source_control_status") or "unknown"
),
"prod_branch": str(source.get("prod_branch") or "main"),
"prod_sha_short": str(source.get("prod_sha_short") or ""),
"visibility_readback": str(
source.get("visibility_readback") or "unknown"
),
"inventory_state": str(desired.get("inventory_state") or "unknown"),
"existing_capability_ids": existing_ids,
"recommended_capability_ids": recommended_ids,
"rejected_capability_ids": rejected_ids,
"existing_capabilities": [
_capability_summary(capability_index[item]) for item in existing_ids
],
"recommended_capabilities": [
_capability_summary(capability_index[item])
for item in recommended_ids
],
"rejected_capabilities": [
_capability_summary(capability_index[item]) for item in rejected_ids
],
"blockers": _strings(desired.get("blockers")),
}
)
runtime_payload = runtime or {
"requested": False,
"status": "not_requested",
"provider_registry": {
"status": "not_requested",
"provider_count": 0,
"provider_names": [],
"tool_count": 0,
},
"gateway_audit_24h": {
"status": "not_requested",
"call_count": 0,
"success_count": 0,
"blocked_count": 0,
"failed_count": 0,
},
"rag": {
"status": "not_requested",
"total_chunks": 0,
"sources": 0,
},
"federated_runtime": {
"status": "not_requested",
"receipts": [],
"verified_fresh_receipt_count": 0,
"expected_receipt_count": 2,
"blockers": [],
},
"federated_product_runtime_receipt_count": 0,
"federated_product_runtime_receipt_expected": 12,
}
federation_runtime = runtime_payload.get("federated_runtime")
federation_runtime = (
federation_runtime if isinstance(federation_runtime, dict) else {}
)
federation_receipt_index = {
str(row.get("product_id")): row
for row in _dict_rows(federation_runtime.get("receipts"))
if row.get("product_id") and row.get("fresh") is True
}
for product in products:
receipt = federation_receipt_index.get(product["product_id"])
product["federated_runtime_receipt"] = receipt
if receipt is None:
continue
product["blockers"] = sorted(
set(product["blockers"])
.difference({"awoooi_federated_runtime_readback_missing"})
.union(_strings(receipt.get("blockers")))
)
product["inventory_state"] = (
"federated_runtime_readback_verified"
if receipt.get("health_status") == "ready"
else "federated_runtime_readback_partial_degraded"
)
lifecycle_runtime = runtime_payload.get("version_lifecycle")
lifecycle_runtime = lifecycle_runtime if isinstance(lifecycle_runtime, dict) else {}
version_lifecycle = dict(catalog["version_lifecycle"])
version_lifecycle["runtime"] = lifecycle_runtime
lifecycle_status = str(lifecycle_runtime.get("status") or "not_requested")
if lifecycle_status == "ready" and lifecycle_runtime.get("latest_run"):
version_lifecycle["runtime_state"] = "running_fail_closed"
elif lifecycle_status == "pending_first_run":
version_lifecycle["runtime_state"] = "scheduled_pending_first_receipt"
elif lifecycle_status == "degraded":
version_lifecycle["runtime_state"] = "degraded_with_safe_next_action"
external_rows = [
row for row in capability_rows if row.get("source_type") == "external"
]
promotion_ready = sum(
1 for row in external_rows if row.get("deployment_allowed") is True
)
detected_products = sum(
1
for row in products
if row["inventory_state"]
not in {
"no_committed_mcp_runtime_detected",
"no_federated_mcp_inventory_readback",
}
)
quarantined_products = sum(
1
for row in products
if "quarantine" in row["inventory_state"]
or "remediation_required" in row["inventory_state"]
)
active_blockers = set(_strings(version_lifecycle.get("active_blockers")))
active_blockers.update(_strings(lifecycle_runtime.get("blockers")))
active_blockers.update(_strings(federation_runtime.get("blockers")))
active_blockers.update(
blocker
for product in products
for blocker in _strings(product.get("blockers"))
)
active_blockers.update(
{
"external_candidate_immutable_supply_chain_receipts_missing",
"external_rag_quarantine_promotion_verifier_missing",
"distributed_gateway_rate_limit_receipt_missing",
}
)
federated_receipt_count = int(
runtime_payload.get("federated_product_runtime_receipt_count") or 0
)
federated_receipt_expected = int(
runtime_payload.get("federated_product_runtime_receipt_expected") or 12
)
if federated_receipt_count < federated_receipt_expected:
active_blockers.add("cross_product_runtime_federation_receipts_missing")
rag = (
runtime_payload.get("rag")
if isinstance(runtime_payload.get("rag"), dict)
else {}
)
if rag.get("total_chunks") == 0:
active_blockers.add("internal_rag_index_empty")
if runtime_payload.get("status") not in {"ready", "not_requested"}:
active_blockers.add("mcp_runtime_readback_degraded")
source_summary = product_matrix.get("summary")
source_summary = source_summary if isinstance(source_summary, dict) else {}
return {
"schema_version": SCHEMA_VERSION,
"generated_at": generated_at
or datetime.now(TZ_TAIPEI).isoformat(timespec="seconds"),
"status": "partial_degraded_with_safe_next_action",
"summary": {
"product_count": len(products),
"expected_product_count": 12,
"source_control_ready_product_count": int(
source_summary.get("source_control_ready_product_count") or 0
),
"mcp_source_detected_product_count": detected_products,
"mcp_source_gap_product_count": len(products) - detected_products,
"quarantined_or_remediation_product_count": quarantined_products,
"capability_count": len(capability_rows),
"external_candidate_count": len(external_rows),
"external_promotion_ready_count": promotion_ready,
"github_in_scope_count": 0,
"active_blocker_count": len(active_blockers),
"runtime_provider_count": int(
_nested(runtime_payload, "provider_registry", "provider_count") or 0
),
"runtime_tool_count": int(
_nested(runtime_payload, "provider_registry", "tool_count") or 0
),
"federated_product_runtime_receipt_count": federated_receipt_count,
"federated_product_runtime_receipt_expected": federated_receipt_expected,
},
"architecture": catalog["architecture"],
"security_policy": catalog["security_policy"],
"supply_chain_policy": catalog["supply_chain_policy"],
"version_lifecycle": version_lifecycle,
"runtime": runtime_payload,
"catalog_sources": catalog["source_policy"]["catalog_sources"],
"capabilities": capability_rows,
"products": products,
"active_blockers": sorted(active_blockers),
"next_actions": [
(
"resolve_ewoooc_momo_runtime_blockers_and_expand_next_product_federation_receipts"
if len(federation_receipt_index) == 2
else "federate_ewoooc_and_momo_read_only_inventory_health_and_version_receipts"
),
"disable_agent_bounty_github_and_prompt_injection_tool_path",
"remove_bitan_github_external_provider_from_effective_policy",
"promote_first_internally_mirrored_candidate_through_replay_shadow_and_canary",
"mirror_and_pin_each_approved_external_candidate_before_shadow",
"wire_quarantine_scan_citation_verifier_and_governed_rag_promotion",
],
"operation_boundaries": {
"read_only_api_allowed": True,
"public_response_redacted_aggregate_only": True,
"mutation_endpoint_exposed": False,
"operator_auth_required_for_future_mutation": True,
"normalized_version_receipt_write_allowed": True,
"external_install_allowed": False,
"external_tool_call_allowed": False,
"external_rag_write_allowed": False,
"github_allowed": False,
"secret_value_read_allowed": False,
"request_or_response_body_storage_allowed": False,
"production_upgrade_allowed": False,
},
"source_refs": {
"catalog": f"docs/operations/{_CATALOG_FILE}",
"product_matrix": "GET /api/v1/agents/product-governance-matrix-readback",
"runtime": "live provider registry, MCP tool registry, gateway audit aggregate, RAG stats, durable version lifecycle receipts, and normalized federated product receipts",
},
}
async def collect_mcp_control_plane_runtime() -> dict[str, Any]:
"""Collect aggregate-only runtime evidence without request or response bodies."""
blockers: list[str] = []
lifecycle_payload, federation_payload = await asyncio.gather(
collect_mcp_version_lifecycle_readback(),
collect_mcp_federation_readback(),
)
if lifecycle_payload.get("status") == "degraded":
blockers.append("version_lifecycle_runtime_readback_degraded")
if federation_payload.get("status") not in {"ready", "not_requested"}:
blockers.append("federation_runtime_readback_degraded")
try:
provider_registry = get_provider_registry()
tool_registry = get_mcp_tool_registry()
provider_payload = {
"status": "registered",
"provider_count": len(provider_registry.names()),
"provider_names": sorted(provider_registry.names()),
"tool_count": tool_registry.tool_count,
}
except Exception as exc:
logger.warning(
"mcp_control_plane_provider_registry_readback_failed",
error_type=type(exc).__name__,
)
blockers.append("provider_registry_readback_failed")
provider_payload = {
"status": "degraded",
"provider_count": 0,
"provider_names": [],
"tool_count": 0,
}
try:
# Control-plane readback is deliberately scoped to the canonical AWOOOI
# tenant. Query the governed pgvector table directly so repository
# fallback-to-zero cannot disguise a DB/RLS failure as a healthy empty
# index. Only aggregate counts leave this service.
async with get_db_context("awoooi") as db:
result = await db.execute(
text(
"""
SELECT
COUNT(*)::int AS total_chunks,
COUNT(DISTINCT source)::int AS sources
FROM rag_chunks
"""
)
)
rag_stats = result.mappings().one()
rag_payload = {
"status": "ready",
"total_chunks": int(rag_stats.get("total_chunks") or 0),
"sources": int(rag_stats.get("sources") or 0),
"scope": "project:awoooi",
}
except Exception as exc:
logger.warning(
"mcp_control_plane_rag_readback_failed",
error_type=type(exc).__name__,
)
blockers.append("rag_stats_readback_failed")
rag_payload = {
"status": "degraded",
"total_chunks": 0,
"sources": 0,
"scope": "project:awoooi",
}
try:
async with get_db_context("awoooi") as db:
result = await db.execute(
text(
"""
SELECT
COUNT(*)::int AS call_count,
COUNT(*) FILTER (WHERE result_status = 'success')::int AS success_count,
COUNT(*) FILTER (WHERE result_status = 'blocked')::int AS blocked_count,
COUNT(*) FILTER (WHERE result_status IN ('failed', 'timeout'))::int AS failed_count
FROM awooop_mcp_gateway_audit
WHERE created_at >= NOW() - INTERVAL '24 hours'
"""
)
)
row = result.mappings().one()
gateway_payload = {
"status": "ready",
"call_count": int(row["call_count"] or 0),
"success_count": int(row["success_count"] or 0),
"blocked_count": int(row["blocked_count"] or 0),
"failed_count": int(row["failed_count"] or 0),
"body_storage": "hash_only",
"scope": "project:awoooi",
}
except Exception as exc:
logger.warning(
"mcp_control_plane_gateway_audit_readback_failed",
error_type=type(exc).__name__,
)
blockers.append("gateway_audit_readback_failed")
gateway_payload = {
"status": "degraded",
"call_count": 0,
"success_count": 0,
"blocked_count": 0,
"failed_count": 0,
"body_storage": "hash_only",
"scope": "project:awoooi",
}
return {
"requested": True,
"status": "ready" if not blockers else "degraded",
"provider_registry": provider_payload,
"gateway_audit_24h": gateway_payload,
"rag": rag_payload,
"version_lifecycle": lifecycle_payload,
"federated_runtime": federation_payload,
"federated_product_runtime_receipt_count": int(
federation_payload.get("verified_fresh_receipt_count") or 0
),
"federated_product_runtime_receipt_expected": 12,
"blockers": sorted(blockers),
}
def _validate_catalog(payload: dict[str, Any], label: str) -> None:
if payload.get("schema_version") != CATALOG_SCHEMA_VERSION:
raise ValueError(f"{label}: invalid schema_version")
architecture = payload.get("architecture") or {}
if (
architecture.get("decision")
!= "single_control_plane_reuse_existing_gateway_registry_rag"
):
raise ValueError(f"{label}: duplicate gateway/RAG architecture is forbidden")
if architecture.get("separate_gateway_allowed") is not False:
raise ValueError(f"{label}: separate gateway must remain false")
if architecture.get("separate_rag_database_allowed") is not False:
raise ValueError(f"{label}: separate RAG database must remain false")
source_policy = payload.get("source_policy") or {}
for key in (
"github_allowed",
"github_actions_allowed",
"github_artifact_sources_allowed",
):
if source_policy.get(key) is not False:
raise ValueError(f"{label}: {key} must remain false")
security = payload.get("security_policy") or {}
if security.get("external_rag_auto_write_allowed") is not False:
raise ValueError(f"{label}: external RAG auto-write must remain false")
if security.get("gateway_request_body_storage") != "forbidden_hash_only":
raise ValueError(f"{label}: gateway request body policy must be hash-only")
capabilities = _dict_rows(payload.get("capabilities"))
capability_ids = [str(row.get("capability_id") or "") for row in capabilities]
if not all(capability_ids) or len(capability_ids) != len(set(capability_ids)):
raise ValueError(f"{label}: capability IDs must be non-empty and unique")
capability_id_set = set(capability_ids)
github_rows = [
row for row in capabilities if row.get("capability_id") == "rejected.github"
]
if len(github_rows) != 1 or github_rows[0].get("decision") != "rejected":
raise ValueError(f"{label}: GitHub capability must be explicitly rejected")
for row in capabilities:
if row.get("source_type") != "external":
continue
if row.get("deployment_allowed") is True and any(
row.get(field) in {None, "", "missing", "unresolved"}
for field in (
"version_state",
"digest_state",
"sbom_state",
"signature_state",
)
):
raise ValueError(
f"{label}: external capability {row.get('capability_id')} cannot deploy without immutable receipts"
)
if row.get("compatibility_state") != "protocol_schema_compatibility_verified":
continue
if row.get("replay_status") != "completed_protocol_schema_replay_verified":
raise ValueError(
f"{label}: verified compatibility requires a completed replay verifier receipt"
)
if row.get("replay_independent_verifier") is not True:
raise ValueError(
f"{label}: verified compatibility requires an independent verifier"
)
if not isinstance(row.get("replay_tool_count"), int) or int(
row["replay_tool_count"]
) <= 0:
raise ValueError(
f"{label}: verified compatibility requires a positive replay tool count"
)
if row.get("replay_process_exit_code") != 0 or row.get(
"replay_shutdown_mode"
) != "stdin_eof_clean_exit":
raise ValueError(
f"{label}: verified compatibility requires a clean MCP process terminal"
)
if row.get("replay_ephemeral_container_removed") is not True:
raise ValueError(
f"{label}: verified compatibility requires ephemeral container removal"
)
no_effect_fields = (
"replay_browser_started",
"replay_tool_call_performed",
"replay_navigation_performed",
"replay_external_rag_write_performed",
"replay_production_write_performed",
"replay_promotion_allowed",
)
if any(row.get(field) is not False for field in no_effect_fields):
raise ValueError(
f"{label}: compatibility replay must remain no-browser, no-tool, no-write, and no-promotion"
)
if row.get("deployment_allowed") is not False:
raise ValueError(
f"{label}: compatibility verification alone cannot enable deployment"
)
fixed_hex_fields = {
"replay_audit_commit": 40,
"replay_artifact_audit_commit": 40,
"artifact_latest_revalidation_audit_commit": 40,
"replay_controller_receipt_sha256": 64,
"replay_verifier_receipt_sha256": 64,
"replay_tool_name_set_sha256": 64,
"replay_tool_schema_manifest_sha256": 64,
}
if any(
not _is_lower_hex(row.get(field), length)
for field, length in fixed_hex_fields.items()
):
raise ValueError(
f"{label}: verified compatibility requires immutable audit and replay hashes"
)
if "compatibility_replay_not_executed" in _strings(row.get("blockers")):
raise ValueError(
f"{label}: verified compatibility cannot retain replay-not-executed blocker"
)
products = _dict_rows(payload.get("products"))
product_ids = {str(row.get("product_id") or "") for row in products}
if product_ids != _EXPECTED_PRODUCT_IDS or len(products) != 12:
raise ValueError(
f"{label}: catalog must contain exact 12 products; "
f"missing={sorted(_EXPECTED_PRODUCT_IDS - product_ids)}, "
f"unexpected={sorted(product_ids - _EXPECTED_PRODUCT_IDS)}"
)
for row in products:
refs = (
_strings(row.get("existing_capability_ids"))
+ _strings(row.get("recommended_capability_ids"))
+ _strings(row.get("rejected_capability_ids"))
)
unknown = sorted(set(refs) - capability_id_set)
if unknown:
raise ValueError(
f"{label}: product {row.get('product_id')} references unknown capabilities {unknown}"
)
def _capability_summary(row: dict[str, Any]) -> dict[str, Any]:
return {
"capability_id": row["capability_id"],
"title": row["title"],
"decision": row["decision"],
"risk_tier": row["risk_tier"],
"deployment_allowed": row["deployment_allowed"],
}
def _is_lower_hex(value: Any, length: int) -> bool:
return (
isinstance(value, str)
and len(value) == length
and all(character in "0123456789abcdef" for character in value)
)
def _dict_rows(value: Any) -> list[dict[str, Any]]:
if not isinstance(value, list):
return []
return [row for row in value if isinstance(row, dict)]
def _strings(value: Any) -> list[str]:
if not isinstance(value, list):
return []
return [str(item) for item in value if str(item)]
def _nested(payload: dict[str, Any], first: str, second: str) -> Any:
nested = payload.get(first)
return nested.get(second) if isinstance(nested, dict) else None