@qulib/mcp 0.7.0 → 0.8.2
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.js
CHANGED
|
@@ -14,7 +14,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
14
14
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
15
15
|
const requirePkg = createRequire(import.meta.url);
|
|
16
16
|
const pkg = requirePkg('../package.json');
|
|
17
|
-
import { analyzeApp, detectAuth, exploreAuth, scanRepo, computeAutomationMaturity, scaffoldTests, } from '@qulib/core';
|
|
17
|
+
import { analyzeApp, detectAuth, exploreAuth, scanRepo, computeAutomationMaturity, scaffoldTests, discoverApiSurfaceWithRepo, computeApiCoverage, } from '@qulib/core';
|
|
18
18
|
import { z } from 'zod';
|
|
19
19
|
import { buildAnalyzeAppMcpPayload } from './analyze-app-mcp-payload.js';
|
|
20
20
|
import { log } from './logger.js';
|
|
@@ -309,5 +309,55 @@ mcpServer.registerTool('qulib_scaffold_tests', {
|
|
|
309
309
|
return toolError('QULIB_SCAFFOLD_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
310
310
|
}
|
|
311
311
|
});
|
|
312
|
+
const ScoreApiInputSchema = z.object({
|
|
313
|
+
repoPath: z.string().describe('Absolute path to the repository on the MCP host filesystem'),
|
|
314
|
+
enableTier3: z
|
|
315
|
+
.boolean()
|
|
316
|
+
.optional()
|
|
317
|
+
.describe('Enable Tier3 heuristic discovery (currently: tRPC router definitions). Default false. Tier1=OpenAPI specs, Tier2=framework routes (Next.js, Express, Fastify, NestJS), Tier3=heuristic.'),
|
|
318
|
+
includeEndpointDetail: z
|
|
319
|
+
.boolean()
|
|
320
|
+
.optional()
|
|
321
|
+
.describe('When true, includes per-endpoint coverage detail in the response. Default false.'),
|
|
322
|
+
});
|
|
323
|
+
mcpServer.registerTool('qulib_score_api', {
|
|
324
|
+
description: 'Discover API endpoints in a repository and score their test coverage. Returns an api-test-coverage dimension score (0–100) with per-endpoint contextual evidence — which endpoints are covered by tests and which are not. Discovery is evidence-only: Tier1=OpenAPI/Swagger specs, Tier2=framework routes (Next.js App-Router route.ts exports, Pages API routes, Express, Fastify, Hono, NestJS decorators), Tier3=heuristic opt-in (tRPC). Never fabricates endpoints. Returns "not_applicable" when no API endpoints are found.',
|
|
325
|
+
inputSchema: ScoreApiInputSchema,
|
|
326
|
+
}, async ({ repoPath, enableTier3, includeEndpointDetail }) => {
|
|
327
|
+
try {
|
|
328
|
+
const abs = validateAbsoluteRepoPath(repoPath);
|
|
329
|
+
log.info(`qulib_score_api repoPath=${abs} enableTier3=${enableTier3 ?? false}`);
|
|
330
|
+
const repo = await scanRepo(abs);
|
|
331
|
+
const apiSurfaceResult = await discoverApiSurfaceWithRepo(abs, repo, {
|
|
332
|
+
enableTier3: enableTier3 ?? false,
|
|
333
|
+
});
|
|
334
|
+
const coverageResult = computeApiCoverage(repo, apiSurfaceResult);
|
|
335
|
+
const payload = {
|
|
336
|
+
repoPath: abs,
|
|
337
|
+
computedAt: new Date().toISOString(),
|
|
338
|
+
endpointsDiscovered: apiSurfaceResult.endpoints.length,
|
|
339
|
+
openApiSpecsFound: apiSurfaceResult.openApiSpecsFound,
|
|
340
|
+
tier3Enabled: apiSurfaceResult.tier3Enabled,
|
|
341
|
+
dimension: coverageResult.dimension,
|
|
342
|
+
untestedHighSeverityCount: coverageResult.untestedHighSeverityCount,
|
|
343
|
+
untestedMediumSeverityCount: coverageResult.untestedMediumSeverityCount,
|
|
344
|
+
};
|
|
345
|
+
if (includeEndpointDetail === true) {
|
|
346
|
+
payload['endpointCoverage'] = coverageResult.endpointCoverage;
|
|
347
|
+
}
|
|
348
|
+
log.info(`qulib_score_api done endpoints=${apiSurfaceResult.endpoints.length} score=${coverageResult.dimension.score} applicability=${coverageResult.dimension.applicability ?? 'applicable'}`);
|
|
349
|
+
return {
|
|
350
|
+
content: [{ type: 'text', text: JSON.stringify(payload, null, 2) }],
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
catch (err) {
|
|
354
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
355
|
+
if (msg.includes('repoPath must')) {
|
|
356
|
+
return toolError('QULIB_INPUT_INVALID', msg, undefined);
|
|
357
|
+
}
|
|
358
|
+
log.error(`qulib_score_api failed: ${msg}`);
|
|
359
|
+
return toolError('QULIB_API_SCORE_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
360
|
+
}
|
|
361
|
+
});
|
|
312
362
|
const transport = new StdioServerTransport();
|
|
313
363
|
await mcpServer.connect(transport);
|
|
@@ -71,7 +71,7 @@ export declare function summarizeAnalyzeResult(result: AnalyzeResult, includeFul
|
|
|
71
71
|
topRecommendations: string[];
|
|
72
72
|
dimensions: {
|
|
73
73
|
guidance?: string | undefined;
|
|
74
|
-
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio";
|
|
74
|
+
dimension: "test-coverage-breadth" | "framework-adoption" | "test-id-hygiene" | "ci-integration" | "auth-test-coverage" | "component-test-ratio" | "api-test-coverage";
|
|
75
75
|
score: number;
|
|
76
76
|
applicability: "unknown" | "applicable" | "not_applicable";
|
|
77
77
|
}[];
|
|
@@ -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";
|
|
99
|
+
category: "untested-route" | "a11y" | "console-error" | "broken-link" | "auth-surface" | "coverage" | "untested-api-endpoint";
|
|
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";
|
|
155
|
+
category: "untested-route" | "a11y" | "console-error" | "broken-link" | "auth-surface" | "coverage" | "untested-api-endpoint";
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA6G84d,CAAC;sBAA4C,CAAC;sBAA4C,CAAC;iBAAuC,CAAC;;;;;;;;;;;;;;;;;uBAAghB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;EADznf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qulib/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "MCP server for Qulib — AI-callable QA gap analysis",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tapesh Nagarwal",
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
36
|
-
"@qulib/core": "0.
|
|
36
|
+
"@qulib/core": "0.8.2",
|
|
37
37
|
"zod": "^3.23.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|