Spaces:
Paused
Paused
| import express from 'express'; | |
| import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; | |
| import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; | |
| import { z } from 'zod'; | |
| import cors from 'cors'; | |
| import { chromium } from 'playwright-extra'; | |
| import StealthPlugin from 'puppeteer-extra-plugin-stealth'; | |
| chromium.use(StealthPlugin()); | |
| const server = new McpServer({ name: "HF-Scraper", version: "1.0.0" }); | |
| // 简单的抓取工具 | |
| server.tool( | |
| "scrape_site", | |
| "Scrape a small website and return its text/HTML", | |
| { url: z.string().url() }, | |
| async ({ url }) => { | |
| let browser; | |
| try { | |
| browser = await chromium.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] }); | |
| const page = await browser.newPage(); | |
| await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 }); | |
| const content = await page.content(); | |
| return { content: [{ type: "text", text: content }] }; | |
| } catch (e) { | |
| return { content: [{ type: "text", text: `Error: ${e.message}` }], isError: true }; | |
| } finally { | |
| if (browser) await browser.close(); | |
| } | |
| } | |
| ); | |
| const app = express(); | |
| app.use(cors()); | |
| app.use(express.json()); | |
| app.set('trust proxy', true); // 信任云端 HTTPS | |
| app.get('/', (req, res) => res.send('🟢 HF MCP Server Online!')); | |
| let activeTransport = null; | |
| app.get('/sse', async (req, res) => { | |
| res.setHeader('X-Accel-Buffering', 'no'); | |
| res.setHeader('Cache-Control', 'no-cache'); | |
| activeTransport = new SSEServerTransport('/messages', res); | |
| await server.connect(activeTransport); | |
| }); | |
| app.post('/messages', async (req, res) => { | |
| if (activeTransport) await activeTransport.handlePostMessage(req, res); | |
| }); | |
| // Hugging Face 规定必须监听 7860 端口 | |
| app.listen(7860, '0.0.0.0', () => console.log('🚀 Server running on 7860')); |