@certscore/mcp 0.2.19 → 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,5 +1,8 @@
1
+ import type { McpResponseSummary } from "@website-signal-risk-scanner/shared";
2
+ import { type McpCallerInput } from "@website-signal-risk-scanner/shared/dist/mcp-caller-input.js";
1
3
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { RequestInfo } from "@modelcontextprotocol/sdk/types.js";
4
+ import { type RequestInfo } from "@modelcontextprotocol/sdk/types.js";
5
+ import { type McpTaskContext } from "@website-signal-risk-scanner/shared/dist/mcp-product-context.js";
3
6
  export interface CertScoreMcpOptions {
4
7
  apiKey?: string;
5
8
  baseUrl?: string;
@@ -12,12 +15,44 @@ export interface CertScoreMcpOptions {
12
15
  toolProfile?: "full" | "light";
13
16
  initialPreConsentPreviewWaitMs?: number;
14
17
  exampleDomainDemoUrl?: string | null;
18
+ onToolInvocationStarted?: (input: {
19
+ requestId: string;
20
+ toolName: string;
21
+ startedAt: string;
22
+ }) => void | Promise<void>;
15
23
  onToolInvocation?: (observation: McpToolInvocationObservation, requestContext: McpToolInvocationRequestContext) => void | Promise<void>;
16
24
  }
17
25
  export type McpToolInvocationRequestContext = {
18
26
  headers: RequestInfo["headers"] | null;
19
27
  };
20
28
  export type McpToolInvocationObservation = {
29
+ requestId?: string;
30
+ timing?: {
31
+ startedAt: string;
32
+ responseGeneratedAt: string;
33
+ };
34
+ callerInput?: McpCallerInput;
35
+ captureBasis?: "protocol_request";
36
+ taskContext?: McpTaskContext;
37
+ response?: {
38
+ bytes: number | null;
39
+ truncated: boolean | null;
40
+ effectiveMaxBytes?: number;
41
+ summary?: McpResponseSummary;
42
+ };
43
+ requestArguments?: {
44
+ values: Record<string, string | number | boolean>;
45
+ omitted: boolean;
46
+ };
47
+ rateLimit?: {
48
+ kind: "scan_creation" | "upstream";
49
+ retryAfterSeconds?: number;
50
+ scope?: string;
51
+ windowId?: string;
52
+ limit?: number;
53
+ used?: number;
54
+ windowSeconds?: number;
55
+ };
21
56
  durationMs: number;
22
57
  errorCode: string | null;
23
58
  freshness: "latest" | "refresh" | null;
@@ -34,6 +69,11 @@ export type McpToolInvocationObservation = {
34
69
  toolName: string;
35
70
  transportOutcome: "mcp_result" | "mcp_error";
36
71
  };
72
+ /** Retain only bounded tool options; URL paths, queries and unknown/free-text inputs are omitted. */
73
+ export declare function projectMcpTelemetryArguments(args: Record<string, unknown>): {
74
+ values: Record<string, string | number | boolean>;
75
+ omitted: boolean;
76
+ };
37
77
  export declare function projectMcpToolInvocationObservation(input: {
38
78
  args: unknown;
39
79
  durationMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAItE,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,wBAAwB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9E,gCAAgC,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACvD,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,gBAAgB,CAAC,EAAE,WAAW,GAAG,eAAe,GAAG,IAAI,CAAC;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/B,8BAA8B,CAAC,EAAE,MAAM,CAAC;IACxC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,gBAAgB,CAAC,EAAE,CACjB,WAAW,EAAE,4BAA4B,EACzC,cAAc,EAAE,+BAA+B,KAC5C,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAID,MAAM,MAAM,+BAA+B,GAAG;IAC5C,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;CACxC,CAAC;AA4BF,MAAM,MAAM,4BAA4B,GAAG;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC;IACvC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,SAAS,GAAG,OAAO,GAAG,cAAc,CAAC;IAC9C,YAAY,EAAE,SAAS,GAAG,cAAc,CAAC;IACzC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,qBAAqB,EAAE,KAAK,GAAG,QAAQ,GAAG,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC;IACtE,YAAY,EAAE,QAAQ,GAAG,KAAK,GAAG,aAAa,GAAG,gBAAgB,CAAC;IAClE,QAAQ,EAAE,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,IAAI,CAAC;IAClD,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,YAAY,GAAG,WAAW,CAAC;CAC9C,CAAC;AAqKF,wBAAgB,mCAAmC,CAAC,KAAK,EAAE;IACzD,IAAI,EAAE,OAAO,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,4BAA4B,CAqD/B;AAkBD,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,mBAAwB,aAwZzE"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/dist/server.js CHANGED
@@ -1,6 +1,12 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { captureMcpResponse, withResponseCapture } from "./response-capture.js";
3
+ import { z } from "zod";
4
+ import { captureMcpCallerInput } from "@website-signal-risk-scanner/shared/dist/mcp-caller-input.js";
1
5
  import { CertScoreClient } from "@certscore/sdk";
2
6
  import { certScoreMcpToolContracts, isCanonicalScanId } from "@certscore/api-contracts";
3
7
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
8
+ import { CallToolRequestSchema, ErrorCode, McpError } from "@modelcontextprotocol/sdk/types.js";
9
+ import { sanitizeMcpTaskContext } from "@website-signal-risk-scanner/shared/dist/mcp-product-context.js";
4
10
  import { CERTSCORE_MCP_VERSION } from "./version.js";
5
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";
6
12
  const LIGHT_MCP_BUNDLE_RESPONSE_CEILING_BYTES = 25_000;
@@ -159,6 +165,38 @@ function isCertScoreCanaryUrl(value) {
159
165
  return false;
160
166
  }
161
167
  }
168
+ /** Retain only bounded tool options; URL paths, queries and unknown/free-text inputs are omitted. */
169
+ export function projectMcpTelemetryArguments(args) {
170
+ const values = {};
171
+ const options = {
172
+ freshness: ["latest", "refresh"], scanFrom: ["eu_de", "eu_ie", "california"],
173
+ detail: ["tiny", "quick", "standard", "full", "summary", "evidence", "findings"], format: ["json", "markdown"],
174
+ };
175
+ for (const [key, allowed] of Object.entries(options)) {
176
+ if (typeof args[key] === "string" && allowed.includes(args[key]))
177
+ values[key] = args[key];
178
+ }
179
+ for (const key of ["scanId", "jobId", "findingId"]) {
180
+ const token = boundedTelemetryToken(args[key], 128);
181
+ if (token)
182
+ values[key] = token;
183
+ }
184
+ for (const key of ["maxWaitSeconds", "maxBytes", "maxFindings", "maxPreConsentRows", "maxRows", "limit", "offset"]) {
185
+ const value = args[key];
186
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 1_000_000)
187
+ values[key] = value;
188
+ }
189
+ if (typeof args.waitForCompletion === "boolean")
190
+ values.waitForCompletion = args.waitForCompletion;
191
+ const url = telemetryUrl(args.url);
192
+ if (url)
193
+ values.url = url;
194
+ const domain = telemetryHostname(args.domain);
195
+ if (domain && /^[a-z0-9.-]+$/.test(domain))
196
+ values.domain = domain;
197
+ const omitted = Object.keys(args).some((key) => !(key in values) || args[key] !== values[key]);
198
+ return { values, omitted };
199
+ }
162
200
  export function projectMcpToolInvocationObservation(input) {
163
201
  const args = input.args && typeof input.args === "object" && !Array.isArray(input.args)
164
202
  ? input.args
@@ -167,9 +205,17 @@ export function projectMcpToolInvocationObservation(input) {
167
205
  const error = result.error && typeof result.error === "object" && !Array.isArray(result.error)
168
206
  ? result.error
169
207
  : null;
170
- 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);
171
216
  const rateLimited = errorCode === "rate_limited" || result.status === "rate_limited";
172
- const isError = Boolean(input.result?.isError) || Boolean(error);
217
+ const isError = !completedNoGo
218
+ && (Boolean(input.result?.isError) || Boolean(error));
173
219
  const outcome = rateLimited ? "rate_limited" : isError ? "error" : "success";
174
220
  const resultScanId = boundedTelemetryToken(result.scanId ?? result.scan_id ?? result.jobId, 128);
175
221
  const inputScanId = boundedTelemetryToken(args.scanId, 128);
@@ -192,6 +238,8 @@ export function projectMcpToolInvocationObservation(input) {
192
238
  ? "new"
193
239
  : "unavailable";
194
240
  return {
241
+ requestArguments: projectMcpTelemetryArguments(args),
242
+ ...(rateLimited ? { rateLimit: projectMcpRateLimit(error ?? result) } : {}),
195
243
  durationMs: Math.max(0, Math.min(Math.round(input.durationMs), 3_600_000)),
196
244
  errorCode: rateLimited ? "rate_limited" : errorCode,
197
245
  freshness: args.freshness === "refresh" ? "refresh" : input.toolName === "certscore_scan_site" ? "latest" : null,
@@ -205,13 +253,30 @@ export function projectMcpToolInvocationObservation(input) {
205
253
  : result.scanFrom === "eu_de" || result.scanFrom === "eu_ie" || result.scanFrom === "california"
206
254
  ? result.scanFrom
207
255
  : null,
208
- scanId: resultScanId ?? inputScanId,
256
+ scanId: outcome === "error" && ["invalid_scan_id", "invalid_arguments", "invalid_url", "unknown_tool"].includes(errorCode ?? "")
257
+ ? null : resultScanId ?? inputScanId,
209
258
  scanStatus: boundedTelemetryToken(result.status, 64),
210
259
  targetHostname,
211
260
  toolName: input.toolName,
212
261
  transportOutcome: isError ? "mcp_error" : "mcp_result",
213
262
  };
214
263
  }
264
+ function projectMcpRateLimit(error) {
265
+ const creation = error.creationRateLimit && typeof error.creationRateLimit === "object" && !Array.isArray(error.creationRateLimit)
266
+ ? error.creationRateLimit : null;
267
+ const projected = { kind: creation ? "scan_creation" : "upstream" };
268
+ for (const key of ["scope", "windowId"]) {
269
+ const value = boundedTelemetryToken(creation?.[key], 128);
270
+ if (value)
271
+ projected[key] = value;
272
+ }
273
+ for (const key of ["retryAfterSeconds", "limit", "used", "windowSeconds"]) {
274
+ const value = key === "retryAfterSeconds" ? error[key] : creation?.[key];
275
+ if (typeof value === "number" && Number.isInteger(value) && value >= 0 && value <= 1_000_000)
276
+ projected[key] = value;
277
+ }
278
+ return projected;
279
+ }
215
280
  function observeToolInvocation(observer, observation, requestContext) {
216
281
  if (!observer)
217
282
  return;
@@ -247,6 +312,7 @@ export function createCertScoreMcpServer(options = {}) {
247
312
  server.createToolError = (message) => message.includes("Input validation error:")
248
313
  ? toInvalidArgumentsToolError(message)
249
314
  : sdkCreateToolError(message);
315
+ const registeredToolNames = new Set();
250
316
  const lightTools = new Set(["certscore_scan_site", "certscore_get_scan_status", "certscore_get_scan_bundle"]);
251
317
  const scanIdTools = new Set([
252
318
  "certscore_explain_finding",
@@ -259,44 +325,105 @@ export function createCertScoreMcpServer(options = {}) {
259
325
  "certscore_get_scan_status",
260
326
  "certscore_list_findings",
261
327
  ]);
262
- const registerMcpTool = server.registerTool.bind(server);
263
- const registerTool = (name, contract, handler) => {
264
- if (options.toolProfile === "light" && !lightTools.has(name)) {
265
- return;
266
- }
267
- const typedHandler = handler;
268
- registerMcpTool(name, contract, async (input, extra) => {
328
+ // Intercept SDK registration through its public API so lookup/validation errors
329
+ // and original arguments are observed once, before SDK normalization. Restore
330
+ // the registration method after constructing this server; no private handler map.
331
+ const registerRequest = server.server.setRequestHandler.bind(server.server);
332
+ server.server.setRequestHandler = ((schema, handler) => {
333
+ if (schema !== CallToolRequestSchema)
334
+ return registerRequest(schema, handler);
335
+ return registerRequest(CallToolRequestSchema, async (request, extra) => {
269
336
  const startedAt = Date.now();
337
+ const requestId = randomUUID();
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
+ }
343
+ const args = request.params.arguments ?? {};
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);
355
+ let result;
356
+ let protocolFailure;
270
357
  try {
271
- const scanId = input && typeof input === "object" && !Array.isArray(input)
272
- ? input.scanId
273
- : null;
274
- const result = scanIdTools.has(name) && !isCanonicalScanId(scanId)
275
- ? toInvalidScanIdToolError()
276
- : await typedHandler(input, extra);
277
- observeToolInvocation(options.onToolInvocation, projectMcpToolInvocationObservation({
278
- args: input,
279
- durationMs: Date.now() - startedAt,
280
- result,
281
- toolName: name,
282
- }), { headers: extra.requestInfo?.headers ?? null });
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
+ });
283
377
  return result;
284
378
  }
285
379
  catch (error) {
286
- observeToolInvocation(options.onToolInvocation, {
287
- ...projectMcpToolInvocationObservation({
288
- args: input,
289
- durationMs: Date.now() - startedAt,
290
- result: { isError: true, structuredContent: { error: { code: "handler_exception" } } },
291
- toolName: name,
292
- }),
293
- errorCode: "handler_exception",
294
- outcome: "error",
295
- transportOutcome: "mcp_error",
296
- }, { headers: extra.requestInfo?.headers ?? null });
380
+ protocolFailure = error;
381
+ result ??= { isError: true, structuredContent: { error: { code: "handler_exception" } } };
297
382
  throw error;
298
383
  }
384
+ finally {
385
+ try {
386
+ const observation = projectMcpToolInvocationObservation({ args, durationMs: Date.now() - startedAt, result, toolName: name });
387
+ if (!known)
388
+ observation.errorCode = "unknown_tool";
389
+ else if (observation.outcome === "error" && !observation.errorCode)
390
+ observation.errorCode = "protocol_error";
391
+ const payload = telemetryResultRecord(result);
392
+ const metadata = payload.mcpMetadata;
393
+ observeToolInvocation(options.onToolInvocation, {
394
+ ...observation,
395
+ requestId,
396
+ timing: { startedAt: new Date(startedAt).toISOString(), responseGeneratedAt: new Date().toISOString() },
397
+ captureBasis: "protocol_request",
398
+ callerInput: captureMcpCallerInput(args, request.params._meta),
399
+ ...(taskContext ? { taskContext } : {}),
400
+ response: {
401
+ summary: captureMcpResponse(result, protocolFailure),
402
+ bytes: protocolFailure ? null : Math.min(10_000_000, Buffer.byteLength(JSON.stringify(result ?? null))),
403
+ truncated: typeof metadata?.truncated === "boolean" ? metadata.truncated : null,
404
+ ...(typeof metadata?.effectiveMaxBytes === "number" ? { effectiveMaxBytes: metadata.effectiveMaxBytes } : {}),
405
+ },
406
+ }, { headers: extra.requestInfo?.headers ?? null });
407
+ }
408
+ catch {
409
+ // Best-effort telemetry must never replace a tool response or its error.
410
+ console.error("[certscore-mcp] telemetry projection failed");
411
+ }
412
+ }
299
413
  });
414
+ });
415
+ const registerMcpTool = server.registerTool.bind(server);
416
+ const registerTool = (name, contract, handler) => {
417
+ if (options.toolProfile === "light" && !lightTools.has(name))
418
+ return;
419
+ const typedHandler = handler;
420
+ registerMcpTool(name, contract, async (input, extra) => {
421
+ const scanId = input && typeof input === "object" && !Array.isArray(input)
422
+ ? input.scanId : null;
423
+ return scanIdTools.has(name) && !isCanonicalScanId(scanId)
424
+ ? toInvalidScanIdToolError() : typedHandler(input, extra);
425
+ });
426
+ registeredToolNames.add(name);
300
427
  };
301
428
  registerTool("certscore_scan_site", toolContract("certscore_scan_site"), async (input, extra) => {
302
429
  const toolStartedAtMs = Date.now();
@@ -304,11 +431,13 @@ export function createCertScoreMcpServer(options = {}) {
304
431
  const client = clientForRequest(extra);
305
432
  const demoSubstitution = exampleDomainDemoSubstitution(input.url, options.exampleDomainDemoUrl);
306
433
  const effectiveUrl = demoSubstitution?.effectiveUrl ?? input.url;
434
+ let creationCompleted = false;
307
435
  try {
308
436
  const created = await client.scans.create(effectiveUrl, {
309
437
  freshness: input.freshness ?? "latest",
310
438
  scanFrom: input.scanFrom
311
439
  });
440
+ creationCompleted = true;
312
441
  console.log(JSON.stringify({
313
442
  event: "mcp.certscore_scan_site.creation_completed",
314
443
  durationMs: Date.now() - creationStartedAtMs,
@@ -387,7 +516,7 @@ export function createCertScoreMcpServer(options = {}) {
387
516
  durationMs: Date.now() - creationStartedAtMs,
388
517
  errorName: error instanceof Error ? error.name : "UnknownError",
389
518
  }));
390
- return toToolError(error);
519
+ return toToolError(error, { scanCreation: !creationCompleted });
391
520
  }
392
521
  });
393
522
  registerTool("certscore_get_scan", toolContract("certscore_get_scan"), async ({ scanId }) => {
@@ -560,5 +689,6 @@ export function createCertScoreMcpServer(options = {}) {
560
689
  return toToolError(error);
561
690
  }
562
691
  });
692
+ server.server.setRequestHandler = registerRequest;
563
693
  return server;
564
694
  }
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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"}