@qulib/mcp 0.5.3 → 0.7.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.
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AnalyzeResult } from '@qulib/core';
|
|
2
|
+
export interface AnalyzeAppMcpPayloadOptions {
|
|
3
|
+
includeFullReport?: boolean;
|
|
4
|
+
/** When true, returns only `toAgentSummary(result)` JSON (QLIB-001). Ignores `includeFullReport`. */
|
|
5
|
+
agentSummary?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Single place for analyze_app response shaping: default summary-first,
|
|
9
|
+
* optional full report, or compact agent gate summary.
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildAnalyzeAppMcpPayload(result: AnalyzeResult, input: AnalyzeAppMcpPayloadOptions): unknown;
|
|
12
|
+
//# sourceMappingURL=analyze-app-mcp-payload.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyze-app-mcp-payload.d.ts","sourceRoot":"","sources":["../src/analyze-app-mcp-payload.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAIjD,MAAM,WAAW,2BAA2B;IAC1C,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qGAAqG;IACrG,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAKT"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { toAgentSummary } from '@qulib/core';
|
|
2
|
+
import { summarizeAnalyzeResult } from './summarize-analyze-result.js';
|
|
3
|
+
/**
|
|
4
|
+
* Single place for analyze_app response shaping: default summary-first,
|
|
5
|
+
* optional full report, or compact agent gate summary.
|
|
6
|
+
*/
|
|
7
|
+
export function buildAnalyzeAppMcpPayload(result, input) {
|
|
8
|
+
if (input.agentSummary === true) {
|
|
9
|
+
return toAgentSummary(result);
|
|
10
|
+
}
|
|
11
|
+
return summarizeAnalyzeResult(result, input.includeFullReport === true);
|
|
12
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -14,9 +14,9 @@ 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, } from '@qulib/core';
|
|
17
|
+
import { analyzeApp, detectAuth, exploreAuth, scanRepo, computeAutomationMaturity, scaffoldTests, } from '@qulib/core';
|
|
18
18
|
import { z } from 'zod';
|
|
19
|
-
import {
|
|
19
|
+
import { buildAnalyzeAppMcpPayload } from './analyze-app-mcp-payload.js';
|
|
20
20
|
import { log } from './logger.js';
|
|
21
21
|
function toolError(code, message, detail) {
|
|
22
22
|
return {
|
|
@@ -68,6 +68,10 @@ const AnalyzeInputSchema = z.object({
|
|
|
68
68
|
timeoutMs: z.number().int().positive().optional(),
|
|
69
69
|
auth: z.discriminatedUnion('type', [FormLoginMcpAuthSchema, StorageStateMcpAuthSchema]).optional(),
|
|
70
70
|
includeFullReport: z.boolean().optional(),
|
|
71
|
+
agentSummary: z
|
|
72
|
+
.boolean()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('When true, return only the versioned agent-summary JSON ({ schemaVersion: 1, gate, coverageStatus, topRisks, recommendedNextChecks, honestyNotes, costSummary, deterministicFollowUps }). Use this for CI gates and orchestrators that need a single small payload to decide pass/warn/fail. Overrides includeFullReport.'),
|
|
71
75
|
llmTokenBudget: z.number().int().positive().optional(),
|
|
72
76
|
llmMaxOutputTokensPerCall: z.number().int().positive().optional(),
|
|
73
77
|
testGenerationLimit: z.number().int().positive().max(50).optional(),
|
|
@@ -153,7 +157,7 @@ mcpServer.registerTool('detect_auth', {
|
|
|
153
157
|
}
|
|
154
158
|
});
|
|
155
159
|
mcpServer.registerTool('analyze_app', {
|
|
156
|
-
description: 'Analyze a deployed web app for quality gaps. Default response is summary-first (top gaps, cost summary, next checks). Set includeFullReport for the full gapAnalysis. Optional llmMaxOutputTokensPerCall / llmTokenBudget (legacy), testGenerationLimit, enableLlmScenarios align with @qulib/core HarnessConfig.',
|
|
160
|
+
description: 'Analyze a deployed web app for quality gaps. Default response is summary-first (top gaps, cost summary, next checks). Set includeFullReport for the full gapAnalysis. Set agentSummary for the compact gate-decision payload (pass/warn/fail with honesty notes) — use this when calling from a CI gate or orchestrator. Optional llmMaxOutputTokensPerCall / llmTokenBudget (legacy), testGenerationLimit, enableLlmScenarios align with @qulib/core HarnessConfig.',
|
|
157
161
|
inputSchema: AnalyzeInputSchema,
|
|
158
162
|
}, async (input) => {
|
|
159
163
|
try {
|
|
@@ -202,7 +206,10 @@ mcpServer.registerTool('analyze_app', {
|
|
|
202
206
|
progressLog: mcpProgressLog,
|
|
203
207
|
telemetry: telemetrySink,
|
|
204
208
|
});
|
|
205
|
-
const payload =
|
|
209
|
+
const payload = buildAnalyzeAppMcpPayload(result, {
|
|
210
|
+
includeFullReport: input.includeFullReport,
|
|
211
|
+
agentSummary: input.agentSummary,
|
|
212
|
+
});
|
|
206
213
|
return {
|
|
207
214
|
content: [
|
|
208
215
|
{
|
|
@@ -254,5 +261,53 @@ mcpServer.registerTool('qulib_score_automation', {
|
|
|
254
261
|
return toolError('QULIB_REPO_SCORE_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
255
262
|
}
|
|
256
263
|
});
|
|
264
|
+
const ScaffoldTestsInputSchema = z.object({
|
|
265
|
+
url: z.string().url().describe('URL of the deployed web app to scaffold tests for'),
|
|
266
|
+
framework: z
|
|
267
|
+
.enum(['cypress-e2e', 'playwright'])
|
|
268
|
+
.optional()
|
|
269
|
+
.describe('Test framework to generate. Default: cypress-e2e'),
|
|
270
|
+
maxPagesToScan: z
|
|
271
|
+
.number()
|
|
272
|
+
.int()
|
|
273
|
+
.min(1)
|
|
274
|
+
.max(20)
|
|
275
|
+
.optional()
|
|
276
|
+
.describe('Max pages to crawl when running analyze_app internally. Default: 10'),
|
|
277
|
+
});
|
|
278
|
+
mcpServer.registerTool('qulib_scaffold_tests', {
|
|
279
|
+
description: 'Generate a ready-to-run test scaffold for a deployed web app. Crawls the URL, identifies quality gaps and user flows, then produces framework-specific test files (Cypress or Playwright) plus the project config (cypress.config.ts or playwright.config.ts) and package.json deps. Returns generatedTests (array of {filename, code, outputPath}) and projectConfig so an agent can write the files directly to a repo without any manual test-writing.',
|
|
280
|
+
inputSchema: ScaffoldTestsInputSchema,
|
|
281
|
+
}, async ({ url, framework, maxPagesToScan }) => {
|
|
282
|
+
try {
|
|
283
|
+
log.info(`qulib_scaffold_tests url=${url} framework=${framework ?? 'cypress-e2e'} maxPagesToScan=${maxPagesToScan ?? 10}`);
|
|
284
|
+
const result = await scaffoldTests(url, {
|
|
285
|
+
framework: framework ?? 'cypress-e2e',
|
|
286
|
+
maxPagesToScan: maxPagesToScan ?? 10,
|
|
287
|
+
progressLog: mcpProgressLog,
|
|
288
|
+
telemetry: telemetrySink,
|
|
289
|
+
});
|
|
290
|
+
return {
|
|
291
|
+
content: [
|
|
292
|
+
{
|
|
293
|
+
type: 'text',
|
|
294
|
+
text: JSON.stringify({
|
|
295
|
+
url: result.url,
|
|
296
|
+
framework: result.framework,
|
|
297
|
+
scenarioCount: result.scenarios.length,
|
|
298
|
+
testCount: result.generatedTests.length,
|
|
299
|
+
generatedTests: result.generatedTests,
|
|
300
|
+
projectConfig: result.projectConfig,
|
|
301
|
+
}, null, 2),
|
|
302
|
+
},
|
|
303
|
+
],
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
catch (err) {
|
|
307
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
308
|
+
log.error(`qulib_scaffold_tests failed: ${msg}`);
|
|
309
|
+
return toolError('QULIB_SCAFFOLD_FAILED', msg, err instanceof Error ? err.stack : undefined);
|
|
310
|
+
}
|
|
311
|
+
});
|
|
257
312
|
const transport = new StdioServerTransport();
|
|
258
313
|
await mcpServer.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qulib/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "MCP server for Qulib — AI-callable QA gap analysis",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Tapesh Nagarwal",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"scripts": {
|
|
30
30
|
"build": "npm --prefix ../.. run build -w @qulib/core && tsc && chmod +x dist/index.js",
|
|
31
31
|
"dev": "tsx src/index.ts",
|
|
32
|
-
"test": "node --import tsx/esm --test src/__tests__/summarize-analyze-result.test.ts"
|
|
32
|
+
"test": "node --import tsx/esm --test src/__tests__/summarize-analyze-result.test.ts src/__tests__/analyze-app-mcp-payload.test.ts"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
36
|
-
"@qulib/core": "0.
|
|
36
|
+
"@qulib/core": "0.7.0",
|
|
37
37
|
"zod": "^3.23.0"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|