@qulib/mcp 0.10.0 → 0.10.1
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/dist/index.d.ts +11 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +96 -13
- package/dist/summarize-analyze-result.d.ts +2 -2
- package/dist/summarize-analyze-result.d.ts.map +1 -1
- package/dist/tool-error.d.ts +7 -0
- package/dist/tool-error.d.ts.map +1 -0
- package/dist/tool-error.js +10 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
export {
|
|
2
|
+
export declare function handleQulibDiff(input: {
|
|
3
|
+
from: string;
|
|
4
|
+
to: string;
|
|
5
|
+
labelFrom?: string;
|
|
6
|
+
labelTo?: string;
|
|
7
|
+
}): Promise<{
|
|
8
|
+
content: [{
|
|
9
|
+
type: 'text';
|
|
10
|
+
text: string;
|
|
11
|
+
}];
|
|
12
|
+
}>;
|
|
3
13
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAoqBA,wBAAsB,eAAe,CAAC,KAAK,EAAE;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,CAAC,CAsBzD"}
|
package/dist/index.js
CHANGED
|
@@ -10,25 +10,17 @@
|
|
|
10
10
|
// vs. write-capable tools (analyze_app with writeArtifacts) should carry different trust levels.
|
|
11
11
|
import { createRequire } from 'node:module';
|
|
12
12
|
import { isAbsolute, normalize, resolve } from 'node:path';
|
|
13
|
+
import { fileURLToPath } from 'node:url';
|
|
13
14
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
14
15
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
15
16
|
const requirePkg = createRequire(import.meta.url);
|
|
16
17
|
const pkg = requirePkg('../package.json');
|
|
17
|
-
import { analyzeApp, detectAuth, exploreAuth, scanRepo, computeAutomationMaturity, scaffoldTests, discoverApiSurfaceWithRepo, computeApiCoverage, computeReleaseConfidence, buildConfidenceInputFromQulib, } from '@qulib/core';
|
|
18
|
+
import { analyzeApp, detectAuth, exploreAuth, scanRepo, computeAutomationMaturity, scaffoldTests, discoverApiSurfaceWithRepo, computeApiCoverage, computeReleaseConfidence, buildConfidenceInputFromQulib, analyzeRunDiff, loadGapAnalysisFile, detectPromptLeakage, } from '@qulib/core';
|
|
18
19
|
import { RecipeIdSchema } from '@qulib/core';
|
|
19
20
|
import { z } from 'zod';
|
|
20
21
|
import { buildAnalyzeAppMcpPayload } from './analyze-app-mcp-payload.js';
|
|
21
22
|
import { log } from './logger.js';
|
|
22
|
-
|
|
23
|
-
return {
|
|
24
|
-
content: [
|
|
25
|
-
{
|
|
26
|
-
type: 'text',
|
|
27
|
-
text: JSON.stringify({ error: { code, message, detail: detail ?? null } }, null, 2),
|
|
28
|
-
},
|
|
29
|
-
],
|
|
30
|
-
};
|
|
31
|
-
}
|
|
23
|
+
import { toolError } from './tool-error.js';
|
|
32
24
|
function stderrTelemetrySink() {
|
|
33
25
|
return {
|
|
34
26
|
emit(event) {
|
|
@@ -511,5 +503,96 @@ mcpServer.registerTool('qulib_score_confidence', {
|
|
|
511
503
|
return toolError('QULIB_CONFIDENCE_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
512
504
|
}
|
|
513
505
|
});
|
|
514
|
-
|
|
515
|
-
|
|
506
|
+
function validateAbsoluteGapAnalysisPath(path) {
|
|
507
|
+
const norm = normalize(path.trim());
|
|
508
|
+
if (!isAbsolute(norm)) {
|
|
509
|
+
throw new Error('from and to must be absolute paths');
|
|
510
|
+
}
|
|
511
|
+
return resolve(norm);
|
|
512
|
+
}
|
|
513
|
+
export async function handleQulibDiff(input) {
|
|
514
|
+
try {
|
|
515
|
+
const fromPath = validateAbsoluteGapAnalysisPath(input.from);
|
|
516
|
+
const toPath = validateAbsoluteGapAnalysisPath(input.to);
|
|
517
|
+
log.info(`qulib_diff from=${fromPath} to=${toPath}`);
|
|
518
|
+
const fromGap = await loadGapAnalysisFile(fromPath);
|
|
519
|
+
const toGap = await loadGapAnalysisFile(toPath);
|
|
520
|
+
const result = analyzeRunDiff(fromGap, toGap, {
|
|
521
|
+
fromLabel: input.labelFrom,
|
|
522
|
+
toLabel: input.labelTo,
|
|
523
|
+
});
|
|
524
|
+
return {
|
|
525
|
+
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
catch (err) {
|
|
529
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
530
|
+
if (msg.includes('from and to must be absolute paths')) {
|
|
531
|
+
return toolError('QULIB_DIFF_INVALID_INPUT', 'from and to must be absolute paths');
|
|
532
|
+
}
|
|
533
|
+
log.error(`qulib_diff failed: ${msg}`);
|
|
534
|
+
return toolError('QULIB_DIFF_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
const QulibDiffInputSchema = z.object({
|
|
538
|
+
from: z
|
|
539
|
+
.string()
|
|
540
|
+
.describe('Absolute path to the baseline qulib report.json (the "before" analyze output)'),
|
|
541
|
+
to: z
|
|
542
|
+
.string()
|
|
543
|
+
.describe('Absolute path to the current qulib report.json (the "after" analyze output)'),
|
|
544
|
+
labelFrom: z
|
|
545
|
+
.string()
|
|
546
|
+
.optional()
|
|
547
|
+
.describe('Optional human label for the baseline report (default: the from path)'),
|
|
548
|
+
labelTo: z
|
|
549
|
+
.string()
|
|
550
|
+
.optional()
|
|
551
|
+
.describe('Optional human label for the current report (default: the to path)'),
|
|
552
|
+
});
|
|
553
|
+
mcpServer.registerTool('qulib_diff', {
|
|
554
|
+
description: 'Structured diff between two analyze outputs — added findings, resolved findings, severity changes, and a confidence delta.',
|
|
555
|
+
inputSchema: QulibDiffInputSchema,
|
|
556
|
+
}, handleQulibDiff);
|
|
557
|
+
// ---------------------------------------------------------------------------
|
|
558
|
+
// qulib_detect_prompt_leakage — scan a page surface for exposed AI system prompts
|
|
559
|
+
// ---------------------------------------------------------------------------
|
|
560
|
+
const DetectPromptLeakageInputSchema = z.object({
|
|
561
|
+
path: z.string().describe('The URL path being scanned (used as the gap path label, e.g. "/api/chat")'),
|
|
562
|
+
bodySnippet: z
|
|
563
|
+
.string()
|
|
564
|
+
.max(8000)
|
|
565
|
+
.optional()
|
|
566
|
+
.describe('Up to 8000 characters of raw HTML body from the page. Include inline scripts, HTML comments, meta tags, and any visible text.'),
|
|
567
|
+
headers: z
|
|
568
|
+
.record(z.string(), z.string())
|
|
569
|
+
.optional()
|
|
570
|
+
.describe('Response headers from the page request, as a flat string→string map.'),
|
|
571
|
+
});
|
|
572
|
+
mcpServer.registerTool('qulib_detect_prompt_leakage', {
|
|
573
|
+
description: 'Scan a captured page surface (HTML body, inline scripts, HTML comments, meta tags, response headers) for signals that an AI system prompt or agent instructions are inadvertently exposed to the public. Conservative — requires corroborating signals to minimise false positives. Returns an array of prompt-leakage Gaps (may be empty when nothing is detected). Each Gap includes severity (critical/high/medium), evidence, and a remediation recommendation.',
|
|
574
|
+
inputSchema: DetectPromptLeakageInputSchema,
|
|
575
|
+
}, async ({ path, bodySnippet, headers }) => {
|
|
576
|
+
try {
|
|
577
|
+
log.info(`qulib_detect_prompt_leakage path=${path}`);
|
|
578
|
+
const gaps = detectPromptLeakage({ path, bodySnippet, headers });
|
|
579
|
+
log.info(`qulib_detect_prompt_leakage done gapsFound=${gaps.length}`);
|
|
580
|
+
return {
|
|
581
|
+
content: [{ type: 'text', text: JSON.stringify({ path, gapsFound: gaps.length, gaps }, null, 2) }],
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
catch (err) {
|
|
585
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
586
|
+
log.error(`qulib_detect_prompt_leakage failed: ${msg}`);
|
|
587
|
+
return toolError('QULIB_PROMPT_LEAKAGE_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
async function startMcpServer() {
|
|
591
|
+
const transport = new StdioServerTransport();
|
|
592
|
+
await mcpServer.connect(transport);
|
|
593
|
+
}
|
|
594
|
+
const isDirectExecution = process.argv[1] !== undefined &&
|
|
595
|
+
fileURLToPath(import.meta.url) === resolve(process.argv[1]);
|
|
596
|
+
if (isDirectExecution) {
|
|
597
|
+
await startMcpServer();
|
|
598
|
+
}
|
|
@@ -96,7 +96,7 @@ export declare function summarizeAnalyzeResult(result: AnalyzeResult, includeFul
|
|
|
96
96
|
};
|
|
97
97
|
topGaps: {
|
|
98
98
|
path: string;
|
|
99
|
-
category: "untested-route" | "a11y" | "console-error" | "broken-link" | "auth-surface" | "coverage" | "untested-api-endpoint";
|
|
99
|
+
category: "untested-route" | "a11y" | "console-error" | "broken-link" | "auth-surface" | "coverage" | "untested-api-endpoint" | "prompt-leakage";
|
|
100
100
|
severity: "critical" | "high" | "medium" | "low";
|
|
101
101
|
reason: string;
|
|
102
102
|
}[];
|
|
@@ -152,7 +152,7 @@ export declare function summarizeAnalyzeResult(result: AnalyzeResult, includeFul
|
|
|
152
152
|
id: string;
|
|
153
153
|
severity: "critical" | "high" | "medium" | "low";
|
|
154
154
|
reason: string;
|
|
155
|
-
category: "untested-route" | "a11y" | "console-error" | "broken-link" | "auth-surface" | "coverage" | "untested-api-endpoint";
|
|
155
|
+
category: "untested-route" | "a11y" | "console-error" | "broken-link" | "auth-surface" | "coverage" | "untested-api-endpoint" | "prompt-leakage";
|
|
156
156
|
recommendation?: string | undefined;
|
|
157
157
|
description?: string | undefined;
|
|
158
158
|
}[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize-analyze-result.d.ts","sourceRoot":"","sources":["../src/summarize-analyze-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAqBjD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"summarize-analyze-result.d.ts","sourceRoot":"","sources":["../src/summarize-analyze-result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAqBjD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,EAAE,iBAAiB,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA6Gihe,CAAC;sBAA4C,CAAC;sBAA4C,CAAC;iBAAuC,CAAC;;;;;;;;;;;;;;;;;uBAAghB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;EAD5vf"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-error.d.ts","sourceRoot":"","sources":["../src/tool-error.ts"],"names":[],"mappings":"AAAA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,GAAG;IAC1E,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC3C,CASA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qulib/mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "MCP server for Qulib — AI-callable release confidence. Seven tools: fused verdict, live-app scan, automation maturity, API coverage, test scaffold, and auth tools.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tapesh Nagarwal",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
"build": "npm --prefix ../.. run build -w @qulib/core && tsc && chmod +x dist/index.js",
|
|
31
31
|
"prepublishOnly": "npm run build",
|
|
32
32
|
"dev": "tsx src/index.ts",
|
|
33
|
-
"test": "node --import tsx/esm --test src/__tests__/summarize-analyze-result.test.ts src/__tests__/analyze-app-mcp-payload.test.ts src/__tests__/score-confidence-mcp.test.ts src/__tests__/naming-aliases.test.ts"
|
|
33
|
+
"test": "node --import tsx/esm --test src/__tests__/summarize-analyze-result.test.ts src/__tests__/analyze-app-mcp-payload.test.ts src/__tests__/score-confidence-mcp.test.ts src/__tests__/naming-aliases.test.ts src/__tests__/diff.test.ts"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
37
|
-
"@qulib/core": "0.10.
|
|
37
|
+
"@qulib/core": "0.10.1",
|
|
38
38
|
"zod": "^3.23.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|