@agentsid/scanner 0.1.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 (116) hide show
  1. package/README.md +205 -0
  2. package/action/action.yml +42 -0
  3. package/action/index.mjs +179 -0
  4. package/docs/state-of-agent-security-2026.md +377 -0
  5. package/examples/security-scan.yml +57 -0
  6. package/package.json +37 -0
  7. package/reports/aashari-mcp-server-atlassian-confluence.json +110 -0
  8. package/reports/aashari-mcp-server-atlassian-jira.json +138 -0
  9. package/reports/aashari-mcp-server-aws-sso.json +122 -0
  10. package/reports/agentdeskai-browser-tools-mcp.json +361 -0
  11. package/reports/ahmetkca-mcp-server-postgres.json +43 -0
  12. package/reports/aiondadotcom-mcp-ssh.json +166 -0
  13. package/reports/apify-actors-mcp-server.json +43 -0
  14. package/reports/azure-mcp.json +43 -0
  15. package/reports/boilerplate-mcp-tool.json +43 -0
  16. package/reports/browserstack-mcp-server.json +43 -0
  17. package/reports/canvas-mcp-server.json +43 -0
  18. package/reports/canvas-mcp-tool.json +43 -0
  19. package/reports/chrome-devtools-mcp.json +300 -0
  20. package/reports/chrome-local-mcp.json +222 -0
  21. package/reports/claude-flow-mcp.json +43 -0
  22. package/reports/cloudflare-mcp-server.json +43 -0
  23. package/reports/code-canvas-server.json +43 -0
  24. package/reports/cognitionai-metabase-mcp-server.json +43 -0
  25. package/reports/composio-mcp.json +43 -0
  26. package/reports/contentful-mcp-server.json +43 -0
  27. package/reports/dbhub.json +43 -0
  28. package/reports/desktop-commander.json +43 -0
  29. package/reports/dynatrace-oss-dynatrace-mcp-server.json +43 -0
  30. package/reports/e2b-mcp-server.json +67 -0
  31. package/reports/eslint-mcp.json +51 -0
  32. package/reports/european-parliament-mcp-server.json +1467 -0
  33. package/reports/exa-mcp-server.json +74 -0
  34. package/reports/executeautomation-playwright-mcp-server.json +418 -0
  35. package/reports/fast-kit-spec-kit.json +43 -0
  36. package/reports/felores-airtable-mcp-server.json +43 -0
  37. package/reports/figma-mcp.json +103 -0
  38. package/reports/forestadmin-mcp-server.json +43 -0
  39. package/reports/fullrun-mcp.json +43 -0
  40. package/reports/gemini-mcp-tool.json +43 -0
  41. package/reports/gitlab-mcp-agent-server.json +186 -0
  42. package/reports/grackle-ai-mcp.json +43 -0
  43. package/reports/heroku-mcp-server.json +333 -0
  44. package/reports/hisma-server-puppeteer.json +93 -0
  45. package/reports/hubspot-mcp-server.json +43 -0
  46. package/reports/hyper-mcp-shell.json +59 -0
  47. package/reports/iflow-mcp-server-github.json +327 -0
  48. package/reports/jpisnice-shadcn-ui-mcp-server.json +149 -0
  49. package/reports/jsonresume-mcp.json +43 -0
  50. package/reports/mapbox-mcp-server.json +43 -0
  51. package/reports/mcp-framework.json +43 -0
  52. package/reports/mcp-from-openapi.json +43 -0
  53. package/reports/mcp-handler.json +43 -0
  54. package/reports/mcp-proxy.json +43 -0
  55. package/reports/mcp-server-docker.json +59 -0
  56. package/reports/mcp-server-github-gist.json +108 -0
  57. package/reports/mcp-server-google-calendar.json +43 -0
  58. package/reports/mcp-server-jira-cloud.json +43 -0
  59. package/reports/mcp-server-kubernetes.json +43 -0
  60. package/reports/mcp-server-slack.json +411 -0
  61. package/reports/mcp-server-sqlite-npx.json +43 -0
  62. package/reports/mcp-server.json +43 -0
  63. package/reports/mcp-starter.json +59 -0
  64. package/reports/mcp-tool-lint.json +43 -0
  65. package/reports/mcporter.json +43 -0
  66. package/reports/mcptoolshop-mcp-tool-registry.json +43 -0
  67. package/reports/microsoft-devbox-mcp.json +43 -0
  68. package/reports/mobilenext-mobile-mcp.json +214 -0
  69. package/reports/modelcontextprotocol-server-brave-search.json +43 -0
  70. package/reports/modelcontextprotocol-server-everything.json +165 -0
  71. package/reports/modelcontextprotocol-server-fetch.json +43 -0
  72. package/reports/modelcontextprotocol-server-filesystem.json +259 -0
  73. package/reports/modelcontextprotocol-server-github.json +391 -0
  74. package/reports/modelcontextprotocol-server-memory.json +117 -0
  75. package/reports/modelcontextprotocol-server-postgres.json +43 -0
  76. package/reports/modelcontextprotocol-server-puppeteer.json +101 -0
  77. package/reports/modelcontextprotocol-server-sequential-thinking.json +67 -0
  78. package/reports/mongodb-mcp-server.json +43 -0
  79. package/reports/mseep-linear-mcp-server.json +43 -0
  80. package/reports/mseep-mcp-server-sqlite-npx.json +43 -0
  81. package/reports/n8n-mcp.json +123 -0
  82. package/reports/notepost-mcp.json +43 -0
  83. package/reports/notionhq-notion-mcp-server.json +220 -0
  84. package/reports/nx-mcp.json +59 -0
  85. package/reports/obsidian-mcp-server.json +43 -0
  86. package/reports/opengraph-io-mcp.json +130 -0
  87. package/reports/payloadcms-plugin-mcp.json +43 -0
  88. package/reports/peac-mappings-mcp.json +43 -0
  89. package/reports/playwright-mcp.json +236 -0
  90. package/reports/puppeteer-mcp-server.json +43 -0
  91. package/reports/railway-mcp-server.json +194 -0
  92. package/reports/razorpay-blade-mcp.json +182 -0
  93. package/reports/rekog-mcp-nest.json +43 -0
  94. package/reports/remotion-mcp.json +51 -0
  95. package/reports/rollbar-mcp-server.json +43 -0
  96. package/reports/sap-ux-fiori-mcp-server.json +80 -0
  97. package/reports/sentry-mcp-server.json +43 -0
  98. package/reports/server-filesystem.json +43 -0
  99. package/reports/server-memory.json +43 -0
  100. package/reports/shortcut-mcp.json +43 -0
  101. package/reports/supabase-mcp-server-supabase.json +43 -0
  102. package/reports/tavily-mcp.json +79 -0
  103. package/reports/thelord-mcp-server-docker-npx.json +43 -0
  104. package/reports/tyk-technologies-api-to-mcp.json +43 -0
  105. package/reports/tyk-technologies-tyk-dashboard-mcp.json +43 -0
  106. package/reports/ui5-mcp-server.json +157 -0
  107. package/reports/upstash-context7-mcp.json +82 -0
  108. package/reports/vantasdk-vanta-mcp-server.json +43 -0
  109. package/reports/winor30-mcp-server-datadog.json +43 -0
  110. package/reports/wonderwhy-er-desktop-commander.json +43 -0
  111. package/reports/xzxzzx-bilibili-mcp.json +58 -0
  112. package/src/grader.mjs +66 -0
  113. package/src/index.mjs +108 -0
  114. package/src/reporter.mjs +158 -0
  115. package/src/rules.mjs +363 -0
  116. package/src/scanner.mjs +208 -0
