UNPKG

@langgpt/weixin-mcp-server

Version:

一站式微信公众号内容抓取、生成与多平台内容迁移的智能中台,基于 Model Context Protocol (MCP) 实现内容自动化流转

738 lines (672 loc) 24.5 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { extract, ExtractSchema, search, SearchSchema } from "@langgraph-js/crawler"; import { z } from "zod"; // 初始化 MCP Server const server = new McpServer({ name: "weixin-mcp-server", version: "1.1.2" }); // 常量配置 const SILICONFLOW_API_BASE = "https://api.siliconflow.cn/v1"; const USER_AGENT = "weixin-mcp-server/1.0"; // 获取 API Key const SILICONFLOW_API_KEY = process.env.SILICONFLOW_API_KEY; if (!SILICONFLOW_API_KEY) { console.error("请设置 SILICONFLOW_API_KEY 环境变量"); console.error("获取 API Key: https://cloud.siliconflow.cn/i/TxUlXG3u"); process.exit(1); } // 辅助函数:调用 SiliconFlow API async function callSiliconFlowAPI( messages: any[], model = "Qwen/Qwen3-8B", // 按你示例新模型 userOptions: any = {} ) { const payload = { model, messages, stream: false, max_tokens: 4096, enable_thinking: false, thinking_budget: 4096, min_p: 0.05, stop: null, temperature: 0.7, top_p: 0.7, top_k: 50, frequency_penalty: 0.5, n: 1, response_format: { type: "text" }, // tools: [], // 新API可省略 ...userOptions // 支持扩展参数 }; const response = await fetch(`${SILICONFLOW_API_BASE}/chat/completions`, { method: "POST", headers: { "Authorization": `Bearer ${SILICONFLOW_API_KEY}`, "Content-Type": "application/json", "User-Agent": USER_AGENT }, body: JSON.stringify(payload) }); if (!response.ok) { const errMsg = await response.text(); throw new Error(`SiliconFlow API 错误: ${response.status} ${response.statusText}\n${errMsg}`); } const data = await response.json(); // 返回完整 message 结构 return data.choices[0]?.message?.content || ""; } // 辅助函数:生成图片 async function generateImage(prompt: string, model = "Kwai-Kolors/Kolors") { const response = await fetch(`${SILICONFLOW_API_BASE}/images/generations`, { method: "POST", headers: { "Authorization": `Bearer ${SILICONFLOW_API_KEY}`, "Content-Type": "application/json", "User-Agent": USER_AGENT }, body: JSON.stringify({ model, prompt, image_size: "1024x1024", batch_size: 1, seed: Math.floor(Math.random() * 5000000000), num_inference_steps: 20, guidance_scale: 7.5 }) }); if (!response.ok) { throw new Error(`图片生成 API 错误: ${response.status} ${response.statusText}`); } const data = await response.json(); return data.images[0]?.url || ""; } // 1. 抓取网页内容工具 server.tool( "crawl_url", { url: z.string().url().describe("要抓取的网页URL"), extract_main: z.boolean().default(true).describe("是否只提取主要内容") }, async ({ url, extract_main }) => { try { const content = await extract({ url, raw: false }); let processedContent = content; if (extract_main) { // 使用 AI 提取主要内容 const messages = [ { role: "system", content: "你是一个内容提取专家。请从以下网页内容中提取主要文章内容,去除广告、导航、侧边栏等无关信息。只返回核心文章内容。" }, { role: "user", content: `请提取以下网页的主要内容:\n\n${content.substring(0, 8000)}` } ]; processedContent = await callSiliconFlowAPI(messages); } return { content: [{ type: "text", text: JSON.stringify({ url, title: "抓取的网页内容", content: processedContent, timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `抓取失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 2. 搜索网页信息工具 server.tool( "search_web", { query: z.string().describe("搜索关键词"), max_results: z.number().default(5).describe("最大搜索结果数量"), language: z.string().default("zh").describe("搜索语言") }, async ({ query, max_results, language }) => { try { const searchResults = await search({ query: `${query} site:zh`, engines: ["basic"], // 你可以根据需求扩展多个 returnType: "json", withMetadata: false }); // 聚合所有engine结果 let allResults: any[] = []; if (Array.isArray(searchResults)) { for (const engineResult of searchResults) { if (Array.isArray(engineResult.results)) { allResults = allResults.concat(engineResult.results); } } } // 裁剪前N个 const topResults = allResults.slice(0, max_results); return { content: [{ type: "text", text: JSON.stringify({ query, results: topResults, timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `搜索失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 3. 生成小红书文案工具 server.tool( "generate_redbook_content", { content: z.string().describe("原始内容"), style: z.enum(["lifestyle", "tech", "food", "travel", "beauty", "fitness"]).default("lifestyle").describe("小红书风格"), include_hashtags: z.boolean().default(true).describe("是否包含话题标签"), include_emojis: z.boolean().default(true).describe("是否包含表情符号") }, async ({ content, style, include_hashtags, include_emojis }) => { try { const stylePrompts = { lifestyle: "生活方式博主,语言轻松活泼,善用表情符号", tech: "科技达人,专业但不失趣味,注重实用性", food: "美食博主,描述生动,让人垂涎欲滴", travel: "旅行达人,文艺清新,充满诗意", beauty: "美妆博主,时尚前沿,注重细节", fitness: "健身达人,积极正能量,注重健康" }; const messages = [ { role: "system", content: `你是一个专业的小红书内容创作者,擅长${stylePrompts[style]}的风格。 请将用户提供的内容改写成小红书文案,要求: 1. 语言生动有趣,符合小红书用户习惯 2. 结构清晰,使用适当的换行和分段 3. ${include_emojis ? "合理使用表情符号增加趣味性" : "不使用表情符号"} 4. ${include_hashtags ? "在末尾添加3-5个相关话题标签" : "不添加话题标签"} 5. 控制在500字以内 6. 开头要有吸引人的标题或句子 7. 内容要有互动性,引导用户评论或点赞` }, { role: "user", content: `请将以下内容改写成小红书文案:\n\n${content}` } ]; const redBookContent = await callSiliconFlowAPI(messages); return { content: [{ type: "text", text: JSON.stringify({ original_content: content.substring(0, 200) + "...", redbook_content: redBookContent, style, features: { hashtags_included: include_hashtags, emojis_included: include_emojis }, timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `生成小红书文案失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 4. 生成微信公众号文章工具 server.tool( "generate_wechat_article", { topic: z.string().describe("文章主题"), style: z.enum(["professional", "casual", "narrative", "tutorial", "news"]).default("professional").describe("文章风格"), length: z.enum(["short", "medium", "long"]).default("medium").describe("文章长度"), include_image_suggestions: z.boolean().default(true).describe("是否包含配图建议"), target_audience: z.string().default("一般公众").describe("目标读者群体") }, async ({ topic, style, length, include_image_suggestions, target_audience }) => { try { const lengthMap = { short: "800-1200字", medium: "1500-2500字", long: "3000-5000字" }; const stylePrompts = { professional: "专业严谨,逻辑清晰,适合商务和知识分享", casual: "轻松随意,贴近生活,适合日常交流", narrative: "故事化叙述,情感丰富,引人入胜", tutorial: "教程式写作,步骤清晰,实用性强", news: "新闻报道风格,客观中性,信息丰富" }; const messages = [ { role: "system", content: `你是一个专业的微信公众号内容创作者,擅长创作${stylePrompts[style]}的文章。 请根据用户提供的主题创作一篇微信公众号文章,要求: 1. 文章长度:${lengthMap[length]} 2. 风格:${stylePrompts[style]} 3. 目标读者:${target_audience} 4. 结构完整:标题、引言、正文(多个段落)、结语 5. 语言流畅,逻辑清晰 6. 适合微信阅读习惯,段落不宜过长 7. 标题要吸引人,正文要有价值 8. ${include_image_suggestions ? "在适当位置标注[配图建议:具体描述]" : ""} 输出格式: 【标题】 【引言】 【正文】 【结语】 ${include_image_suggestions ? "【配图建议】" : ""}` }, { role: "user", content: `请创作主题为"${topic}"的微信公众号文章` } ]; const article = await callSiliconFlowAPI(messages); let imageSuggestions = ""; if (include_image_suggestions) { const imageMessages = [ { role: "system", content: "你是一个配图专家,根据文章内容提供配图建议。请为文章的关键段落提供3-5个配图建议,描述要具体生动。" }, { role: "user", content: `请为以下文章提供配图建议:\n\n${article.substring(0, 1000)}` } ]; imageSuggestions = await callSiliconFlowAPI(imageMessages); } return { content: [{ type: "text", text: JSON.stringify({ topic, article, metadata: { style, length, target_audience, word_count: Math.floor(article.length * 0.7) // 粗略估算字数 }, image_suggestions: include_image_suggestions ? imageSuggestions : null, timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `生成微信公众号文章失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 5. 将任意内容转换为小红书文案 server.tool( "rewrite_to_redbook", { content: z.string().describe("原始内容"), keep_key_points: z.boolean().default(true).describe("是否保留关键信息点"), personalize: z.boolean().default(true).describe("是否个性化改写"), add_call_to_action: z.boolean().default(true).describe("是否添加互动引导") }, async ({ content, keep_key_points, personalize, add_call_to_action }) => { try { const messages = [ { role: "system", content: `你是小红书内容改写专家。请将用户提供的任何内容(文章、新闻、教程等)改写成适合小红书的文案。 改写要求: 1. ${keep_key_points ? "保留原内容的核心信息和要点" : "可以适度简化信息"} 2. 语言要生动活泼,符合小红书用户习惯 3. 使用合适的表情符号增加趣味性 4. 添加换行和段落,提高可读性 5. ${personalize ? "采用第一人称视角,增加个人色彩" : "保持客观描述"} 6. ${add_call_to_action ? "在结尾添加互动引导语" : ""} 7. 控制在300-500字之间 8. 添加3-5个相关话题标签` }, { role: "user", content: `请将以下内容改写成小红书文案:\n\n${content}` } ]; const rewrittenContent = await callSiliconFlowAPI(messages); return { content: [{ type: "text", text: JSON.stringify({ original_length: content.length, rewritten_content: rewrittenContent, options: { key_points_preserved: keep_key_points, personalized: personalize, call_to_action_added: add_call_to_action }, timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `转换小红书文案失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 6. 将微信公众号文章转为小红书文案 server.tool( "wechat_article_to_redbook", { wechat_article: z.string().describe("微信公众号文章内容"), extract_highlights: z.boolean().default(true).describe("是否提取亮点总结"), split_multiple: z.boolean().default(false).describe("是否拆分成多条小红书内容") }, async ({ wechat_article, extract_highlights, split_multiple }) => { try { if (split_multiple) { // 拆分成多条内容 const messages = [ { role: "system", content: `你是内容拆分专家。请将一篇完整的微信公众号文章拆分成2-4条独立的小红书内容,每条都要完整有趣。 拆分原则: 1. 每条内容都要有独立的主题和价值 2. 每条控制在200-300字 3. 保持小红书的轻松活泼风格 4. 每条都要有吸引人的开头 5. 添加相关表情符号和话题标签 6. 确保每条都能独立阅读理解` }, { role: "user", content: `请将以下微信公众号文章拆分成多条小红书内容:\n\n${wechat_article}` } ]; const splitContent = await callSiliconFlowAPI(messages); return { content: [{ type: "text", text: JSON.stringify({ original_article_length: wechat_article.length, split_contents: splitContent, is_split: true, extract_highlights, timestamp: new Date().toISOString() }, null, 2) }] }; } else { // 整体转换 const systemPrompt = extract_highlights ? "你是内容转换专家。请将微信公众号文章转换成小红书文案,重点提取和突出文章的核心亮点。" : "你是内容转换专家。请将微信公众号文章转换成小红书文案,保持内容的完整性。"; const messages = [ { role: "system", content: `${systemPrompt} 转换要求: 1. 保持核心信息的准确性 2. 改写成小红书用户喜欢的表达方式 3. 添加表情符号和互动元素 4. 控制在400-600字 5. 结构清晰,使用换行分段 6. 添加话题标签 7. 增加个人化的语言色彩` }, { role: "user", content: `请将以下微信公众号文章转换成小红书文案:\n\n${wechat_article}` } ]; const convertedContent = await callSiliconFlowAPI(messages); return { content: [{ type: "text", text: JSON.stringify({ original_article_length: wechat_article.length, redbook_content: convertedContent, is_split: false, highlights_extracted: extract_highlights, timestamp: new Date().toISOString() }, null, 2) }] }; } } catch (error) { return { content: [{ type: "text", text: `转换失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 7. 将网页内容转为微信公众号文章 server.tool( "rewrite_to_wechat_article", { web_content: z.string().describe("网页内容"), add_personal_insights: z.boolean().default(true).describe("是否添加个人见解"), restructure: z.boolean().default(true).describe("是否重新组织结构"), target_length: z.enum(["keep", "expand", "compress"]).default("expand").describe("长度调整策略") }, async ({ web_content, add_personal_insights, restructure, target_length }) => { try { const lengthInstructions = { keep: "保持与原内容相似的长度", expand: "适当扩展内容,增加详细说明和案例", compress: "精简内容,保留核心要点" }; const messages = [ { role: "system", content: `你是专业的微信公众号编辑。请将网页内容改写成适合微信公众号发布的文章。 改写要求: 1. ${lengthInstructions[target_length]} 2. ${restructure ? "重新组织文章结构,确保逻辑清晰" : "保持原有结构"} 3. ${add_personal_insights ? "适当添加个人观点和见解" : "保持客观中性"} 4. 语言要适合中文读者,表达自然流畅 5. 添加合适的小标题划分段落 6. 开头要有吸引人的引言 7. 结尾要有总结或思考 8. 适合微信阅读的段落长度` }, { role: "user", content: `请将以下网页内容改写成微信公众号文章:\n\n${web_content}` } ]; const wechatArticle = await callSiliconFlowAPI(messages); return { content: [{ type: "text", text: JSON.stringify({ original_content_length: web_content.length, wechat_article: wechatArticle, processing_options: { personal_insights_added: add_personal_insights, restructured: restructure, length_strategy: target_length }, estimated_reading_time: Math.ceil(wechatArticle.length / 400) + "分钟", timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `转换微信公众号文章失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 8. 内容摘要工具 server.tool( "summarize_content", { content: z.string().describe("需要摘要的内容"), summary_type: z.enum(["brief", "detailed", "bullet_points", "executive"]).default("brief").describe("摘要类型"), language: z.enum(["zh", "en"]).default("zh").describe("摘要语言"), max_length: z.number().default(200).describe("摘要最大长度(字符数)") }, async ({ content, summary_type, language, max_length }) => { try { const summaryInstructions = { brief: "简要摘要,突出核心要点", detailed: "详细摘要,保留重要细节", bullet_points: "要点列表形式的摘要", executive: "高管摘要,适合快速决策" }; const messages = [ { role: "system", content: `你是专业的内容摘要专家。请根据要求对内容进行摘要。 摘要要求: 1. 类型:${summaryInstructions[summary_type]} 2. 语言:${language === "zh" ? "中文" : "英文"} 3. 长度:不超过${max_length}个字符 4. 保留最重要的信息 5. 语言简洁明了 6. 逻辑清晰 ${summary_type === "bullet_points" ? "7. 使用项目符号列表格式" : ""}` }, { role: "user", content: `请对以下内容进行摘要:\n\n${content}` } ]; const summary = await callSiliconFlowAPI(messages); return { content: [{ type: "text", text: JSON.stringify({ original_length: content.length, summary, summary_type, language, compression_ratio: Math.round((summary.length / content.length) * 100) + "%", timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `生成摘要失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 9. 生成文章配图工具 server.tool( "generate_article_image", { content: z.string().describe("文章内容或描述"), image_style: z.enum(["realistic", "cartoon", "minimalist", "professional", "artistic"]).default("professional").describe("图片风格"), image_type: z.enum(["cover", "illustration", "infographic", "background"]).default("cover").describe("图片类型"), color_tone: z.enum(["warm", "cool", "neutral", "vibrant", "monochrome"]).default("neutral").describe("色调") }, async ({ content, image_style, image_type, color_tone }) => { try { // 首先生成图片描述 const messages = [ { role: "system", content: `你是专业的图片创意设计师。根据文章内容生成适合的图片描述。 设计要求: 1. 图片风格:${image_style} 2. 图片类型:${image_type} 3. 色调:${color_tone} 4. 描述要具体生动,适合AI绘图 5. 避免文字元素,专注视觉表达 6. 符合文章主题和情感基调` }, { role: "user", content: `请为以下内容生成图片描述:\n\n${content.substring(0, 500)}` } ]; const imageDescription = await callSiliconFlowAPI(messages); // 生成图片 const imageUrl = await generateImage(imageDescription); return { content: [{ type: "text", text: JSON.stringify({ image_url: imageUrl, image_description: imageDescription, style_settings: { style: image_style, type: image_type, color_tone: color_tone }, timestamp: new Date().toISOString() }, null, 2) }] }; } catch (error) { return { content: [{ type: "text", text: `生成配图失败: ${error instanceof Error ? error.message : '未知错误'}` }], isError: true }; } } ); // 启动服务器 console.log("正在启动微信公众号 MCP Server..."); console.log("请确保已设置 SILICONFLOW_API_KEY 环境变量"); console.log("获取 API Key: https://cloud.siliconflow.cn/i/TxUlXG3u"); const transport = new StdioServerTransport(); await server.connect(transport); console.log("微信公众号 MCP Server 已启动成功!");