feat(market-intel): add internal mcp contract
All checks were successful
CD Pipeline / deploy (push) Successful in 1m1s

This commit is contained in:
OoO
2026-05-18 14:42:25 +08:00
parent b8ca756090
commit 07b76870c9
9 changed files with 271 additions and 24 deletions

View File

@@ -14,6 +14,7 @@ from services.market_intel.adapters import get_adapter, get_adapter_summaries
from services.market_intel.candidate_preview import build_candidate_preview_from_discovery
from services.market_intel.discovery_runner import ManualDiscoveryRunner
from services.market_intel.html_diagnostics import parse_html_diagnostics
from services.market_intel.mcp_contract import build_mcp_tool_contract_preview
from services.market_intel.mcp_readiness import build_mcp_readiness_plan
from services.market_intel.platform_seed_db_diff import build_platform_seed_db_diff_plan
from services.market_intel.schema_db_probe import build_schema_db_probe_plan
@@ -386,6 +387,7 @@ def test_market_intel_preview_template_uses_safe_fetch_false_endpoint():
assert "data-market-intel-mcp-servers" in template
assert "data-market-intel-mcp-checks" in template
assert "data-market-intel-mcp-tools" in template
assert "market_intel_contract" in template
assert "data-market-intel-migration" in template
assert "data-market-intel-migration-tables" in template
assert "data-market-intel-approval" in template
@@ -425,7 +427,7 @@ def test_legacy_source_bridge_default_is_planned_only():
bridge = MarketIntelService().build_legacy_source_bridge()
assert bridge["mode"] == "legacy_source_bridge_planned"
assert bridge["phase"] == "phase_28_mcp_readiness_preview"
assert bridge["phase"] == "phase_29_internal_mcp_contract_preview"
assert bridge["execute_requested"] is False
assert bridge["read_only_query_executed"] is False
assert bridge["database_connection_opened"] is False
@@ -579,18 +581,80 @@ def test_legacy_source_bridge_read_only_sqlite_counts_sources():
)
def test_mcp_tool_contract_preview_is_read_only_and_whitelisted():
contract = MarketIntelService().build_mcp_tool_contract()
assert contract["mode"] == "mcp_tool_contract_preview"
assert contract["phase"] == "phase_29_internal_mcp_contract_preview"
assert contract["caller"] == "market_intel"
assert contract["contract_ready"] is True
assert contract["blocked_reasons"] == []
assert contract["tool_count"] == 3
assert contract["database_session_created"] is False
assert contract["database_write_executed"] is False
assert contract["database_commit_executed"] is False
assert contract["external_network_executed"] is False
assert contract["scheduler_attached"] is False
assert contract["writes_executed"] is False
assert contract["would_write_database"] is False
assert contract["checks"]["market_intel_caller_registered"] is True
assert contract["checks"]["all_router_tools_whitelisted"] is True
assert contract["checks"]["all_tools_read_only"] is True
assert contract["checks"]["no_database_write_allowed"] is True
assert contract["checks"]["no_scheduler_attach_allowed"] is True
assert {item["name"] for item in contract["tools"]} == {
"market_campaign_search",
"market_campaign_scrape",
"market_product_match_lookup",
}
assert all(item["router_tools_whitelisted"] is True for item in contract["tools"])
assert all(item["write_risk"] is False for item in contract["tools"])
def test_mcp_tool_contract_detects_missing_router_whitelist():
contract = build_mcp_tool_contract_preview(tool_registry={})
assert contract["contract_ready"] is False
assert "market_intel_caller_registered" in contract["blocked_reasons"]
assert "all_router_tools_whitelisted" in contract["blocked_reasons"]
def test_mcp_tool_contract_route_is_preview_only():
from routes.market_intel_routes import market_intel_bp
app = Flask(__name__)
app.secret_key = "test-secret"
app.register_blueprint(market_intel_bp)
client = app.test_client()
with client.session_transaction() as session:
session["logged_in"] = True
response = client.get("/api/market_intel/mcp_tool_contract")
data = response.get_json()
assert response.status_code == 200
assert data["mode"] == "mcp_tool_contract_preview"
assert data["contract_ready"] is True
assert data["database_session_created"] is False
assert data["database_write_executed"] is False
assert data["database_commit_executed"] is False
assert data["external_network_executed"] is False
assert data["scheduler_attached"] is False
def test_mcp_readiness_default_is_planned_only(monkeypatch):
monkeypatch.delenv("MCP_ROUTER_ENABLED", raising=False)
readiness = MarketIntelService().build_mcp_readiness()
assert readiness["mode"] == "mcp_readiness_planned"
assert readiness["phase"] == "phase_28_mcp_readiness_preview"
assert readiness["phase"] == "phase_29_internal_mcp_contract_preview"
assert readiness["execute_requested"] is False
assert readiness["router_enabled"] is False
assert readiness["external_mcp_complete"] is False
assert readiness["internal_mcp_complete"] is False
assert readiness["market_intel_mcp_integrated"] is False
assert readiness["market_intel_mcp_integrated"] is True
assert readiness["mcp_tool_contract"]["contract_ready"] is True
assert readiness["database_session_created"] is False
assert readiness["database_write_executed"] is False
assert readiness["database_commit_executed"] is False
@@ -602,12 +666,15 @@ def test_mcp_readiness_default_is_planned_only(monkeypatch):
assert readiness["telemetry"]["database_session_created"] is False
assert readiness["telemetry"]["database_write_executed"] is False
assert readiness["readiness_checks"]["base_callers_registered"] is True
assert readiness["readiness_checks"]["market_intel_caller_registered"] is False
assert readiness["readiness_checks"]["market_intel_tools_registered"] is False
assert readiness["readiness_checks"]["market_intel_caller_registered"] is True
assert readiness["readiness_checks"]["market_intel_tools_registered"] is True
assert readiness["readiness_checks"]["market_intel_tool_contract_ready"] is True
assert len(readiness["server_statuses"]) == 4
assert all(item["health_checked"] is False for item in readiness["server_statuses"])
assert all(item["healthy"] is False for item in readiness["server_statuses"])
assert "execute_false_planned_only" in readiness["blocked_reasons"]
assert "market_intel_caller_registered" not in readiness["blocked_reasons"]
assert "market_intel_tools_registered" not in readiness["blocked_reasons"]
def test_mcp_readiness_sqlite_read_only_counts_telemetry(monkeypatch):
@@ -689,7 +756,9 @@ def test_mcp_readiness_sqlite_read_only_counts_telemetry(monkeypatch):
assert readiness["execute_requested"] is True
assert readiness["router_enabled"] is False
assert readiness["external_mcp_complete"] is False
assert readiness["internal_mcp_complete"] is False
assert readiness["internal_mcp_complete"] is True
assert readiness["market_intel_mcp_integrated"] is True
assert readiness["mcp_tool_contract"]["contract_ready"] is True
assert readiness["telemetry"]["mode"] == "mcp_telemetry_read_only"
assert readiness["telemetry"]["table_exists"] is True
assert readiness["telemetry"]["total_calls"] == 3
@@ -710,7 +779,7 @@ def test_mcp_readiness_sqlite_read_only_counts_telemetry(monkeypatch):
"postgres": 1,
}
assert "mcp_router_enabled" in readiness["blocked_reasons"]
assert "market_intel_caller_registered" in readiness["blocked_reasons"]
assert "market_intel_caller_registered" not in readiness["blocked_reasons"]
def test_market_intel_schema_smoke_checks_platform_columns():
@@ -962,6 +1031,7 @@ def test_deployment_readiness_reports_app_only_release_gate():
assert readiness["checks"]["platform_seed_db_diff_planned_safe"] is True
assert readiness["checks"]["legacy_source_bridge_planned_safe"] is True
assert readiness["checks"]["mcp_readiness_planned_safe"] is True
assert readiness["checks"]["mcp_tool_contract_ready"] is True
assert readiness["checks"]["writer_plan_dry_run_only"] is True
assert readiness["writer_plan_summary"]["writes_executed"] is False
assert "readiness_checks_not_all_passed" not in readiness["blocked_reasons"]
@@ -978,6 +1048,7 @@ def test_deployment_readiness_reports_app_only_release_gate():
assert "/api/market_intel/platform_seed_db_diff" in readiness["production_smoke_targets"]
assert "/api/market_intel/legacy_source_bridge" in readiness["production_smoke_targets"]
assert "/api/market_intel/mcp_readiness" in readiness["production_smoke_targets"]
assert "/api/market_intel/mcp_tool_contract" in readiness["production_smoke_targets"]
assert readiness["write_approval_runbook"]["ready_for_real_write"] is False
assert readiness["write_approval_runbook"]["writes_executed"] is False
assert readiness["migration_blueprint"]["migration_executed"] is False
@@ -988,6 +1059,8 @@ def test_deployment_readiness_reports_app_only_release_gate():
assert readiness["legacy_source_bridge"]["read_only_query_executed"] is False
assert readiness["mcp_readiness"]["mode"] == "mcp_readiness_planned"
assert readiness["mcp_readiness"]["telemetry"]["read_only_query_executed"] is False
assert readiness["mcp_tool_contract"]["contract_ready"] is True
assert readiness["mcp_tool_contract"]["database_write_executed"] is False
def test_write_approval_runbook_is_read_only_and_blocks_real_write():