echelongraph-mcp 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +77 -0
  2. package/dist/index.js +99 -0
  3. package/package.json +49 -0
package/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # EchelonGraph MCP server
2
+
3
+ Real-time **CVE & internet-exposure intelligence** for Claude, Cursor, Cline, and any
4
+ [MCP](https://modelcontextprotocol.io) client — straight from
5
+ [EchelonGraph](https://echelongraph.io)'s free public feed.
6
+
7
+ It exposes EchelonGraph's CVE Pulse (NVD + MITRE-CNA *pre-NVD* + CISA-KEV + EPSS + GitHub
8
+ GHSA, fused into one score) **plus the one thing no other CVE source has: the live
9
+ internet-exposure footprint of a CVE** — how many internet-exposed hosts are running an
10
+ affected version *right now*.
11
+
12
+ No API key. No auth. Read-only.
13
+
14
+ ## Tools
15
+
16
+ | Tool | What it does |
17
+ |---|---|
18
+ | `cve_summary` | Live counts of active CVEs by severity + feed freshness. |
19
+ | `search_cves` | Search/filter CVEs (severity, min CVSS, text, sort) with EchelonGraph scores. |
20
+ | `get_cve` | Full detail for one CVE (CVSS v3/v4, EG score, EPSS, KEV+ransomware, GHSA, CWE, references). |
21
+ | `cve_exposure` | **Unique:** live internet-exposure footprint for a CVE — exposed host count + country/product breakdown. |
22
+ | `exposure_radar` | Live totals across the exposure radars (shadow AI, KEV-exploited hosts, open databases, leaked creds). |
23
+
24
+ ## Install
25
+
26
+ Add it to your MCP client's config. It runs via `npx` — no global install needed.
27
+
28
+ ### Claude Desktop
29
+
30
+ `claude_desktop_config.json` → `mcpServers`:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "echelongraph": {
36
+ "command": "npx",
37
+ "args": ["-y", "echelongraph-mcp"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ### Cursor / Cline / Windsurf
44
+
45
+ `~/.cursor/mcp.json` (or the client's MCP settings):
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "echelongraph": {
51
+ "command": "npx",
52
+ "args": ["-y", "echelongraph-mcp"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ Restart the client, then ask: *"Is CVE-2023-44487 actively exploited, and how exposed is
59
+ the internet to it?"*
60
+
61
+ ## Configuration
62
+
63
+ | Env var | Default | Purpose |
64
+ |---|---|---|
65
+ | `ECHELONGRAPH_API_BASE` | `https://app.echelongraph.io` | Override the API base (self-host / proxy). |
66
+
67
+ ## Develop
68
+
69
+ ```bash
70
+ npm install
71
+ npm run build # tsc → dist/
72
+ npm run smoke # spawn the server + call cve_exposure against the live API
73
+ ```
74
+
75
+ ## License
76
+
77
+ MIT · Data © EchelonGraph, served under the CVE Pulse free-access terms.
package/dist/index.js ADDED
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+ // EchelonGraph CVE & internet-exposure MCP server.
3
+ // Exposes EchelonGraph's free public CVE/exposure intelligence as MCP tools so Claude,
4
+ // Cursor, Cline, and any MCP client can query real-time vulnerability data — including the
5
+ // one thing no other CVE source has: the LIVE internet-exposure footprint per CVE.
6
+ // stdio transport; no auth required; read-only.
7
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
+ import { z } from "zod";
10
+ const BASE = (process.env.ECHELONGRAPH_API_BASE || "https://app.echelongraph.io").replace(/\/+$/, "");
11
+ const UA = "echelongraph-mcp/1.0 (+https://echelongraph.io/pulse/mcp)";
12
+ async function api(path) {
13
+ const ctrl = new AbortController();
14
+ const t = setTimeout(() => ctrl.abort(), 15000);
15
+ try {
16
+ const res = await fetch(`${BASE}${path}`, {
17
+ headers: { "User-Agent": UA, Accept: "application/json" },
18
+ signal: ctrl.signal,
19
+ });
20
+ if (!res.ok)
21
+ throw new Error(`EchelonGraph API returned HTTP ${res.status} for ${path}`);
22
+ return await res.json();
23
+ }
24
+ finally {
25
+ clearTimeout(t);
26
+ }
27
+ }
28
+ const ok = (data) => ({ content: [{ type: "text", text: JSON.stringify(data, null, 2) }] });
29
+ const fail = (e) => ({
30
+ content: [{ type: "text", text: `Error querying EchelonGraph: ${e instanceof Error ? e.message : String(e)}` }],
31
+ isError: true,
32
+ });
33
+ const server = new McpServer({ name: "echelongraph-cve", version: "1.0.0" });
34
+ server.tool("cve_summary", "Live summary of EchelonGraph's CVE Pulse feed: total active CVEs and counts by severity (critical/high/medium/low/none), plus feed freshness. Use to gauge the current vulnerability landscape.", {}, async () => {
35
+ try {
36
+ return ok(await api("/api/v1/public/cves/summary"));
37
+ }
38
+ catch (e) {
39
+ return fail(e);
40
+ }
41
+ });
42
+ server.tool("search_cves", "Search/list CVEs from EchelonGraph's real-time feed (NVD + MITRE-CNA pre-NVD + CISA-KEV + EPSS + GitHub GHSA). Filter by severity, minimum CVSS, free text, and sort. Returns CVEs with the EchelonGraph multi-source score, severity, CVSS, EPSS, and KEV status.", {
43
+ search: z.string().optional().describe("free-text search (product, vendor, or keyword, e.g. 'tomcat')"),
44
+ severity: z.enum(["CRITICAL", "HIGH", "MEDIUM", "LOW"]).optional().describe("filter to one severity"),
45
+ min_cvss: z.number().min(0).max(10).optional().describe("minimum CVSS score"),
46
+ sort: z.enum(["published", "modified", "nvd", "echelongraph", "epss"]).optional().describe("sort order (default: published)"),
47
+ limit: z.number().int().min(1).max(50).optional().describe("page size (default 20, max 50)"),
48
+ }, async (a) => {
49
+ try {
50
+ const q = new URLSearchParams();
51
+ if (a.search)
52
+ q.set("search", a.search);
53
+ if (a.severity)
54
+ q.set("severity", a.severity);
55
+ if (a.min_cvss !== undefined)
56
+ q.set("min_cvss", String(a.min_cvss));
57
+ if (a.sort)
58
+ q.set("sort", a.sort);
59
+ q.set("limit", String(a.limit ?? 20));
60
+ return ok(await api(`/api/v1/public/cves?${q.toString()}`));
61
+ }
62
+ catch (e) {
63
+ return fail(e);
64
+ }
65
+ });
66
+ server.tool("get_cve", "Full detail for one CVE: description, NVD CVSS v3/v4, the EchelonGraph multi-source score + confidence, EPSS, CISA-KEV status (including ransomware-campaign use), GitHub GHSA, CWE, and references. Pass a CVE ID like CVE-2023-44487.", { cve_id: z.string().describe("a CVE ID, e.g. CVE-2023-44487") }, async ({ cve_id }) => {
67
+ try {
68
+ return ok(await api(`/api/v1/public/cves/${encodeURIComponent(cve_id.trim())}`));
69
+ }
70
+ catch (e) {
71
+ return fail(e);
72
+ }
73
+ });
74
+ server.tool("cve_exposure", "UNIQUE to EchelonGraph: the LIVE internet-exposure footprint for a CVE — how many internet-exposed hosts our passive radar currently sees running an affected version, with a country/product breakdown and a ransomware flag. Aggregate and host-redacted. No other CVE source has this. Returns exposed_hosts=0 for CVEs the radar doesn't track (it focuses on actively-exploited / high-EPSS CVEs).", { cve_id: z.string().describe("a CVE ID, e.g. CVE-2023-44487") }, async ({ cve_id }) => {
75
+ try {
76
+ return ok(await api(`/api/v1/public/kev-exposure/cve/${encodeURIComponent(cve_id.trim())}`));
77
+ }
78
+ catch (e) {
79
+ return fail(e);
80
+ }
81
+ });
82
+ server.tool("exposure_radar", "Live totals from EchelonGraph's passive internet-exposure radars: exposed AI services, hosts running actively-exploited (CISA-KEV) CVEs (plus ransomware-linked), unauthenticated databases, and leaked credentials. The current state of internet exposure EchelonGraph maps passively.", {}, async () => {
83
+ try {
84
+ const [kev, db, leaked, shadow] = await Promise.all([
85
+ api("/api/v1/public/kev-exposure/stats").catch(() => null),
86
+ api("/api/v1/public/exposed-databases/stats").catch(() => null),
87
+ api("/api/v1/public/leaked-credentials/stats").catch(() => null),
88
+ api("/api/v1/public/shadow-ai-radar/stats").catch(() => null),
89
+ ]);
90
+ return ok({ kev_exposure: kev, exposed_databases: db, leaked_credentials: leaked, shadow_ai: shadow });
91
+ }
92
+ catch (e) {
93
+ return fail(e);
94
+ }
95
+ });
96
+ const transport = new StdioServerTransport();
97
+ await server.connect(transport);
98
+ // MCP uses stdout for the protocol — diagnostics go to stderr.
99
+ console.error(`EchelonGraph CVE MCP server running (API: ${BASE})`);
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "echelongraph-mcp",
3
+ "version": "1.0.0",
4
+ "description": "EchelonGraph CVE & internet-exposure intelligence as an MCP server — real-time CVEs, EchelonGraph multi-source scores, CISA-KEV/EPSS, and the unique LIVE internet-exposure footprint per CVE — for Claude, Cursor, and any MCP client.",
5
+ "type": "module",
6
+ "bin": {
7
+ "echelongraph-mcp": "dist/index.js"
8
+ },
9
+ "files": [
10
+ "dist",
11
+ "README.md"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "start": "node dist/index.js",
16
+ "smoke": "node test/smoke.mjs"
17
+ },
18
+ "keywords": [
19
+ "mcp",
20
+ "model-context-protocol",
21
+ "cve",
22
+ "vulnerability",
23
+ "security",
24
+ "kev",
25
+ "epss",
26
+ "exposure",
27
+ "echelongraph",
28
+ "claude",
29
+ "cursor"
30
+ ],
31
+ "author": "EchelonGraph",
32
+ "license": "MIT",
33
+ "homepage": "https://echelongraph.io/pulse/mcp",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/AkshayDubey29/EchelonGraph.git"
37
+ },
38
+ "engines": {
39
+ "node": ">=18"
40
+ },
41
+ "dependencies": {
42
+ "@modelcontextprotocol/sdk": "^1.10.0",
43
+ "zod": "^3.23.8"
44
+ },
45
+ "devDependencies": {
46
+ "@types/node": "^20.14.0",
47
+ "typescript": "^5.4.5"
48
+ }
49
+ }