@langgpt/weixin-mcp-server
Version:
一站式微信公众号内容抓取、生成与多平台内容迁移的智能中台,基于 Model Context Protocol (MCP) 实现内容自动化流转
628 lines (619 loc) • 26 kB
JavaScript
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { extract, search } from "@langgraph-js/crawler";
import { z } from "zod";
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";
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);
}
async function callSiliconFlowAPI(messages, model = "Qwen/Qwen3-8B", userOptions = {}) {
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" },
...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();
return data.choices[0]?.message?.content || "";
}
async function generateImage(prompt, 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 || "";
}
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) {
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
};
}
});
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
});
let allResults = [];
if (Array.isArray(searchResults)) {
for (const engineResult of searchResults) {
if (Array.isArray(engineResult.results)) {
allResults = allResults.concat(engineResult.results);
}
}
}
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
};
}
});
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
};
}
});
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
};
}
});
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
};
}
});
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
};
}
});
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
};
}
});
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
};
}
});
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 已启动成功!");
//# sourceMappingURL=index.js.map