Skip to content

feat: MCP ecosystem tracking + Slack/Discord notifications#122

Open
howardpen9 wants to merge 1 commit intoduanyytop:masterfrom
howardpen9:feat/rss-notify-mcp
Open

feat: MCP ecosystem tracking + Slack/Discord notifications#122
howardpen9 wants to merge 1 commit intoduanyytop:masterfrom
howardpen9:feat/rss-notify-mcp

Conversation

@howardpen9
Copy link

Summary

Split from #41 as suggested — this PR contains only the three features approved for merge:

  • MCP ecosystem tracking: 6 new repos tracked daily — MCP Specification, TypeScript/Python SDKs, Official Servers, GitHub MCP Server, Context7. Generates ai-mcp.md + ai-mcp-en.md reports with cross-project comparison.
  • Slack + Discord notifications: Extends the existing Telegram-only notify.ts to support Slack (incoming webhook) and Discord (embed webhook). All channels are opt-in via env vars (SLACK_WEBHOOK_URL, DISCORD_WEBHOOK_URL). Telegram behavior is unchanged.
  • Pipeline integration: MCP repos flow through the existing fetch → summarize → compare → save pipeline with minimal changes to index.ts.

What's NOT in this PR

The config-driven YAML refactor (config/sources.yaml, generalized pipeline groups) is intentionally excluded per reviewer feedback — that deserves a separate discussion.

Changes

File Change
src/config.ts Add DEFAULT_MCP_REPOS (6 repos) + mcpRepos to RadarConfig
src/index.ts Fetch MCP repos, generate summaries, build + save ai-mcp.md reports
src/prompts.ts Add buildMcpComparisonPrompt for cross-project MCP analysis
src/report-builders.ts Add buildMcpReportContent
src/notify.ts Add Slack + Discord webhook dispatchers alongside existing Telegram
src/generate-manifest.ts Add ai-mcp / ai-mcp-en to report files + labels
src/github.ts Add mcp / mcp-en label colors
index.html Add MCP labels to Web UI sidebar
.github/workflows/daily-digest.yml Add SLACK_WEBHOOK_URL + DISCORD_WEBHOOK_URL env vars

No new dependencies

All notification channels use native fetch() — zero new runtime dependencies added.

Test plan

  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm format:check passes
  • pnpm start generates ai-mcp.md + ai-mcp-en.md alongside existing reports
  • Slack/Discord env vars are opt-in (no effect when unset)
  • Existing Telegram notification behavior unchanged

🤖 Generated with Claude Code

- Track 6 MCP repos (spec, TypeScript/Python SDKs, official servers,
  GitHub MCP, Context7) with daily ai-mcp.md reports in ZH + EN
- Add Slack and Discord webhook support to notifications alongside
  existing Telegram (opt-in via SLACK_WEBHOOK_URL, DISCORD_WEBHOOK_URL)
- New prompt builder for MCP cross-project analysis
- Update manifest, RSS feed, Web UI labels, and GitHub issue labels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Owner

@duanyytop duanyytop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deleted

Copy link
Owner

@duanyytop duanyytop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Clean PR — follows existing pipeline patterns well, and the Slack/Discord notifications are nicely done (opt-in, zero dependencies). A few things to address:

Action items

1. MCP summaries reuse buildPeerPrompt (src/index.ts:458)

MCP repos call buildPeerPrompt directly. If that prompt contains OpenClaw-specific framing or terminology, the generated MCP summaries may be subtly off. Either confirm buildPeerPrompt is generic enough, or create a dedicated buildMcpPrompt.

2. MCP summaries run sequentially after CLI/OpenClaw (src/index.ts:441-471)

generateMcpDigests waits for generateSummaries to finish, but they're independent. Running them in parallel saves ~30s of latency:

const [zhSummaries, enSummaries, zhMcpDigests, enMcpDigests] = await Promise.all([
  generateSummaries(..., "zh"),
  generateSummaries(..., "en"),
  generateMcpDigests("zh"),
  generateMcpDigests("en"),
]);

3. Missing documentation updates

Per the "Adding a new report type" checklist in CLAUDE.md, still need:

  • Update the report outputs table and tracked sources in CLAUDE.md
  • Update README

