@nohacklabs/mcp-server 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.
package/README.md ADDED
@@ -0,0 +1,243 @@
1
+ # NoHack Security MCP Server
2
+
3
+ An MCP (Model Context Protocol) server that provides a **generalized Directus query interface** for the NoHack security scanning API. This follows the same pattern as the AI chat agent, using a powerful `query_collection` tool that leverages Directus's full query capabilities.
4
+
5
+ ## Key Design
6
+
7
+ Instead of creating specific tools for each entity (list_scans, list_vulnerabilities, etc.), this MCP server uses a **generalized approach**:
8
+
9
+ 1. **`query_collection`** - The powerhouse tool that can query ANY Directus collection with full filter, aggregate, groupBy, sort, and pagination support
10
+ 2. **`get_collection_schema`** - Discover fields and relations before querying
11
+ 3. **Convenience tools** - For fetching full records with all relations
12
+
13
+ This approach is more flexible and maintainable - any new query capability in Directus is automatically available without code changes.
14
+
15
+ ## Tools
16
+
17
+ ### Schema Discovery
18
+ | Tool | Description |
19
+ |------|-------------|
20
+ | `get_collection_schema` | Get fields, types, and relations for any collection |
21
+
22
+ ### The Powerhouse Tool
23
+ | Tool | Description |
24
+ |------|-------------|
25
+ | `query_collection` | Generic Directus query with full capabilities |
26
+
27
+ ### Convenience Tools
28
+ | Tool | Description |
29
+ |------|-------------|
30
+ | `get_scan_details` | Full scan with vulns/secrets |
31
+ | `get_vulnerability_details` | Full vulnerability record |
32
+ | `get_repo_config_details` | Full repo with all relations |
33
+ | `get_organization` | Organization details |
34
+
35
+ ## Available Collections
36
+
37
+ - `scans` - Security scan records
38
+ - `vulnerabilities` - Detected vulnerabilities
39
+ - `secrets` - Detected secrets
40
+ - `github_repo_config` - Repository configurations
41
+ - `organisations` - Organization data
42
+
43
+ ## Query Examples
44
+
45
+ ### List Recent Scans
46
+
47
+ ```json
48
+ {
49
+ "collection": "scans",
50
+ "fields": ["id", "session_id", "scan_type", "url", "branch", "date_created"],
51
+ "sort": ["-date_created"],
52
+ "limit": 10,
53
+ "orgId": "org-123"
54
+ }
55
+ ```
56
+
57
+ ### Count Vulnerabilities by Severity
58
+
59
+ ```json
60
+ {
61
+ "collection": "vulnerabilities",
62
+ "aggregate": { "count": "*" },
63
+ "groupBy": ["severity"],
64
+ "limit": -1,
65
+ "orgId": "org-123"
66
+ }
67
+ ```
68
+
69
+ ### Critical Vulnerabilities from Last 7 Days
70
+
71
+ ```json
72
+ {
73
+ "collection": "vulnerabilities",
74
+ "filter": {
75
+ "_and": [
76
+ { "severity": { "_eq": "Critical" } },
77
+ { "date_created": { "_gte": "$NOW(-7 days)" } }
78
+ ]
79
+ },
80
+ "fields": ["id", "type", "file", "line", "description"],
81
+ "limit": 50,
82
+ "orgId": "org-123"
83
+ }
84
+ ```
85
+
86
+ ### Vulnerabilities for a Specific Repo
87
+
88
+ ```json
89
+ {
90
+ "collection": "vulnerabilities",
91
+ "filter": {
92
+ "scan": {
93
+ "repo_config": {
94
+ "name": { "_eq": "my-repo" }
95
+ }
96
+ }
97
+ },
98
+ "fields": ["id", "type", "severity", "file", "scan.repo_config.name"],
99
+ "limit": 100
100
+ }
101
+ ```
102
+
103
+ ### Vulnerability Trend by Month
104
+
105
+ ```json
106
+ {
107
+ "collection": "vulnerabilities",
108
+ "aggregate": { "count": "*" },
109
+ "groupBy": ["year(date_created)", "month(date_created)"],
110
+ "sort": ["year(date_created)", "month(date_created)"],
111
+ "limit": -1,
112
+ "orgId": "org-123"
113
+ }
114
+ ```
115
+
116
+ ### Repos with Most Critical Vulnerabilities
117
+
118
+ ```json
119
+ {
120
+ "collection": "vulnerabilities",
121
+ "filter": { "severity": { "_eq": "Critical" } },
122
+ "aggregate": { "count": "*" },
123
+ "groupBy": ["repo_config"],
124
+ "fields": ["repo_config.name", "repo_config.full_name"],
125
+ "sort": ["-count"],
126
+ "limit": -1
127
+ }
128
+ ```
129
+
130
+ ## Filter Operators
131
+
132
+ | Operator | Description | Example |
133
+ |----------|-------------|---------|
134
+ | `_eq` | Equals | `{ "severity": { "_eq": "Critical" } }` |
135
+ | `_neq` | Not equals | `{ "status": { "_neq": "archived" } }` |
136
+ | `_in` | In array | `{ "severity": { "_in": ["Critical", "High"] } }` |
137
+ | `_gt`, `_gte`, `_lt`, `_lte` | Comparisons | `{ "confidence": { "_gte": 80 } }` |
138
+ | `_contains`, `_icontains` | Text search | `{ "file": { "_icontains": "auth" } }` |
139
+ | `_starts_with`, `_ends_with` | Text match | `{ "file": { "_ends_with": ".js" } }` |
140
+ | `_null`, `_nnull` | Null checks | `{ "description": { "_nnull": true } }` |
141
+ | `_and`, `_or` | Logical | `{ "_and": [{...}, {...}] }` |
142
+
143
+ ## Dynamic Date Expressions
144
+
145
+ Directus supports `$NOW()` for relative dates:
146
+
147
+ | Expression | Meaning |
148
+ |------------|---------|
149
+ | `$NOW(-7 days)` | 7 days ago |
150
+ | `$NOW(-1 month)` | 1 month ago |
151
+ | `$NOW(-1 year)` | 1 year ago |
152
+ | `$NOW(-2 weeks)` | 2 weeks ago |
153
+
154
+ ## Installation
155
+
156
+ ### From npm (Recommended)
157
+
158
+ ```bash
159
+ npm install -g @nohacklabs/mcp-server
160
+ ```
161
+
162
+ Or use directly with `npx`:
163
+
164
+ ```bash
165
+ npx @nohacklabs/mcp-server
166
+ ```
167
+
168
+ ### From Source
169
+
170
+ ```bash
171
+ git clone https://github.com/nohacklabs/mcp-server
172
+ cd mcp-server
173
+ npm install
174
+ npm run build
175
+ ```
176
+
177
+ ## Configuration
178
+
179
+ The server requires two environment variables:
180
+
181
+ | Variable | Description |
182
+ |----------|-------------|
183
+ | `NOHACK_API_URL` | Your NoHack API endpoint |
184
+ | `NOHACK_API_TOKEN` | Your API authentication token |
185
+
186
+ ## Usage
187
+
188
+ ### Claude Desktop Integration
189
+
190
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
191
+
192
+ ```json
193
+ {
194
+ "mcpServers": {
195
+ "nohack-security": {
196
+ "command": "npx",
197
+ "args": ["-y", "@nohacklabs/mcp-server"],
198
+ "env": {
199
+ "NOHACK_API_URL": "https://your-api-endpoint.com",
200
+ "NOHACK_API_TOKEN": "your-api-token"
201
+ }
202
+ }
203
+ }
204
+ }
205
+ ```
206
+
207
+ ### Cursor Integration
208
+
209
+ Add to `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally:
210
+
211
+ ```json
212
+ {
213
+ "mcpServers": {
214
+ "nohack-security": {
215
+ "command": "npx",
216
+ "args": ["-y", "@nohacklabs/mcp-server"],
217
+ "env": {
218
+ "NOHACK_API_URL": "https://your-api-endpoint.com",
219
+ "NOHACK_API_TOKEN": "your-api-token"
220
+ }
221
+ }
222
+ }
223
+ }
224
+ ```
225
+
226
+ ### Test with MCP Inspector
227
+
228
+ ```bash
229
+ npx @anthropic-ai/mcp-inspector npx @nohacklabs/mcp-server
230
+ ```
231
+
232
+ ## Development
233
+
234
+ ```bash
235
+ npm install # Install dependencies
236
+ npm run build # Build TypeScript
237
+ npm run dev # Watch mode
238
+ npm run inspector # Test with MCP Inspector
239
+ ```
240
+
241
+ ## License
242
+
243
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,525 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ // ============================================================================
6
+ // DIRECTUS API CLIENT
7
+ // ============================================================================
8
+ class DirectusClient {
9
+ apiUrl;
10
+ token;
11
+ constructor(apiUrl, token) {
12
+ this.apiUrl = apiUrl;
13
+ this.token = token;
14
+ }
15
+ async fetch(endpoint, options) {
16
+ const url = `${this.apiUrl}${endpoint}`;
17
+ const response = await fetch(url, {
18
+ ...options,
19
+ headers: {
20
+ Authorization: `Bearer ${this.token}`,
21
+ "Content-Type": "application/json",
22
+ ...options?.headers,
23
+ },
24
+ });
25
+ if (!response.ok) {
26
+ throw new Error(`API Error: ${response.status} ${response.statusText}`);
27
+ }
28
+ return response.json();
29
+ }
30
+ // ---------------------------------------------------------------------------
31
+ // Schema Discovery
32
+ // ---------------------------------------------------------------------------
33
+ async getCollectionSchema(collection) {
34
+ const result = await this.fetch(`/fields/${collection}`);
35
+ const fields = result.data || [];
36
+ // Filter out system/hidden fields and extract essential info
37
+ const relevantFields = fields
38
+ .filter((f) => !f.meta?.hidden &&
39
+ ![
40
+ "sort",
41
+ "user_created",
42
+ "user_updated",
43
+ "date_created",
44
+ "date_updated",
45
+ ].includes(f.field))
46
+ .map((field) => {
47
+ const isRelation = field.schema?.foreign_key_table ||
48
+ field.meta?.special?.includes("m2o") ||
49
+ field.meta?.special?.includes("o2m");
50
+ return {
51
+ field: field.field,
52
+ type: field.type,
53
+ ...(isRelation && {
54
+ relation: field.meta?.related_collection || field.schema?.foreign_key_table,
55
+ relationType: field.meta?.special?.find((s) => ["m2o", "o2m", "m2m"].includes(s)),
56
+ }),
57
+ };
58
+ });
59
+ const regularFields = relevantFields.filter((f) => !f.relation);
60
+ const relationFields = relevantFields.filter((f) => f.relation);
61
+ return {
62
+ collection,
63
+ totalFields: relevantFields.length,
64
+ fields: regularFields.map((f) => `${f.field} (${f.type})`),
65
+ relations: relationFields.map((f) => `${f.field} → ${f.relation} (${f.relationType})`),
66
+ };
67
+ }
68
+ // ---------------------------------------------------------------------------
69
+ // Generic Query
70
+ // ---------------------------------------------------------------------------
71
+ async queryCollection(options) {
72
+ const { collection, filter, aggregate, groupBy, sort, limit, offset, fields, deep, orgId, } = options;
73
+ // Define org filter paths for each collection
74
+ const orgFilterPaths = {
75
+ scans: {
76
+ repo_config: {
77
+ organisation: { _eq: orgId },
78
+ },
79
+ },
80
+ vulnerabilities: {
81
+ scan: {
82
+ repo_config: {
83
+ organisation: { _eq: orgId },
84
+ },
85
+ },
86
+ },
87
+ secrets: {
88
+ session: {
89
+ repo_config: {
90
+ organisation: { _eq: orgId },
91
+ },
92
+ },
93
+ },
94
+ github_repo_config: {
95
+ organisation: { _eq: orgId },
96
+ },
97
+ organisations: {
98
+ id: { _eq: orgId },
99
+ },
100
+ };
101
+ // Get org filter for this collection (if orgId provided)
102
+ let combinedFilter = filter;
103
+ if (orgId) {
104
+ const orgFilter = orgFilterPaths[collection];
105
+ if (orgFilter) {
106
+ combinedFilter = filter ? { _and: [orgFilter, filter] } : orgFilter;
107
+ }
108
+ }
109
+ const params = new URLSearchParams();
110
+ if (combinedFilter) {
111
+ params.set("filter", JSON.stringify(combinedFilter));
112
+ }
113
+ // Add aggregation
114
+ if (aggregate) {
115
+ if (aggregate.count) {
116
+ if (Array.isArray(aggregate.count)) {
117
+ aggregate.count.forEach((field) => params.append("aggregate[count][]", field));
118
+ }
119
+ else {
120
+ params.set("aggregate[count]", aggregate.count);
121
+ }
122
+ }
123
+ if (aggregate.avg) {
124
+ aggregate.avg.forEach((field) => params.append("aggregate[avg][]", field));
125
+ }
126
+ if (aggregate.sum) {
127
+ aggregate.sum.forEach((field) => params.append("aggregate[sum][]", field));
128
+ }
129
+ if (aggregate.min) {
130
+ aggregate.min.forEach((field) => params.append("aggregate[min][]", field));
131
+ }
132
+ if (aggregate.max) {
133
+ aggregate.max.forEach((field) => params.append("aggregate[max][]", field));
134
+ }
135
+ if (aggregate.countDistinct) {
136
+ aggregate.countDistinct.forEach((field) => params.append("aggregate[countDistinct][]", field));
137
+ }
138
+ }
139
+ // Add groupBy
140
+ if (groupBy && groupBy.length > 0) {
141
+ groupBy.forEach((field) => params.append("groupBy[]", field));
142
+ }
143
+ // Add sort
144
+ if (sort && sort.length > 0) {
145
+ sort.forEach((field) => params.append("sort[]", field));
146
+ }
147
+ // Add limit
148
+ if (limit !== undefined) {
149
+ params.set("limit", limit.toString());
150
+ }
151
+ // Add offset (for pagination)
152
+ if (offset !== undefined) {
153
+ params.set("offset", offset.toString());
154
+ }
155
+ // Add fields (supports dot notation for relations)
156
+ if (fields && fields.length > 0) {
157
+ fields.forEach((field) => params.append("fields[]", field));
158
+ }
159
+ // Add deep query parameters for nested relations
160
+ if (deep) {
161
+ Object.entries(deep).forEach(([key, value]) => {
162
+ if (typeof value === "object") {
163
+ Object.entries(value).forEach(([deepKey, deepValue]) => {
164
+ params.set(`deep[${key}][${deepKey}]`, String(deepValue));
165
+ });
166
+ }
167
+ });
168
+ }
169
+ // Add meta for total count
170
+ params.set("meta", "total_count,filter_count");
171
+ const result = await this.fetch(`/items/${collection}?${params.toString()}`);
172
+ let data = result.data || [];
173
+ // Post-process: If we're grouping by a relation and requesting relation fields,
174
+ // Directus returns only UUIDs. We need to fetch the relation details separately.
175
+ if (groupBy && fields && data.length > 0) {
176
+ const relationFields = fields.filter((f) => f.includes("."));
177
+ const groupedRelations = groupBy.filter((g) => relationFields.some((f) => f.startsWith(g + ".")) &&
178
+ typeof data[0][g] === "string" // Check if it's a UUID (not expanded)
179
+ );
180
+ if (groupedRelations.length > 0) {
181
+ for (const relation of groupedRelations) {
182
+ const relationIds = [
183
+ ...new Set(data.map((item) => item[relation]).filter(Boolean)),
184
+ ];
185
+ if (relationIds.length === 0)
186
+ continue;
187
+ const relationCollection = relation === "repo_config"
188
+ ? "github_repo_config"
189
+ : relation === "scan"
190
+ ? "scans"
191
+ : relation === "session"
192
+ ? "sessions"
193
+ : relation;
194
+ const subFields = relationFields
195
+ .filter((f) => f.startsWith(relation + "."))
196
+ .map((f) => f.substring(relation.length + 1));
197
+ const relationParams = new URLSearchParams();
198
+ relationParams.set("filter", JSON.stringify({ id: { _in: relationIds } }));
199
+ subFields.forEach((sf) => relationParams.append("fields[]", sf));
200
+ relationParams.append("fields[]", "id");
201
+ relationParams.set("limit", "-1");
202
+ const relationResult = await this.fetch(`/items/${relationCollection}?${relationParams.toString()}`);
203
+ const relationMap = new Map(relationResult.data.map((item) => [item.id, item]));
204
+ data = data.map((item) => {
205
+ const relationId = item[relation];
206
+ const relationDetails = relationMap.get(relationId);
207
+ if (relationDetails) {
208
+ return { ...item, [relation]: relationDetails };
209
+ }
210
+ return item;
211
+ });
212
+ }
213
+ }
214
+ }
215
+ return {
216
+ data,
217
+ meta: result.meta || { total_count: 0, filter_count: 0 },
218
+ count: data.length,
219
+ };
220
+ }
221
+ // ---------------------------------------------------------------------------
222
+ // Convenience Methods
223
+ // ---------------------------------------------------------------------------
224
+ async getScanById(scanId) {
225
+ const result = await this.fetch(`/items/scans/${scanId}?fields=*,secrets.*,vulnerabilities.*,repo_config.organisation,repo_config.name` +
226
+ `&deep[secrets][_limit]=-1&deep[secrets][_filter][status][_eq]=published` +
227
+ `&deep[vulnerabilities][_limit]=-1&deep[vulnerabilities][_filter][status][_in]=published,archived`);
228
+ return result.data;
229
+ }
230
+ async getVulnerabilityById(vulnId) {
231
+ const result = await this.fetch(`/items/vulnerabilities/${vulnId}`);
232
+ return result.data;
233
+ }
234
+ async getRepoConfigById(repoId) {
235
+ const result = await this.fetch(`/items/github_repo_config/${repoId}?fields=*,scans.*,secrets.*,vulnerabilities.*,organisation` +
236
+ `&deep[scans][_limit]=-1&deep[scans][_filter][status][_eq]=published` +
237
+ `&deep[secrets][_limit]=-1&deep[secrets][_filter][status][_eq]=published` +
238
+ `&deep[vulnerabilities][_limit]=-1`);
239
+ return {
240
+ repository: result.data,
241
+ scans: result.data.scans,
242
+ secrets: result.data.secrets,
243
+ vulnerabilities: result.data.vulnerabilities,
244
+ };
245
+ }
246
+ async getOrganization(orgId) {
247
+ const result = await this.fetch(`/items/organisations/${orgId}?fields=id,name,quota`);
248
+ return result.data;
249
+ }
250
+ }
251
+ // ============================================================================
252
+ // MCP SERVER
253
+ // ============================================================================
254
+ const server = new McpServer({
255
+ name: "nohack-security-api",
256
+ version: "1.0.0",
257
+ description: "MCP server for NoHack security scanning API - Generic Directus query interface for managing repo configs, scans, vulnerabilities, and secrets",
258
+ });
259
+ // Get API configuration from environment
260
+ function getClient() {
261
+ const apiUrl = process.env.NOHACK_API_URL;
262
+ const apiToken = process.env.NOHACK_API_TOKEN;
263
+ if (!apiUrl || !apiToken) {
264
+ throw new Error("NOHACK_API_URL and NOHACK_API_TOKEN environment variables are required");
265
+ }
266
+ return new DirectusClient(apiUrl, apiToken);
267
+ }
268
+ // ============================================================================
269
+ // TOOL DEFINITIONS
270
+ // ============================================================================
271
+ // Define collections enum for reuse
272
+ const collectionsEnum = z.enum([
273
+ "scans",
274
+ "vulnerabilities",
275
+ "secrets",
276
+ "github_repo_config",
277
+ "organisations",
278
+ ]);
279
+ // --- Schema Discovery Tool ---
280
+ server.registerTool("get_collection_schema", {
281
+ description: `Get the complete schema (fields, types, and relations) for any Directus collection.
282
+ Use this FIRST if you don't know what fields are available.
283
+
284
+ Available collections:
285
+ - 'scans': Security scan records
286
+ - 'vulnerabilities': Detected vulnerabilities (43 fields)
287
+ - 'secrets': Detected secrets
288
+ - 'github_repo_config': Repository configurations
289
+ - 'organisations': Organization data`,
290
+ inputSchema: z.object({
291
+ collection: collectionsEnum.describe("The collection to get schema for"),
292
+ }),
293
+ }, async ({ collection }) => {
294
+ try {
295
+ const client = getClient();
296
+ const schema = await client.getCollectionSchema(collection);
297
+ return {
298
+ content: [{ type: "text", text: JSON.stringify(schema, null, 2) }],
299
+ };
300
+ }
301
+ catch (error) {
302
+ return {
303
+ content: [{ type: "text", text: `Error: ${error.message}` }],
304
+ isError: true,
305
+ };
306
+ }
307
+ });
308
+ // --- The Powerhouse Tool: queryCollection ---
309
+ server.registerTool("query_collection", {
310
+ description: `THE POWERHOUSE TOOL - Generic query for ANY Directus collection with FULL capabilities.
311
+
312
+ USE THIS FOR:
313
+ - Listing data (scans, vulnerabilities, secrets, repos)
314
+ - Getting counts (without fetching all data)
315
+ - Filtering by any field or relation
316
+ - Trend analysis & time-series data
317
+ - Grouping & aggregations
318
+ - Complex multi-condition filters
319
+ - Pagination
320
+
321
+ AVAILABLE COLLECTIONS:
322
+ - 'scans': Security scan data
323
+ - 'vulnerabilities': Vulnerability findings
324
+ - 'secrets': Exposed secrets
325
+ - 'github_repo_config': Repository configurations
326
+ - 'organisations': Organization data
327
+
328
+ CRITICAL RULES:
329
+ 1. ALWAYS specify fields (collections have 40+ fields!)
330
+ 2. Use limit: -1 ONLY for aggregations (to count ALL records)
331
+ 3. Use limit: 10-100 for data queries
332
+ 4. Use orgId to filter by organization
333
+
334
+ FILTER OPERATORS:
335
+ - Equality: _eq, _neq, _in, _nin
336
+ - Comparison: _gt, _gte, _lt, _lte
337
+ - Text: _contains, _icontains, _starts_with, _ends_with
338
+ - Null: _null, _nnull, _empty, _nempty
339
+ - Logical: _and, _or
340
+ - Relations: _some, _none
341
+
342
+ DYNAMIC DATES (use in filters):
343
+ - Last 7 days: { "date_created": { "_gte": "$NOW(-7 days)" } }
344
+ - Last month: { "date_created": { "_gte": "$NOW(-1 month)" } }
345
+
346
+ AGGREGATIONS:
347
+ - count: Count records (use "*" or specific field)
348
+ - avg, sum, min, max: Numeric operations
349
+ - groupBy: Group results (e.g., ["severity", "vuln_status"])
350
+
351
+ EXAMPLES:
352
+ // List critical vulnerabilities
353
+ { collection: "vulnerabilities", filter: { severity: { _eq: "Critical" } }, fields: ["id", "type", "file"], limit: 50 }
354
+
355
+ // Count by severity
356
+ { collection: "vulnerabilities", aggregate: { count: "*" }, groupBy: ["severity"], limit: -1 }
357
+
358
+ // Recent scans for a repo
359
+ { collection: "scans", filter: { repo_config: { name: { _eq: "my-repo" } } }, fields: ["id", "scan_type", "date_created"], limit: 10 }`,
360
+ inputSchema: z.object({
361
+ collection: collectionsEnum.describe("The collection to query"),
362
+ filter: z
363
+ .record(z.any())
364
+ .optional()
365
+ .describe('Directus filter object. Supports nested relations. Example: {"severity": {"_eq": "Critical"}, "scan": {"scan_type": {"_eq": "sast"}}}'),
366
+ aggregate: z
367
+ .object({
368
+ count: z.union([z.string(), z.array(z.string())]).optional(),
369
+ avg: z.array(z.string()).optional(),
370
+ sum: z.array(z.string()).optional(),
371
+ min: z.array(z.string()).optional(),
372
+ max: z.array(z.string()).optional(),
373
+ countDistinct: z.array(z.string()).optional(),
374
+ })
375
+ .optional()
376
+ .describe("Aggregation functions"),
377
+ groupBy: z
378
+ .array(z.string())
379
+ .optional()
380
+ .describe('Fields to group by (e.g., ["severity", "vuln_status"])'),
381
+ sort: z
382
+ .array(z.string())
383
+ .optional()
384
+ .describe('Sort fields (prefix with - for descending, e.g., ["-date_created"])'),
385
+ limit: z
386
+ .number()
387
+ .optional()
388
+ .describe("Max results. Use -1 for aggregations to count ALL records, 10-100 for data queries"),
389
+ offset: z.number().optional().describe("Records to skip (for pagination)"),
390
+ fields: z
391
+ .array(z.string())
392
+ .optional()
393
+ .describe('Fields to return. Use dot notation for relations: ["id", "scan.repo_config.name"]'),
394
+ deep: z
395
+ .record(z.any())
396
+ .optional()
397
+ .describe("Deep query parameters for nested relations"),
398
+ orgId: z
399
+ .string()
400
+ .optional()
401
+ .describe("Organization ID to filter by (auto-applied to queries)"),
402
+ }),
403
+ }, async ({ collection, filter, aggregate, groupBy, sort, limit, offset, fields, deep, orgId, }) => {
404
+ try {
405
+ const client = getClient();
406
+ const result = await client.queryCollection({
407
+ collection,
408
+ filter,
409
+ aggregate,
410
+ groupBy,
411
+ sort,
412
+ limit,
413
+ offset,
414
+ fields,
415
+ deep,
416
+ orgId,
417
+ });
418
+ return {
419
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
420
+ };
421
+ }
422
+ catch (error) {
423
+ return {
424
+ content: [{ type: "text", text: `Error: ${error.message}` }],
425
+ isError: true,
426
+ };
427
+ }
428
+ });
429
+ // --- Convenience Tools ---
430
+ server.registerTool("get_scan_details", {
431
+ description: `Get detailed information about a specific scan including all vulnerabilities, secrets, and related data.
432
+ Use this when you need the FULL scan record with all relations.`,
433
+ inputSchema: z.object({
434
+ scanId: z.string().describe("The scan ID"),
435
+ }),
436
+ }, async ({ scanId }) => {
437
+ try {
438
+ const client = getClient();
439
+ const result = await client.getScanById(scanId);
440
+ return {
441
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
442
+ };
443
+ }
444
+ catch (error) {
445
+ return {
446
+ content: [{ type: "text", text: `Error: ${error.message}` }],
447
+ isError: true,
448
+ };
449
+ }
450
+ });
451
+ server.registerTool("get_vulnerability_details", {
452
+ description: `Get detailed information about a specific vulnerability including code context, source, sink, data flow, and recommendations.
453
+ Use this when you need the FULL vulnerability record.`,
454
+ inputSchema: z.object({
455
+ vulnerabilityId: z.string().describe("The vulnerability ID"),
456
+ }),
457
+ }, async ({ vulnerabilityId }) => {
458
+ try {
459
+ const client = getClient();
460
+ const result = await client.getVulnerabilityById(vulnerabilityId);
461
+ return {
462
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
463
+ };
464
+ }
465
+ catch (error) {
466
+ return {
467
+ content: [{ type: "text", text: `Error: ${error.message}` }],
468
+ isError: true,
469
+ };
470
+ }
471
+ });
472
+ server.registerTool("get_repo_config_details", {
473
+ description: `Get detailed repository configuration including all related scans, vulnerabilities, and secrets.
474
+ Use this when you need the FULL repository record with all relations.`,
475
+ inputSchema: z.object({
476
+ repoId: z.string().describe("The repository configuration ID"),
477
+ }),
478
+ }, async ({ repoId }) => {
479
+ try {
480
+ const client = getClient();
481
+ const result = await client.getRepoConfigById(repoId);
482
+ return {
483
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
484
+ };
485
+ }
486
+ catch (error) {
487
+ return {
488
+ content: [{ type: "text", text: `Error: ${error.message}` }],
489
+ isError: true,
490
+ };
491
+ }
492
+ });
493
+ server.registerTool("get_organization", {
494
+ description: `Get organization details including name and quota.`,
495
+ inputSchema: z.object({
496
+ orgId: z.string().describe("The organization ID"),
497
+ }),
498
+ }, async ({ orgId }) => {
499
+ try {
500
+ const client = getClient();
501
+ const result = await client.getOrganization(orgId);
502
+ return {
503
+ content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
504
+ };
505
+ }
506
+ catch (error) {
507
+ return {
508
+ content: [{ type: "text", text: `Error: ${error.message}` }],
509
+ isError: true,
510
+ };
511
+ }
512
+ });
513
+ // ============================================================================
514
+ // SERVER STARTUP
515
+ // ============================================================================
516
+ async function main() {
517
+ const transport = new StdioServerTransport();
518
+ await server.connect(transport);
519
+ console.error("NoHack Security MCP Server running on stdio");
520
+ }
521
+ main().catch((error) => {
522
+ console.error("Fatal error:", error);
523
+ process.exit(1);
524
+ });
525
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@nohacklabs/mcp-server",
3
+ "version": "1.0.0",
4
+ "description": "MCP server for NoHack security scanning API - query vulnerabilities, secrets, scans, and repo configs",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "nohack-mcp": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "start": "node dist/index.js",
17
+ "dev": "tsc --watch",
18
+ "prepublishOnly": "npm run build",
19
+ "inspector": "npx @anthropic-ai/mcp-inspector node dist/index.js"
20
+ },
21
+ "dependencies": {
22
+ "@modelcontextprotocol/sdk": "^1.11.0",
23
+ "zod": "^3.25.76"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "^22.15.0",
27
+ "typescript": "^5.7.3"
28
+ },
29
+ "engines": {
30
+ "node": ">=18"
31
+ },
32
+ "keywords": [
33
+ "mcp",
34
+ "model-context-protocol",
35
+ "security",
36
+ "vulnerability",
37
+ "sast",
38
+ "scanning",
39
+ "nohack",
40
+ "ai",
41
+ "cursor",
42
+ "claude"
43
+ ],
44
+ "author": "NoHack Labs",
45
+ "license": "MIT",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/nohacklabs/mcp-server"
49
+ },
50
+ "homepage": "https://nohacklabs.com",
51
+ "publishConfig": {
52
+ "access": "public"
53
+ }
54
+ }