import * as dotenv from "dotenv";
dotenv.config();
import { randomUUID } from "crypto";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { Context } from "./context.js";
import { TOOLS } from "./tools/index.js";
import { RESOURCE_TEMPLATES } from "./mcp/resources.js";
import { ListResourcesRequestSchema, ReadResourceRequestSchema, ListResourceTemplatesRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
// Configuration schema for Smithery - matches existing Config interface
export const configSchema = z
    .object({
    browserbaseApiKey: z.string().describe("The Browserbase API Key to use"),
    browserbaseProjectId: z
        .string()
        .describe("The Browserbase Project ID to use"),
    proxies: z
        .boolean()
        .optional()
        .describe("Whether or not to use Browserbase proxies"),
    advancedStealth: z
        .boolean()
        .optional()
        .describe("Use advanced stealth mode. Only available to Browserbase Scale Plan users"),
    keepAlive: z
        .boolean()
        .optional()
        .describe("Whether or not to keep the Browserbase session alive"),
    context: z
        .object({
        contextId: z
            .string()
            .optional()
            .describe("The ID of the context to use"),
        persist: z
            .boolean()
            .optional()
            .describe("Whether or not to persist the context"),
    })
        .optional(),
    viewPort: z
        .object({
        browserWidth: z
            .number()
            .optional()
            .describe("The width of the browser"),
        browserHeight: z
            .number()
            .optional()
            .describe("The height of the browser"),
    })
        .optional(),
    server: z
        .object({
        port: z
            .number()
            .optional()
            .describe("The port to listen on for SHTTP or MCP transport"),
        host: z
            .string()
            .optional()
            .describe("The host to bind the server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces"),
    })
        .optional(),
    modelName: z
        .string()
        .optional()
        .describe("The model to use for Stagehand (default: gemini-2.0-flash)"),
    modelApiKey: z
        .string()
        .optional()
        .describe("API key for the custom model provider. Required when using a model other than the default gemini-2.0-flash"),
    experimental: z
        .boolean()
        .optional()
        .describe("Enable experimental Stagehand features"),
})
    .refine((data) => {
    // If a non-default model is explicitly specified, API key is required
    if (data.modelName && data.modelName !== "gemini-2.0-flash") {
        return (data.modelApiKey !== undefined &&
            typeof data.modelApiKey === "string" &&
            data.modelApiKey.length > 0);
    }
    return true;
}, {
    message: "modelApiKey is required when specifying a custom model",
    path: ["modelApiKey"],
});
// Default function for Smithery
export default function ({ config }) {
    if (!config.browserbaseApiKey) {
        throw new Error("browserbaseApiKey is required");
    }
    if (!config.browserbaseProjectId) {
        throw new Error("browserbaseProjectId is required");
    }
    const server = new McpServer({
        name: "Browserbase MCP Server",
        version: "2.3.0",
        description: "Cloud browser automation server powered by Browserbase and Stagehand. Enables LLMs to navigate websites, interact with elements, extract data, and capture screenshots using natural language commands.",
        capabilities: {
            resources: {
                subscribe: true,
                listChanged: true,
            },
            tools: {},
        },
    });
    const internalConfig = config;
    // Create the context, passing server instance and config
    const contextId = randomUUID();
    const context = new Context(server.server, internalConfig, contextId);
    server.server.registerCapabilities({
        resources: {
            subscribe: true,
            listChanged: true,
        },
    });
    // Add resource handlers
    server.server.setRequestHandler(ListResourcesRequestSchema, async () => {
        return context.listResources();
    });
    server.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
        return context.readResource(request.params.uri);
    });
    server.server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
        return { resourceTemplates: RESOURCE_TEMPLATES };
    });
    const tools = [...TOOLS];
    // Register each tool with the Smithery server
    tools.forEach((tool) => {
        if (tool.schema.inputSchema instanceof z.ZodObject) {
            server.tool(tool.schema.name, tool.schema.description, tool.schema.inputSchema.shape, async (params) => {
                try {
                    const result = await context.run(tool, params);
                    return result;
                }
                catch (error) {
                    const errorMessage = error instanceof Error ? error.message : String(error);
                    process.stderr.write(`[Smithery Error] ${new Date().toISOString()} Error running tool ${tool.schema.name}: ${errorMessage}\n`);
                    throw new Error(`Failed to run tool '${tool.schema.name}': ${errorMessage}`);
                }
            });
        }
        else {
            console.warn(`Tool "${tool.schema.name}" has an input schema that is not a ZodObject. Schema type: ${tool.schema.inputSchema.constructor.name}`);
        }
    });
    return server.server;
}