Suggestions

  • buildSlackMessage and buildDiscordDescription in notify.ts duplicate the report ordering logic — consider extracting a shared orderedBaseReports(reports) helper.
  • generateMcpDigests reimplements the same pattern as generateSummaries (check activity → call LLM → handle error). Consider reusing the existing infrastructure.
  • REPORT_EMOJIS is only used by Slack/Discord — Telegram's buildMessage could use it too for consistency.

Looks good

  • Purple label colors — nice visual distinction
  • -en suffix naming consistent with ai-cli-en / ai-agents-en
  • Promise.allSettled + catch-log for notifications is the right call — one channel failure shouldn't block others

@duanyytop
Copy link
Owner

@claude review this pr

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new “MCP ecosystem” report to the existing daily digest pipeline and extends notifications beyond Telegram to Slack and Discord, wiring both into the daily workflow and UI/manifest metadata.

Changes:

  • Track 6 MCP-related repos and generate new ai-mcp.md / ai-mcp-en.md reports (including cross-project comparison).
  • Extend notify.ts to optionally send Slack + Discord webhooks in addition to Telegram.
  • Register MCP report IDs across manifest generation, GitHub issue labels/colors, and the Web UI sidebar.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/config.ts Adds default MCP repo list + config parsing (mcp_reposmcpRepos).
