#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js";
import { SimpleVectorStore } from "./vector/simple-store.js";
import { VectorStore, SearchResult } from "./types.js";
const TOOLS: Tool[] = [
{
name: "search_security_docs",
description:
"Search across security documentation from OWASP, NIST, AWS, Azure, Google, SANS, CIS, MITRE ATT&CK, and compliance frameworks (PCI DSS, HIPAA, ISO 27001, SOC 2, GDPR). Use natural language queries to find relevant security guidance, best practices, vulnerabilities, and controls.",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "The security question or topic to search for",
},
limit: {
type: "number",
description: "Maximum number of results to return (default: 5)",
default: 5,
},
source: {
type: "string",
description:
"Optional: Filter results to a specific source (OWASP, NIST, AWS, Azure, Google, SANS, CIS, MITRE, Compliance)",
},
},
required: ["query"],
},
},
{
name: "get_security_context",
description:
"Get comprehensive security context for a specific topic. Returns detailed information from multiple authoritative sources.",
inputSchema: {
type: "object",
properties: {
topic: {
type: "string",
description:
"Security topic (e.g., 'SQL injection', 'zero trust', 'IAM best practices')",
},
},
required: ["topic"],
},
},
{
name: "list_security_sources",
description:
"List all available security documentation sources and their categories",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "get_owasp_top10",
description:
"Get information about OWASP Top 10 vulnerabilities for a specific year or category",
inputSchema: {
type: "object",
properties: {
category: {
type: "string",
description:
"Optional: Specific OWASP Top 10 category (e.g., 'A01:2021 - Broken Access Control')",
},
},
},
},
];
class SecurityMCPServer {
private server: Server;
private vectorStore: VectorStore;
constructor() {
this.server = new Server(
{
name: "security-context-mcp",
version: "1.0.0",
},
{
capabilities: {
tools: {},
},
}
);
this.vectorStore = new SimpleVectorStore();
this.setupHandlers();
}
private setupHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: TOOLS,
}));
this.server.setRequestHandler(
CallToolRequestSchema,
async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "search_security_docs":
return await this.handleSearchDocs(args);
case "get_security_context":
return await this.handleGetContext(args);
case "list_security_sources":
return await this.handleListSources();
case "get_owasp_top10":
return await this.handleOWASPTop10(args);
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: "text",
text: `Error: ${errorMessage}`,
},
],
};
}
}
);
}
private async handleSearchDocs(args: any) {
const query = args.query as string;
const limit = (args.limit as number) || 5;
const sourceFilter = args.source as string | undefined;
const results = await this.vectorStore.search(query, limit * 2);
// Filter by source if specified
const filteredResults = sourceFilter
? results.filter((r) =>
r.document.source.toLowerCase() === sourceFilter.toLowerCase()
)
: results;
const topResults = filteredResults.slice(0, limit);
if (topResults.length === 0) {
return {
content: [
{
type: "text",
text: `No results found for query: "${query}"${sourceFilter ? ` from source: ${sourceFilter}` : ""}`,
},
],
};
}
const formattedResults = topResults
.map((result, idx) => {
const doc = result.document;
return `
## Result ${idx + 1}: ${doc.title}
**Source:** ${doc.source}
**Category:** ${doc.category}
**Relevance Score:** ${(result.score * 100).toFixed(1)}%
**URL:** ${doc.url}
${result.relevantChunk}
---
`;
})
.join("\n");
return {
content: [
{
type: "text",
text: `# Security Documentation Search Results\n\nQuery: "${query}"\nFound ${topResults.length} relevant results:\n\n${formattedResults}`,
},
],
};
}
private async handleGetContext(args: any) {
const topic = args.topic as string;
// Search across all sources for comprehensive context
const results = await this.vectorStore.search(topic, 10);
if (results.length === 0) {
return {
content: [
{
type: "text",
text: `No security context found for topic: "${topic}"`,
},
],
};
}
// Group by source
const bySource: { [key: string]: SearchResult[] } = {};
for (const result of results) {
const source = result.document.source;
if (!bySource[source]) {
bySource[source] = [];
}
bySource[source].push(result);
}
let output = `# Security Context: ${topic}\n\n`;
output += `Aggregated information from ${Object.keys(bySource).length} authoritative sources:\n\n`;
for (const [source, sourceResults] of Object.entries(bySource)) {
output += `## ${source}\n\n`;
for (const result of sourceResults.slice(0, 3)) {
output += `### ${result.document.title}\n`;
output += `${result.relevantChunk}\n\n`;
output += `[Read more](${result.document.url})\n\n`;
}
}
return {
content: [
{
type: "text",
text: output,
},
],
};
}
private async handleListSources() {
const sources = [
{
name: "OWASP",
description: "Open Web Application Security Project",
resources: [
"OWASP Top 10 2021",
"API Security Top 10 2023",
"Mobile Top 10 2024",
"Application Security Verification Standard (ASVS)",
"Mobile Application Security Verification Standard (MASVS)",
"Cheat Sheet Series",
],
},
{
name: "NIST",
description: "National Institute of Standards and Technology",
resources: [
"Cybersecurity Framework (CSF) 2.0",
"SP 800-53 Security Controls",
"SP 800-171 Protecting CUI",
"SP 800-207 Zero Trust Architecture",
"SP 800-63 Digital Identity Guidelines",
"SP 800-61 Incident Handling Guide",
"SP 800-82 ICS Security",
"SP 800-190 Container Security",
"SP 800-218 SSDF (Secure Development)",
"Privacy Framework",
],
},
{
name: "AWS",
description: "Amazon Web Services Security",
resources: [
"Security Best Practices",
"Well-Architected Framework - Security Pillar",
"IAM, S3, VPC, KMS Best Practices",
"GuardDuty, Security Hub, CloudTrail, Config",
"Shared Responsibility Model",
],
},
{
name: "Azure",
description: "Microsoft Azure Security",
resources: [
"Security Best Practices",
"Identity (Entra ID) Security",
"Network Security",
"Microsoft Defender for Cloud",
"Microsoft Sentinel SIEM/SOAR",
"Key Vault, Storage, AKS Security",
"Zero Trust Architecture",
],
},
{
name: "Google",
description: "Google Cloud Security",
resources: [
"Security Best Practices",
"BeyondCorp Zero Trust",
"IAM Best Practices",
"Security Command Center",
"VPC Service Controls",
"Confidential Computing",
],
},
{
name: "MITRE",
description: "MITRE Corporation Security Frameworks",
resources: [
"ATT&CK Enterprise (Tactics & Techniques)",
"ATT&CK for Cloud",
"D3FEND (Defensive Techniques)",
"Engage (Adversary Engagement)",
],
},
{
name: "SANS",
description: "SysAdmin, Audit, Network, and Security Institute",
resources: [
"CWE Top 25 Most Dangerous Software Weaknesses",
"Security Architecture Principles",
"Incident Response Process",
"Penetration Testing Methodology",
],
},
{
name: "CIS",
description: "Center for Internet Security",
resources: [
"CIS Controls v8 (IG1, IG2, IG3)",
"CIS Benchmarks",
"CIS Risk Assessment Method (RAM)",
],
},
{
name: "Compliance",
description: "Regulatory Compliance Frameworks",
resources: [
"PCI DSS 4.0",
"HIPAA Security Rule",
"ISO 27001/27002:2022",
"SOC 2 Trust Services Criteria",
"GDPR Data Protection",
],
},
];
const formatted = sources
.map((s) => {
const resources = s.resources.map((r) => ` - ${r}`).join("\n");
return `## ${s.name}\n${s.description}\n\n**Available Resources:**\n${resources}`;
})
.join("\n\n");
return {
content: [
{
type: "text",
text: `# Available Security Documentation Sources\n\n${formatted}`,
},
],
};
}
private async handleOWASPTop10(args: any) {
const category = args.category as string | undefined;
const query = category || "OWASP Top 10 2021";
const results = await this.vectorStore.search(query, 5);
const owaspResults = results.filter((r) =>
r.document.source === "OWASP" &&
r.document.title.includes("Top 10")
);
if (owaspResults.length === 0) {
return {
content: [
{
type: "text",
text: "OWASP Top 10 information not yet indexed. Please run the documentation fetcher first.",
},
],
};
}
const formatted = owaspResults
.map((result) => {
return `## ${result.document.title}\n\n${result.relevantChunk}\n\n[Read more](${result.document.url})\n`;
})
.join("\n");
return {
content: [
{
type: "text",
text: `# OWASP Top 10\n\n${formatted}`,
},
],
};
}
async start() {
try {
// Initialize vector store
await this.vectorStore.initialize();
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error("Security Context MCP Server running on stdio");
} catch (error) {
console.error("Failed to start server:", error);
process.exit(1);
}
}
}
const server = new SecurityMCPServer();
server.start();