Files
reverse-engineering-anything/src/contracts/compactOutputSchema.ts
T
gensokyo-devandAkshad Jogi 9085222ca1 feat(mcp): support compact output schema advertisements (#7218)
Add opt-in bounded output-schema advertisements while preserving the full default, canonical server validation and complete structured content. Verify real stdio discovery under a 1 MiB receive cap, all 5,367 libcrypto export coordinates, complete Evidence parity, whole-task serialization estimates and resource bounds.

Fixes #2512. Integrates #7054 by Akshad Jogi with original authorship retained.

Co-authored-by: Akshad Jogi <akshadjogi@gmail.com>
2026-10-26 17:59:51 +08:00

96 lines
3.6 KiB
TypeScript

import {
COMPACT_SCHEMA_MAX_DEPTH,
inlineWithinBudget,
isSchemaObject,
jsonValueSchema,
reduceToShallowProperties,
schemaDepth,
serializedBytes,
stripAnnotations,
} from "./compactJsonSchema.js";
// Output schemas dominate a complete `tools/list` frame. The compact profile
// bounds each advertised output contract so frame-capped hosts can finish the
// handshake, while canonical result validation and `structuredContent` stay
// unchanged. Every projection is a widening: a valid canonical result always
// satisfies the advertised schema.
export type AdvertisedOutputSchemaPresentation = "inline" | "reduced";
/** Budget selected by the caller for compact MCP output-schema presentation. */
export interface CompactOutputSchemaPresentation {
readonly budgetBytes: number;
}
export interface CompactedOutputSchema {
readonly schema: Record<string, unknown>;
readonly presentation: AdvertisedOutputSchemaPresentation;
}
const OUTPUT_REDUCED_ANNOTATION =
"Advertised in reduced form by the compact output schema profile; the server still validates complete canonical results.";
/**
* Drop the canonical contract's content-bound `$id` and anchors. The compact
* bytes differ from the canonical schema the identity was derived from, so
* retaining that identity would misstate what the advertised document is.
* References are already inlined, so no identity is needed to resolve them.
*/
const withoutContentBoundIdentity = (
schema: Record<string, unknown>,
): Record<string, unknown> => {
const { $id: _id, $anchor: _anchor, ...advertised } = schema;
return advertised;
};
/**
* Render an advertised output schema within a per-schema byte budget. The
* complete validation structure is kept when it fits; otherwise the root
* property shape and first-level types remain and nested detail is elided.
* The registered canonical schema still validates every delivered result.
*/
export const compactAdvertisedOutputSchema = (
schema: Record<string, unknown>,
budgetBytes: number,
): CompactedOutputSchema => {
const inline = inlineWithinBudget(stripAnnotations(schema), budgetBytes);
if (inline !== undefined && schemaDepth(inline) <= COMPACT_SCHEMA_MAX_DEPTH)
return {
schema: withoutContentBoundIdentity(inline),
presentation: "inline",
};
// Every REA output contract is an object at the root. A non-object root still
// advertises an accepting shape rather than a projection that could reject
// valid canonical output.
const reduced =
schema.type === "object" || isSchemaObject(schema.properties)
? reduceToShallowProperties(schema, OUTPUT_REDUCED_ANNOTATION)
: jsonValueSchema();
if (serializedBytes(reduced) <= budgetBytes)
return {
schema: withoutContentBoundIdentity(reduced),
presentation: "reduced",
};
// A root description can itself be large; keep the advertisement inside the
// budget instead of carrying it into a shape with no nested detail left.
const minimal = reduceToShallowProperties(
{ type: "object" },
OUTPUT_REDUCED_ANNOTATION,
);
return {
schema:
serializedBytes(minimal) <= budgetBytes ? minimal : jsonValueSchema(),
presentation: "reduced",
};
};
/** Return the JSON schema clients receive for the selected output presentation. */
export const presentAdvertisedOutputSchema = (
schema: Record<string, unknown>,
compactPresentation: CompactOutputSchemaPresentation | undefined,
): Record<string, unknown> =>
compactPresentation === undefined
? schema
: compactAdvertisedOutputSchema(schema, compactPresentation.budgetBytes)
.schema;