src/index.ts Integrates MCP repos into fetch/summarize/compare/save + GitHub issue creation.
src/prompts.ts Adds buildMcpComparisonPrompt() for cross-project MCP analysis.
src/report-builders.ts Adds buildMcpReportContent() to render the MCP digest report.
src/notify.ts Adds Slack + Discord sending and new message builders.
src/generate-manifest.ts Registers ai-mcp and ai-mcp-en report IDs and labels.
src/github.ts Adds label colors for mcp and mcp-en.
index.html Adds MCP labels to the sidebar label map.
.github/workflows/daily-digest.yml Passes Slack/Discord webhook env vars to notification step.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines 91 to 135
export function loadConfig(configPath = "config.yml"): RadarConfig {
const resolved = path.resolve(configPath);

if (!fs.existsSync(resolved)) {
console.log(`[config] ${configPath} not found — using built-in defaults.`);
return {
cliRepos: DEFAULT_CLI_REPOS,
mcpRepos: DEFAULT_MCP_REPOS,
skillsRepo: DEFAULT_SKILLS_REPO,
openclaw: DEFAULT_OPENCLAW,
openclawPeers: DEFAULT_OPENCLAW_PEERS,
};
}

const raw = yaml.load(fs.readFileSync(resolved, "utf-8")) as RawConfig;

const cliRepos =
Array.isArray(raw?.cli_repos) && raw.cli_repos.length > 0
? raw.cli_repos.map(toRepoConfig)
: DEFAULT_CLI_REPOS;

const skillsRepo =
typeof raw?.skills_repo === "string" && raw.skills_repo.trim()
? raw.skills_repo.trim()
: DEFAULT_SKILLS_REPO;

const openclaw = raw?.openclaw?.id && raw.openclaw.repo ? toRepoConfig(raw.openclaw) : DEFAULT_OPENCLAW;

const mcpRepos =
Array.isArray(raw?.mcp_repos) && raw.mcp_repos.length > 0
? raw.mcp_repos.map(toRepoConfig)
: DEFAULT_MCP_REPOS;

const openclawPeers =
Array.isArray(raw?.openclaw_peers) && raw.openclaw_peers.length > 0
? raw.openclaw_peers.map(toRepoConfig)
: DEFAULT_OPENCLAW_PEERS;

console.log(
`[config] Loaded from ${configPath}: ` +
`${cliRepos.length} CLI repos, ${openclawPeers.length} OpenClaw peers`,
`${cliRepos.length} CLI repos, ${mcpRepos.length} MCP repos, ${openclawPeers.length} OpenClaw peers`,
);

return { cliRepos, skillsRepo, openclaw, openclawPeers };
return { cliRepos, mcpRepos, skillsRepo, openclaw, openclawPeers };
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loadConfig() now supports mcp_repos and returns mcpRepos, but the config tests don’t assert default MCP repos are present or that YAML mcp_repos overrides are parsed/fallback correctly. Add test cases similar to cli_repos coverage to lock in this new config behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +456 to +461
console.log(` [${cfg.id}] Calling LLM for MCP summary (${lang})...`);
try {
const summary = await callLlm(
buildPeerPrompt(cfg, issues, prs, releases, dateStr, undefined, undefined, lang),
);
return { config: cfg, issues, prs, releases, summary };
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MCP per-repo summaries are generated with buildPeerPrompt(), which is explicitly tailored to “AI agent and personal AI assistant open-source projects”. For MCP spec/SDK/server repos this mismatches the domain and will likely produce irrelevant/incorrect summaries. Introduce an MCP-specific per-repo prompt (or parameterize buildPeerPrompt wording) and use that here instead.

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +176
for (const r of ordered) {
const emoji = REPORT_EMOJIS[r] ?? "📄";
const label = EN_LABELS[r] ?? r;
const url = `${pagesUrl}/#${date}/${r}`;
lines.push(`${emoji} <${url}|${label}>`);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slack notifications use EN_LABELS but always link to the base (non -en) report (/#${date}/${r}). When English reports exist in the manifest (e.g. ai-cli-en), this sends users to the Chinese page despite an English label. Consider including both zh/en links (like Telegram) or linking to ${r}-en when present.

Copilot uses AI. Check for mistakes.
.map((r) => {
const emoji = REPORT_EMOJIS[r] ?? "📄";
const label = EN_LABELS[r] ?? r;
const url = `${pagesUrl}/#${date}/${r}`;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discord embeds are built from baseReports only and link to /#${date}/${r} regardless of whether an English report exists. Since the embed uses EN_LABELS, this can send users to Chinese content even when *-en pages are available. Adjust the description builder to prefer ${r}-en when present or include both links.

Suggested change
const url = `${pagesUrl}/#${date}/${r}`;
const englishId = `${r}-en`;
const targetId = reports.includes(englishId) ? englishId : r;
const url = `${pagesUrl}/#${date}/${targetId}`;

Copilot uses AI. Check for mistakes.
Comment on lines +158 to +197
function buildSlackMessage(date: string, reports: string[], pagesUrl: string): string {
const baseReports = reports.filter((r) => !r.endsWith("-en"));
const isWeekly = baseReports.includes("ai-weekly");
const isMonthly = baseReports.includes("ai-monthly");

const icon = isMonthly ? "📆" : isWeekly ? "📅" : "📡";
const suffix = isMonthly ? " Monthly" : isWeekly ? " Weekly" : "";
const lines: string[] = [`${icon} *agents-radar${suffix} · ${date}*\n`];

const ordered = [
...baseReports.filter((r) => !r.includes("weekly") && !r.includes("monthly")),
...baseReports.filter((r) => r.includes("weekly") || r.includes("monthly")),
];

for (const r of ordered) {
const emoji = REPORT_EMOJIS[r] ?? "📄";
const label = EN_LABELS[r] ?? r;
const url = `${pagesUrl}/#${date}/${r}`;
lines.push(`${emoji} <${url}|${label}>`);
}

lines.push(`\n<${pagesUrl}|🌐 Web UI> · <${pagesUrl}/feed.xml|⊕ RSS>`);
return lines.join("\n");
}

function buildDiscordDescription(date: string, reports: string[], pagesUrl: string): string {
const baseReports = reports.filter((r) => !r.endsWith("-en"));
const ordered = [
...baseReports.filter((r) => !r.includes("weekly") && !r.includes("monthly")),
...baseReports.filter((r) => r.includes("weekly") || r.includes("monthly")),
];

return ordered
.map((r) => {
const emoji = REPORT_EMOJIS[r] ?? "📄";
const label = EN_LABELS[r] ?? r;
const url = `${pagesUrl}/#${date}/${r}`;
return `${emoji} [${label}](${url})`;
})
.join("\n");
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New Slack/Discord message builders were added but existing tests only cover buildMessage(). Please add unit tests for buildSlackMessage/buildDiscordDescription (ordering, weekly/monthly suffix/icon, link selection when -en exists) to keep notification formatting stable.

Copilot uses AI. Check for mistakes.
Comment on lines +162 to +214
export function buildMcpReportContent(
mcpDigests: RepoDigest[],
comparison: string,
utcStr: string,
dateStr: string,
footer: string,
lang: "zh" | "en" = "zh",
): string {
const repoLinks = mcpDigests
.map((d) => `- [${d.config.name}](https://github.com/${d.config.repo})`)
.join("\n");

const t =
lang === "en"
? {
title: `# MCP Ecosystem Digest ${dateStr}\n\n`,
meta: `> Generated: ${utcStr} UTC | Projects covered: ${mcpDigests.length}\n\n`,
comparison: `## Cross-Project Analysis\n\n`,
detail: `## Per-Project Reports\n\n`,
}
: {
title: `# MCP 生态日报 ${dateStr}\n\n`,
meta: `> 生成时间: ${utcStr} UTC | 覆盖项目: ${mcpDigests.length} 个\n\n`,
comparison: `## 横向对比\n\n`,
detail: `## 各项目详细报告\n\n`,
};

const sections = mcpDigests
.map((d) =>
[
`<details>`,
`<summary><strong>${d.config.name}</strong> — <a href="https://github.com/${d.config.repo}">${d.config.repo}</a></summary>`,
``,
d.summary,
``,
`</details>`,
].join("\n"),
)
.join("\n\n");

return (
t.title +
t.meta +
`${repoLinks}\n\n` +
`---\n\n` +
t.comparison +
comparison +
`\n\n---\n\n` +
t.detail +
sections +
footer
);
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildMcpReportContent() is new behavior but report-builders tests currently cover only buildCliReportContent/buildOpenclawReportContent. Add tests asserting MCP title/meta, repo link list, cross-project section, and per-project

Details rendering (zh + en) to prevent regressions.

Copilot uses AI. Check for mistakes.
Comment on lines +874 to +918
export function buildMcpComparisonPrompt(
digests: RepoDigest[],
dateStr: string,
lang: "zh" | "en" = "zh",
): string {
const summaries = digests
.map((d) => `### ${d.config.name} (${d.config.repo})\n${d.summary}`)
.join("\n\n---\n\n");

if (lang === "en") {
return `You are an expert on the Model Context Protocol (MCP) ecosystem. Based on the following per-repo summaries for ${dateStr}, produce a cross-project comparison:

${summaries}

---

Generate a structured English analysis:

1. **Ecosystem Highlights** — 2-3 sentences on the most important MCP developments today
2. **Spec & SDK Progress** — Key changes to the specification and official SDKs
3. **Server Ecosystem** — Notable new servers, integrations, or community contributions
4. **Cross-Project Themes** — Common patterns, recurring issues, or coordinated efforts
5. **Developer Impact** — What these changes mean for MCP adopters and tool builders

Style: concise and professional, include GitHub links where possible.
`;
}

return `你是 Model Context Protocol (MCP) 生态的技术分析师。请根据以下 ${dateStr} 各仓库的总结,生成一份横向对比分析:

${summaries}

---

请生成结构清晰的中文分析报告:

1. **今日速览** — 2-3 句话概括今日 MCP 生态最重要的动态
2. **规范与 SDK 进展** — 规范和官方 SDK 的重要变更
3. **Server 生态** — 值得关注的新 Server、集成或社区贡献
4. **跨项目主题** — 各项目间的共同模式、重复出现的问题或协同工作
5. **开发者影响** — 这些变更对 MCP 使用者和工具开发者意味着什么

语言要求:中文,简洁专业,保留所有 GitHub 链接。
`;
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

buildMcpComparisonPrompt() adds a new prompt surface, but prompts/prompt-builders tests don’t cover it yet. Add a unit test to assert both zh/en variants include the repo summary blocks and the expected section headings so prompt structure stays stable.

Copilot uses AI. Check for mistakes.
@howardpen9
Copy link
Author

howardpen9 commented Mar 10, 2026

what's your TG or X.com? @duanyytop

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants