#!/usr/bin/env node

import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
  CallToolRequestSchema,
  ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import { RequestPayloadSchema } from "./types.js";
import { Fetcher } from "./Fetcher.js";
import SSE from 'express-sse';

// 創建 Express 應用
const app = express();
app.use(cors());
app.use(bodyParser.json());

// 默認端口
const PORT = process.env.PORT || 3000;

// 創建 MCP 服務器
const server = new Server(
  {
    name: "zcaceres/fetch",
    version: "0.1.0",
  },
  {
    capabilities: {
      resources: {},
      tools: {},
    },
  },
);

// 設置工具列表處理程序
server.setRequestHandler(ListToolsRequestSchema, async () => {
  // 檢查 fetch_html 工具是否啟用
  const fetchHtmlEnv = process.env.fetch_html || "Disable";
  const isFetchHtmlEnabled = fetchHtmlEnv.toLowerCase() === "enable";
  
  // 準備工具列表
  const tools = [];
  
  // 根據環境變量決定是否添加 fetch_html 工具
  if (isFetchHtmlEnabled) {
    tools.push({
      name: "fetch_html",
      description: "Fetch and return the raw HTML content from a website",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the website to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    });
  }
  
  // 添加其他工具（這些工具始終啟用）
  tools.push(
    {
      name: "fetch_markdown",
      description: "Fetch content from a website and convert it to Markdown format",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the website to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    },
    {
      name: "fetch_txt",
      description: "Fetch and return plain text content from a website (HTML tags removed)",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the website to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    },
    {
      name: "fetch_json",
      description: "Fetch and return JSON content from a URL",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the JSON resource to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    }
  );
  
  return { tools };
});

// 設置工具處理程序
const toolHandlers: { [key: string]: (payload: any) => Promise<any> } = {
  fetch_html: Fetcher.html,
  fetch_json: Fetcher.json,
  fetch_txt: Fetcher.txt,
  fetch_markdown: Fetcher.markdown,
};

server.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;
  
  // 檢查 fetch_html 工具是否啟用
  if (name === "fetch_html") {
    const fetchHtmlEnv = process.env.fetch_html || "Disable";
    const isFetchHtmlEnabled = fetchHtmlEnv.toLowerCase() === "enable";
    
    if (!isFetchHtmlEnabled) {
      throw new Error("The fetch_html tool is disabled. Please set the environment variable fetch_html=Enable to enable this tool.");
    }
  }
  
  const validatedArgs = RequestPayloadSchema.parse(args);
  const handler = toolHandlers[name];
  if (handler) {
    return handler(validatedArgs);
  }
  throw new Error("Tool not found");
});

// 啟動 HTTP 服務器
app.get('/', (req, res) => {
  res.send('MCP Fetch Server is running. Use /sse endpoint for SSE connections or /api for direct API access.');
});

// 啟動服務器
async function main() {
  // 輸出環境變量設置信息
  console.log("Environment variables settings:");
  console.log(`- fetch_html: ${process.env.fetch_html || "Disable"} (default: Disable)`);
  console.log(`- DNListCheck: ${process.env.DNListCheck || "Enable"} (default: Enable)`);
  
  // 決定使用哪種傳輸方式
  const transportType = process.env.TRANSPORT_TYPE || 'stdio';
  
  if (transportType.toLowerCase() === 'sse') {
    // 創建 SSE 實例
    const sse = new SSE();
    
    // 設置 SSE 端點
    app.get('/sse', sse.init);
    
    // 設置 API 端點
    app.post('/api/list-tools', async (req, res) => {
      try {
        const tools = await getTools();
        res.json({ tools });
      } catch (error) {
        console.error('Error handling listTools request:', error);
        res.status(500).json({ error: 'Internal server error' });
      }
    });
    
    app.post('/api/call-tool', async (req, res) => {
      try {
        const { name, arguments: args } = req.body;
        
        // 檢查 fetch_html 工具是否啟用
        if (name === "fetch_html") {
          const fetchHtmlEnv = process.env.fetch_html || "Disable";
          const isFetchHtmlEnabled = fetchHtmlEnv.toLowerCase() === "enable";
          
          if (!isFetchHtmlEnabled) {
            throw new Error("The fetch_html tool is disabled. Please set the environment variable fetch_html=Enable to enable this tool.");
          }
        }
        
        // 驗證參數
        const validatedArgs = RequestPayloadSchema.parse(args);
        
        // 獲取處理程序
        const handler = toolHandlers[name];
        if (!handler) {
          throw new Error("Tool not found");
        }
        
        // 執行工具
        const result = await handler(validatedArgs);
        
        // 通過 SSE 發送結果
        sse.send(result, 'tool-result');
        
        res.json({ status: 'ok', message: 'Tool call initiated, results will be sent via SSE' });
      } catch (error) {
        console.error('Error handling callTool request:', error);
        res.status(500).json({ error: 'Internal server error' });
      }
    });
    
    // 啟動 HTTP 服務器
    app.listen(PORT, () => {
      console.log(`MCP Server running on http://localhost:${PORT}`);
      console.log(`SSE endpoint available at http://localhost:${PORT}/sse`);
      console.log(`API endpoints:`);
      console.log(`  - POST http://localhost:${PORT}/api/list-tools`);
      console.log(`  - POST http://localhost:${PORT}/api/call-tool`);
    });
  } else {
    // 使用標準 stdio 傳輸
    const stdioTransport = new StdioServerTransport();
    await server.connect(stdioTransport);
  }
}

// 輔助函數：獲取工具列表
async function getTools() {
  // 檢查 fetch_html 工具是否啟用
  const fetchHtmlEnv = process.env.fetch_html || "Disable";
  const isFetchHtmlEnabled = fetchHtmlEnv.toLowerCase() === "enable";
  
  // 準備工具列表
  const tools = [];
  
  // 根據環境變量決定是否添加 fetch_html 工具
  if (isFetchHtmlEnabled) {
    tools.push({
      name: "fetch_html",
      description: "Fetch and return the raw HTML content from a website",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the website to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    });
  }
  
  // 添加其他工具（這些工具始終啟用）
  tools.push(
    {
      name: "fetch_markdown",
      description: "Fetch content from a website and convert it to Markdown format",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the website to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    },
    {
      name: "fetch_txt",
      description: "Fetch and return plain text content from a website (HTML tags removed)",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the website to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    },
    {
      name: "fetch_json",
      description: "Fetch and return JSON content from a URL",
      inputSchema: {
        type: "object",
        properties: {
          url: {
            type: "string",
            description: "The URL of the JSON resource to fetch",
          },
          headers: {
            type: "object",
            description: "Optional request headers",
          },
        },
        required: ["url"],
      },
    }
  );
  
  return tools;
}

main().catch((error) => {
  console.error("Critical error in main():", error);
  process.exit(1);
}); 