from __future__ import annotations from typing import Literal from pydantic import BaseModel, Field McpClientApplyState = Literal["pending_local_apply", "user_confirmed", "not_required"] McpExecutionMode = Literal["backend_direct", "local_bridge"] McpRuntimeProbeStatus = Literal["unknown", "ready", "error", "local_bridge_required"] class McpFieldSpec(BaseModel): key: str label: str field_type: Literal["text", "path_list", "readonly"] = "text" required: bool = False placeholder: str | None = None description: str | None = None default_value: str | list[str] | None = None class McpCommandPreview(BaseModel): add_command: str verify_command: str expected_output: str class McpRuntimeProbe(BaseModel): status: McpRuntimeProbeStatus = "unknown" checked_at: str | None = None message: str | None = None tool_names: list[str] = Field(default_factory=list) class McpTemplateSpec(BaseModel): id: str name: str description: str transport: Literal["stdio", "streamable_http"] execution_mode: McpExecutionMode icon: str recommended: bool = False docs_url: str | None = None fields: list[McpFieldSpec] = Field(default_factory=list) command_hint: str | None = None verify_hint: str | None = None class McpServerConfigPayload(BaseModel): id: str name: str display_name: str template_id: str transport: Literal["stdio", "streamable_http"] execution_mode: McpExecutionMode = "local_bridge" params: dict[str, object] = Field(default_factory=dict) preview: McpCommandPreview client_apply_state: McpClientApplyState = "pending_local_apply" runtime_probe: McpRuntimeProbe = Field(default_factory=McpRuntimeProbe) created_at: str updated_at: str confirmed_at: str | None = None