From 0a15246d32bce2c80030cc25d499ed982d9ce9ff Mon Sep 17 00:00:00 2001 From: Chirag Date: Mon, 9 Nov 2026 18:31:52 +0530 Subject: [PATCH] docs(mcp): name the accepted seed kinds on trace_application_feature (#8220) * docs(mcp): name the accepted seed kinds on trace_application_feature The compact input profile reduces this schema to shallow properties, which drops the seed union and its kind enums, so agents could not see which kinds a seed accepts without reading the source. Describe the seed field with its kinds, match defaults and one example; shallow reduction keeps per-property descriptions, so the guidance survives the compact profile. Closes #8205 * test(mcp): isolate seed guidance catalog configuration --------- Co-authored-by: morluto <76467478+morluto@users.noreply.github.com> --- .../javascriptFeatureTraceSchemas.ts | 4 +- .../mcp/traceFeatureSeedGuidanceMcp.test.ts | 68 +++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 tests/boundary/mcp/traceFeatureSeedGuidanceMcp.test.ts diff --git a/src/domain/javascript/javascriptFeatureTraceSchemas.ts b/src/domain/javascript/javascriptFeatureTraceSchemas.ts index 8b6a90393b..cfef64739a 100644 --- a/src/domain/javascript/javascriptFeatureTraceSchemas.ts +++ b/src/domain/javascript/javascriptFeatureTraceSchemas.ts @@ -105,7 +105,9 @@ export const traceApplicationFeatureInputSchema = z .strictObject({ application: evidenceSchema, native_observations: z.array(evidenceSchema).default([]), - seed: applicationFeatureSeedSchema, + seed: applicationFeatureSeedSchema.describe( + 'Typed literal starting point. kind is one of node-id, route, string, channel, module, native-export, or api; value is the literal text. match defaults to contains for string seeds and exact otherwise; an empty value requires match exact. api seeds may add entry_path. Example: {"kind":"module","value":"search.js","match":"exact"}.', + ), semantic_page: z .strictObject({ offset: z.int().nonnegative().default(0), diff --git a/tests/boundary/mcp/traceFeatureSeedGuidanceMcp.test.ts b/tests/boundary/mcp/traceFeatureSeedGuidanceMcp.test.ts new file mode 100644 index 0000000000..a10c899bbc --- /dev/null +++ b/tests/boundary/mcp/traceFeatureSeedGuidanceMcp.test.ts @@ -0,0 +1,68 @@ +import { expect, it } from "vitest"; + +import { createApplicationMcpHarness } from "../../fixtures/applicationMcpHarness.js"; +import { createTestBinarySession } from "../../fixtures/binarySession.js"; +import { silentLogger } from "../../../src/logger.js"; + +const SEED_KINDS = [ + "node-id", + "route", + "string", + "channel", + "module", + "native-export", + "api", +]; + +const advertisedSeed = async ( + profile: "full" | "compact", + parentEnvironment: NodeJS.ProcessEnv = process.env, +) => { + const environment: NodeJS.ProcessEnv = { + ...parentEnvironment, + REA_MCP_INPUT_SCHEMA_PROFILE: profile, + REA_MCP_TOOL_CATALOG_PROFILE: "full", + }; + delete environment.REA_MCP_TOOL_FAMILIES; + const harness = await createApplicationMcpHarness({ + session: createTestBinarySession(() => { + throw new Error("tools/list must not acquire a binary provider"); + }), + serverOptions: { + logger: silentLogger, + environment, + }, + clientIdentity: { name: "trace-seed-guidance", version: "1" }, + }); + const tool = (await harness.client.listTools()).tools.find( + ({ name }) => name === "trace_application_feature", + ); + const properties = tool?.inputSchema.properties as + | Record + | undefined; + return properties?.seed; +}; + +// The compact profile reduces this schema to shallow properties, which drops +// the seed union and its kind enums. The field description must still name +// every accepted kind so an agent can form a valid seed without the source. +it.each([ + ["full", false], + ["compact", false], + ["full", true], + ["compact", true], +] as const)( + "names every trace seed kind (%s schema, restricted parent: %s)", + async (profile, restricted) => { + const parent = restricted + ? { + ...process.env, + REA_MCP_TOOL_FAMILIES: "native", + REA_MCP_TOOL_CATALOG_PROFILE: "hot-cold", + } + : process.env; + const seed = await advertisedSeed(profile, parent); + expect(seed).toBeDefined(); + for (const kind of SEED_KINDS) expect(seed?.description).toContain(kind); + }, +);