Newer
Older
navi-1 / navi / mcp / config.py
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()}