@posthog/mcp
Advanced tools
| import type { LoggerFn } from './logger'; | ||
| /** | ||
| * The `conversation_id` session handle reaches the agent as a text block appended to the | ||
| * tool result. That block is invisible to any client that reads | ||
| * `structuredContent` instead of `content` — which is what clients do whenever a | ||
| * tool declares an `outputSchema`. Measured against Claude Code, correlation for | ||
| * such tools drops to zero. | ||
| * | ||
| * The fix is to mirror the session handle into `structuredContent` as well, which this | ||
| * module does in two halves that must stay in that order: | ||
| * | ||
| * 1. declare `_mcp_instructions` on the tool's advertised `outputSchema` | ||
| * 2. write it into the result's `structuredContent` | ||
| * | ||
| * The declaration is what makes the write safe. The MCP client ajv-validates | ||
| * `structuredContent` against the schema from `tools/list`, and | ||
| * `zod-to-json-schema` emits `additionalProperties: false` for a plain | ||
| * `z.object`, so an undeclared key is not ignored — it fails the entire tool | ||
| * result. Only tools that got the declaration are ever written to. | ||
| */ | ||
| export declare const MCP_INSTRUCTIONS_KEY = "_mcp_instructions"; | ||
| export interface OutputInstructionsInjectableTool { | ||
| name?: string; | ||
| outputSchema?: unknown; | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * True when we can safely declare {@link MCP_INSTRUCTIONS_KEY} on this tool's | ||
| * advertised output schema. | ||
| * | ||
| * Requires a plain-object schema we can extend. A tool with no `outputSchema` | ||
| * has nothing to mirror into and keeps working through `content`; a composed | ||
| * schema (`oneOf`/`allOf`/`anyOf`/`$ref`) has no single `properties` bag to add | ||
| * to. Both stay content-only, matching the policy on the input side. | ||
| */ | ||
| export declare function canDeclareOutputInstructions(outputSchema: unknown): boolean; | ||
| /** | ||
| * Returns a copy of the tool with an optional {@link MCP_INSTRUCTIONS_KEY} | ||
| * property added to its output schema, or the tool untouched when it has no | ||
| * output schema to extend. | ||
| * | ||
| * The property is never added to `required` — a result without it must stay | ||
| * valid, since every tool result predating this change lacks it. | ||
| */ | ||
| export declare function addInstructionsToOutputSchema<TTool extends OutputInstructionsInjectableTool>(tool: TTool, logger?: LoggerFn): TTool; | ||
| /** | ||
| * Declares {@link MCP_INSTRUCTIONS_KEY} across a tool listing. Tools without an | ||
| * output schema, and tools whose schema we cannot extend, pass through unchanged. | ||
| */ | ||
| export declare function addInstructionsToOutputSchemas<TTool extends OutputInstructionsInjectableTool>(tools: TTool[], logger?: LoggerFn): TTool[]; | ||
| export interface ConversationInstructions { | ||
| conversation_id: string; | ||
| instructions: string; | ||
| } | ||
| /** The payload mirrored into `structuredContent` for a tool we declared the key on. */ | ||
| export declare function buildConversationInstructions(conversationId: string): ConversationInstructions; | ||
| /** | ||
| * Adds {@link MCP_INSTRUCTIONS_KEY} to a result's `structuredContent`, which is | ||
| * where clients look once a tool declares an `outputSchema` — the `content` text | ||
| * block carrying the session handle is invisible to them. | ||
| * | ||
| * Unlike the text block, this rides *every* response rather than only the one | ||
| * that minted the session handle, so an agent that drops it can read it back. | ||
| * | ||
| * Returns the result untouched when there is no plain-object `structuredContent` | ||
| * to extend, or when the tool already produced its own key — customer data wins. | ||
| * Never mutates the input. | ||
| */ | ||
| export declare function mirrorInstructionsIntoStructuredContent(result: unknown, conversationId: string): unknown; | ||
| //# sourceMappingURL=output-instructions.d.ts.map |
| {"version":3,"file":"output-instructions.d.ts","sourceRoot":"","sources":["../../src/extensions/output-instructions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAIxC;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,oBAAoB,sBAAsB,CAAA;AAQvD,MAAM,WAAW,gCAAgC;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAgC3E;AAwCD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,SAAS,gCAAgC,EAC1F,IAAI,EAAE,KAAK,EACX,MAAM,GAAE,QAAc,GACrB,KAAK,CA8CP;AAED;;;GAGG;AACH,wBAAgB,8BAA8B,CAAC,KAAK,SAAS,gCAAgC,EAC3F,KAAK,EAAE,KAAK,EAAE,EACd,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAET;AAED,MAAM,WAAW,wBAAwB;IACvC,eAAe,EAAE,MAAM,CAAA;IACvB,YAAY,EAAE,MAAM,CAAA;CACrB;AAID,uFAAuF;AACvF,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG,wBAAwB,CAE9F;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uCAAuC,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAkBxG"} |
| "use strict"; | ||
| var __webpack_require__ = {}; | ||
| (()=>{ | ||
| __webpack_require__.d = (exports1, definition)=>{ | ||
| for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, { | ||
| enumerable: true, | ||
| get: definition[key] | ||
| }); | ||
| }; | ||
| })(); | ||
| (()=>{ | ||
| __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop); | ||
| })(); | ||
| (()=>{ | ||
| __webpack_require__.r = (exports1)=>{ | ||
| if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, { | ||
| value: 'Module' | ||
| }); | ||
| Object.defineProperty(exports1, '__esModule', { | ||
| value: true | ||
| }); | ||
| }; | ||
| })(); | ||
| var __webpack_exports__ = {}; | ||
| __webpack_require__.r(__webpack_exports__); | ||
| __webpack_require__.d(__webpack_exports__, { | ||
| mirrorInstructionsIntoStructuredContent: ()=>mirrorInstructionsIntoStructuredContent, | ||
| addInstructionsToOutputSchema: ()=>addInstructionsToOutputSchema, | ||
| addInstructionsToOutputSchemas: ()=>addInstructionsToOutputSchemas, | ||
| MCP_INSTRUCTIONS_KEY: ()=>MCP_INSTRUCTIONS_KEY, | ||
| buildConversationInstructions: ()=>buildConversationInstructions, | ||
| canDeclareOutputInstructions: ()=>canDeclareOutputInstructions | ||
| }); | ||
| const external_logger_js_namespaceObject = require("./logger.js"); | ||
| const MCP_INSTRUCTIONS_KEY = '_mcp_instructions'; | ||
| const INSTRUCTIONS_FIELD_DESCRIPTION = 'Server-issued handles for this conversation, and what to do with them. Read and follow.'; | ||
| const CONVERSATION_ID_FIELD_DESCRIPTION = 'Echo this exact value as the conversation_id argument on every subsequent tool call.'; | ||
| function canDeclareOutputInstructions(outputSchema) { | ||
| if (!outputSchema || 'object' != typeof outputSchema) return false; | ||
| if (isSchemaObjectLike(outputSchema)) return false; | ||
| const schema = outputSchema; | ||
| if (schema.$ref || schema.oneOf || schema.allOf || schema.anyOf) return false; | ||
| const { properties } = schema; | ||
| if (void 0 !== properties && ('object' != typeof properties || null === properties || Array.isArray(properties))) return false; | ||
| return !properties || !Object.prototype.hasOwnProperty.call(properties, MCP_INSTRUCTIONS_KEY); | ||
| } | ||
| function isZodLike(entry) { | ||
| return !!entry && 'object' == typeof entry && ('_def' in entry || '_zod' in entry || '~standard' in entry); | ||
| } | ||
| function looksLikeJsonSchema(candidate) { | ||
| if ('string' == typeof candidate.type || 'string' == typeof candidate.$ref) return true; | ||
| if (Array.isArray(candidate.oneOf) || Array.isArray(candidate.allOf) || Array.isArray(candidate.anyOf)) return true; | ||
| const { properties } = candidate; | ||
| return !!properties && 'object' == typeof properties && !isZodLike(properties); | ||
| } | ||
| function isSchemaObjectLike(value) { | ||
| const candidate = value; | ||
| if (isZodLike(candidate)) return true; | ||
| if (looksLikeJsonSchema(candidate)) return false; | ||
| return Object.values(candidate).some(isZodLike); | ||
| } | ||
| function addInstructionsToOutputSchema(tool, logger = external_logger_js_namespaceObject.log) { | ||
| const toolName = tool.name || 'unknown'; | ||
| const original = tool.outputSchema; | ||
| if (!original || 'object' != typeof original) return tool; | ||
| if (!canDeclareOutputInstructions(original)) { | ||
| const schema = original; | ||
| logger(schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, MCP_INSTRUCTIONS_KEY) ? `WARN: Tool "${toolName}" already declares '${MCP_INSTRUCTIONS_KEY}' in its output schema. Leaving it alone.` : `WARN: Tool "${toolName}" has a complex output schema (oneOf/allOf/anyOf/$ref). Skipping '${MCP_INSTRUCTIONS_KEY}' declaration; its session handle stays content-only.`); | ||
| return tool; | ||
| } | ||
| const modifiedTool = { | ||
| ...tool | ||
| }; | ||
| const outputSchema = JSON.parse(JSON.stringify(original)); | ||
| if (!outputSchema.properties) outputSchema.properties = {}; | ||
| outputSchema.properties[MCP_INSTRUCTIONS_KEY] = { | ||
| type: 'object', | ||
| description: INSTRUCTIONS_FIELD_DESCRIPTION, | ||
| properties: { | ||
| conversation_id: { | ||
| type: 'string', | ||
| description: CONVERSATION_ID_FIELD_DESCRIPTION | ||
| }, | ||
| instructions: { | ||
| type: 'string' | ||
| } | ||
| } | ||
| }; | ||
| modifiedTool.outputSchema = outputSchema; | ||
| return modifiedTool; | ||
| } | ||
| function addInstructionsToOutputSchemas(tools, logger = external_logger_js_namespaceObject.log) { | ||
| return tools.map((tool)=>addInstructionsToOutputSchema(tool, logger)); | ||
| } | ||
| const ECHO_INSTRUCTION = 'Send this conversation_id as an argument on every subsequent tool call in this conversation.'; | ||
| function buildConversationInstructions(conversationId) { | ||
| return { | ||
| conversation_id: conversationId, | ||
| instructions: ECHO_INSTRUCTION | ||
| }; | ||
| } | ||
| function mirrorInstructionsIntoStructuredContent(result, conversationId) { | ||
| if (!result || 'object' != typeof result) return result; | ||
| const structuredContent = result.structuredContent; | ||
| if (!structuredContent || 'object' != typeof structuredContent || Array.isArray(structuredContent)) return result; | ||
| if (Object.prototype.hasOwnProperty.call(structuredContent, MCP_INSTRUCTIONS_KEY)) return result; | ||
| return { | ||
| ...result, | ||
| structuredContent: { | ||
| ...structuredContent, | ||
| [MCP_INSTRUCTIONS_KEY]: buildConversationInstructions(conversationId) | ||
| } | ||
| }; | ||
| } | ||
| exports.MCP_INSTRUCTIONS_KEY = __webpack_exports__.MCP_INSTRUCTIONS_KEY; | ||
| exports.addInstructionsToOutputSchema = __webpack_exports__.addInstructionsToOutputSchema; | ||
| exports.addInstructionsToOutputSchemas = __webpack_exports__.addInstructionsToOutputSchemas; | ||
| exports.buildConversationInstructions = __webpack_exports__.buildConversationInstructions; | ||
| exports.canDeclareOutputInstructions = __webpack_exports__.canDeclareOutputInstructions; | ||
| exports.mirrorInstructionsIntoStructuredContent = __webpack_exports__.mirrorInstructionsIntoStructuredContent; | ||
| for(var __webpack_i__ in __webpack_exports__)if (-1 === [ | ||
| "MCP_INSTRUCTIONS_KEY", | ||
| "addInstructionsToOutputSchema", | ||
| "addInstructionsToOutputSchemas", | ||
| "buildConversationInstructions", | ||
| "canDeclareOutputInstructions", | ||
| "mirrorInstructionsIntoStructuredContent" | ||
| ].indexOf(__webpack_i__)) exports[__webpack_i__] = __webpack_exports__[__webpack_i__]; | ||
| Object.defineProperty(exports, '__esModule', { | ||
| value: true | ||
| }); |
| import { log } from "./logger.mjs"; | ||
| const MCP_INSTRUCTIONS_KEY = '_mcp_instructions'; | ||
| const INSTRUCTIONS_FIELD_DESCRIPTION = 'Server-issued handles for this conversation, and what to do with them. Read and follow.'; | ||
| const CONVERSATION_ID_FIELD_DESCRIPTION = 'Echo this exact value as the conversation_id argument on every subsequent tool call.'; | ||
| function canDeclareOutputInstructions(outputSchema) { | ||
| if (!outputSchema || 'object' != typeof outputSchema) return false; | ||
| if (isSchemaObjectLike(outputSchema)) return false; | ||
| const schema = outputSchema; | ||
| if (schema.$ref || schema.oneOf || schema.allOf || schema.anyOf) return false; | ||
| const { properties } = schema; | ||
| if (void 0 !== properties && ('object' != typeof properties || null === properties || Array.isArray(properties))) return false; | ||
| return !properties || !Object.prototype.hasOwnProperty.call(properties, MCP_INSTRUCTIONS_KEY); | ||
| } | ||
| function isZodLike(entry) { | ||
| return !!entry && 'object' == typeof entry && ('_def' in entry || '_zod' in entry || '~standard' in entry); | ||
| } | ||
| function looksLikeJsonSchema(candidate) { | ||
| if ('string' == typeof candidate.type || 'string' == typeof candidate.$ref) return true; | ||
| if (Array.isArray(candidate.oneOf) || Array.isArray(candidate.allOf) || Array.isArray(candidate.anyOf)) return true; | ||
| const { properties } = candidate; | ||
| return !!properties && 'object' == typeof properties && !isZodLike(properties); | ||
| } | ||
| function isSchemaObjectLike(value) { | ||
| const candidate = value; | ||
| if (isZodLike(candidate)) return true; | ||
| if (looksLikeJsonSchema(candidate)) return false; | ||
| return Object.values(candidate).some(isZodLike); | ||
| } | ||
| function addInstructionsToOutputSchema(tool, logger = log) { | ||
| const toolName = tool.name || 'unknown'; | ||
| const original = tool.outputSchema; | ||
| if (!original || 'object' != typeof original) return tool; | ||
| if (!canDeclareOutputInstructions(original)) { | ||
| const schema = original; | ||
| logger(schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, MCP_INSTRUCTIONS_KEY) ? `WARN: Tool "${toolName}" already declares '${MCP_INSTRUCTIONS_KEY}' in its output schema. Leaving it alone.` : `WARN: Tool "${toolName}" has a complex output schema (oneOf/allOf/anyOf/$ref). Skipping '${MCP_INSTRUCTIONS_KEY}' declaration; its session handle stays content-only.`); | ||
| return tool; | ||
| } | ||
| const modifiedTool = { | ||
| ...tool | ||
| }; | ||
| const outputSchema = JSON.parse(JSON.stringify(original)); | ||
| if (!outputSchema.properties) outputSchema.properties = {}; | ||
| outputSchema.properties[MCP_INSTRUCTIONS_KEY] = { | ||
| type: 'object', | ||
| description: INSTRUCTIONS_FIELD_DESCRIPTION, | ||
| properties: { | ||
| conversation_id: { | ||
| type: 'string', | ||
| description: CONVERSATION_ID_FIELD_DESCRIPTION | ||
| }, | ||
| instructions: { | ||
| type: 'string' | ||
| } | ||
| } | ||
| }; | ||
| modifiedTool.outputSchema = outputSchema; | ||
| return modifiedTool; | ||
| } | ||
| function addInstructionsToOutputSchemas(tools, logger = log) { | ||
| return tools.map((tool)=>addInstructionsToOutputSchema(tool, logger)); | ||
| } | ||
| const ECHO_INSTRUCTION = 'Send this conversation_id as an argument on every subsequent tool call in this conversation.'; | ||
| function buildConversationInstructions(conversationId) { | ||
| return { | ||
| conversation_id: conversationId, | ||
| instructions: ECHO_INSTRUCTION | ||
| }; | ||
| } | ||
| function mirrorInstructionsIntoStructuredContent(result, conversationId) { | ||
| if (!result || 'object' != typeof result) return result; | ||
| const structuredContent = result.structuredContent; | ||
| if (!structuredContent || 'object' != typeof structuredContent || Array.isArray(structuredContent)) return result; | ||
| if (Object.prototype.hasOwnProperty.call(structuredContent, MCP_INSTRUCTIONS_KEY)) return result; | ||
| return { | ||
| ...result, | ||
| structuredContent: { | ||
| ...structuredContent, | ||
| [MCP_INSTRUCTIONS_KEY]: buildConversationInstructions(conversationId) | ||
| } | ||
| }; | ||
| } | ||
| export { MCP_INSTRUCTIONS_KEY, addInstructionsToOutputSchema, addInstructionsToOutputSchemas, buildConversationInstructions, canDeclareOutputInstructions, mirrorInstructionsIntoStructuredContent }; |
| import type { LoggerFn } from './logger' | ||
| import { log } from './logger' | ||
| import type { AnalyticsInjectableJsonSchema } from './analytics-parameters' | ||
| /** | ||
| * The `conversation_id` session handle reaches the agent as a text block appended to the | ||
| * tool result. That block is invisible to any client that reads | ||
| * `structuredContent` instead of `content` — which is what clients do whenever a | ||
| * tool declares an `outputSchema`. Measured against Claude Code, correlation for | ||
| * such tools drops to zero. | ||
| * | ||
| * The fix is to mirror the session handle into `structuredContent` as well, which this | ||
| * module does in two halves that must stay in that order: | ||
| * | ||
| * 1. declare `_mcp_instructions` on the tool's advertised `outputSchema` | ||
| * 2. write it into the result's `structuredContent` | ||
| * | ||
| * The declaration is what makes the write safe. The MCP client ajv-validates | ||
| * `structuredContent` against the schema from `tools/list`, and | ||
| * `zod-to-json-schema` emits `additionalProperties: false` for a plain | ||
| * `z.object`, so an undeclared key is not ignored — it fails the entire tool | ||
| * result. Only tools that got the declaration are ever written to. | ||
| */ | ||
| export const MCP_INSTRUCTIONS_KEY = '_mcp_instructions' | ||
| const INSTRUCTIONS_FIELD_DESCRIPTION = | ||
| 'Server-issued handles for this conversation, and what to do with them. Read and follow.' | ||
| const CONVERSATION_ID_FIELD_DESCRIPTION = | ||
| 'Echo this exact value as the conversation_id argument on every subsequent tool call.' | ||
| export interface OutputInstructionsInjectableTool { | ||
| name?: string | ||
| outputSchema?: unknown | ||
| [key: string]: unknown | ||
| } | ||
| /** | ||
| * True when we can safely declare {@link MCP_INSTRUCTIONS_KEY} on this tool's | ||
| * advertised output schema. | ||
| * | ||
| * Requires a plain-object schema we can extend. A tool with no `outputSchema` | ||
| * has nothing to mirror into and keeps working through `content`; a composed | ||
| * schema (`oneOf`/`allOf`/`anyOf`/`$ref`) has no single `properties` bag to add | ||
| * to. Both stay content-only, matching the policy on the input side. | ||
| */ | ||
| export function canDeclareOutputInstructions(outputSchema: unknown): boolean { | ||
| if (!outputSchema || typeof outputSchema !== 'object') { | ||
| return false | ||
| } | ||
| // Only the JSON Schema a tool advertises can answer this. A Zod schema or raw | ||
| // shape — what the high-level registry stores — has no `properties` bag, so | ||
| // every check below would pass vacuously and report `true` for a tool whose | ||
| // schema we actually skipped. Refuse rather than guess: callers holding a Zod | ||
| // value must read the recorded answer off the ownership registry instead. | ||
| if (isSchemaObjectLike(outputSchema)) { | ||
| return false | ||
| } | ||
| const schema = outputSchema as AnalyticsInjectableJsonSchema | ||
| if (schema.$ref || schema.oneOf || schema.allOf || schema.anyOf) { | ||
| return false | ||
| } | ||
| // `properties` must be a plain object if it is present at all. A tool that | ||
| // advertises something else is malformed, and harmlessly so until we try to | ||
| // declare into it — assigning a key to a boolean throws, and that throw | ||
| // surfaces inside the `tools/list` wrapper, failing the entire listing over a | ||
| // schema we only wanted to annotate. | ||
| const { properties } = schema | ||
| if ( | ||
| properties !== undefined && | ||
| (typeof properties !== 'object' || properties === null || Array.isArray(properties)) | ||
| ) { | ||
| return false | ||
| } | ||
| return !properties || !Object.prototype.hasOwnProperty.call(properties, MCP_INSTRUCTIONS_KEY) | ||
| } | ||
| /** A single Zod schema — the internals every version brands its instances with. */ | ||
| function isZodLike(entry: unknown): boolean { | ||
| return !!entry && typeof entry === 'object' && ('_def' in entry || '_zod' in entry || '~standard' in entry) | ||
| } | ||
| /** | ||
| * Whether this is a JSON Schema, judged on the *value* of each marker rather | ||
| * than the key alone — a raw Zod shape is free to name a field `type` or | ||
| * `properties`, but its values are Zod schemas, not a string and a property bag. | ||
| */ | ||
| function looksLikeJsonSchema(candidate: Record<string, unknown>): boolean { | ||
| if (typeof candidate.type === 'string' || typeof candidate.$ref === 'string') { | ||
| return true | ||
| } | ||
| if (Array.isArray(candidate.oneOf) || Array.isArray(candidate.allOf) || Array.isArray(candidate.anyOf)) { | ||
| return true | ||
| } | ||
| const { properties } = candidate | ||
| return !!properties && typeof properties === 'object' && !isZodLike(properties) | ||
| } | ||
| /** A Zod schema, or a raw shape whose values are Zod schemas. */ | ||
| function isSchemaObjectLike(value: unknown): boolean { | ||
| const candidate = value as Record<string, unknown> | ||
| if (isZodLike(candidate)) { | ||
| return true | ||
| } | ||
| // Settle "is this a JSON Schema" before scanning the values, because a schema | ||
| // may legitimately declare a property named `_def` — and the scan below would | ||
| // read that property's schema object as a Zod value and skip a tool we could | ||
| // have annotated perfectly well. | ||
| if (looksLikeJsonSchema(candidate)) { | ||
| return false | ||
| } | ||
| return Object.values(candidate).some(isZodLike) | ||
| } | ||
| /** | ||
| * Returns a copy of the tool with an optional {@link MCP_INSTRUCTIONS_KEY} | ||
| * property added to its output schema, or the tool untouched when it has no | ||
| * output schema to extend. | ||
| * | ||
| * The property is never added to `required` — a result without it must stay | ||
| * valid, since every tool result predating this change lacks it. | ||
| */ | ||
| export function addInstructionsToOutputSchema<TTool extends OutputInstructionsInjectableTool>( | ||
| tool: TTool, | ||
| logger: LoggerFn = log | ||
| ): TTool { | ||
| const toolName = tool.name || 'unknown' | ||
| const original = tool.outputSchema | ||
| // No output schema means the client reads `content`, where the session handle already | ||
| // rides. Nothing to declare, and nothing broken. | ||
| if (!original || typeof original !== 'object') { | ||
| return tool | ||
| } | ||
| if (!canDeclareOutputInstructions(original)) { | ||
| const schema = original as AnalyticsInjectableJsonSchema | ||
| if (schema.properties && Object.prototype.hasOwnProperty.call(schema.properties, MCP_INSTRUCTIONS_KEY)) { | ||
| logger( | ||
| `WARN: Tool "${toolName}" already declares '${MCP_INSTRUCTIONS_KEY}' in its output schema. Leaving it alone.` | ||
| ) | ||
| } else { | ||
| logger( | ||
| `WARN: Tool "${toolName}" has a complex output schema (oneOf/allOf/anyOf/$ref). Skipping '${MCP_INSTRUCTIONS_KEY}' declaration; its session handle stays content-only.` | ||
| ) | ||
| } | ||
| return tool | ||
| } | ||
| const modifiedTool = { ...tool } | ||
| // Deep copy: the server may reuse or freeze the schema object it handed us. | ||
| const outputSchema = JSON.parse(JSON.stringify(original)) as AnalyticsInjectableJsonSchema | ||
| if (!outputSchema.properties) { | ||
| outputSchema.properties = {} | ||
| } | ||
| outputSchema.properties[MCP_INSTRUCTIONS_KEY] = { | ||
| type: 'object', | ||
| description: INSTRUCTIONS_FIELD_DESCRIPTION, | ||
| properties: { | ||
| conversation_id: { | ||
| type: 'string', | ||
| description: CONVERSATION_ID_FIELD_DESCRIPTION, | ||
| }, | ||
| instructions: { type: 'string' }, | ||
| }, | ||
| } | ||
| modifiedTool.outputSchema = outputSchema | ||
| return modifiedTool | ||
| } | ||
| /** | ||
| * Declares {@link MCP_INSTRUCTIONS_KEY} across a tool listing. Tools without an | ||
| * output schema, and tools whose schema we cannot extend, pass through unchanged. | ||
| */ | ||
| export function addInstructionsToOutputSchemas<TTool extends OutputInstructionsInjectableTool>( | ||
| tools: TTool[], | ||
| logger: LoggerFn = log | ||
| ): TTool[] { | ||
| return tools.map((tool) => addInstructionsToOutputSchema(tool, logger)) | ||
| } | ||
| export interface ConversationInstructions { | ||
| conversation_id: string | ||
| instructions: string | ||
| } | ||
| const ECHO_INSTRUCTION = 'Send this conversation_id as an argument on every subsequent tool call in this conversation.' | ||
| /** The payload mirrored into `structuredContent` for a tool we declared the key on. */ | ||
| export function buildConversationInstructions(conversationId: string): ConversationInstructions { | ||
| return { conversation_id: conversationId, instructions: ECHO_INSTRUCTION } | ||
| } | ||
| /** | ||
| * Adds {@link MCP_INSTRUCTIONS_KEY} to a result's `structuredContent`, which is | ||
| * where clients look once a tool declares an `outputSchema` — the `content` text | ||
| * block carrying the session handle is invisible to them. | ||
| * | ||
| * Unlike the text block, this rides *every* response rather than only the one | ||
| * that minted the session handle, so an agent that drops it can read it back. | ||
| * | ||
| * Returns the result untouched when there is no plain-object `structuredContent` | ||
| * to extend, or when the tool already produced its own key — customer data wins. | ||
| * Never mutates the input. | ||
| */ | ||
| export function mirrorInstructionsIntoStructuredContent(result: unknown, conversationId: string): unknown { | ||
| if (!result || typeof result !== 'object') { | ||
| return result | ||
| } | ||
| const structuredContent = (result as { structuredContent?: unknown }).structuredContent | ||
| if (!structuredContent || typeof structuredContent !== 'object' || Array.isArray(structuredContent)) { | ||
| return result | ||
| } | ||
| if (Object.prototype.hasOwnProperty.call(structuredContent, MCP_INSTRUCTIONS_KEY)) { | ||
| return result | ||
| } | ||
| return { | ||
| ...result, | ||
| structuredContent: { | ||
| ...structuredContent, | ||
| [MCP_INSTRUCTIONS_KEY]: buildConversationInstructions(conversationId), | ||
| }, | ||
| } | ||
| } |
@@ -15,4 +15,9 @@ import type { AnalyticsParameterOwnership } from '../types'; | ||
| export declare function analyticsOwnsParameter(inputSchema: unknown, parameterName: string): boolean; | ||
| export declare function getAnalyticsParameterOwnership(inputSchema: unknown): AnalyticsParameterOwnership; | ||
| export declare function stripOwnedAnalyticsArguments(args: unknown, ownership: AnalyticsParameterOwnership): unknown; | ||
| export declare function getAnalyticsParameterOwnership(inputSchema: unknown, outputSchema?: unknown): AnalyticsParameterOwnership; | ||
| /** | ||
| * Removes the arguments we injected, leaving the host's own. Input-side only, so | ||
| * it takes just those two flags rather than the whole ownership record — callers | ||
| * that have no output-schema context should not have to invent a value for it. | ||
| */ | ||
| export declare function stripOwnedAnalyticsArguments(args: unknown, ownership: Pick<AnalyticsParameterOwnership, 'context' | 'conversationId'>): unknown; | ||
| //# sourceMappingURL=analytics-parameters.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"analytics-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/analytics-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AAgB3D,MAAM,WAAW,6BAA6B;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAET;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAyB3F;AAED,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,OAAO,GAAG,2BAA2B,CAKhG;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,2BAA2B,GAAG,OAAO,CAW3G"} | ||
| {"version":3,"file":"analytics-parameters.d.ts","sourceRoot":"","sources":["../../src/extensions/analytics-parameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAA;AAiB3D,MAAM,WAAW,6BAA6B;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACpC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAET;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,6BAA6B,GAAG,SAAS,EACjD,aAAa,EAAE,MAAM,GACpB,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAyB3F;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,OAAO,EACpB,YAAY,CAAC,EAAE,OAAO,GACrB,2BAA2B,CAM7B;AAED;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,OAAO,EACb,SAAS,EAAE,IAAI,CAAC,2BAA2B,EAAE,SAAS,GAAG,gBAAgB,CAAC,GACzE,OAAO,CAWT"} |
@@ -34,2 +34,3 @@ "use strict"; | ||
| const external_mcp_sdk_compat_js_namespaceObject = require("./mcp-sdk-compat.js"); | ||
| const external_output_instructions_js_namespaceObject = require("./output-instructions.js"); | ||
| const JSON_SCHEMA_KEYWORDS = [ | ||
@@ -67,6 +68,7 @@ '$defs', | ||
| } | ||
| function getAnalyticsParameterOwnership(inputSchema) { | ||
| function getAnalyticsParameterOwnership(inputSchema, outputSchema) { | ||
| return { | ||
| context: analyticsOwnsParameter(inputSchema, 'context'), | ||
| conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id') | ||
| conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id'), | ||
| outputInstructions: (0, external_output_instructions_js_namespaceObject.canDeclareOutputInstructions)(outputSchema) | ||
| }; | ||
@@ -73,0 +75,0 @@ } |
| import { getObjectShape, isZodRawShapeCompat } from "./mcp-sdk-compat.mjs"; | ||
| import { canDeclareOutputInstructions } from "./output-instructions.mjs"; | ||
| const JSON_SCHEMA_KEYWORDS = [ | ||
@@ -34,6 +35,7 @@ '$defs', | ||
| } | ||
| function getAnalyticsParameterOwnership(inputSchema) { | ||
| function getAnalyticsParameterOwnership(inputSchema, outputSchema) { | ||
| return { | ||
| context: analyticsOwnsParameter(inputSchema, 'context'), | ||
| conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id') | ||
| conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id'), | ||
| outputInstructions: canDeclareOutputInstructions(outputSchema) | ||
| }; | ||
@@ -40,0 +42,0 @@ } |
@@ -10,3 +10,9 @@ import { type AnalyticsInjectableJsonSchema } from './analytics-parameters'; | ||
| export declare function addConversationIdToTool<TTool extends ConversationIdInjectableTool>(tool: TTool, logger?: LoggerFn): TTool; | ||
| export declare function addConversationIdToTools<TTool extends ConversationIdInjectableTool>(tools: TTool[], missingCapabilityToolName?: string, skipMissingCapabilityTool?: boolean, logger?: LoggerFn): TTool[]; | ||
| /** | ||
| * Injects `conversation_id` across a tool listing, including the virtual | ||
| * `get_more_tools` tool. Its calls publish `$mcp_missing_capability`, and a | ||
| * capability gap is only meaningful next to the work that hit it — so it belongs | ||
| * in the same session as the surrounding tool calls. | ||
| */ | ||
| export declare function addConversationIdToTools<TTool extends ConversationIdInjectableTool>(tools: TTool[], logger?: LoggerFn): TTool[]; | ||
| export type ConversationIdResolution = { | ||
@@ -21,11 +27,34 @@ minted: false; | ||
| * Decides which conversation_id to use for a tool call: | ||
| * - disabled or get_more_tools → none | ||
| * - agent supplied a value → use it | ||
| * - agent omitted → mint a UUID | ||
| * - disabled → none | ||
| * - agent echoed a handle we could have minted → use it | ||
| * - anything else → mint a fresh one | ||
| * | ||
| * The shape check matters because this value becomes `$session_id`, and the | ||
| * derivation is deterministic so that two pods agree — which also means two | ||
| * *callers* sending the same string land in the same session. The strings agents | ||
| * invent are not random (`conv-1`, `1`, `session`), so trusting them verbatim | ||
| * would silently merge unrelated conversations, potentially across users. | ||
| * | ||
| * A compliant agent echoes the uuidv7 we minted and is unaffected. Anything else | ||
| * is treated exactly as if the handle were absent: mint, and prompt back. Shape | ||
| * rather than a registry of issued ids, because a per-request server has no | ||
| * memory of what it minted. | ||
| * | ||
| * This narrows the problem, it does not prove provenance: a caller supplying a | ||
| * well-formed uuidv7 is trusted, so two that pick the *same* one still merge. That | ||
| * residue is far smaller than the case it replaces — an agent ignoring the | ||
| * parameter description reaches for `conv-1` or `1`, not a conforming uuidv7 — and | ||
| * closing it needs a signed handle, i.e. a secret shared by every pod. Worth doing | ||
| * if this ever anchors something security-bearing; `$session_id` is an analytics | ||
| * grouping key, so it does not today. | ||
| */ | ||
| export declare function resolveConversationId(enabled: boolean, args: unknown, toolName: string | undefined, missingCapabilityToolName?: string): ConversationIdResolution; | ||
| export declare function resolveConversationId(enabled: boolean, args: unknown): ConversationIdResolution; | ||
| /** | ||
| * Predicate matching the same eligibility checks injectConversationIdPromptBack uses, | ||
| * exposed so callers can pre-decide whether the prompt-back will actually land | ||
| * (and clear event.conversationId if not, to avoid orphan ids in analytics). | ||
| * Whether the prompt-back can ride this result's `content`. The only requirement | ||
| * is an array to append to. | ||
| * | ||
| * Errored results included on purpose. A tool that fails on the first call of a | ||
| * conversation is exactly when the agent needs the session handle: without it the | ||
| * retry starts a fresh conversation, so the failure and its fix land in different | ||
| * sessions. | ||
| */ | ||
@@ -32,0 +61,0 @@ export declare function canInjectConversationIdPromptBack(result: unknown): boolean; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"conversation-id.d.ts","sourceRoot":"","sources":["../../src/extensions/conversation-id.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAG7C,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,4BAA4B,EAChF,IAAI,EAAE,KAAK,EACX,MAAM,GAAE,QAAc,GACrB,KAAK,CA4CP;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,4BAA4B,EACjF,KAAK,EAAE,KAAK,EAAE,EACd,yBAAyB,GAAE,MAA4B,EACvD,yBAAyB,UAAO,EAChC,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAOT;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5C;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,OAAO,EACb,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,yBAAyB,GAAE,MAA4B,GACtD,wBAAwB,CAS1B;AAED;;;;GAIG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAS1E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAUvE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAKA;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAS/F"} | ||
| {"version":3,"file":"conversation-id.d.ts","sourceRoot":"","sources":["../../src/extensions/conversation-id.ts"],"names":[],"mappings":"AAMA,OAAO,EAGL,KAAK,6BAA6B,EACnC,MAAM,wBAAwB,CAAA;AAE/B,OAAO,EAAO,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AAE7C,eAAO,MAAM,0BAA0B,oBAAoB,CAAA;AAE3D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,6BAA6B,CAAA;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAgB,uBAAuB,CAAC,KAAK,SAAS,4BAA4B,EAChF,IAAI,EAAE,KAAK,EACX,MAAM,GAAE,QAAc,GACrB,KAAK,CA4CP;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,4BAA4B,EACjF,KAAK,EAAE,KAAK,EAAE,EACd,MAAM,GAAE,QAAc,GACrB,KAAK,EAAE,CAET;AAQD,MAAM,MAAM,wBAAwB,GAChC;IAAE,MAAM,EAAE,KAAK,CAAC;IAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GACrD;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAAA;AAE5C;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,wBAAwB,CAa/F;AAED;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAK1E;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAUvE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAM1D;AAED,wBAAgB,6BAA6B,CAAC,cAAc,EAAE,MAAM,GAAG;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb,CAKA;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAS/F"} |
@@ -41,3 +41,2 @@ "use strict"; | ||
| const external_logger_js_namespaceObject = require("./logger.js"); | ||
| const external_tools_js_namespaceObject = require("./tools.js"); | ||
| const CONVERSATION_ID_PARAM_NAME = 'conversation_id'; | ||
@@ -69,10 +68,8 @@ function addConversationIdToTool(tool, logger = external_logger_js_namespaceObject.log) { | ||
| } | ||
| function addConversationIdToTools(tools, missingCapabilityToolName = external_tools_js_namespaceObject.GET_MORE_TOOLS_NAME, skipMissingCapabilityTool = true, logger = external_logger_js_namespaceObject.log) { | ||
| return tools.map((tool)=>{ | ||
| if (skipMissingCapabilityTool && tool.name === missingCapabilityToolName) return tool; | ||
| return addConversationIdToTool(tool, logger); | ||
| }); | ||
| function addConversationIdToTools(tools, logger = external_logger_js_namespaceObject.log) { | ||
| return tools.map((tool)=>addConversationIdToTool(tool, logger)); | ||
| } | ||
| function resolveConversationId(enabled, args, toolName, missingCapabilityToolName = external_tools_js_namespaceObject.GET_MORE_TOOLS_NAME) { | ||
| if (!enabled || toolName === missingCapabilityToolName) return { | ||
| const MINTED_CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; | ||
| function resolveConversationId(enabled, args) { | ||
| if (!enabled) return { | ||
| minted: false, | ||
@@ -82,5 +79,5 @@ conversationId: void 0 | ||
| const supplied = extractConversationId(args); | ||
| if (supplied) return { | ||
| if (supplied && MINTED_CONVERSATION_ID.test(supplied)) return { | ||
| minted: false, | ||
| conversationId: supplied | ||
| conversationId: supplied.toLowerCase() | ||
| }; | ||
@@ -94,5 +91,3 @@ return { | ||
| if (!(result && 'object' == typeof result)) return false; | ||
| const resultObj = result; | ||
| if (true === resultObj.isError) return false; | ||
| return Array.isArray(resultObj.content); | ||
| return Array.isArray(result.content); | ||
| } | ||
@@ -99,0 +94,0 @@ function extractConversationId(args) { |
@@ -5,3 +5,2 @@ import { uuidv7 } from "@posthog/core"; | ||
| import { log } from "./logger.mjs"; | ||
| import { GET_MORE_TOOLS_NAME } from "./tools.mjs"; | ||
| const CONVERSATION_ID_PARAM_NAME = 'conversation_id'; | ||
@@ -33,10 +32,8 @@ function addConversationIdToTool(tool, logger = log) { | ||
| } | ||
| function addConversationIdToTools(tools, missingCapabilityToolName = GET_MORE_TOOLS_NAME, skipMissingCapabilityTool = true, logger = log) { | ||
| return tools.map((tool)=>{ | ||
| if (skipMissingCapabilityTool && tool.name === missingCapabilityToolName) return tool; | ||
| return addConversationIdToTool(tool, logger); | ||
| }); | ||
| function addConversationIdToTools(tools, logger = log) { | ||
| return tools.map((tool)=>addConversationIdToTool(tool, logger)); | ||
| } | ||
| function resolveConversationId(enabled, args, toolName, missingCapabilityToolName = GET_MORE_TOOLS_NAME) { | ||
| if (!enabled || toolName === missingCapabilityToolName) return { | ||
| const MINTED_CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; | ||
| function resolveConversationId(enabled, args) { | ||
| if (!enabled) return { | ||
| minted: false, | ||
@@ -46,5 +43,5 @@ conversationId: void 0 | ||
| const supplied = extractConversationId(args); | ||
| if (supplied) return { | ||
| if (supplied && MINTED_CONVERSATION_ID.test(supplied)) return { | ||
| minted: false, | ||
| conversationId: supplied | ||
| conversationId: supplied.toLowerCase() | ||
| }; | ||
@@ -58,5 +55,3 @@ return { | ||
| if (!(result && 'object' == typeof result)) return false; | ||
| const resultObj = result; | ||
| if (true === resultObj.isError) return false; | ||
| return Array.isArray(resultObj.content); | ||
| return Array.isArray(result.content); | ||
| } | ||
@@ -63,0 +58,0 @@ function extractConversationId(args) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,sBAAsB,EAIvB,MAAM,UAAU,CAAA;AASjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AA8PxC,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA2BhG"} | ||
| {"version":3,"file":"instrument-highlevel.d.ts","sourceRoot":"","sources":["../../src/extensions/instrument-highlevel.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAEV,sBAAsB,EAIvB,MAAM,UAAU,CAAA;AASjB,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAgQxC,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,EAAE,QAAQ,GAAG,IAAI,CA2BhG"} |
@@ -180,3 +180,3 @@ "use strict"; | ||
| execute: (downstreamRequest)=>originalCallToolHandler(downstreamRequest, extra), | ||
| parameterOwnership: registeredTool ? (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(registeredTool.inputSchema) : void 0, | ||
| parameterOwnership: registeredTool ? (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(registeredTool.inputSchema, registeredTool.outputSchema) : void 0, | ||
| takeCapturedError: ()=>{ | ||
@@ -183,0 +183,0 @@ const captured = extra?.__mcp_analytics_error; |
@@ -152,3 +152,3 @@ import { analyticsOwnsParameter, getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from "./analytics-parameters.mjs"; | ||
| execute: (downstreamRequest)=>originalCallToolHandler(downstreamRequest, extra), | ||
| parameterOwnership: registeredTool ? getAnalyticsParameterOwnership(registeredTool.inputSchema) : void 0, | ||
| parameterOwnership: registeredTool ? getAnalyticsParameterOwnership(registeredTool.inputSchema, registeredTool.outputSchema) : void 0, | ||
| takeCapturedError: ()=>{ | ||
@@ -155,0 +155,0 @@ const captured = extra?.__mcp_analytics_error; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../src/extensions/instrumentation.ts"],"names":[],"mappings":"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"} |
@@ -40,2 +40,3 @@ "use strict"; | ||
| const external_client_identity_js_namespaceObject = require("./client-identity.js"); | ||
| const external_output_instructions_js_namespaceObject = require("./output-instructions.js"); | ||
| const external_capture_js_namespaceObject = require("./capture.js"); | ||
@@ -56,3 +57,3 @@ const external_event_types_js_namespaceObject = require("./event-types.js"); | ||
| const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership, resolvedEventType === external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability); | ||
| const conversation = (0, external_conversation_id_js_namespaceObject.resolveConversationId)(ownership.conversationId, request.params?.arguments, request.params?.name, resolvedEventType === external_event_types_js_namespaceObject.MCPAnalyticsEventType.mcpMissingCapability ? (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options) : ''); | ||
| const conversation = (0, external_conversation_id_js_namespaceObject.resolveConversationId)(ownership.conversationId, request.params?.arguments); | ||
| const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership); | ||
@@ -69,3 +70,3 @@ const startTime = new Date(); | ||
| } | ||
| const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation); | ||
| const finalResult = applyConversationInstructions(preparedEvent?.event ?? null, result, conversation, ownership); | ||
| publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError); | ||
@@ -75,6 +76,8 @@ return finalResult; | ||
| function getActiveAnalyticsParameterOwnership(data, toolName, override, isMissingCapabilityTool) { | ||
| const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0); | ||
| const listed = toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0; | ||
| const ownership = override ?? listed; | ||
| return { | ||
| context: !isMissingCapabilityTool && (0, external_context_parameters_js_namespaceObject.isContextEnabled)(data.options.context) && ownership?.context === true, | ||
| conversationId: !isMissingCapabilityTool && true === data.options.enableConversationId && ownership?.conversationId === true | ||
| conversationId: true === data.options.enableConversationId && ownership?.conversationId === true, | ||
| outputInstructions: true === data.options.enableConversationId && listed?.outputInstructions === true | ||
| }; | ||
@@ -96,5 +99,5 @@ } | ||
| try { | ||
| const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra); | ||
| const sessionId = (0, external_session_js_namespaceObject.getSessionId)(server, extra, conversation.conversationId); | ||
| const sessionInfo = (0, external_session_js_namespaceObject.getSessionInfo)(server, data, sessionId); | ||
| const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, sessionInfo, extra); | ||
| const identity = await (0, external_internal_js_namespaceObject.handleIdentify)(server, data, sessionId, request, sessionInfo, extra, !!conversation.conversationId); | ||
| const requestAttribution = (0, external_internal_js_namespaceObject.withIdentity)(sessionInfo, identity); | ||
@@ -124,7 +127,18 @@ const toolName = request.params?.name; | ||
| } | ||
| function applyConversationPromptBack(event, result, conversation) { | ||
| if (!conversation.minted) return result; | ||
| if ((0, external_conversation_id_js_namespaceObject.canInjectConversationIdPromptBack)(result)) return (0, external_conversation_id_js_namespaceObject.injectConversationIdPromptBack)(result, conversation.conversationId); | ||
| if (event) event.conversationId = void 0; | ||
| return result; | ||
| function applyConversationInstructions(event, result, conversation, ownership) { | ||
| const conversationId = conversation.conversationId; | ||
| if (!conversationId) return result; | ||
| let updated = result; | ||
| let delivered = false; | ||
| if (ownership.outputInstructions) { | ||
| const mirrored = (0, external_output_instructions_js_namespaceObject.mirrorInstructionsIntoStructuredContent)(updated, conversationId); | ||
| delivered = mirrored !== updated; | ||
| updated = mirrored; | ||
| } | ||
| if (conversation.minted && (0, external_conversation_id_js_namespaceObject.canInjectConversationIdPromptBack)(updated)) { | ||
| updated = (0, external_conversation_id_js_namespaceObject.injectConversationIdPromptBack)(updated, conversationId); | ||
| delivered = true; | ||
| } | ||
| if (!delivered && conversation.minted && event) event.conversationId = void 0; | ||
| return updated; | ||
| } | ||
@@ -249,3 +263,3 @@ function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) { | ||
| function cacheToolAnalyticsParameterOwnership(cache, tools) { | ||
| for (const tool of tools)if (tool?.name) cache.set(tool.name, (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(tool.inputSchema)); | ||
| for (const tool of tools)if (tool?.name) cache.set(tool.name, (0, external_analytics_parameters_js_namespaceObject.getAnalyticsParameterOwnership)(tool.inputSchema, tool.outputSchema)); | ||
| } | ||
@@ -268,3 +282,2 @@ function collectListedToolNames(tools) { | ||
| const missingToolName = (0, external_tools_js_namespaceObject.resolveMissingCapabilityToolName)(data.options); | ||
| let injectedMissingCapabilityTool = false; | ||
| if (data.options.reportMissing) { | ||
@@ -274,7 +287,13 @@ const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName); | ||
| else { | ||
| tools.push((0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName)); | ||
| injectedMissingCapabilityTool = true; | ||
| const virtualTool = (0, external_tools_js_namespaceObject.getReportMissingToolDescriptor)(missingToolName); | ||
| tools.push(virtualTool); | ||
| cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [ | ||
| virtualTool | ||
| ]); | ||
| } | ||
| } | ||
| if (data.options.enableConversationId) tools = (0, external_conversation_id_js_namespaceObject.addConversationIdToTools)(tools, missingToolName, injectedMissingCapabilityTool, data.logger); | ||
| if (data.options.enableConversationId) { | ||
| tools = (0, external_conversation_id_js_namespaceObject.addConversationIdToTools)(tools, data.logger); | ||
| tools = (0, external_output_instructions_js_namespaceObject.addInstructionsToOutputSchemas)(tools, data.logger); | ||
| } | ||
| } | ||
@@ -281,0 +300,0 @@ if (data) { |
@@ -5,2 +5,3 @@ import { getAnalyticsParameterOwnership, stripOwnedAnalyticsArguments } from "./analytics-parameters.mjs"; | ||
| import { stampMetaClientInfo } from "./client-identity.mjs"; | ||
| import { addInstructionsToOutputSchemas, mirrorInstructionsIntoStructuredContent } from "./output-instructions.mjs"; | ||
| import { captureEvent } from "./capture.mjs"; | ||
@@ -21,3 +22,3 @@ import { MCPAnalyticsEventType } from "./event-types.mjs"; | ||
| const ownership = getActiveAnalyticsParameterOwnership(data, request.params?.name, parameterOwnership, resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability); | ||
| const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments, request.params?.name, resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability ? resolveMissingCapabilityToolName(data.options) : ''); | ||
| const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments); | ||
| const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership); | ||
@@ -34,3 +35,3 @@ const startTime = new Date(); | ||
| } | ||
| const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation); | ||
| const finalResult = applyConversationInstructions(preparedEvent?.event ?? null, result, conversation, ownership); | ||
| publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError); | ||
@@ -40,6 +41,8 @@ return finalResult; | ||
| function getActiveAnalyticsParameterOwnership(data, toolName, override, isMissingCapabilityTool) { | ||
| const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0); | ||
| const listed = toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : void 0; | ||
| const ownership = override ?? listed; | ||
| return { | ||
| context: !isMissingCapabilityTool && isContextEnabled(data.options.context) && ownership?.context === true, | ||
| conversationId: !isMissingCapabilityTool && true === data.options.enableConversationId && ownership?.conversationId === true | ||
| conversationId: true === data.options.enableConversationId && ownership?.conversationId === true, | ||
| outputInstructions: true === data.options.enableConversationId && listed?.outputInstructions === true | ||
| }; | ||
@@ -61,5 +64,5 @@ } | ||
| try { | ||
| const sessionId = getSessionId(server, extra); | ||
| const sessionId = getSessionId(server, extra, conversation.conversationId); | ||
| const sessionInfo = getSessionInfo(server, data, sessionId); | ||
| const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra); | ||
| const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra, !!conversation.conversationId); | ||
| const requestAttribution = withIdentity(sessionInfo, identity); | ||
@@ -89,7 +92,18 @@ const toolName = request.params?.name; | ||
| } | ||
| function applyConversationPromptBack(event, result, conversation) { | ||
| if (!conversation.minted) return result; | ||
| if (canInjectConversationIdPromptBack(result)) return injectConversationIdPromptBack(result, conversation.conversationId); | ||
| if (event) event.conversationId = void 0; | ||
| return result; | ||
| function applyConversationInstructions(event, result, conversation, ownership) { | ||
| const conversationId = conversation.conversationId; | ||
| if (!conversationId) return result; | ||
| let updated = result; | ||
| let delivered = false; | ||
| if (ownership.outputInstructions) { | ||
| const mirrored = mirrorInstructionsIntoStructuredContent(updated, conversationId); | ||
| delivered = mirrored !== updated; | ||
| updated = mirrored; | ||
| } | ||
| if (conversation.minted && canInjectConversationIdPromptBack(updated)) { | ||
| updated = injectConversationIdPromptBack(updated, conversationId); | ||
| delivered = true; | ||
| } | ||
| if (!delivered && conversation.minted && event) event.conversationId = void 0; | ||
| return updated; | ||
| } | ||
@@ -214,3 +228,3 @@ function publishSuccessfulToolEvent(server, preparedEvent, result, startTime, logger, takeCapturedError) { | ||
| function cacheToolAnalyticsParameterOwnership(cache, tools) { | ||
| for (const tool of tools)if (tool?.name) cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema)); | ||
| for (const tool of tools)if (tool?.name) cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema, tool.outputSchema)); | ||
| } | ||
@@ -233,3 +247,2 @@ function collectListedToolNames(tools) { | ||
| const missingToolName = resolveMissingCapabilityToolName(data.options); | ||
| let injectedMissingCapabilityTool = false; | ||
| if (data.options.reportMissing) { | ||
@@ -239,7 +252,13 @@ const alreadyPresent = tools.some((tool)=>tool?.name === missingToolName); | ||
| else { | ||
| tools.push(getReportMissingToolDescriptor(missingToolName)); | ||
| injectedMissingCapabilityTool = true; | ||
| const virtualTool = getReportMissingToolDescriptor(missingToolName); | ||
| tools.push(virtualTool); | ||
| cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [ | ||
| virtualTool | ||
| ]); | ||
| } | ||
| } | ||
| if (data.options.enableConversationId) tools = addConversationIdToTools(tools, missingToolName, injectedMissingCapabilityTool, data.logger); | ||
| if (data.options.enableConversationId) { | ||
| tools = addConversationIdToTools(tools, data.logger); | ||
| tools = addInstructionsToOutputSchemas(tools, data.logger); | ||
| } | ||
| } | ||
@@ -246,0 +265,0 @@ if (data) { |
@@ -27,3 +27,10 @@ import type { CompatibleRequestHandlerExtra, MCPAnalyticsData, MCPRequestLike, MCPServerLike, SessionInfo, UserIdentity } from '../types'; | ||
| */ | ||
| export declare function handleIdentify(server: MCPServerLike, data: MCPAnalyticsData, sessionId: string, request: MCPRequestLike, requestAttribution: SessionInfo, extra?: CompatibleRequestHandlerExtra): Promise<UserIdentity | undefined>; | ||
| export declare function handleIdentify(server: MCPServerLike, data: MCPAnalyticsData, sessionId: string, request: MCPRequestLike, requestAttribution: SessionInfo, extra?: CompatibleRequestHandlerExtra, | ||
| /** | ||
| * True when this session id came from an agent-carried `conversation_id` | ||
| * rather than the transport. Such a session is brand new and was never | ||
| * announced at `initialize`, whatever `data.sessionSource` still says about | ||
| * the connection. | ||
| */ | ||
| sessionFromConversation?: boolean): Promise<UserIdentity | undefined>; | ||
| export declare function withIdentity(sessionInfo: SessionInfo, identity: UserIdentity | undefined): SessionInfo; | ||
@@ -30,0 +37,0 @@ /** |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,WAAW,EACX,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,kBAAkB,EAAE,WAAW,EAC/B,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAsDnC;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,CAOtG;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"} | ||
| {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../../src/extensions/internal.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,cAAc,EACd,aAAa,EAEb,WAAW,EACX,YAAY,EACb,MAAM,UAAU,CAAA;AAKjB;;;;;GAKG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;gBAErB,OAAO,SAAO;IAI1B,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAWhD,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI;IAapD,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAI/B,IAAI,IAAI,MAAM;CAGf;AAID,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS,CAEzF;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,gBAAgB,GAAG,IAAI,CAEzF;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,OAAO,CA4B5E;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,YAAY,GAAG,SAAS,EAAE,IAAI,EAAE,YAAY,GAAG,YAAY,CAapG;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,cAAc,EACvB,kBAAkB,EAAE,WAAW,EAC/B,KAAK,CAAC,EAAE,6BAA6B;AACrC;;;;;GAKG;AACH,uBAAuB,UAAQ,GAC9B,OAAO,CAAC,YAAY,GAAG,SAAS,CAAC,CAuDnC;AAED,wBAAgB,YAAY,CAAC,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,GAAG,SAAS,GAAG,WAAW,CAOtG;AAED;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,cAAc,EACvB,KAAK,CAAC,EAAE,6BAA6B,GACpC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC,CAUzC"} |
@@ -98,3 +98,3 @@ "use strict"; | ||
| } | ||
| async function handleIdentify(server, data, sessionId, request, requestAttribution, extra) { | ||
| async function handleIdentify(server, data, sessionId, request, requestAttribution, extra, sessionFromConversation = false) { | ||
| const identityBeforeRequest = data.identifiedSessions.get(sessionId); | ||
@@ -121,3 +121,3 @@ const sessionSourceBeforeIdentify = data.sessionSource; | ||
| const firstSeen = void 0 === previousIdentity; | ||
| const announcedAtInitialize = 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method; | ||
| const announcedAtInitialize = !sessionFromConversation && 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method; | ||
| const shouldPublish = changed || firstSeen && !announcedAtInitialize; | ||
@@ -124,0 +124,0 @@ data.identifiedSessions.set(sessionId, mergedIdentity); |
@@ -63,3 +63,3 @@ import { MCPAnalyticsEventType } from "./event-types.mjs"; | ||
| } | ||
| async function handleIdentify(server, data, sessionId, request, requestAttribution, extra) { | ||
| async function handleIdentify(server, data, sessionId, request, requestAttribution, extra, sessionFromConversation = false) { | ||
| const identityBeforeRequest = data.identifiedSessions.get(sessionId); | ||
@@ -86,3 +86,3 @@ const sessionSourceBeforeIdentify = data.sessionSource; | ||
| const firstSeen = void 0 === previousIdentity; | ||
| const announcedAtInitialize = 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method; | ||
| const announcedAtInitialize = !sessionFromConversation && 'token' === sessionSourceBeforeIdentify && 'initialize' !== request.method; | ||
| const shouldPublish = changed || firstSeen && !announcedAtInitialize; | ||
@@ -89,0 +89,0 @@ data.identifiedSessions.set(sessionId, mergedIdentity); |
@@ -9,9 +9,30 @@ import type { CompatibleRequestHandlerExtra, MCPAnalyticsData, MCPServerLike, SessionInfo } from '../types'; | ||
| /** | ||
| * Resolves the session id for a request: from the replayed session token, from | ||
| * the transport's MCP session id, or — when the request carries nothing — from | ||
| * this instance's memory. Also saves the token's client name/version so events | ||
| * built later in the request can use them (see getSessionInfo). | ||
| * Derives the SDK session id from the agent's conversation handle. Deterministic | ||
| * and unsalted on purpose: two pods that never met must agree on the session, and | ||
| * the 2026-07-28 revision leaves them no shared state to agree through. | ||
| * | ||
| * Hashed rather than used verbatim so an MCP session can never collide with a | ||
| * Session Replay id — a bare uuidv7 would render a "View recording" button that | ||
| * resolves to nothing. | ||
| * | ||
| * Exported because this *is* the cross-SDK contract: posthog-python has to | ||
| * reproduce it byte for byte or the same conversation splits into two sessions | ||
| * depending on which SDK served the call. | ||
| */ | ||
| export declare function getSessionId(server: MCPServerLike, extra?: CompatibleRequestHandlerExtra): string; | ||
| export declare function deriveSessionIdFromConversation(conversationId: string): string; | ||
| /** | ||
| * Resolves the session id for a request. Three steps, first match wins: | ||
| * | ||
| * 1. the agent carried a `conversation_id` tool argument — 2026-07-28 | ||
| * 2. the request carried a session id — 2025-11-25 | ||
| * 3. nothing was carried, so reuse this instance's own id — stdio | ||
| * | ||
| * The split mirrors the two protocol revisions. 2026-07-28 removed protocol-level | ||
| * sessions, so the only thing that can carry a session across calls is the agent | ||
| * itself (1). 2025-11-25 kept the session on the connection, so the request | ||
| * carries it (2). 3 is for stdio, where neither applies — there is no | ||
| * HTTP request to carry anything, and no agent handle unless the host opted in. | ||
| */ | ||
| export declare function getSessionId(server: MCPServerLike, extra?: CompatibleRequestHandlerExtra, conversationId?: string): string; | ||
| /** | ||
| * Builds the session metadata stamped onto an event. The caller passes the | ||
@@ -18,0 +39,0 @@ * session id resolved for *this* request so identity attribution can't be |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/extensions/session.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,aAAa,EAEb,WAAW,EACZ,MAAM,UAAU,CAAA;AAMjB,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,CAAC,EAAE,6BAA6B,GAAG,MAAM,CAgCjG;AAgBD;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAClC,SAAS,CAAC,EAAE,MAAM,GACjB,WAAW,CAmCb"} | ||
| {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/extensions/session.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,6BAA6B,EAC7B,gBAAgB,EAChB,aAAa,EAEb,WAAW,EACZ,MAAM,UAAU,CAAA;AAOjB,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE1E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,+BAA+B,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAE9E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EACrB,KAAK,CAAC,EAAE,6BAA6B,EACrC,cAAc,CAAC,EAAE,MAAM,GACtB,MAAM,CA0CR;AA4ED;;;;GAIG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,gBAAgB,GAAG,SAAS,EAClC,SAAS,CAAC,EAAE,MAAM,GACjB,WAAW,CAmCb"} |
@@ -27,2 +27,3 @@ "use strict"; | ||
| __webpack_require__.d(__webpack_exports__, { | ||
| deriveSessionIdFromConversation: ()=>deriveSessionIdFromConversation, | ||
| getSessionId: ()=>getSessionId, | ||
@@ -44,18 +45,14 @@ deriveSessionIdFromMCPSession: ()=>deriveSessionIdFromMCPSession, | ||
| } | ||
| function getSessionId(server, extra) { | ||
| function deriveSessionIdFromConversation(conversationId) { | ||
| return (0, external_ids_js_namespaceObject.deterministicPrefixedId)('ses', conversationId); | ||
| } | ||
| function getSessionId(server, extra, conversationId) { | ||
| const data = (0, external_internal_js_namespaceObject.getServerTrackingData)(server); | ||
| if (!data) throw new Error('Server tracking data not found'); | ||
| const sessionHeader = (0, external_session_token_js_namespaceObject.readMcpSessionHeader)(extra?.requestInfo?.headers); | ||
| const token = (0, external_session_token_js_namespaceObject.decodeSessionId)(sessionHeader); | ||
| let sessionId; | ||
| if (token) { | ||
| data.sessionSource = 'token'; | ||
| data.sessionInfo.clientName = token.clientName; | ||
| data.sessionInfo.clientVersion = token.clientVersion; | ||
| data.sessionInfo.protocolVersion = token.protocolVersion; | ||
| sessionId = token.sessionId; | ||
| } else if (extra?.sessionId) { | ||
| data.sessionSource = 'mcp'; | ||
| sessionId = deriveSessionIdFromMCPSession(extra.sessionId); | ||
| } else sessionId = getSessionIdFromMemory(data); | ||
| if (conversationId) { | ||
| applyTokenClientIdentity(data, extra); | ||
| return deriveSessionIdFromConversation(conversationId); | ||
| } | ||
| const carriedByRequest = readSessionIdFromRequest(data, extra); | ||
| const sessionId = carriedByRequest ?? getSessionIdFromMemory(data); | ||
| data.sessionId = sessionId; | ||
@@ -66,2 +63,21 @@ data.lastActivity = new Date(); | ||
| } | ||
| function applyTokenClientIdentity(data, extra) { | ||
| const token = (0, external_session_token_js_namespaceObject.decodeSessionId)((0, external_session_token_js_namespaceObject.readMcpSessionHeader)(extra?.requestInfo?.headers)); | ||
| if (!token) return; | ||
| data.sessionInfo.clientName = token.clientName; | ||
| data.sessionInfo.clientVersion = token.clientVersion; | ||
| data.sessionInfo.protocolVersion = token.protocolVersion; | ||
| return token; | ||
| } | ||
| function readSessionIdFromRequest(data, extra) { | ||
| const token = applyTokenClientIdentity(data, extra); | ||
| if (token) { | ||
| data.sessionSource = 'token'; | ||
| return token.sessionId; | ||
| } | ||
| if (extra?.sessionId) { | ||
| data.sessionSource = 'mcp'; | ||
| return deriveSessionIdFromMCPSession(extra.sessionId); | ||
| } | ||
| } | ||
| function getSessionIdFromMemory(data) { | ||
@@ -100,2 +116,3 @@ const timeoutMs = 60 * external_constants_js_namespaceObject.INACTIVITY_TIMEOUT_IN_MINUTES * 1000; | ||
| } | ||
| exports.deriveSessionIdFromConversation = __webpack_exports__.deriveSessionIdFromConversation; | ||
| exports.deriveSessionIdFromMCPSession = __webpack_exports__.deriveSessionIdFromMCPSession; | ||
@@ -106,2 +123,3 @@ exports.getSessionId = __webpack_exports__.getSessionId; | ||
| for(var __webpack_i__ in __webpack_exports__)if (-1 === [ | ||
| "deriveSessionIdFromConversation", | ||
| "deriveSessionIdFromMCPSession", | ||
@@ -108,0 +126,0 @@ "getSessionId", |
@@ -12,18 +12,14 @@ import { version } from "../version.mjs"; | ||
| } | ||
| function getSessionId(server, extra) { | ||
| function deriveSessionIdFromConversation(conversationId) { | ||
| return deterministicPrefixedId('ses', conversationId); | ||
| } | ||
| function getSessionId(server, extra, conversationId) { | ||
| const data = getServerTrackingData(server); | ||
| if (!data) throw new Error('Server tracking data not found'); | ||
| const sessionHeader = readMcpSessionHeader(extra?.requestInfo?.headers); | ||
| const token = decodeSessionId(sessionHeader); | ||
| let sessionId; | ||
| if (token) { | ||
| data.sessionSource = 'token'; | ||
| data.sessionInfo.clientName = token.clientName; | ||
| data.sessionInfo.clientVersion = token.clientVersion; | ||
| data.sessionInfo.protocolVersion = token.protocolVersion; | ||
| sessionId = token.sessionId; | ||
| } else if (extra?.sessionId) { | ||
| data.sessionSource = 'mcp'; | ||
| sessionId = deriveSessionIdFromMCPSession(extra.sessionId); | ||
| } else sessionId = getSessionIdFromMemory(data); | ||
| if (conversationId) { | ||
| applyTokenClientIdentity(data, extra); | ||
| return deriveSessionIdFromConversation(conversationId); | ||
| } | ||
| const carriedByRequest = readSessionIdFromRequest(data, extra); | ||
| const sessionId = carriedByRequest ?? getSessionIdFromMemory(data); | ||
| data.sessionId = sessionId; | ||
@@ -34,2 +30,21 @@ data.lastActivity = new Date(); | ||
| } | ||
| function applyTokenClientIdentity(data, extra) { | ||
| const token = decodeSessionId(readMcpSessionHeader(extra?.requestInfo?.headers)); | ||
| if (!token) return; | ||
| data.sessionInfo.clientName = token.clientName; | ||
| data.sessionInfo.clientVersion = token.clientVersion; | ||
| data.sessionInfo.protocolVersion = token.protocolVersion; | ||
| return token; | ||
| } | ||
| function readSessionIdFromRequest(data, extra) { | ||
| const token = applyTokenClientIdentity(data, extra); | ||
| if (token) { | ||
| data.sessionSource = 'token'; | ||
| return token.sessionId; | ||
| } | ||
| if (extra?.sessionId) { | ||
| data.sessionSource = 'mcp'; | ||
| return deriveSessionIdFromMCPSession(extra.sessionId); | ||
| } | ||
| } | ||
| function getSessionIdFromMemory(data) { | ||
@@ -68,2 +83,2 @@ const timeoutMs = 60 * INACTIVITY_TIMEOUT_IN_MINUTES * 1000; | ||
| } | ||
| export { deriveSessionIdFromMCPSession, getSessionId, getSessionInfo, newSessionId }; | ||
| export { deriveSessionIdFromConversation, deriveSessionIdFromMCPSession, getSessionId, getSessionInfo, newSessionId }; |
+23
-1
@@ -49,3 +49,17 @@ import type { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; | ||
| missingCapabilityToolName?: string; | ||
| /** Enables the `conversation_id` tool parameter + prompt-back loop. */ | ||
| /** | ||
| * Opt in to session correlation for the MCP **2026-07-28** revision, which removed | ||
| * protocol-level sessions: no `initialize`, no `mcp-session-id` header, and a fresh | ||
| * server instance per HTTP request. With none of those left to anchor on, the only | ||
| * thing that can carry a session across calls is the agent itself. | ||
| * | ||
| * Turning this on injects a `conversation_id` parameter into every tool, mints one | ||
| * on the first call, asks the agent to echo it back, and derives `$session_id` from | ||
| * that handle — so calls correlate across reconnects, restarts, and per-request | ||
| * instances. | ||
| * | ||
| * Off by default, and fully inert when off: no parameter is injected, no schema is | ||
| * touched, no prompt-back is appended, and `$session_id` resolves exactly as it did | ||
| * before (the request's own session id, else this instance's). | ||
| */ | ||
| enableConversationId?: boolean; | ||
@@ -100,2 +114,4 @@ /** | ||
| inputSchema?: unknown; | ||
| /** Present when the tool was registered with a declared output schema. */ | ||
| outputSchema?: unknown; | ||
| update?: (...args: unknown[]) => unknown; | ||
@@ -248,2 +264,8 @@ } & ({ | ||
| conversationId: boolean; | ||
| /** | ||
| * True when we declared `_mcp_instructions` on this tool's advertised output | ||
| * schema, so writing that key into `structuredContent` will validate. False | ||
| * for tools with no output schema, or one we could not extend. | ||
| */ | ||
| outputInstructions: boolean; | ||
| } | ||
@@ -250,0 +272,0 @@ export interface MCPAnalyticsData { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} |
@@ -1,2 +0,2 @@ | ||
| export declare const version = "0.10.7"; | ||
| export declare const version = "0.10.8"; | ||
| //# sourceMappingURL=version.d.ts.map |
+1
-1
@@ -29,3 +29,3 @@ "use strict"; | ||
| }); | ||
| const version = '0.10.7'; | ||
| const version = '0.10.8'; | ||
| exports.version = __webpack_exports__.version; | ||
@@ -32,0 +32,0 @@ for(var __webpack_i__ in __webpack_exports__)if (-1 === [ |
+1
-1
@@ -1,2 +0,2 @@ | ||
| const version = '0.10.7'; | ||
| const version = '0.10.8'; | ||
| export { version }; |
+4
-4
| { | ||
| "name": "@posthog/mcp", | ||
| "version": "0.10.7", | ||
| "version": "0.10.8", | ||
| "bugs": { | ||
@@ -31,3 +31,3 @@ "url": "https://github.com/PostHog/posthog-js/issues" | ||
| "dependencies": { | ||
| "@posthog/core": "^1.46.6" | ||
| "@posthog/core": "^1.46.9" | ||
| }, | ||
@@ -43,4 +43,4 @@ "devDependencies": { | ||
| "zod": "^3.25.0", | ||
| "@posthog-tooling/tsconfig-base": "1.1.1", | ||
| "posthog-node": "^5.47.9" | ||
| "posthog-node": "^5.48.1", | ||
| "@posthog-tooling/tsconfig-base": "1.1.1" | ||
| }, | ||
@@ -47,0 +47,0 @@ "peerDependencies": { |
| import type { AnalyticsParameterOwnership } from '../types' | ||
| import { getObjectShape, isZodRawShapeCompat } from './mcp-sdk-compat' | ||
| import { canDeclareOutputInstructions } from './output-instructions' | ||
@@ -71,10 +72,22 @@ const JSON_SCHEMA_KEYWORDS = [ | ||
| export function getAnalyticsParameterOwnership(inputSchema: unknown): AnalyticsParameterOwnership { | ||
| export function getAnalyticsParameterOwnership( | ||
| inputSchema: unknown, | ||
| outputSchema?: unknown | ||
| ): AnalyticsParameterOwnership { | ||
| return { | ||
| context: analyticsOwnsParameter(inputSchema, 'context'), | ||
| conversationId: analyticsOwnsParameter(inputSchema, 'conversation_id'), | ||
| outputInstructions: canDeclareOutputInstructions(outputSchema), | ||
| } | ||
| } | ||
| export function stripOwnedAnalyticsArguments(args: unknown, ownership: AnalyticsParameterOwnership): unknown { | ||
| /** | ||
| * Removes the arguments we injected, leaving the host's own. Input-side only, so | ||
| * it takes just those two flags rather than the whole ownership record — callers | ||
| * that have no output-schema context should not have to invent a value for it. | ||
| */ | ||
| export function stripOwnedAnalyticsArguments( | ||
| args: unknown, | ||
| ownership: Pick<AnalyticsParameterOwnership, 'context' | 'conversationId'> | ||
| ): unknown { | ||
| let cleanedArgs = args | ||
@@ -81,0 +94,0 @@ if (ownership.context && cleanedArgs && typeof cleanedArgs === 'object' && 'context' in cleanedArgs) { |
@@ -14,3 +14,2 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| import { log, type LoggerFn } from './logger' | ||
| import { GET_MORE_TOOLS_NAME } from './tools' | ||
@@ -74,16 +73,21 @@ export const CONVERSATION_ID_PARAM_NAME = 'conversation_id' | ||
| /** | ||
| * Injects `conversation_id` across a tool listing, including the virtual | ||
| * `get_more_tools` tool. Its calls publish `$mcp_missing_capability`, and a | ||
| * capability gap is only meaningful next to the work that hit it — so it belongs | ||
| * in the same session as the surrounding tool calls. | ||
| */ | ||
| export function addConversationIdToTools<TTool extends ConversationIdInjectableTool>( | ||
| tools: TTool[], | ||
| missingCapabilityToolName: string = GET_MORE_TOOLS_NAME, | ||
| skipMissingCapabilityTool = true, | ||
| logger: LoggerFn = log | ||
| ): TTool[] { | ||
| return tools.map((tool) => { | ||
| if (skipMissingCapabilityTool && tool.name === missingCapabilityToolName) { | ||
| return tool | ||
| } | ||
| return addConversationIdToTool(tool, logger) | ||
| }) | ||
| return tools.map((tool) => addConversationIdToTool(tool, logger)) | ||
| } | ||
| /** | ||
| * The shape of every id we mint: a uuidv7. Used to tell an echo of our own handle | ||
| * from a value the agent made up. | ||
| */ | ||
| const MINTED_CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i | ||
| export type ConversationIdResolution = | ||
@@ -95,18 +99,36 @@ | { minted: false; conversationId: string | undefined } | ||
| * Decides which conversation_id to use for a tool call: | ||
| * - disabled or get_more_tools → none | ||
| * - agent supplied a value → use it | ||
| * - agent omitted → mint a UUID | ||
| * - disabled → none | ||
| * - agent echoed a handle we could have minted → use it | ||
| * - anything else → mint a fresh one | ||
| * | ||
| * The shape check matters because this value becomes `$session_id`, and the | ||
| * derivation is deterministic so that two pods agree — which also means two | ||
| * *callers* sending the same string land in the same session. The strings agents | ||
| * invent are not random (`conv-1`, `1`, `session`), so trusting them verbatim | ||
| * would silently merge unrelated conversations, potentially across users. | ||
| * | ||
| * A compliant agent echoes the uuidv7 we minted and is unaffected. Anything else | ||
| * is treated exactly as if the handle were absent: mint, and prompt back. Shape | ||
| * rather than a registry of issued ids, because a per-request server has no | ||
| * memory of what it minted. | ||
| * | ||
| * This narrows the problem, it does not prove provenance: a caller supplying a | ||
| * well-formed uuidv7 is trusted, so two that pick the *same* one still merge. That | ||
| * residue is far smaller than the case it replaces — an agent ignoring the | ||
| * parameter description reaches for `conv-1` or `1`, not a conforming uuidv7 — and | ||
| * closing it needs a signed handle, i.e. a secret shared by every pod. Worth doing | ||
| * if this ever anchors something security-bearing; `$session_id` is an analytics | ||
| * grouping key, so it does not today. | ||
| */ | ||
| export function resolveConversationId( | ||
| enabled: boolean, | ||
| args: unknown, | ||
| toolName: string | undefined, | ||
| missingCapabilityToolName: string = GET_MORE_TOOLS_NAME | ||
| ): ConversationIdResolution { | ||
| if (!enabled || toolName === missingCapabilityToolName) { | ||
| export function resolveConversationId(enabled: boolean, args: unknown): ConversationIdResolution { | ||
| if (!enabled) { | ||
| return { minted: false, conversationId: undefined } | ||
| } | ||
| const supplied = extractConversationId(args) | ||
| if (supplied) { | ||
| return { minted: false, conversationId: supplied } | ||
| if (supplied && MINTED_CONVERSATION_ID.test(supplied)) { | ||
| // Lowercased because the shape test is case-insensitive but the hash behind | ||
| // `$session_id` is not. Some hosts normalise uuids to uppercase, and an | ||
| // uppercased echo of our own handle would otherwise clear the gate and then | ||
| // land in a different session than the call that minted it. | ||
| return { minted: false, conversationId: supplied.toLowerCase() } | ||
| } | ||
@@ -117,5 +139,9 @@ return { minted: true, conversationId: uuidv7() } | ||
| /** | ||
| * Predicate matching the same eligibility checks injectConversationIdPromptBack uses, | ||
| * exposed so callers can pre-decide whether the prompt-back will actually land | ||
| * (and clear event.conversationId if not, to avoid orphan ids in analytics). | ||
| * Whether the prompt-back can ride this result's `content`. The only requirement | ||
| * is an array to append to. | ||
| * | ||
| * Errored results included on purpose. A tool that fails on the first call of a | ||
| * conversation is exactly when the agent needs the session handle: without it the | ||
| * retry starts a fresh conversation, so the failure and its fix land in different | ||
| * sessions. | ||
| */ | ||
@@ -126,7 +152,3 @@ export function canInjectConversationIdPromptBack(result: unknown): boolean { | ||
| } | ||
| const resultObj = result as { content?: unknown; isError?: unknown } | ||
| if (resultObj.isError === true) { | ||
| return false | ||
| } | ||
| return Array.isArray(resultObj.content) | ||
| return Array.isArray((result as { content?: unknown }).content) | ||
| } | ||
@@ -133,0 +155,0 @@ |
@@ -265,3 +265,5 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| execute: (downstreamRequest) => originalCallToolHandler(downstreamRequest as MCPRequest, extra), | ||
| parameterOwnership: registeredTool ? getAnalyticsParameterOwnership(registeredTool.inputSchema) : undefined, | ||
| parameterOwnership: registeredTool | ||
| ? getAnalyticsParameterOwnership(registeredTool.inputSchema, registeredTool.outputSchema) | ||
| : undefined, | ||
| takeCapturedError: () => { | ||
@@ -268,0 +270,0 @@ const captured = extra?.__mcp_analytics_error |
@@ -27,2 +27,3 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| import { stampMetaClientInfo } from './client-identity' | ||
| import { addInstructionsToOutputSchemas, mirrorInstructionsIntoStructuredContent } from './output-instructions' | ||
| import { captureEvent } from './capture' | ||
@@ -110,10 +111,3 @@ import { MCPAnalyticsEventType } from './event-types' | ||
| ) | ||
| const conversation = resolveConversationId( | ||
| ownership.conversationId, | ||
| request.params?.arguments, | ||
| request.params?.name, | ||
| resolvedEventType === MCPAnalyticsEventType.mcpMissingCapability | ||
| ? resolveMissingCapabilityToolName(data.options) | ||
| : '' | ||
| ) | ||
| const conversation = resolveConversationId(ownership.conversationId, request.params?.arguments) | ||
| const downstreamRequest = cloneRequestWithoutOwnedAnalyticsArguments(request, ownership) | ||
@@ -147,3 +141,3 @@ | ||
| const finalResult = applyConversationPromptBack(preparedEvent?.event ?? null, result, conversation) | ||
| const finalResult = applyConversationInstructions(preparedEvent?.event ?? null, result, conversation, ownership) | ||
| publishSuccessfulToolEvent(server, preparedEvent, finalResult, startTime, data.logger, takeCapturedError) | ||
@@ -164,7 +158,24 @@ return finalResult | ||
| ): AnalyticsParameterOwnership { | ||
| const ownership = override ?? (toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : undefined) | ||
| const listed = toolName ? data.toolAnalyticsParameterOwnership.get(toolName) : undefined | ||
| const ownership = override ?? listed | ||
| return { | ||
| context: !isMissingCapabilityTool && isContextEnabled(data.options.context) && ownership?.context === true, | ||
| conversationId: | ||
| !isMissingCapabilityTool && data.options.enableConversationId === true && ownership?.conversationId === true, | ||
| conversationId: data.options.enableConversationId === true && ownership?.conversationId === true, | ||
| // Deliberately read off `listed`, never the override. This asks whether | ||
| // `tools/list` actually declared `_mcp_instructions`, and only the advertised | ||
| // JSON Schema can answer it — an override is built from the live registry, | ||
| // which on the high-level path holds Zod. | ||
| // | ||
| // The cache is per-instance, so this is not merely "before the first | ||
| // `tools/list`": an instance that never serves a listing never writes the | ||
| // mirror at all. That is the per-request server pattern — `tools/list` lands | ||
| // on one instance, `tools/call` on a cold one — where the handle falls back | ||
| // to the `content` block and a structuredContent-only client misses it. | ||
| // | ||
| // Failing closed is deliberate. Writing a key the advertised schema did not | ||
| // declare fails the *entire* tool result under `additionalProperties: false`, | ||
| // so guessing costs the caller their result, while not guessing costs us one | ||
| // delivery channel. The fix is a process-scoped ownership cache, so a listing | ||
| // served by any instance answers for the rest — not a per-call guess. | ||
| outputInstructions: data.options.enableConversationId === true && listed?.outputInstructions === true, | ||
| } | ||
@@ -203,7 +214,15 @@ } | ||
| try { | ||
| const sessionId = getSessionId(server, extra) | ||
| const sessionId = getSessionId(server, extra, conversation.conversationId) | ||
| // Snapshot token/client/protocol metadata synchronously, before identify or | ||
| // metadata callbacks can yield and let another request replace shared state. | ||
| const sessionInfo = getSessionInfo(server, data, sessionId) | ||
| const identity = await handleIdentify(server, data, sessionId, request, sessionInfo, extra) | ||
| const identity = await handleIdentify( | ||
| server, | ||
| data, | ||
| sessionId, | ||
| request, | ||
| sessionInfo, | ||
| extra, | ||
| !!conversation.conversationId | ||
| ) | ||
| const requestAttribution = withIdentity(sessionInfo, identity) | ||
@@ -239,21 +258,47 @@ | ||
| /** | ||
| * When we minted a conversation id, append the prompt-back so the agent echoes | ||
| * it on subsequent calls. If the result can't carry it, clear the id off the | ||
| * event so analytics doesn't show an orphan the agent never received. | ||
| * Delivers the conversation session handle back to the agent, over both channels a tool | ||
| * result has: | ||
| * | ||
| * - `structuredContent`, on *every* response for a tool whose output schema we | ||
| * declared the key on. Clients that read structured results never see the text | ||
| * block, and re-sending it each time lets an agent that dropped the session handle read | ||
| * it back. | ||
| * - `content`, as a text block, only on the response that minted the session handle. | ||
| * Repeating it every call would put a `[SERVER]:` line in front of the user on | ||
| * every single tool result. | ||
| * | ||
| * If neither channel could carry a session handle we minted, the agent never received it, | ||
| * so clear it off the event rather than showing analytics an id nobody has. | ||
| */ | ||
| function applyConversationPromptBack( | ||
| function applyConversationInstructions( | ||
| event: McpEvent | null, | ||
| result: unknown, | ||
| conversation: ConversationIdResolution | ||
| conversation: ConversationIdResolution, | ||
| ownership: AnalyticsParameterOwnership | ||
| ): unknown { | ||
| if (!conversation.minted) { | ||
| const conversationId = conversation.conversationId | ||
| if (!conversationId) { | ||
| return result | ||
| } | ||
| if (canInjectConversationIdPromptBack(result)) { | ||
| return injectConversationIdPromptBack(result, conversation.conversationId) | ||
| let updated = result | ||
| let delivered = false | ||
| if (ownership.outputInstructions) { | ||
| const mirrored = mirrorInstructionsIntoStructuredContent(updated, conversationId) | ||
| delivered = mirrored !== updated | ||
| updated = mirrored | ||
| } | ||
| if (event) { | ||
| if (conversation.minted && canInjectConversationIdPromptBack(updated)) { | ||
| updated = injectConversationIdPromptBack(updated, conversationId) | ||
| delivered = true | ||
| } | ||
| // Only a minted session handle can be lost this way — one the agent supplied, it has. | ||
| if (!delivered && conversation.minted && event) { | ||
| event.conversationId = undefined | ||
| } | ||
| return result | ||
| return updated | ||
| } | ||
@@ -487,3 +532,3 @@ | ||
| if (tool?.name) { | ||
| cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema)) | ||
| cache.set(tool.name, getAnalyticsParameterOwnership(tool.inputSchema, tool.outputSchema)) | ||
| } | ||
@@ -525,3 +570,2 @@ } | ||
| const missingToolName = resolveMissingCapabilityToolName(data.options) | ||
| let injectedMissingCapabilityTool = false | ||
| if (data.options.reportMissing) { | ||
@@ -534,4 +578,7 @@ const alreadyPresent = tools.some((tool) => tool?.name === missingToolName) | ||
| } else { | ||
| tools.push(getReportMissingToolDescriptor(missingToolName)) | ||
| injectedMissingCapabilityTool = true | ||
| const virtualTool = getReportMissingToolDescriptor(missingToolName) | ||
| tools.push(virtualTool) | ||
| // Cached separately because the virtual tool is added after the listing | ||
| // was cached, and its calls need ownership like any other tool's. | ||
| cacheToolAnalyticsParameterOwnership(data.toolAnalyticsParameterOwnership, [virtualTool]) | ||
| } | ||
@@ -541,3 +588,4 @@ } | ||
| if (data.options.enableConversationId) { | ||
| tools = addConversationIdToTools(tools, missingToolName, injectedMissingCapabilityTool, data.logger) | ||
| tools = addConversationIdToTools(tools, data.logger) | ||
| tools = addInstructionsToOutputSchemas(tools, data.logger) | ||
| } | ||
@@ -544,0 +592,0 @@ } |
@@ -133,3 +133,10 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| requestAttribution: SessionInfo, | ||
| extra?: CompatibleRequestHandlerExtra | ||
| extra?: CompatibleRequestHandlerExtra, | ||
| /** | ||
| * True when this session id came from an agent-carried `conversation_id` | ||
| * rather than the transport. Such a session is brand new and was never | ||
| * announced at `initialize`, whatever `data.sessionSource` still says about | ||
| * the connection. | ||
| */ | ||
| sessionFromConversation = false | ||
| ): Promise<UserIdentity | undefined> { | ||
@@ -170,3 +177,4 @@ const identityBeforeRequest = data.identifiedSessions.get(sessionId) | ||
| const firstSeen = previousIdentity === undefined | ||
| const announcedAtInitialize = sessionSourceBeforeIdentify === 'token' && request.method !== 'initialize' | ||
| const announcedAtInitialize = | ||
| !sessionFromConversation && sessionSourceBeforeIdentify === 'token' && request.method !== 'initialize' | ||
| const shouldPublish = changed || (firstSeen && !announcedAtInitialize) | ||
@@ -173,0 +181,0 @@ |
+127
-28
@@ -18,2 +18,3 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| import { decodeSessionId, readMcpSessionHeader } from './session-token' | ||
| import type { SessionTokenPayload } from './session-token' | ||
@@ -33,8 +34,36 @@ export function newSessionId(): string { | ||
| /** | ||
| * Resolves the session id for a request: from the replayed session token, from | ||
| * the transport's MCP session id, or — when the request carries nothing — from | ||
| * this instance's memory. Also saves the token's client name/version so events | ||
| * built later in the request can use them (see getSessionInfo). | ||
| * Derives the SDK session id from the agent's conversation handle. Deterministic | ||
| * and unsalted on purpose: two pods that never met must agree on the session, and | ||
| * the 2026-07-28 revision leaves them no shared state to agree through. | ||
| * | ||
| * Hashed rather than used verbatim so an MCP session can never collide with a | ||
| * Session Replay id — a bare uuidv7 would render a "View recording" button that | ||
| * resolves to nothing. | ||
| * | ||
| * Exported because this *is* the cross-SDK contract: posthog-python has to | ||
| * reproduce it byte for byte or the same conversation splits into two sessions | ||
| * depending on which SDK served the call. | ||
| */ | ||
| export function getSessionId(server: MCPServerLike, extra?: CompatibleRequestHandlerExtra): string { | ||
| export function deriveSessionIdFromConversation(conversationId: string): string { | ||
| return deterministicPrefixedId('ses', conversationId) | ||
| } | ||
| /** | ||
| * Resolves the session id for a request. Three steps, first match wins: | ||
| * | ||
| * 1. the agent carried a `conversation_id` tool argument — 2026-07-28 | ||
| * 2. the request carried a session id — 2025-11-25 | ||
| * 3. nothing was carried, so reuse this instance's own id — stdio | ||
| * | ||
| * The split mirrors the two protocol revisions. 2026-07-28 removed protocol-level | ||
| * sessions, so the only thing that can carry a session across calls is the agent | ||
| * itself (1). 2025-11-25 kept the session on the connection, so the request | ||
| * carries it (2). 3 is for stdio, where neither applies — there is no | ||
| * HTTP request to carry anything, and no agent handle unless the host opted in. | ||
| */ | ||
| export function getSessionId( | ||
| server: MCPServerLike, | ||
| extra?: CompatibleRequestHandlerExtra, | ||
| conversationId?: string | ||
| ): string { | ||
| const data = getServerTrackingData(server) | ||
@@ -45,24 +74,34 @@ if (!data) { | ||
| // Our token rides the `mcp-session-id` request header, which stateless | ||
| // transports ignore — so read it ourselves. | ||
| const sessionHeader = readMcpSessionHeader(extra?.requestInfo?.headers) | ||
| const token = decodeSessionId(sessionHeader) | ||
| let sessionId: string | ||
| if (token) { | ||
| // Token we minted at `initialize` (see session-token.ts). | ||
| data.sessionSource = 'token' | ||
| data.sessionInfo.clientName = token.clientName | ||
| data.sessionInfo.clientVersion = token.clientVersion | ||
| data.sessionInfo.protocolVersion = token.protocolVersion | ||
| sessionId = token.sessionId | ||
| } else if (extra?.sessionId) { | ||
| // Session id issued by a stateful transport: hash it so the same MCP | ||
| // session maps to the same SDK session across restarts. | ||
| data.sessionSource = 'mcp' | ||
| sessionId = deriveSessionIdFromMCPSession(extra.sessionId) | ||
| } else { | ||
| sessionId = getSessionIdFromMemory(data) | ||
| // 1. The agent's conversation handle. It outranks both steps below because it | ||
| // is the only id that survives reconnects, restarts, and the per-request | ||
| // server instances the 2026-07-28 revision introduces. Hashed rather than used | ||
| // verbatim so it can never collide with Session Replay ids. | ||
| // | ||
| // This returns instead of falling through to the shared-state writes at the | ||
| // end: the handle belongs to this one request, and persisting it would leak | ||
| // one chat's session onto a concurrent chat's `tools/list`. | ||
| // | ||
| // `lastActivity` therefore does not advance either, so a conversation that | ||
| // always echoes lets the in-memory fallback age past the inactivity timeout — | ||
| // and a later call carrying no handle rotates it. That is the honest reading: | ||
| // the fallback session really has been idle for that whole time. | ||
| if (conversationId) { | ||
| // The handle decides the *session*, but the request may still carry our token, | ||
| // and on a stateless instance that never processed `initialize` its payload is | ||
| // the only place client identity exists. Restore that before returning: the | ||
| // early return is about not persisting a session, not about ignoring what the | ||
| // request told us about the client. Without this, tool calls and `$identify` | ||
| // go out unattributed on exactly the deployments this branch exists for. | ||
| applyTokenClientIdentity(data, extra) | ||
| return deriveSessionIdFromConversation(conversationId) | ||
| } | ||
| // 2. A session id the request itself carried (undefined if it carried none). | ||
| const carriedByRequest = readSessionIdFromRequest(data, extra) | ||
| // 3. Nothing carried, so fall back to the id this instance already holds. | ||
| const sessionId = carriedByRequest ?? getSessionIdFromMemory(data) | ||
| // 2 and 3 are connection-scoped, so their result is remembered for the | ||
| // next request on this instance. 1 never reaches here. | ||
| data.sessionId = sessionId | ||
@@ -75,6 +114,66 @@ data.lastActivity = new Date() | ||
| /** | ||
| * Nothing replayed on this request: keep the id we already have. Only | ||
| * generated sessions roll over on inactivity — token/MCP ids live as long as | ||
| * the client replays them, and regenerating one would split the session. | ||
| * Restores the client name/version and protocol version baked into our token at | ||
| * mint time, and hands the decoded token back so the caller can also take the | ||
| * session id from it. | ||
| * | ||
| * Split out from step 2 because the two halves of the token have different | ||
| * scopes. The session id it carries is per-chat, so a conversation-anchored | ||
| * request must not adopt it. The client identity is per-connection — the same | ||
| * client for every request on it — so a conversation-anchored request should, | ||
| * and on a stateless instance that never saw `initialize` this is the only | ||
| * source of it. | ||
| */ | ||
| function applyTokenClientIdentity( | ||
| data: MCPAnalyticsData, | ||
| extra?: CompatibleRequestHandlerExtra | ||
| ): SessionTokenPayload | undefined { | ||
| const token = decodeSessionId(readMcpSessionHeader(extra?.requestInfo?.headers)) | ||
| if (!token) { | ||
| return undefined | ||
| } | ||
| data.sessionInfo.clientName = token.clientName | ||
| data.sessionInfo.clientVersion = token.clientVersion | ||
| data.sessionInfo.protocolVersion = token.protocolVersion | ||
| return token | ||
| } | ||
| /** | ||
| * 2. The session id a request carried. Two sources, tried in order: our own token | ||
| * on the `mcp-session-id` header, then the raw session id a stateful transport | ||
| * issued. Returns undefined when the request carried neither, which is what | ||
| * sends the caller on to 3. | ||
| * | ||
| * Both are 2025-11-25 mechanisms. The 2026-07-28 revision removed that header | ||
| * outright — servers MUST NOT mint or echo it — so this entire step becomes | ||
| * legacy-only once era detection lands. | ||
| */ | ||
| function readSessionIdFromRequest(data: MCPAnalyticsData, extra?: CompatibleRequestHandlerExtra): string | undefined { | ||
| // 2a. A token we minted at `initialize` and the client replayed. It rides the | ||
| // `mcp-session-id` header, which stateless transports don't surface as | ||
| // extra.sessionId, so read the header ourselves. | ||
| const token = applyTokenClientIdentity(data, extra) | ||
| if (token) { | ||
| data.sessionSource = 'token' | ||
| return token.sessionId | ||
| } | ||
| // 2b. No token, but a stateful transport issued its own session id. Hash it so | ||
| // the same MCP session maps to the same SDK session across restarts. | ||
| if (extra?.sessionId) { | ||
| data.sessionSource = 'mcp' | ||
| return deriveSessionIdFromMCPSession(extra.sessionId) | ||
| } | ||
| return undefined | ||
| } | ||
| /** | ||
| * 3. The request carried nothing, so keep the id this instance already holds — | ||
| * minted once at `instrument()`. This is what groups a stdio server's calls, | ||
| * where there is no header and no transport session to read. | ||
| * | ||
| * Only self-generated ids roll over on inactivity. Token and transport ids live | ||
| * as long as the client replays them, so regenerating one would split a session | ||
| * that is still very much alive. | ||
| */ | ||
| function getSessionIdFromMemory(data: MCPAnalyticsData): string { | ||
@@ -81,0 +180,0 @@ const timeoutMs = INACTIVITY_TIMEOUT_IN_MINUTES * 60 * 1000 |
+23
-1
@@ -60,3 +60,17 @@ // Portions of this file are derived from agentcathq/agentcat-typescript-sdk | ||
| missingCapabilityToolName?: string | ||
| /** Enables the `conversation_id` tool parameter + prompt-back loop. */ | ||
| /** | ||
| * Opt in to session correlation for the MCP **2026-07-28** revision, which removed | ||
| * protocol-level sessions: no `initialize`, no `mcp-session-id` header, and a fresh | ||
| * server instance per HTTP request. With none of those left to anchor on, the only | ||
| * thing that can carry a session across calls is the agent itself. | ||
| * | ||
| * Turning this on injects a `conversation_id` parameter into every tool, mints one | ||
| * on the first call, asks the agent to echo it back, and derives `$session_id` from | ||
| * that handle — so calls correlate across reconnects, restarts, and per-request | ||
| * instances. | ||
| * | ||
| * Off by default, and fully inert when off: no parameter is injected, no schema is | ||
| * touched, no prompt-back is appended, and `$session_id` resolves exactly as it did | ||
| * before (the request's own session id, else this instance's). | ||
| */ | ||
| enableConversationId?: boolean | ||
@@ -127,2 +141,4 @@ /** | ||
| inputSchema?: unknown | ||
| /** Present when the tool was registered with a declared output schema. */ | ||
| outputSchema?: unknown | ||
| update?: (...args: unknown[]) => unknown | ||
@@ -279,2 +295,8 @@ } & ({ callback: ToolCallback; handler?: never } | { handler: ToolCallback; callback?: never }) | ||
| conversationId: boolean | ||
| /** | ||
| * True when we declared `_mcp_instructions` on this tool's advertised output | ||
| * schema, so writing that key into `structuredContent` will validate. False | ||
| * for tools with no output schema, or one we could not extend. | ||
| */ | ||
| outputInstructions: boolean | ||
| } | ||
@@ -281,0 +303,0 @@ |
+1
-1
@@ -1,1 +0,1 @@ | ||
| export const version = '0.10.7' | ||
| export const version = '0.10.8' |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
626178
7.32%163
3.16%12686
7.1%0
-100%Updated