claude-code-ultimate-guide/mcp-server/src/tools/threats.ts
Florian BRUNIAUX 7236362c1e feat(mcp): add 4 new tools — compare_versions, get_threat, list_threats, search_examples
New tools (8 → 12 total):
- compare_versions(from, to): diff Claude Code releases between two versions,
  aggregating highlights and breaking changes across the range
- get_threat(id): look up any CVE or attack technique (T-code) with full details,
  severity, mitigation, and source references
- list_threats(category?): browse the threat database — summary table or
  detailed view by section (cves, authors, skills, techniques, mitigations, sources)
- search_examples(query, limit?): semantic search across 199 templates with
  token-aware scoring and get_example() hints

Infrastructure:
- content.ts: add loadThreatDb() with memory cache and dual-mode loading
  (GUIDE_ROOT filesystem in dev, GitHub fetch in production)
- Threat DB interface with correct Record<string, string> type for minimum_safe_versions

Docs:
- mcp-server/README.md: document all 12 tools with usage examples
- mcp-server/IDEAS.md: future ideas (quiz, methodology, workflow, diff resource)
- CHANGELOG.md: [Unreleased] entry for all 4 tools
- README.md: promote MCP section to standalone ## after Quick Start (was ### inside Quick Start)
- guide/architecture.md: add MCP server to Extended Tool Ecosystem

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-28 19:22:20 +01:00

