@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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA6G0td,CAAC;sBAA4C,CAAC;sBAA4C,CAAC;iBAAuC,CAAC;;;;;;;;;;;;;;;;;uBAAghB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;EADr8e"}
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.7.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.7.0",
36
+ "@qulib/core": "0.8.2",
37
37
  "zod": "^3.23.0"
38
38
  },
39
39
  "devDependencies": {