@certscore/mcp 0.2.20 → 0.2.21

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 CHANGED
@@ -11,4 +11,5 @@ export declare function getCertScoreMcpDoctorReport(options?: CertScoreMcpDoctor
11
11
  exitCode: number;
12
12
  lines: string[];
13
13
  }>;
14
+ export { captureMcpResponse, withResponseCapture } from "./response-capture.js";
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAMrD,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgDD,wBAAsB,2BAA2B,CAAC,OAAO,GAAE,yBAA8B;;;GAyFxF"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AAMrD,MAAM,WAAW,yBAAyB;IACxC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACzC,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgDD,wBAAsB,2BAA2B,CAAC,OAAO,GAAE,yBAA8B;;;GAyFxF;AAsBD,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
package/dist/index.js CHANGED
@@ -163,3 +163,4 @@ if (isMainModule()) {
163
163
  process.exitCode = 1;
164
164
  });
165
165
  }
166
+ export { captureMcpResponse, withResponseCapture } from "./response-capture.js";
@@ -0,0 +1,12 @@
1
+ import { type McpResponseSummary } from "@website-signal-risk-scanner/shared/dist/mcp-response-summary.js";
2
+ type SafeMetadata = {
3
+ message?: string;
4
+ recommendedNextAction?: string;
5
+ upstream?: McpResponseSummary["upstream"];
6
+ };
7
+ /** Only call with template-owned text. Never mark upstream messages or caller values. */
8
+ export declare function withResponseCapture<T extends object>(result: T, metadata: SafeMetadata): T;
9
+ export declare function transferResponseCapture<T extends object>(payload: unknown, result: T): T;
10
+ export declare function captureMcpResponse(result: unknown, protocolError?: unknown): McpResponseSummary;
11
+ export {};
12
+ //# sourceMappingURL=response-capture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response-capture.d.ts","sourceRoot":"","sources":["../src/response-capture.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,kBAAkB,EAAE,MAAM,kEAAkE,CAAC;AAErI,KAAK,YAAY,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAA;CAAE,CAAC;AAEpH,yFAAyF;AACzF,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,YAAY,GAAG,CAAC,CAG1F;AACD,wBAAgB,uBAAuB,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAGxF;AAGD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,EAAE,aAAa,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAsC/F"}
@@ -0,0 +1,64 @@
1
+ import { mcpResponseSummarySchema } from "@website-signal-risk-scanner/shared/dist/mcp-response-summary.js";
2
+ const controlled = new WeakMap();
3
+ /** Only call with template-owned text. Never mark upstream messages or caller values. */
4
+ export function withResponseCapture(result, metadata) {
5
+ controlled.set(result, metadata);
6
+ return result;
7
+ }
8
+ export function transferResponseCapture(payload, result) {
9
+ const metadata = payload && typeof payload === "object" ? controlled.get(payload) : undefined;
10
+ return metadata ? withResponseCapture(result, metadata) : result;
11
+ }
12
+ const record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
13
+ const token = (value) => typeof value === "string" && /^[a-zA-Z0-9_.:-]{1,80}$/.test(value) ? value : undefined;
14
+ export function captureMcpResponse(result, protocolError) {
15
+ const outer = record(result);
16
+ let payload = record(outer.structuredContent);
17
+ if (!Object.keys(payload).length && Array.isArray(outer.content)) {
18
+ const text = outer.content.find((item) => item?.type === "text")?.text;
19
+ if (typeof text === "string") {
20
+ try {
21
+ payload = record(JSON.parse(text));
22
+ }
23
+ catch { /* Markdown is never retained. */ }
24
+ }
25
+ }
26
+ const protocol = record(protocolError);
27
+ const error = protocolError ? record(protocol.data) : record(payload.error);
28
+ const safe = controlled.get(protocolError ? protocol : outer) ?? {};
29
+ const retryAfterSeconds = Object.hasOwn(error, "retryAfterSeconds") ? error.retryAfterSeconds : payload.retryAfterSeconds;
30
+ const summary = {
31
+ version: 1, captureBasis: "response_generated", templateVersion: "2026-09-11.1",
32
+ kind: protocolError ? "protocol_error" : "tool_result", isError: protocolError ? true : outer.isError === true,
33
+ type: token(payload.type), status: token(payload.status), errorCode: token(error.code), reasonCode: token(error.reasonCode),
34
+ ...(Number.isInteger(protocolError ? protocol.code : error.mcpCode) ? { mcpCode: protocolError ? protocol.code : error.mcpCode } : {}),
35
+ ...(typeof error.retryable === "boolean" ? { retryable: error.retryable } : {}),
36
+ ...(retryAfterSeconds === null || Number.isInteger(retryAfterSeconds) && retryAfterSeconds >= 0 && retryAfterSeconds <= 86400 ? { retryAfterSeconds } : {}),
37
+ recommendedNextTool: payload.recommendedNextTool === null ? null : token(payload.recommendedNextTool),
38
+ ...safe,
39
+ textOmitted: Boolean((protocolError ? protocol.message : error.message) && !safe.message || (error.recommendedNextAction || payload.recommendedNextAction) && !safe.recommendedNextAction),
40
+ summaryTruncated: false,
41
+ };
42
+ // Issues are captured only from our controlled validation response.
43
+ if (safe.message && Array.isArray(error.issues))
44
+ summary.issues = error.issues.slice(0, 8).map((issue) => ({ field: token(issue.field) ?? "arguments", code: token(issue.code) ?? "invalid", ...(issue.required === true ? { required: true } : {}) }));
45
+ for (const [key, limit] of [["message", 400], ["recommendedNextAction", 800]]) {
46
+ if ((summary[key]?.length ?? 0) > limit) {
47
+ summary[key] = summary[key].slice(0, limit);
48
+ summary.summaryTruncated = true;
49
+ }
50
+ }
51
+ // Bound UTF-8 bytes as well as character counts; preserve diagnosis before prose.
52
+ for (const key of ["recommendedNextAction", "message", "issues"]) {
53
+ if (Buffer.byteLength(JSON.stringify(summary)) <= 2048)
54
+ break;
55
+ delete summary[key];
56
+ summary.summaryTruncated = true;
57
+ summary.textOmitted = true;
58
+ }
59
+ const parsed = mcpResponseSummarySchema.safeParse(summary);
60
+ return parsed.success ? parsed.data : {
61
+ version: 1, captureBasis: "response_generated", templateVersion: "2026-09-11.1",
62
+ kind: summary.kind, isError: summary.isError, textOmitted: true, summaryTruncated: true,
63
+ };
64
+ }
package/dist/server.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { McpResponseSummary } from "@website-signal-risk-scanner/shared";
1
2
  import { type McpCallerInput } from "@website-signal-risk-scanner/shared/dist/mcp-caller-input.js";