@@ -0,0 +1,208 @@
1
+ /**
2
+ * MCP Server Scanner — connects to an MCP server, enumerates tools,
3
+ * and runs security analysis across all rule categories.
4
+ *
5
+ * Supports stdio and HTTP transport modes.
6
+ */
7
+
8
+ import { spawn } from "child_process";
9
+ import {
10
+ scanToolDescriptions,
11
+ scanToolNames,
12
+ scanInputSchemas,
13
+ scanAuthIndicators,
14
+ scanOutputSafety,
15
+ scanHallucinationRisks,
16
+ } from "./rules.mjs";
17
+ import { grade } from "./grader.mjs";
18
+ import { formatTerminalReport, formatJsonReport } from "./reporter.mjs";
19
+
20
+ /**
21
+ * Scan an MCP server by spawning it as a subprocess (stdio transport).
22
+ * @param {string} command — Command to start the server (e.g., "npx @some/mcp-server")
23
+ * @param {object} options — { env, timeout, json }
24
+ */
25
+ export async function scanStdio(command, options = {}) {
26
+ const { env = {}, timeout = 30000, json = false } = options;
27
+
28
+ const parts = command.split(/\s+/);
29
+ const proc = spawn(parts[0], parts.slice(1), {
30
+ env: { ...process.env, ...env },
31
+ stdio: ["pipe", "pipe", "pipe"],
32
+ });
33
+
34
+ const result = await communicateWithServer(proc, timeout);
35
+ proc.kill();
36
+
37
+ return generateReport(result.serverInfo, result.tools, json);
38
+ }
39
+
40
+ /**
41
+ * Scan an MCP server by connecting over HTTP (streamable HTTP transport).
42
+ * @param {string} url — Server URL
43
+ * @param {object} options — { headers, timeout, json }
44
+ */
45
+ export async function scanHttp(url, options = {}) {
46
+ const { headers = {}, timeout = 30000, json = false } = options;
47
+
48
+ // For HTTP transport, we send JSON-RPC over HTTP
49
+ const initResponse = await fetchRpc(url, "initialize", {
50
+ protocolVersion: "2024-11-05",
51
+ capabilities: {},
52
+ clientInfo: { name: "agentsid-scanner", version: "0.1.0" },
53
+ }, headers, timeout);
54
+
55
+ const serverInfo = initResponse?.result?.serverInfo || { name: "unknown", version: "?" };
56
+
57
+ // Send initialized notification
58
+ await fetchRpc(url, "notifications/initialized", {}, headers, timeout);
59
+
60
+ // List tools
61
+ const toolsResponse = await fetchRpc(url, "tools/list", {}, headers, timeout);
62
+ const tools = toolsResponse?.result?.tools || [];
63
+
64
+ return generateReport(serverInfo, tools, json);
65
+ }
66
+
67
+ /**
68
+ * Scan from a tool definition list (no server connection needed).
69
+ * Useful for scanning tool configs or package.json MCP definitions.
70
+ * @param {Array} tools — Array of tool definition objects
71
+ * @param {object} options — { serverName, json }
72
+ */
73
+ export function scanToolDefinitions(tools, options = {}) {
74
+ const { serverName = "static-analysis", json = false } = options;
75
+ const serverInfo = { name: serverName, version: "static" };
76
+ return generateReport(serverInfo, tools, json);
77
+ }
78
+
79
+ // ─── Internal ───
80
+
81
+ async function communicateWithServer(proc, timeout) {
82
+ return new Promise((resolve, reject) => {
83
+ let buf = "";
84
+ const responses = {};
85
+
86
+ proc.stdout.on("data", (data) => {
87
+ buf += data.toString();
88
+ while (buf.includes("\n")) {
89
+ const idx = buf.indexOf("\n");
90
+ const line = buf.substring(0, idx);
91
+ buf = buf.substring(idx + 1);
92
+ try {
93
+ const msg = JSON.parse(line);
94
+ if (msg.id) responses[msg.id] = msg;
95
+ } catch {}
96
+ }
97
+ });
98
+
99
+ proc.stderr.on("data", () => {}); // Suppress stderr
100
+
101
+ // Send initialize
102
+ proc.stdin.write(JSON.stringify({
103
+ jsonrpc: "2.0",
104
+ method: "initialize",
105
+ params: {
106
+ protocolVersion: "2024-11-05",
107
+ capabilities: {},
108
+ clientInfo: { name: "agentsid-scanner", version: "0.1.0" },
109
+ },
110
+ id: 1,
111
+ }) + "\n");
112
+
113
+ setTimeout(() => {
114
+ // Send initialized notification
115
+ proc.stdin.write(JSON.stringify({
116
+ jsonrpc: "2.0",
117
+ method: "notifications/initialized",
118
+ params: {},
119
+ }) + "\n");
120
+ }, 500);
121
+
122
+ setTimeout(() => {
123
+ // List tools
124
+ proc.stdin.write(JSON.stringify({
125
+ jsonrpc: "2.0",
126
+ method: "tools/list",
127
+ params: {},
128
+ id: 2,
129
+ }) + "\n");
130
+ }, 1000);
131
+
132
+ // Wait for tools/list response
133
+ const check = setInterval(() => {
134
+ if (responses[2]) {
135
+ clearInterval(check);
136
+ clearTimeout(timer);
137
+
138
+ const serverInfo = responses[1]?.result?.serverInfo || { name: "unknown", version: "?" };
139
+ const tools = responses[2]?.result?.tools || [];
140
+
141
+ resolve({ serverInfo, tools });
142
+ }
143
+ }, 100);
144
+
145
+ const timer = setTimeout(() => {
146
+ clearInterval(check);
147
+ const serverInfo = responses[1]?.result?.serverInfo || { name: "unknown", version: "?" };
148
+ const tools = responses[2]?.result?.tools || [];
149
+ resolve({ serverInfo, tools });
150
+ }, timeout);
151
+ });
152
+ }
153
+
154
+ async function fetchRpc(url, method, params, headers, timeout) {
155
+ const controller = new AbortController();
156
+ const timer = setTimeout(() => controller.abort(), timeout);
157
+
158
+ try {
159
+ const response = await fetch(url, {
160
+ method: "POST",
161
+ headers: {
162
+ "Content-Type": "application/json",
163
+ ...headers,
164
+ },
165
+ body: JSON.stringify({
166
+ jsonrpc: "2.0",
167
+ method,
168
+ params,
169
+ id: Math.floor(Math.random() * 10000),
170
+ }),
171
+ signal: controller.signal,
172
+ });
173
+ clearTimeout(timer);
174
+ return response.json();
175
+ } catch (err) {
176
+ clearTimeout(timer);
177
+ return null;
178
+ }
179
+ }
180
+
181
+ function generateReport(serverInfo, tools, json) {
182
+ // Run all scan rules
183
+ const descriptionFindings = scanToolDescriptions(tools);
184
+ const { findings: nameFindings, riskProfile } = scanToolNames(tools);
185
+ const schemaFindings = scanInputSchemas(tools);
186
+ const authFindings = scanAuthIndicators(tools, serverInfo);
187
+ const outputFindings = scanOutputSafety(tools);
188
+ const hallucinationFindings = scanHallucinationRisks(tools);
189
+
190
+ // Combine all findings
191
+ const allFindings = [
192
+ ...descriptionFindings,
193
+ ...nameFindings,
194
+ ...schemaFindings,
195
+ ...authFindings,
196
+ ...outputFindings,
197
+ ...hallucinationFindings,
198
+ ];
199
+
200
+ // Grade
201
+ const gradeResult = grade(allFindings);
202
+
203
+ // Format report
204
+ if (json) {
205
+ return formatJsonReport(serverInfo, tools, allFindings, gradeResult, riskProfile);
206
+ }
207
+ return formatTerminalReport(serverInfo, tools, allFindings, gradeResult, riskProfile);
208
+ }