Files
ewoooc/services/market_intel/mcp_fetch_gate.py
OoO 921e9eeb15
All checks were successful
CD Pipeline / deploy (push) Successful in 1m6s
feat(market-intel): gate manual fetch behind mcp readiness
2026-05-18 15:40:56 +08:00

109 lines
4.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""市場情報人工 fetch 的 MCP gate preview。
這裡只計算外部 fetch 是否具備前置條件;不呼叫電商平台、不寫 DB、不掛排程。
"""
from services.market_intel.mcp_readiness import build_mcp_readiness_plan
def _status_value(runtime_status, name, default=False):
if isinstance(runtime_status, dict):
return runtime_status.get(name, default)
return getattr(runtime_status, name, default)
def build_mcp_fetch_gate_preview(
runtime_status,
*,
fetch_requested=False,
execute_readiness=False,
readiness=None,
):
"""建立人工 fetch 前的 MCP gate預設不做 health check、不連 DB。"""
fetch_requested = bool(fetch_requested)
execute_readiness = bool(execute_readiness)
readiness = readiness or build_mcp_readiness_plan(
execute_requested=execute_readiness,
)
readiness_checks = readiness.get("readiness_checks") or {}
gate_checks = {
"market_intel_enabled": bool(_status_value(runtime_status, "enabled")),
"market_intel_crawler_enabled": bool(
_status_value(runtime_status, "crawler_enabled")
),
"database_write_still_blocked": not bool(
_status_value(runtime_status, "database_write_allowed")
),
"scheduler_detached": not bool(
_status_value(runtime_status, "scheduler_attached")
),
"mcp_readiness_executed": bool(readiness.get("execute_requested")),
"mcp_router_enabled": bool(readiness.get("router_enabled")),
"external_mcp_complete": bool(readiness.get("external_mcp_complete")),
"internal_mcp_complete": bool(readiness.get("internal_mcp_complete")),
"market_intel_mcp_integrated": bool(
readiness.get("market_intel_mcp_integrated")
),
"market_intel_tool_contract_ready": bool(
readiness_checks.get("market_intel_tool_contract_ready")
),
"external_servers_all_healthy": bool(
readiness_checks.get("external_servers_all_healthy")
),
}
blocked_reasons = [
key for key, passed in gate_checks.items()
if not passed
]
if not fetch_requested:
blocked_reasons.insert(0, "fetch_false_planned_only")
prerequisites_met = not blocked_reasons
network_request_allowed = bool(fetch_requested and prerequisites_met)
return {
"mode": (
"mcp_fetch_gate_read_only"
if execute_readiness
else "mcp_fetch_gate_planned"
),
"fetch_requested": fetch_requested,
"readiness_execute_requested": bool(readiness.get("execute_requested")),
"manual_fetch_prerequisites_met": prerequisites_met,
"manual_fetch_gate_open": network_request_allowed,
"network_request_allowed": network_request_allowed,
"would_use_external_network": network_request_allowed,
"gate_checks": gate_checks,
"blocked_reasons": blocked_reasons,
"operator_message": (
"人工 fetch 已通過 MCP gate仍只允許公開頁面、限速、不得寫 DB。"
if network_request_allowed
else "人工 fetch 仍被 MCP gate 阻擋;需 feature flags、MCP health、router 與 tool contract 全部通過。"
),
"required_sequence": [
"MARKET_INTEL_ENABLED 與 MARKET_INTEL_CRAWLER_ENABLED 需由操作員明確開啟",
"MCP deploy preflight 必須通過必要 env、compose、localhost port 與 fallback 檢查",
"外部 MCP stack 四個 health endpoint 需全部 200",
"MCP_ROUTER_ENABLED 只能在 health 全過後才打開",
"manual discovery fetch 才能進入公開頁面限速探測,且仍不得寫 DB",
],
"mcp_readiness_summary": {
"mode": readiness.get("mode"),
"router_enabled": bool(readiness.get("router_enabled")),
"external_mcp_complete": bool(readiness.get("external_mcp_complete")),
"internal_mcp_complete": bool(readiness.get("internal_mcp_complete")),
"market_intel_mcp_integrated": bool(
readiness.get("market_intel_mcp_integrated")
),
"blocked_reasons": readiness.get("blocked_reasons", []),
},
"database_session_created": False,
"database_write_executed": False,
"database_commit_executed": False,
"external_network_executed": False,
"scheduler_attached": False,
"writes_executed": False,
"would_write_database": False,
}