2
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
4
  import { type RequestInfo } from "@modelcontextprotocol/sdk/types.js";
@@ -14,19 +15,30 @@ export interface CertScoreMcpOptions {
14
15
  toolProfile?: "full" | "light";
15
16
  initialPreConsentPreviewWaitMs?: number;
16
17
  exampleDomainDemoUrl?: string | null;
18
+ onToolInvocationStarted?: (input: {
19
+ requestId: string;
20
+ toolName: string;
21
+ startedAt: string;
22
+ }) => void | Promise<void>;
17
23
  onToolInvocation?: (observation: McpToolInvocationObservation, requestContext: McpToolInvocationRequestContext) => void | Promise<void>;
18
24
  }
19
25
  export type McpToolInvocationRequestContext = {
20
26
  headers: RequestInfo["headers"] | null;
21
27
  };
22
28
  export type McpToolInvocationObservation = {
29
+ requestId?: string;
30
+ timing?: {
31
+ startedAt: string;
32
+ responseGeneratedAt: string;
33
+ };
23
34
  callerInput?: McpCallerInput;
24
35
  captureBasis?: "protocol_request";
25
36
  taskContext?: McpTaskContext;
26
37
  response?: {
27
- bytes: number;
38
+ bytes: number | null;
28
39
  truncated: boolean | null;
29
40
  effectiveMaxBytes?: number;
41
+ summary?: McpResponseSummary;
30
42
  };
31
43
  requestArguments?: {
32
44
  values: Record<string, string | number | boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -1,8 +1,11 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { captureMcpResponse, withResponseCapture } from "./response-capture.js";
3
+ import { z } from "zod";
1
4
  import { captureMcpCallerInput } from "@website-signal-risk-scanner/shared/dist/mcp-caller-input.js";
2
5
  import { CertScoreClient } from "@certscore/sdk";
3
6
  import { certScoreMcpToolContracts, isCanonicalScanId } from "@certscore/api-contracts";
4
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
- import { CallToolRequestSchema } from "@modelcontextprotocol/sdk/types.js";
8
+ import { CallToolRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
6
9
  import { sanitizeMcpTaskContext } from "@website-signal-risk-scanner/shared/dist/mcp-product-context.js";
7
10
  import { CERTSCORE_MCP_VERSION } from "./version.js";
8
11
  import { boundEvidencePacket, buildScanBundle, exportFindings, findingListText, limitPreConsentRows, markdownReportText, MAX_EVIDENCE_PACKET_CHARS, normalizeDetail, normalizeFormat, paginateFindingList, preConsentInventoryText, pulseReportText, scanBundleText, scanSiteText, scanStatusText, toInvalidArgumentsToolError, toInvalidScanIdToolError, toToolError, toToolResult, withMcpAgentGuidance, withMcpScanProvenanceGuidance } from "./tools.js";
@@ -202,9 +205,17 @@ export function projectMcpToolInvocationObservation(input) {
202
205
  const error = result.error && typeof result.error === "object" && !Array.isArray(result.error)
203
206
  ? result.error
204
207
  : null;
205
- const errorCode = boundedTelemetryToken(error?.code ?? result.errorCode, 100);
208
+ const completedNoGo = result.status === "completed_limited"
209
+ && result.resultDisposition === "no_go";
210
+ // A completed no-go is a usable terminal scan result. Agent guidance embeds
211
+ // its reason-specific remedy in `error`, but the MCP tool call itself
212
+ // succeeded and must not be counted as a transport or invocation failure.
213
+ const errorCode = completedNoGo
214
+ ? null
215
+ : boundedTelemetryToken(error?.code ?? result.errorCode, 100);
206
216
  const rateLimited = errorCode === "rate_limited" || result.status === "rate_limited";
207
- const isError = Boolean(input.result?.isError) || Boolean(error);
217
+ const isError = !completedNoGo
218
+ && (Boolean(input.result?.isError) || Boolean(error));
208
219
  const outcome = rateLimited ? "rate_limited" : isError ? "error" : "success";
209
220
  const resultScanId = boundedTelemetryToken(result.scanId ?? result.scan_id ?? result.jobId, 128);
210
221
  const inputScanId = boundedTelemetryToken(args.scanId, 128);
@@ -242,7 +253,8 @@ export function projectMcpToolInvocationObservation(input) {
242
253
  : result.scanFrom === "eu_de" || result.scanFrom === "eu_ie" || result.scanFrom === "california"
243
254
  ? result.scanFrom
244
255
  : null,
245
- scanId: resultScanId ?? inputScanId,
256
+ scanId: outcome === "error" && ["invalid_scan_id", "invalid_arguments", "invalid_url", "unknown_tool"].includes(errorCode ?? "")
257
+ ? null : resultScanId ?? inputScanId,
246
258
  scanStatus: boundedTelemetryToken(result.status, 64),
247
259
  targetHostname,
248
260
  toolName: input.toolName,
@@ -300,6 +312,7 @@ export function createCertScoreMcpServer(options = {}) {
300
312
  server.createToolError = (message) => message.includes("Input validation error:")
301
313
  ? toInvalidArgumentsToolError(message)
302
314
  : sdkCreateToolError(message);
315
+ const registeredToolNames = new Set();
303
316
  const lightTools = new Set(["certscore_scan_site", "certscore_get_scan_status", "certscore_get_scan_bundle"]);
304
317
  const scanIdTools = new Set([
305
318
  "certscore_explain_finding",
@@ -321,17 +334,51 @@ export function createCertScoreMcpServer(options = {}) {
321
334
  return registerRequest(schema, handler);
322
335
  return registerRequest(CallToolRequestSchema, async (request, extra) => {
323
336
  const startedAt = Date.now();
337
+ const requestId = randomUUID();
324
338
  const name = request.params.name;
339
+ if (options.onToolInvocationStarted) {
340
+ void Promise.resolve().then(() => options.onToolInvocationStarted({ requestId, toolName: name, startedAt: new Date(startedAt).toISOString() }))
341
+ .catch(() => console.error("[certscore-mcp] request-start observation failed"));
342
+ }
325
343
  const args = request.params.arguments ?? {};
326
- const known = certScoreMcpToolContracts.some(tool => tool.name === name)
327
- && (options.toolProfile !== "light" || lightTools.has(name));
344
+ const taskContext = sanitizeMcpTaskContext(args.taskContext);
345
+ const forwardedRequest = name === "certscore_scan_site" && args.taskContext !== undefined && !taskContext
346
+ ? {
347
+ ...request,
348
+ params: {
349
+ ...request.params,
350
+ arguments: Object.fromEntries(Object.entries(args).filter(([key]) => key !== "taskContext")),
351
+ },
352
+ }
353
+ : request;
354
+ const known = registeredToolNames.has(name);
328
355
  let result;
356
+ let protocolFailure;
329
357
  try {
330
- result = await handler(request, extra);
358
+ if (!known) {
359
+ result = { isError: true, structuredContent: { error: { code: "unknown_tool" } } };
360
+ const availableTools = [...registeredToolNames];
361
+ const recommendedNextAction = "Refresh the available tools using your MCP client's tool discovery (tools/list), then call a supported tool.";
362
+ throw withResponseCapture(new McpError(ErrorCode.InvalidParams, `This tool is unavailable on this endpoint. ${recommendedNextAction} Available tools: ${availableTools.join(", ")}.`, { code: "unknown_tool", retryable: false, recommendedNextAction, availableTools }), { message: `This tool is unavailable on this endpoint. ${recommendedNextAction} Available tools: ${availableTools.join(", ")}.`, recommendedNextAction });
363
+ }
364
+ const contract = certScoreMcpToolContracts.find(candidate => candidate.name === name);
365
+ const validation = z.object(contract.inputSchema).safeParse(forwardedRequest.params.arguments ?? {});
366
+ result = validation.success
367
+ ? await handler(forwardedRequest, extra)
368
+ : toInvalidArgumentsToolError(`Input validation error: tool ${name}`, {
369
+ tool: name,
370
+ issues: validation.error.issues.map(issue => ({
371
+ // Only schema-owned top-level names; never echo values or dynamic keys.
372
+ field: typeof issue.path[0] === "string" && Object.hasOwn(contract.inputSchema, issue.path[0]) ? issue.path[0] : "arguments",
373
+ code: issue.code,
374
+ ...(issue.code === "invalid_type" && issue.received === "undefined" ? { required: true } : {}),
375
+ })).filter((issue, index, issues) => issues.findIndex(other => other.field === issue.field) === index).slice(0, 8),
376
+ });
331
377
  return result;
332
378
  }
333
379
  catch (error) {
334
- result = { isError: true, structuredContent: { error: { code: "handler_exception" } } };
380
+ protocolFailure = error;
381
+ result ??= { isError: true, structuredContent: { error: { code: "handler_exception" } } };
335
382
  throw error;
336
383
  }
337
384
  finally {
@@ -343,14 +390,16 @@ export function createCertScoreMcpServer(options = {}) {
343
390
  observation.errorCode = "protocol_error";
344
391
  const payload = telemetryResultRecord(result);
345
392
  const metadata = payload.mcpMetadata;
346
- const taskContext = sanitizeMcpTaskContext(args.taskContext);
347
393
  observeToolInvocation(options.onToolInvocation, {
348
394
  ...observation,
395
+ requestId,
396
+ timing: { startedAt: new Date(startedAt).toISOString(), responseGeneratedAt: new Date().toISOString() },
349
397
  captureBasis: "protocol_request",
350
398
  callerInput: captureMcpCallerInput(args, request.params._meta),
351
399
  ...(taskContext ? { taskContext } : {}),
352
400
  response: {
353
- bytes: Math.min(10_000_000, Buffer.byteLength(JSON.stringify(result ?? null))),
401
+ summary: captureMcpResponse(result, protocolFailure),
402
+ bytes: protocolFailure ? null : Math.min(10_000_000, Buffer.byteLength(JSON.stringify(result ?? null))),
354
403
  truncated: typeof metadata?.truncated === "boolean" ? metadata.truncated : null,
355
404
  ...(typeof metadata?.effectiveMaxBytes === "number" ? { effectiveMaxBytes: metadata.effectiveMaxBytes } : {}),
356
405
  },
@@ -374,6 +423,7 @@ export function createCertScoreMcpServer(options = {}) {
374
423
  return scanIdTools.has(name) && !isCanonicalScanId(scanId)
375
424
  ? toInvalidScanIdToolError() : typedHandler(input, extra);
376
425
  });
426
+ registeredToolNames.add(name);
377
427
  };
378
428
  registerTool("certscore_scan_site", toolContract("certscore_scan_site"), async (input, extra) => {
379
429
  const toolStartedAtMs = Date.now();
@@ -381,11 +431,13 @@ export function createCertScoreMcpServer(options = {}) {
381
431
  const client = clientForRequest(extra);
382
432
  const demoSubstitution = exampleDomainDemoSubstitution(input.url, options.exampleDomainDemoUrl);
383
433
  const effectiveUrl = demoSubstitution?.effectiveUrl ?? input.url;
434
+ let creationCompleted = false;
384
435
  try {
385
436
  const created = await client.scans.create(effectiveUrl, {
386
437
  freshness: input.freshness ?? "latest",
387
438
  scanFrom: input.scanFrom
388
439
  });
440
+ creationCompleted = true;
389
441
  console.log(JSON.stringify({
390
442
  event: "mcp.certscore_scan_site.creation_completed",
391
443
  durationMs: Date.now() - creationStartedAtMs,
@@ -464,7 +516,7 @@ export function createCertScoreMcpServer(options = {}) {
464
516
  durationMs: Date.now() - creationStartedAtMs,
465
517
  errorName: error instanceof Error ? error.name : "UnknownError",
466
518
  }));
467
- return toToolError(error);
519
+ return toToolError(error, { scanCreation: !creationCompleted });
468
520
  }
469
521
  });
470
522
  registerTool("certscore_get_scan", toolContract("certscore_get_scan"), async ({ scanId }) => {
package/dist/tools.d.ts CHANGED
@@ -13,8 +13,17 @@ type ActionableError = {
13
13
  mcpCode?: number;
14
14
  };
15
15
  export declare function toToolResult(payload: unknown, text?: string): CallToolResult;
16
- export declare function toToolError(error: unknown): CallToolResult;
17
- export declare function toInvalidArgumentsToolError(errorMessage: string): CallToolResult;
16
+ export declare function toToolError(error: unknown, context?: {
17
+ scanCreation?: boolean;
18
+ }): CallToolResult;
19
+ export declare function toInvalidArgumentsToolError(errorMessage: string, validation?: {
20
+ tool: string;
21
+ issues: {
22
+ field: string;
23
+ code: string;
24
+ required?: boolean;
25
+ }[];
26
+ }): CallToolResult;
18
27
  export declare function toInvalidScanIdToolError(): CallToolResult;
19
28
  export declare function withMcpAgentGuidance<T extends Record<string, any>>(value: T, fallbackProvenanceMode?: ScanProvenanceMode, pollGuidanceContext?: McpPollGuidanceContext): T & {
20
29
  error: ActionableError | null;
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}