264 lines
9.2 KiB
TypeScript

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { z } from 'zod';
import { loadThreatDb } from '../lib/content.js';
import { githubUrl } from '../lib/urls.js';
const THREAT_DB_GITHUB = githubUrl('examples/commands/resources/threat-db.yaml');
interface CveEntry {
id: string;
component: string;
severity: string;
cvss?: number;
description: string;
source: string;
fixed_in?: string;
mitigation?: string;
notes?: string;
}
interface TechniqueEntry {
id: string;
name: string;
description: string;
examples?: string[];
campaigns?: string[];
cves?: string[];
mitigation?: string;
}
const CATEGORY_LABELS: Record<string, string> = {
cves: 'CVE Database',
authors: 'Malicious Authors',
skills: 'Malicious Skills',
techniques: 'Attack Techniques',
mitigations: 'Minimum Safe Versions',
sources: 'Research Sources',
};
export function registerGetThreat(server: McpServer): void {
server.tool(
'get_threat',
'Look up a specific threat by ID from the security threat database. Supports CVE IDs (e.g. "CVE-2025-53109") and technique IDs (e.g. "T001").',
{
id: z.string().describe('Threat ID: a CVE identifier (e.g. "CVE-2025-53109") or attack technique ID (e.g. "T001")'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ id }) => {
const db = await loadThreatDb();
const idUpper = id.toUpperCase();
// Search CVE database
const cve = (db.cve_database as CveEntry[]).find(
(c) => c.id.toUpperCase() === idUpper,
);
if (cve) {
const lines = [
`# ${cve.id}${cve.component}`,
THREAT_DB_GITHUB,
'',
`**Severity**: ${cve.severity.toUpperCase()}${cve.cvss ? ` (CVSS ${cve.cvss})` : ''}`,
`**Component**: ${cve.component}`,
`**Source**: ${cve.source}`,
'',
`## Description`,
cve.description,
];
if (cve.fixed_in) {
lines.push('', `**Fixed in**: ${cve.fixed_in}`);
}
if (cve.mitigation) {
lines.push('', `## Mitigation`, cve.mitigation);
}
if (cve.notes) {
lines.push('', `## Notes`, cve.notes);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
// Search attack techniques
const technique = (db.attack_techniques as TechniqueEntry[]).find(
(t) => t.id.toUpperCase() === idUpper,
);
if (technique) {
const lines = [
`# ${technique.id}${technique.name}`,
THREAT_DB_GITHUB,
'',
`## Description`,
technique.description,
];
if (technique.examples?.length) {
lines.push('', '## Examples');
for (const ex of technique.examples) lines.push(`- ${ex}`);
}
if (technique.campaigns?.length) {
lines.push('', `**Campaigns**: ${technique.campaigns.join(', ')}`);
}
if (technique.cves?.length) {
lines.push(`**Related CVEs**: ${technique.cves.join(', ')}`);
}
if (technique.mitigation) {
lines.push('', `## Mitigation`, technique.mitigation);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
return {
content: [{
type: 'text',
text: [
`Threat ID "${id}" not found in the database.`,
'',
'Supported formats:',
' • CVE IDs: CVE-2025-53109, CVE-2026-24052, ...',
' • Technique IDs: T001, T002, ...',
'',
`Use list_threats("cves") or list_threats("techniques") to browse all entries.`,
`Full database: ${THREAT_DB_GITHUB}`,
].join('\n'),
}],
};
},
);
}
export function registerListThreats(server: McpServer): void {
server.tool(
'list_threats',
'Browse the security threat database. Without a category, returns a summary with counts. With a category, returns the full list for that section.',
{
category: z.enum(['cves', 'authors', 'skills', 'techniques', 'mitigations', 'sources'])
.optional()
.describe('Section to list: cves | authors | skills | techniques | mitigations | sources. Omit for a global summary.'),
},
{ readOnlyHint: true, destructiveHint: false, openWorldHint: false },
async ({ category }) => {
const db = await loadThreatDb();
if (!category) {
// Global summary
const lines = [
`# Threat Database Summary`,
`Version ${db.version} — updated ${db.updated}`,
THREAT_DB_GITHUB,
'',
'| Category | Count |',
'|----------|-------|',
`| CVEs | ${db.cve_database.length} |`,
`| Malicious Authors | ${db.malicious_authors.length} |`,
`| Malicious Skills | ${db.malicious_skills.length} |`,
`| Attack Techniques | ${db.attack_techniques.length} |`,
`| Minimum Safe Versions | ${Object.keys(db.minimum_safe_versions).length} |`,
`| Research Sources | ${db.sources.length} |`,
'',
'Use list_threats(category) to browse a section, or get_threat(id) for details.',
'Categories: cves | authors | skills | techniques | mitigations | sources',
];
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
const label = CATEGORY_LABELS[category] ?? category;
if (category === 'cves') {
const cves = db.cve_database as CveEntry[];
const lines = [
`# ${label} (${cves.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const c of cves) {
lines.push(`## ${c.id}${c.component}`);
lines.push(`**Severity**: ${c.severity.toUpperCase()}${c.cvss ? ` (CVSS ${c.cvss})` : ''} | **Source**: ${c.source}`);
lines.push(c.description);
if (c.fixed_in) lines.push(`Fixed in: ${c.fixed_in}`);
if (c.mitigation) lines.push(`Mitigation: ${c.mitigation}`);
lines.push('');
}
lines.push(`---\nUse get_threat("CVE-XXXX-XXXXX") for full details on any CVE.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'techniques') {
const techniques = db.attack_techniques as TechniqueEntry[];
const lines = [
`# ${label} (${techniques.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const t of techniques) {
lines.push(`## ${t.id}${t.name}`);
lines.push(t.description);
if (t.mitigation) lines.push(`Mitigation: ${t.mitigation}`);
lines.push('');
}
lines.push(`---\nUse get_threat("T001") for full details including examples and CVE links.`);
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'authors') {
const authors = db.malicious_authors as Array<{ name: string; source?: string; notes?: string }>;
const lines = [
`# ${label} (${authors.length} confirmed)`,
THREAT_DB_GITHUB,
'',
'Block ALL skills from these authors — confirmed malicious by security researchers.',
'',
];
for (const a of authors) {
lines.push(`- **${a.name}**${a.source ? `${a.source}` : ''}${a.notes ? ` (${a.notes})` : ''}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'skills') {
const skills = db.malicious_skills as Array<{ name: string; type?: string; source?: string; risk?: string; notes?: string }>;
const lines = [
`# ${label} (${skills.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const s of skills) {
const tags = [s.type, s.risk ? `risk:${s.risk}` : undefined].filter(Boolean).join(', ');
lines.push(`- **${s.name}**${tags ? ` [${tags}]` : ''}${s.source ? `${s.source}` : ''}${s.notes ? ` (${s.notes})` : ''}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'mitigations') {
const versions = db.minimum_safe_versions;
const entries = Object.entries(versions);
const lines = [
`# ${label} (${entries.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const [component, minVersion] of entries) {
lines.push(`- **${component}**: >= ${minVersion}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
if (category === 'sources') {
const sources = db.sources as Array<{ name: string; url?: string; date?: string }>;
const lines = [
`# ${label} (${sources.length} entries)`,
THREAT_DB_GITHUB,
'',
];
for (const s of sources) {
lines.push(`- **${s.name}**${s.date ? ` (${s.date})` : ''}${s.url ? `\n ${s.url}` : ''}`);
}
return { content: [{ type: 'text', text: lines.join('\n') }] };
}
return {
content: [{ type: 'text', text: `Unknown category: "${category}". Use: cves | authors | skills | techniques | mitigations | sources` }],
};
},
);
}