/**
 * src/mcp/manager.ts
 *
 * MCP (Model Context Protocol) client manager.
 *
 * Reads <dataDir>/mcp.json (Claude Desktop / Cursor compatible format),
 * spawns each configured server over stdio, lists its tools, and exposes
 * them through Muassis's existing tool framework. The agent doesn't know
 * which tools are "native" vs "MCP" — they all show up in the toolbelt
 * and dispatch correctly based on the registered backing.
 *
 * Config format (drop-in compatible with Claude Desktop's mcp.json):
 * {
 *   "mcpServers": {
 *     "playwright": { "command": "npx", "args": ["@playwright/mcp"] },
 *     "github": {
 *       "command": "npx",
 *       "args": ["-y", "@modelcontextprotocol/server-github"],
 *       "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..." }
 *     }
 *   }
 * }
 *
 * Tools from MCP servers are auto-prefixed with `mcp_<server>_` to avoid
 * collisions with native tools. The LLM sees the prefixed name and routes
 * back through callTool() here.
 */
import type { ToolDefinition } from '../models/provider.js';
export interface MCPServerConfig {
    command: string;
    args?: string[];
    env?: Record<string, string>;
    /** Optional human-readable description shown in `muassis mcp list`. */
    description?: string;
    /** If true, the server is registered but not auto-spawned at boot. */
    disabled?: boolean;
}
export interface MCPConfig {
    mcpServers: Record<string, MCPServerConfig>;
}
declare class MCPManager {
    private servers;
    private configPath;
    constructor();
    /** Path to the persistent MCP config file. */
    getConfigPath(): string;
    /** Read the config from disk, returning an empty config if missing. */
    readConfig(): MCPConfig;
    /** Write the config to disk, creating directories as needed. */
    writeConfig(config: MCPConfig): void;
    /** Register a new server in the config. Does NOT spawn — call init() to start. */
    addServer(name: string, config: MCPServerConfig): void;
    /**
     * Hot-attach a freshly-registered server: writes to mcp.json, spawns the
     * process, connects the MCP client, and refreshes the tool catalogue so
     * the brain sees the new tools on the very next message. No restart.
     *
     * Returns the number of new tools surfaced (0 if the server is already
     * connected with the same config).
     */
    addAndConnectServer(name: string, config: MCPServerConfig): Promise<{
        toolCount: number;
        alreadyRunning: boolean;
    }>;
    /**
     * Snapshot of currently-connected servers + their tool catalogue. Used by
     * the list_mcp_tools brain tool so the agent can answer "what can you do
     * with X?" without guessing.
     */
    listConnectedServers(): Array<{
        name: string;
        toolCount: number;
        tools: string[];
    }>;
    /** Remove a server from the config and stop it if running. */
    removeServer(name: string): Promise<boolean>;
    /**
     * Default MCP servers shipped with the gateway. These are auto-written
     * to mcp.json on first boot if no config exists, so the agent has real
     * tools out-of-the-box without any user setup. Each package is a
     * runtime dependency so `npx -y` finds it in local node_modules
     * instantly — no network fetch on first spawn.
     *
     * Only servers that work without API keys get auto-enabled. Token-
     * gated ones (github, slack, etc.) stay opt-in via `muassis mcp install`.
     */
    private static readonly DEFAULT_SERVERS;
    /**
     * Write the default MCP server set to mcp.json. Called automatically on
     * first boot when no config exists. If the user later does
     * `muassis mcp remove <name>`, that change persists — we only auto-write
     * when mcp.json doesn't exist at all (not when it's empty).
     */
    private bootstrapDefaultsIfMissing;
    /**
     * Spawn all enabled servers in the config. Best-effort: a single broken
     * server doesn't take down the whole gateway. Failed servers are logged
     * and skipped.
     */
    init(): Promise<void>;
    private spawnServer;
    /**
     * Resolve the actual command/args to spawn for a server config. Handles
     * three cases:
     *
     *   1. Bundled package — config says `npx -y <pkg>` and <pkg> is already in
     *      the gateway's node_modules. We rewrite to `<bundled-node> <bin.js>`
     *      and skip npx entirely. This is what makes the defaults (memory,
     *      sequential-thinking, playwright) work in the .app.
     *
     *   2. npx fallback — config asks for npx but the package isn't bundled.
     *      We search an extended PATH for npx (homebrew, nvm, etc.) since the
     *      .app's spawn env has a minimal default PATH.
     *
     *   3. Absolute / non-npx command — passed through as-is. The user knows
     *      what they're doing.
     */
    private resolveSpawnCommand;
    /**
     * Look up a package's `bin` entry inside the gateway's node_modules and
     * return the absolute path to its JS entry, or null if not bundled.
     * Strips `@latest` / version suffixes from the package name.
     */
    private resolveBundledPackageBin;
    /**
     * Compose the env passed to the spawned MCP server. We always merge in
     * the parent process env plus an extended PATH so child processes (e.g.
     * `playwright-mcp` shelling out to chromium) can locate auxiliary tools.
     */
    private buildSpawnEnv;
    /** Tear down a single server cleanly. */
    stopServer(name: string): Promise<void>;
    /** Tear down all servers (called at gateway shutdown). */
    shutdown(): Promise<void>;
    /**
     * Flatten every running MCP tool into a Muassis ToolDefinition. Tool
     * names are prefixed with `mcp_<server>_` so they don't collide with
     * native tools like read_file. The LLM only sees the flat list — it
     * doesn't know which server backs which tool.
     *
     * We aggressively filter junk to keep the LLM's toolbelt focused:
     *   1. Demo-fixture tools (echo, get-sum, simulate-research-query,
     *      get-tiny-image, …) come from the modelcontextprotocol/servers
     *      "everything" server which is a TEST harness, not a useful
     *      production server. Easy to install accidentally; useless to
     *      keep around. We filter them by name patterns.
     *   2. Duplicate tool names across multiple servers (which happens
     *      when the user installs two paths to the same upstream package).
     *      Keep only the first.
     *
     * Net effect on a typical setup: 79 tools → ~45, system prompt drops
     * by ~5-7K tokens, model can actually decide.
     */
    getToolDefinitions(): ToolDefinition[];
    /**
     * Look up the (server, original-tool-name) pair for a prefixed name.
     * Returns null if the name doesn't match any registered MCP tool.
     */
    resolveToolName(prefixedName: string): {
        server: string;
        toolName: string;
    } | null;
    /** Dispatch a tool call to the right MCP server. */
    callTool(prefixedName: string, args: Record<string, unknown>): Promise<{
        success: boolean;
        output: string;
        data?: unknown;
    }>;
    /** List currently-running servers + their tool counts (for `muassis mcp list`). */
    status(): Array<{
        name: string;
        running: boolean;
        toolCount: number;
        tools: string[];
    }>;
}
export declare const mcpManager: MCPManager;
export {};
//# sourceMappingURL=manager.d.ts.map