from __future__ import annotations
import json
from pathlib import Path
from typing import Literal
from pydantic import BaseModel, Field
class McpServerConfig(BaseModel):
"""Configuration for a single MCP server."""
transport: Literal["stdio", "sse"] = "stdio"
# stdio fields
command: str | None = None
args: list[str] = Field(default_factory=list)
env: dict[str, str] | None = None
cwd: str | None = None
# sse fields
url: str | None = None
headers: dict[str, str] | None = None
@property
def is_stdio(self) -> bool:
return self.transport == "stdio"
@property
def is_sse(self) -> bool:
return self.transport == "sse"
def load_mcp_servers(path: str | Path | None = None) -> dict[str, McpServerConfig]:
"""Load MCP server configurations from a JSON file.
Default path is ``mcp_servers.json`` in the current working directory.
Returns an empty dict if the file does not exist.
"""
if path is None:
path = Path("mcp_servers.json")
else:
path = Path(path)
if not path.exists():
return {}
raw = json.loads(path.read_text(encoding="utf-8"))
return {name: McpServerConfig.model_validate(cfg) for name, cfg in raw.items()}