Files
rea/tests/fixtures/mcpAdvertisedSchemaValidity.ts
morluto 7bcefead69 test: strengthen and prune audited test coverage (#8573)
* test: strengthen and prune audited test coverage

* test: require delivered DeepSeek skill instructions

* test: keep schema fixture types private

* test: verify Gemini receives skill instructions

* test: bind Qwen skill evidence to its tool result

* test: report NativeAOT verifier checks precisely

* fix: verify Ghidra cleanup paths reliably

* fix: verify Command Code skill activation

* test: tighten cleanup and fixture checks

* test: verify packet capture evidence is recorded

* fix: report HTTP3 capture provenance accurately

* test: preserve resource coverage through MCP

* test: prune repeated assertions and retain cancellation identity

* fix: validate client verifier fixture paths

* test: skip Copilot verifier cases on Windows

* test: keep verifier setup target relative
2026-11-02 02:13:32 +08:00

68 lines
2.4 KiB
TypeScript

import { Ajv2020 } from "ajv/dist/2020.js";
import {
arrayItemSchemaError,
unsupportedInputLiteralSchemaError,
} from "./mcpClientSchemaConstraints.js";
/** Advertised schema pair as a client receives it from `tools/list`. */
interface AdvertisedToolSchemas {
readonly name: string;
readonly inputSchema: Record<string, unknown>;
readonly outputSchema?: Record<string, unknown> | undefined;
}
/**
* Validate advertised schemas as clients receive them: Ajv's declared-dialect
* meta-schema and reference resolution, then the constraints a real client
* enforces. Compiling catches a compact projection that drops a referenced
* definition or leaves a local `$ref` without its target, which a byte-budget
* assertion alone would not.
*/
export function advertisedSchemaErrors(
tools: readonly AdvertisedToolSchemas[],
): string[] {
// Reuse Ajv's meta-schema validators, then clear each root's reference
// namespace, including nested IDs, before validating the next schema.
const ajv = new Ajv2020({
strict: false,
validateFormats: false,
addUsedSchema: false,
// This check compiles schemas to detect invalid references but never runs
// their validators. Generated-code optimization adds substantial work here
// without checking another contract; actual SDK validators keep defaults.
code: { optimize: false },
});
return tools.flatMap((tool) =>
["inputSchema", "outputSchema"].flatMap((kind) => {
const schema =
kind === "inputSchema" ? tool.inputSchema : tool.outputSchema;
if (schema === undefined) return [];
try {
if (!ajv.validateSchema(schema))
return [`${tool.name}.${kind}: ${ajv.errorsText(ajv.errors)}`];
ajv.compile(schema);
const clientError = arrayItemSchemaError(
schema,
`${tool.name}.${kind}`,
);
if (clientError !== undefined) return [clientError];
if (kind === "inputSchema") {
const literalError = unsupportedInputLiteralSchemaError(
schema,
`${tool.name}.${kind}`,
);
if (literalError !== undefined) return [literalError];
}
return [];
} catch (cause: unknown) {
return [
`${tool.name}.${kind}: ${cause instanceof Error ? cause.message : String(cause)}`,
];
} finally {
ajv.removeSchema();
}
}),
);
}