@posthog/mcp 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +76 -0
- package/dist/index.cjs +2695 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +240 -0
- package/dist/index.d.mts +239 -0
- package/dist/index.mjs +2692 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["fsModule","isRecord","packageJson.version","MAX_STACK_FRAMES","isToolResultError","applyResolvedMetadata","getContextArgument","v4Schema","v3Schema","handler","highLevelServer"],"sources":["../src/modules/logging.ts","../src/modules/compatibility.ts","../src/modules/ids.ts","../src/modules/event-types.ts","../src/modules/validation.ts","../src/modules/internal.ts","../src/modules/constants.ts","../src/modules/posthog-events.ts","../src/modules/redaction.ts","../src/modules/mcp-payloads.ts","../src/modules/sanitization.ts","../package.json","../src/modules/session.ts","../src/modules/truncation.ts","../src/modules/event-queue.ts","../src/modules/exceptions.ts","../src/modules/context-parameters.ts","../src/modules/tools.ts","../src/modules/tracing.ts","../src/modules/mcp-sdk-compat.ts","../src/modules/tracing-v2.ts","../src/index.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\n// Lazy-loaded module references for Node.js file logging\n// These are loaded dynamically to support edge environments (Cloudflare Workers, etc.)\nlet fsModule: typeof import(\"fs\") | null = null;\nlet logFilePath: string | null = null;\nlet initAttempted = false;\nlet useConsoleFallback = false;\n\n/**\n * Attempts to initialize Node.js file logging.\n * Falls back to console.log in edge environments where fs/os modules are unavailable.\n */\nfunction tryInitSync(): void {\n if (initAttempted) {\n return;\n }\n initAttempted = true;\n\n try {\n // Use createRequire for ESM compatibility\n // Works in Node.js ESM/CJS, fails gracefully in Workers/edge environments\n const require = createRequire(import.meta.url);\n const fs = require(\"node:fs\");\n const os = require(\"node:os\");\n const path = require(\"node:path\");\n\n const home = os.homedir?.();\n if (home) {\n fsModule = fs;\n logFilePath = path.join(home, \"posthog-mcp-analytics.log\");\n } else {\n // homedir() returned null/undefined - use console fallback\n useConsoleFallback = true;\n }\n } catch {\n // Module not available or homedir() not implemented - use console fallback\n useConsoleFallback = true;\n fsModule = null;\n logFilePath = null;\n }\n}\n\nexport function writeToLog(message: string): void {\n tryInitSync();\n\n const timestamp = new Date().toISOString();\n const logEntry = `[${timestamp}] ${message}`;\n\n if (useConsoleFallback) {\n return;\n }\n\n // Node.js environment: write to file\n if (!(logFilePath && fsModule)) {\n return;\n }\n\n try {\n if (fsModule.existsSync(logFilePath)) {\n fsModule.appendFileSync(logFilePath, `${logEntry}\\n`);\n } else {\n fsModule.writeFileSync(logFilePath, `${logEntry}\\n`);\n }\n } catch {\n // Silently fail to avoid breaking the server\n }\n}\n","import type { HighLevelMCPServerLike, MCPServerLike } from \"../types.js\";\nimport { writeToLog } from \"./logging.js\";\n\ntype ServerRecord = Record<string, unknown>;\n\n/**\n * PostHog MCP analytics Compatibility Module\n *\n * This module ensures compatibility with Model Context Protocol TypeScript SDK.\n * PostHog MCP analytics only supports MCP SDK version 1.11 and above.\n *\n * Version 1.11+ is required because it introduced stable APIs for:\n * - Tool registration and handling\n * - Request handler access patterns\n * - Client version detection\n * - Server info structure\n */\n\n// Function to log compatibility information\nexport function logCompatibilityWarning(): void {\n writeToLog(\n \"PostHog MCP analytics SDK Compatibility: This version only supports Model Context Protocol TypeScript SDK v1.11 and above. Please upgrade if using an older version.\"\n );\n}\n\n// Check if server has high-level structure (wrapper with .server property)\nexport function isHighLevelServer(\n server: unknown\n): server is ServerRecord & { server: ServerRecord } {\n return (\n !!server &&\n typeof server === \"object\" &&\n \"server\" in server &&\n !!server.server &&\n typeof server.server === \"object\"\n );\n}\n\n// Check if server has low-level structure (no .server property)\nexport function isLowLevelServer(server: unknown): server is ServerRecord {\n return !!server && typeof server === \"object\" && !(\"server\" in server);\n}\n\n// Type guard function that validates server compatibility and returns typed server\nexport function isCompatibleServerType(\n server: unknown\n): MCPServerLike | HighLevelMCPServerLike {\n if (!server || typeof server !== \"object\") {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher.\"\n );\n }\n\n if (isHighLevelServer(server)) {\n // Validate high-level server requirements\n if (\n !server._registeredTools ||\n typeof server._registeredTools !== \"object\"\n ) {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: High-level server must have _registeredTools object. This requires MCP SDK v1.11 or higher.\"\n );\n }\n if (typeof server.tool !== \"function\") {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: High-level server must have tool() method. This requires MCP SDK v1.11 or higher.\"\n );\n }\n\n // Validate the underlying low-level server\n const targetServer = server.server;\n validateLowLevelServer(targetServer);\n\n return server as unknown as HighLevelMCPServerLike;\n }\n // Direct low-level server validation\n validateLowLevelServer(server);\n return server as MCPServerLike;\n}\n\n// Helper function to validate low-level server requirements\nfunction validateLowLevelServer(server: unknown): void {\n if (!server || typeof server !== \"object\") {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server must be an object. Ensure you're using MCP SDK v1.11 or higher.\"\n );\n }\n\n const serverRecord = server as ServerRecord;\n\n if (typeof serverRecord.setRequestHandler !== \"function\") {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server must have a setRequestHandler method. This requires MCP SDK v1.11 or higher.\"\n );\n }\n\n if (\n !(\n serverRecord._requestHandlers &&\n serverRecord._requestHandlers instanceof Map\n )\n ) {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server._requestHandlers is not accessible. This requires MCP SDK v1.11 or higher.\"\n );\n }\n\n // Validate that _requestHandlers contains functions with compatible signatures\n if (typeof serverRecord._requestHandlers.get !== \"function\") {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server._requestHandlers must be a Map with a get method. This requires MCP SDK v1.11 or higher.\"\n );\n }\n\n if (typeof serverRecord.getClientVersion !== \"function\") {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server.getClientVersion must be a function. This requires MCP SDK v1.11 or higher.\"\n );\n }\n\n if (\n !serverRecord._serverInfo ||\n typeof serverRecord._serverInfo !== \"object\" ||\n !(\"name\" in serverRecord._serverInfo)\n ) {\n logCompatibilityWarning();\n throw new Error(\n \"PostHog MCP analytics SDK compatibility error: Server._serverInfo is not accessible or missing name. This requires MCP SDK v1.11 or higher.\"\n );\n }\n}\n\nexport function getMCPCompatibleErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n try {\n return JSON.stringify(error, Object.getOwnPropertyNames(error));\n } catch {\n return \"Unknown error\";\n }\n } else if (typeof error === \"string\") {\n return error;\n } else if (typeof error === \"object\" && error !== null) {\n return JSON.stringify(error);\n }\n return \"Unknown error\";\n}\n","import { createHash, randomUUID } from \"node:crypto\";\n\nexport type MCPAnalyticsIDPrefix = \"evt\" | \"ses\";\n\nexport function newPrefixedId(prefix: MCPAnalyticsIDPrefix): string {\n return `${prefix}_${randomUUID()}`;\n}\n\nexport function deterministicPrefixedId(\n prefix: MCPAnalyticsIDPrefix,\n input: string\n): string {\n const hash = createHash(\"sha256\").update(input).digest(\"hex\");\n return `${prefix}_${hash.slice(0, 32)}`;\n}\n","export const MCPAnalyticsEventType = {\n identify: \"posthog:identify\",\n custom: \"posthog:custom\",\n mcpInitialize: \"mcp:initialize\",\n mcpPromptsGet: \"mcp:prompts/get\",\n mcpPromptsList: \"mcp:prompts/list\",\n mcpResourcesList: \"mcp:resources/list\",\n mcpResourcesRead: \"mcp:resources/read\",\n mcpToolsCall: \"mcp:tools/call\",\n mcpToolsList: \"mcp:tools/list\",\n} as const;\n\nexport type MCPAnalyticsEventType =\n (typeof MCPAnalyticsEventType)[keyof typeof MCPAnalyticsEventType];\n","import { writeToLog } from \"./logging.js\";\n\nconst TAG_KEY_REGEX = /^[a-zA-Z0-9$_.:\\- ]+$/;\nconst MAX_TAG_KEY_LENGTH = 32;\nconst MAX_TAG_VALUE_LENGTH = 200;\nconst MAX_TAG_ENTRIES = 50;\n\n/**\n * Validates and filters a tags object against PostHog MCP analytics tag constraints.\n * Invalid entries are logged as warnings and dropped.\n * Returns null if no valid entries remain.\n */\nexport function validateTags(\n tags: Record<string, string>\n): Record<string, string> | null {\n const entries = Object.entries(tags);\n\n if (entries.length === 0) {\n return null;\n }\n\n const valid: [string, string][] = [];\n\n for (const [key, value] of entries) {\n // Key validation\n if (typeof key !== \"string\" || !TAG_KEY_REGEX.test(key)) {\n writeToLog(\n `Dropping invalid tag: \"${String(key)}\" — key contains invalid characters or is empty`\n );\n continue;\n }\n\n if (key.length > MAX_TAG_KEY_LENGTH) {\n writeToLog(\n `Dropping invalid tag: \"${key}\" — key exceeds max length of ${MAX_TAG_KEY_LENGTH}`\n );\n continue;\n }\n\n // Value validation\n if (typeof value !== \"string\") {\n writeToLog(\n `Dropping invalid tag: \"${key}\" — non-string value (got ${typeof value})`\n );\n continue;\n }\n\n if (value.length > MAX_TAG_VALUE_LENGTH) {\n writeToLog(\n `Dropping invalid tag: \"${key}\" — value exceeds max length of ${MAX_TAG_VALUE_LENGTH}`\n );\n continue;\n }\n\n if (value.includes(\"\\n\")) {\n writeToLog(\n `Dropping invalid tag: \"${key}\" — value contains newline character`\n );\n continue;\n }\n\n valid.push([key, value]);\n }\n\n if (valid.length === 0) {\n return null;\n }\n\n if (valid.length > MAX_TAG_ENTRIES) {\n const dropped = valid.length - MAX_TAG_ENTRIES;\n writeToLog(\n `Dropping ${dropped} tag(s) — exceeds maximum of ${MAX_TAG_ENTRIES} entries per event`\n );\n valid.length = MAX_TAG_ENTRIES;\n }\n\n return Object.fromEntries(valid);\n}\n","import type {\n CompatibleRequestHandlerExtra,\n MCPAnalyticsData,\n MCPRequestLike,\n MCPServerLike,\n UnredactedEvent,\n UserIdentity,\n} from \"../types.js\";\nimport { publishEvent } from \"./event-queue.js\";\nimport { MCPAnalyticsEventType } from \"./event-types.js\";\nimport { writeToLog } from \"./logging.js\";\nimport { validateTags } from \"./validation.js\";\n\n/**\n * Simple LRU cache for session identities.\n * Prevents memory leaks by capping at maxSize entries.\n * This cache persists across server instance restarts.\n */\nclass IdentityCache {\n private readonly cache: Map<\n string,\n { identity: UserIdentity; timestamp: number }\n >;\n private readonly maxSize: number;\n\n constructor(maxSize = 1000) {\n this.cache = new Map();\n this.maxSize = maxSize;\n }\n\n get(sessionId: string): UserIdentity | undefined {\n const entry = this.cache.get(sessionId);\n if (entry) {\n // Update timestamp on access (LRU behavior)\n entry.timestamp = Date.now();\n // Move to end (most recently used)\n this.cache.delete(sessionId);\n this.cache.set(sessionId, entry);\n return entry.identity;\n }\n return;\n }\n\n set(sessionId: string, identity: UserIdentity): void {\n // Remove if already exists (to re-add at end)\n this.cache.delete(sessionId);\n\n // Evict oldest if at capacity\n if (this.cache.size >= this.maxSize) {\n const oldestKey = this.cache.keys().next().value;\n if (oldestKey !== undefined) {\n this.cache.delete(oldestKey);\n }\n }\n\n this.cache.set(sessionId, { identity, timestamp: Date.now() });\n }\n\n has(sessionId: string): boolean {\n return this.cache.has(sessionId);\n }\n\n size(): number {\n return this.cache.size;\n }\n}\n\n// Global identity cache shared across all server instances\n// This prevents duplicate identify events when server objects are recreated\nconst _globalIdentityCache = new IdentityCache(1000);\n\n// Internal tracking storage\nconst _serverTracking = new WeakMap<MCPServerLike, MCPAnalyticsData>();\n\nexport function getServerTrackingData(\n server: MCPServerLike\n): MCPAnalyticsData | undefined {\n return _serverTracking.get(server);\n}\n\nexport function setServerTrackingData(\n server: MCPServerLike,\n data: MCPAnalyticsData\n): void {\n _serverTracking.set(server, data);\n}\n\n/**\n * Deep comparison of two UserIdentity objects\n */\nexport function areIdentitiesEqual(a: UserIdentity, b: UserIdentity): boolean {\n if (a.userId !== b.userId) {\n return false;\n }\n if (a.userName !== b.userName) {\n return false;\n }\n\n // Deep compare userData objects\n const aData = a.userData || {};\n const bData = b.userData || {};\n\n const aKeys = Object.keys(aData);\n const bKeys = Object.keys(bData);\n\n if (aKeys.length !== bKeys.length) {\n return false;\n }\n\n for (const key of aKeys) {\n if (!(key in bData)) {\n return false;\n }\n if (JSON.stringify(aData[key]) !== JSON.stringify(bData[key])) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Merges two UserIdentity objects, overwriting userId and userName,\n * but merging userData fields\n */\nexport function mergeIdentities(\n previous: UserIdentity | undefined,\n next: UserIdentity\n): UserIdentity {\n if (!previous) {\n return next;\n }\n\n return {\n userId: next.userId,\n userName: next.userName,\n userData: {\n ...(previous.userData || {}),\n ...(next.userData || {}),\n },\n };\n}\n\n/**\n * Handles user identification for a request.\n * Calls the identify function if configured, compares with previous identity,\n * and publishes an identify event only if the identity has changed.\n *\n * @param server - The MCP server instance\n * @param data - The server tracking data\n * @param request - The request object to pass to identify function\n * @param extra - Optional extra parameters containing headers, sessionId, etc.\n */\nexport async function handleIdentify(\n server: MCPServerLike,\n data: MCPAnalyticsData,\n request: MCPRequestLike,\n extra?: CompatibleRequestHandlerExtra\n): Promise<void> {\n if (!data.options.identify) {\n return;\n }\n\n const sessionId = data.sessionId;\n const identifyEvent: UnredactedEvent = {\n sessionId,\n resourceName: getRequestResourceName(request),\n eventType: MCPAnalyticsEventType.identify,\n parameters: {\n request,\n extra,\n },\n timestamp: new Date(),\n redactionFn: data.options.redactSensitiveInformation,\n };\n\n try {\n const identityResult = await data.options.identify(request, extra);\n if (identityResult) {\n // Now use the (possibly updated) sessionId for all subsequent operations\n const currentSessionId = data.sessionId;\n\n // Check global cache first (works across server instance restarts)\n const previousIdentity = _globalIdentityCache.get(currentSessionId);\n\n // Merge identities (overwrite userId/userName, merge userData)\n const mergedIdentity = mergeIdentities(previousIdentity, identityResult);\n\n // Only publish if identity has changed\n const hasChanged = !(\n previousIdentity && areIdentitiesEqual(previousIdentity, mergedIdentity)\n );\n\n // Update BOTH caches to keep them in sync\n // Global cache: persists across server instances\n _globalIdentityCache.set(currentSessionId, mergedIdentity);\n // Per-server cache: used by getSessionInfo() for fast local access\n data.identifiedSessions.set(data.sessionId, mergedIdentity);\n\n if (hasChanged) {\n writeToLog(\n `Identified session ${currentSessionId} with identity: ${JSON.stringify(mergedIdentity)}`\n );\n publishEvent(server, identifyEvent);\n }\n } else {\n writeToLog(\n `Warning: Supplied identify function returned null for session ${sessionId}`\n );\n }\n } catch (error) {\n writeToLog(\n `Error: User supplied identify function threw an error while identifying session ${sessionId} - ${error}`\n );\n }\n}\n\n/**\n * Resolves the eventTags callback, validates the result, and returns validated tags.\n * Returns null if no callback configured, callback returns nullish, or callback throws.\n */\nexport async function resolveEventTags(\n data: MCPAnalyticsData,\n request: MCPRequestLike,\n extra?: CompatibleRequestHandlerExtra\n): Promise<Record<string, string> | null> {\n if (!data.options.eventTags) {\n return null;\n }\n try {\n const raw = (await data.options.eventTags(request, extra)) ?? null;\n if (!raw) {\n return null;\n }\n return validateTags(raw);\n } catch (e) {\n writeToLog(`eventTags callback error: ${e}`);\n return null;\n }\n}\n\n/**\n * Resolves the eventProperties callback and returns the result.\n * Returns null if no callback configured, callback returns nullish, or callback throws.\n */\nexport async function resolveEventProperties(\n data: MCPAnalyticsData,\n request: MCPRequestLike,\n extra?: CompatibleRequestHandlerExtra\n): Promise<Record<string, unknown> | null> {\n if (!data.options.eventProperties) {\n return null;\n }\n try {\n return (await data.options.eventProperties(request, extra)) ?? null;\n } catch (e) {\n writeToLog(`eventProperties callback error: ${e}`);\n return null;\n }\n}\n\nfunction getRequestResourceName(request: unknown): string {\n if (!request || typeof request !== \"object\" || !(\"params\" in request)) {\n return \"Unknown\";\n }\n\n const params = request.params;\n if (!params || typeof params !== \"object\" || !(\"name\" in params)) {\n return \"Unknown\";\n }\n\n return typeof params.name === \"string\" ? params.name : \"Unknown\";\n}\n","// PostHog MCP analytics settings\nexport const INACTIVITY_TIMEOUT_IN_MINUTES = 30;\nexport const DEFAULT_CONTEXT_PARAMETER_DESCRIPTION = `Explain why you are calling this tool and how it fits into the user's overall goal. This parameter is used for analytics and user intent tracking. YOU MUST provide 15-25 words (count carefully). NEVER use first person ('I', 'we', 'you') - maintain third-person perspective. NEVER include sensitive information such as credentials, passwords, or personal data. Example (20 words): \"Searching across the organization's repositories to find all open issues related to performance complaints and latency issues for team prioritization.\"`;\nexport const POSTHOG_MCP_ANALYTICS_SOURCE = \"posthog_mcp_analytics\";\n\nexport const PostHogMCPAnalyticsProperty = {\n AiInputState: \"$ai_input_state\",\n AiIsError: \"$ai_is_error\",\n AiLatency: \"$ai_latency\",\n AiOutputState: \"$ai_output_state\",\n AiProduct: \"$ai_product\",\n AiSessionId: \"$ai_session_id\",\n AiSpanId: \"$ai_span_id\",\n AiSpanName: \"$ai_span_name\",\n AiTraceId: \"$ai_trace_id\",\n ClientName: \"$mcp_client_name\",\n ClientVersion: \"$mcp_client_version\",\n DurationMs: \"$mcp_duration_ms\",\n IsError: \"$mcp_is_error\",\n Intent: \"$mcp_intent\",\n Parameters: \"$mcp_parameters\",\n ResourceName: \"$mcp_resource_name\",\n Response: \"$mcp_response\",\n ServerName: \"$mcp_server_name\",\n ServerVersion: \"$mcp_server_version\",\n SessionId: \"$session_id\",\n Source: \"$mcp_source\",\n ToolName: \"$mcp_tool_name\",\n} as const;\n\nexport type PostHogMCPAnalyticsProperty =\n (typeof PostHogMCPAnalyticsProperty)[keyof typeof PostHogMCPAnalyticsProperty];\n","import type { Event } from \"../types.js\";\nimport {\n POSTHOG_MCP_ANALYTICS_SOURCE,\n PostHogMCPAnalyticsProperty,\n} from \"./constants.js\";\nimport { MCPAnalyticsEventType } from \"./event-types.js\";\n\nconst MCP_EVENT_PREFIX_REGEX = /^mcp:/;\nconst SLASH_REGEX = /\\//g;\n\nfunction getDistinctId(event: Event): string {\n return event.identifyActorGivenId || event.sessionId || \"anonymous\";\n}\n\nfunction getTimestamp(event: Event): string {\n return event.timestamp\n ? event.timestamp.toISOString()\n : new Date().toISOString();\n}\n\nexport interface PostHogCaptureEvent {\n distinct_id: string;\n event: string;\n properties: Record<string, unknown>;\n timestamp: string;\n type: \"capture\";\n}\n\nexport interface BuildPostHogCaptureEventsOptions {\n enableAITracing?: boolean;\n}\n\nexport function buildPostHogCaptureEvents(\n event: Event,\n options: BuildPostHogCaptureEventsOptions = {}\n): PostHogCaptureEvent[] {\n const batch = [buildCaptureEvent(event, options)];\n\n if (event.isError && event.error) {\n batch.push(buildExceptionEvent(event));\n }\n\n if (shouldBuildAISpan(event, options)) {\n batch.push(buildAISpanEvent(event));\n }\n\n return batch;\n}\n\nfunction buildCaptureEvent(\n event: Event,\n options: BuildPostHogCaptureEventsOptions\n): PostHogCaptureEvent {\n const distinctId = getDistinctId(event);\n const eventName = mapEventType(event.eventType);\n const timestamp = getTimestamp(event);\n\n const properties: Record<string, unknown> = {\n [PostHogMCPAnalyticsProperty.SessionId]: event.sessionId,\n [PostHogMCPAnalyticsProperty.Source]: POSTHOG_MCP_ANALYTICS_SOURCE,\n };\n\n addCommonEventProperties(event, properties);\n addTraceReferenceProperties(event, properties, options);\n addCustomEventProperties(event, properties);\n\n return {\n event: eventName,\n distinct_id: distinctId,\n properties,\n timestamp,\n type: \"capture\",\n };\n}\n\nfunction shouldBuildAISpan(\n event: Event,\n options: BuildPostHogCaptureEventsOptions\n): boolean {\n return (\n options.enableAITracing === true &&\n event.eventType === MCPAnalyticsEventType.mcpToolsCall\n );\n}\n\nfunction getAITraceId(event: Event): string {\n return event.sessionId;\n}\n\nfunction getAISpanId(event: Event): string {\n return event.id;\n}\n\nfunction addTraceReferenceProperties(\n event: Event,\n properties: Record<string, unknown>,\n options: BuildPostHogCaptureEventsOptions\n): void {\n if (!shouldBuildAISpan(event, options)) {\n return;\n }\n\n properties[PostHogMCPAnalyticsProperty.AiTraceId] = getAITraceId(event);\n properties[PostHogMCPAnalyticsProperty.AiSpanId] = getAISpanId(event);\n}\n\nfunction addCommonEventProperties(\n event: Event,\n properties: Record<string, unknown>\n): void {\n if (event.resourceName) {\n properties[PostHogMCPAnalyticsProperty.ResourceName] = event.resourceName;\n if (event.eventType === MCPAnalyticsEventType.mcpToolsCall) {\n properties[PostHogMCPAnalyticsProperty.ToolName] = event.resourceName;\n }\n }\n if (event.duration !== undefined) {\n properties[PostHogMCPAnalyticsProperty.DurationMs] = event.duration;\n }\n if (event.serverName) {\n properties[PostHogMCPAnalyticsProperty.ServerName] = event.serverName;\n }\n if (event.serverVersion) {\n properties[PostHogMCPAnalyticsProperty.ServerVersion] = event.serverVersion;\n }\n if (event.clientName) {\n properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;\n }\n if (event.clientVersion) {\n properties[PostHogMCPAnalyticsProperty.ClientVersion] = event.clientVersion;\n }\n if (event.userIntent) {\n properties[PostHogMCPAnalyticsProperty.Intent] = event.userIntent;\n }\n if (event.isError !== undefined) {\n properties[PostHogMCPAnalyticsProperty.IsError] = event.isError;\n }\n\n if (event.parameters !== undefined) {\n properties[PostHogMCPAnalyticsProperty.Parameters] = event.parameters;\n }\n if (event.response !== undefined) {\n properties[PostHogMCPAnalyticsProperty.Response] = event.response;\n }\n\n const $set: Record<string, unknown> = {};\n if (event.identifyActorName) {\n $set.name = event.identifyActorName;\n }\n if (event.identifyActorData) {\n Object.assign($set, event.identifyActorData);\n }\n if (Object.keys($set).length > 0) {\n properties.$set = $set;\n }\n}\n\nfunction addCustomEventProperties(\n event: Event,\n properties: Record<string, unknown>\n): void {\n if (event.tags) {\n for (const [key, value] of Object.entries(event.tags)) {\n properties[key] = value;\n }\n }\n\n if (event.properties) {\n for (const [key, value] of Object.entries(event.properties)) {\n properties[key] = value;\n }\n }\n}\n\nfunction buildExceptionEvent(event: Event): PostHogCaptureEvent {\n const distinctId = getDistinctId(event);\n const timestamp = getTimestamp(event);\n\n const properties: Record<string, unknown> = {\n $exception_source: \"backend\",\n [PostHogMCPAnalyticsProperty.SessionId]: event.sessionId,\n };\n\n if (event.error) {\n if (event.error.message) {\n properties.$exception_message = event.error.message;\n }\n if (event.error.type) {\n properties.$exception_type = event.error.type;\n }\n if (event.error.stack) {\n properties.$exception_stacktrace = event.error.stack;\n }\n }\n\n if (event.resourceName) {\n properties[PostHogMCPAnalyticsProperty.ResourceName] = event.resourceName;\n if (event.eventType === MCPAnalyticsEventType.mcpToolsCall) {\n properties[PostHogMCPAnalyticsProperty.ToolName] = event.resourceName;\n }\n }\n if (event.serverName) {\n properties[PostHogMCPAnalyticsProperty.ServerName] = event.serverName;\n }\n if (event.serverVersion) {\n properties[PostHogMCPAnalyticsProperty.ServerVersion] = event.serverVersion;\n }\n if (event.clientName) {\n properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;\n }\n if (event.clientVersion) {\n properties[PostHogMCPAnalyticsProperty.ClientVersion] = event.clientVersion;\n }\n\n return {\n event: \"$exception\",\n distinct_id: distinctId,\n properties,\n timestamp,\n type: \"capture\",\n };\n}\n\nfunction buildAISpanEvent(event: Event): PostHogCaptureEvent {\n const distinctId = getDistinctId(event);\n const timestamp = getTimestamp(event);\n\n const properties: Record<string, unknown> = {\n [PostHogMCPAnalyticsProperty.AiSessionId]: `posthog_mcp_analytics_${event.sessionId}`,\n [PostHogMCPAnalyticsProperty.AiTraceId]: getAITraceId(event),\n [PostHogMCPAnalyticsProperty.AiSpanId]: getAISpanId(event),\n [PostHogMCPAnalyticsProperty.AiSpanName]:\n event.resourceName || \"unknown_tool\",\n [PostHogMCPAnalyticsProperty.AiIsError]: event.isError,\n [PostHogMCPAnalyticsProperty.SessionId]: event.sessionId,\n [PostHogMCPAnalyticsProperty.Source]: POSTHOG_MCP_ANALYTICS_SOURCE,\n };\n\n if (event.duration !== undefined) {\n properties[PostHogMCPAnalyticsProperty.AiLatency] = event.duration / 1000;\n }\n if (event.isError && event.error) {\n properties.$ai_error = event.error;\n }\n if (event.parameters !== undefined) {\n properties[PostHogMCPAnalyticsProperty.AiInputState] = event.parameters;\n }\n if (event.response !== undefined) {\n properties[PostHogMCPAnalyticsProperty.AiOutputState] = event.response;\n }\n if (event.serverName) {\n properties[PostHogMCPAnalyticsProperty.ServerName] = event.serverName;\n }\n if (event.clientName) {\n properties[PostHogMCPAnalyticsProperty.ClientName] = event.clientName;\n }\n if (event.userIntent) {\n properties[PostHogMCPAnalyticsProperty.Intent] = event.userIntent;\n }\n\n if (event.tags) {\n for (const [key, value] of Object.entries(event.tags)) {\n properties[key] = value;\n }\n }\n\n if (event.properties) {\n for (const [key, value] of Object.entries(event.properties)) {\n properties[key] = value;\n }\n }\n\n return {\n event: \"$ai_span\",\n distinct_id: distinctId,\n properties,\n timestamp,\n type: \"capture\",\n };\n}\n\nfunction mapEventType(eventType: string): string {\n const mapping: Record<string, string> = {\n [MCPAnalyticsEventType.mcpToolsCall]: \"mcp_tool_call\",\n [MCPAnalyticsEventType.mcpToolsList]: \"mcp_tools_list\",\n [MCPAnalyticsEventType.mcpInitialize]: \"mcp_initialize\",\n [MCPAnalyticsEventType.mcpResourcesRead]: \"mcp_resource_read\",\n [MCPAnalyticsEventType.mcpResourcesList]: \"mcp_resources_list\",\n [MCPAnalyticsEventType.mcpPromptsGet]: \"mcp_prompt_get\",\n [MCPAnalyticsEventType.mcpPromptsList]: \"mcp_prompts_list\",\n };\n\n return (\n mapping[eventType] ||\n `mcp_${eventType.replace(MCP_EVENT_PREFIX_REGEX, \"\").replace(SLASH_REGEX, \"_\")}`\n );\n}\n","import type { Event, RedactFunction, UnredactedEvent } from \"../types.js\";\n\n/**\n * Set of field names that should be protected from redaction.\n * These fields contain system-level identifiers and metadata that\n * need to be preserved for analytics tracking.\n */\nconst PROTECTED_FIELDS = new Set([\n \"sessionId\",\n \"id\",\n \"apiKey\",\n \"server\",\n \"identifyActorGivenId\",\n \"identifyActorName\",\n \"identifyData\",\n \"resourceName\",\n \"eventType\",\n \"actorId\",\n \"tags\",\n \"properties\",\n]);\n\n/**\n * Recursively applies a redaction function to all string values in an object.\n * This ensures that sensitive information is removed from all string fields\n * before events are sent to the analytics service.\n *\n * @param obj - The object to redact strings from\n * @param redactFn - The redaction function to apply to each string\n * @param path - The current path in the object tree (used to check protected fields)\n * @param isProtected - Whether the current object/value is within a protected field\n * @returns A new object with all strings redacted\n */\nasync function redactStringsInObject(\n obj: unknown,\n redactFn: RedactFunction,\n path = \"\",\n isProtected = false\n): Promise<unknown> {\n if (obj === null || obj === undefined) {\n return obj;\n }\n\n // Handle strings\n if (typeof obj === \"string\") {\n // Don't redact if this field or any parent field is protected\n if (isProtected) {\n return obj;\n }\n return await redactFn(obj);\n }\n\n // Handle arrays\n if (Array.isArray(obj)) {\n return Promise.all(\n obj.map((item, index) =>\n redactStringsInObject(item, redactFn, `${path}[${index}]`, isProtected)\n )\n );\n }\n\n // Handle dates (don't redact)\n if (obj instanceof Date) {\n return obj;\n }\n\n // Handle objects\n if (typeof obj === \"object\") {\n const redactedObj: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(obj)) {\n // Skip functions and undefined values\n if (typeof value === \"function\" || value === undefined) {\n continue;\n }\n\n // Build the path for nested fields\n const fieldPath = path ? `${path}.${key}` : key;\n // Check if this field is protected (only check at top level)\n const isFieldProtected =\n isProtected || (path === \"\" && PROTECTED_FIELDS.has(key));\n redactedObj[key] = await redactStringsInObject(\n value,\n redactFn,\n fieldPath,\n isFieldProtected\n );\n }\n\n return redactedObj;\n }\n\n // For all other types (numbers, booleans, etc.), return as-is\n return obj;\n}\n\n/**\n * Applies the customer's redaction function to all string fields in an Event object.\n * This is the main entry point for redacting sensitive information from events\n * before they are sent to the analytics service.\n *\n * @param event - The event to redact\n * @param redactFn - The customer's redaction function\n * @returns A new event object with all strings redacted\n */\nexport function redactEvent(\n event: UnredactedEvent,\n redactFn: RedactFunction\n): Promise<Event> {\n return redactStringsInObject(event, redactFn, \"\", false) as Promise<Event>;\n}\n","const CONTEXT_ARGUMENT_NAME = \"context\";\nconst REDACTED_VALUE = \"[redacted]\";\nconst BASE64_PATTERN = /^[A-Za-z0-9+/\\n\\r]+=*$/;\nconst SIZE_GATE = 10_240;\nconst POSTHOG_TOKEN_PATTERN = /\\bph[a-z]_[A-Za-z0-9_-]{20,}\\b/g;\nconst SENSITIVE_KEY_PATTERN =\n /^(authorization|cookie|set-cookie|x-api-key|api[-_]?key|api[-_]?token|access[-_]?token|refresh[-_]?token|token|password|secret|client[-_]?secret|private[-_]?key)$/i;\n\ntype JsonRecord = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction shouldRedactKey(key: string): boolean {\n return SENSITIVE_KEY_PATTERN.test(key);\n}\n\nfunction sanitizeString(value: string): string {\n if (value.length >= SIZE_GATE && BASE64_PATTERN.test(value)) {\n return \"[binary data redacted - not supported by PostHog MCP analytics]\";\n }\n return value.replace(POSTHOG_TOKEN_PATTERN, REDACTED_VALUE);\n}\n\nexport function sanitizeCapturedValue(value: unknown): unknown {\n if (value == null) {\n return value;\n }\n\n if (typeof value === \"string\") {\n return sanitizeString(value);\n }\n\n if (Array.isArray(value)) {\n return value.map(sanitizeCapturedValue);\n }\n\n if (value instanceof Date) {\n return value;\n }\n\n if (typeof value !== \"object\") {\n return value;\n }\n\n const result: JsonRecord = {};\n for (const [key, nestedValue] of Object.entries(value)) {\n result[key] = shouldRedactKey(key)\n ? REDACTED_VALUE\n : sanitizeCapturedValue(nestedValue);\n }\n return result;\n}\n\nfunction buildCapturedMcpArguments(argumentsValue: unknown): unknown {\n if (!isRecord(argumentsValue)) {\n return sanitizeCapturedValue(argumentsValue);\n }\n\n const capturedArguments: JsonRecord = {};\n for (const [key, value] of Object.entries(argumentsValue)) {\n if (key === CONTEXT_ARGUMENT_NAME) {\n continue;\n }\n capturedArguments[key] = sanitizeCapturedValue(value);\n }\n return capturedArguments;\n}\n\nfunction buildCapturedMcpParams(params: unknown): unknown {\n if (!isRecord(params)) {\n return sanitizeCapturedValue(params);\n }\n\n const capturedParams: JsonRecord = {};\n for (const [key, value] of Object.entries(params)) {\n capturedParams[key] =\n key === \"arguments\"\n ? buildCapturedMcpArguments(value)\n : sanitizeCapturedValue(value);\n }\n return capturedParams;\n}\n\nexport function buildCapturedMcpParameters(request: unknown): JsonRecord {\n if (!isRecord(request)) {\n return { request: sanitizeCapturedValue(request) };\n }\n\n const capturedRequest: JsonRecord = {};\n for (const key of [\"id\", \"jsonrpc\", \"method\"] as const) {\n if (key in request) {\n capturedRequest[key] = sanitizeCapturedValue(request[key]);\n }\n }\n\n if (\"params\" in request) {\n capturedRequest.params = buildCapturedMcpParams(request.params);\n }\n\n return { request: capturedRequest };\n}\n","import type { Event, UnredactedEvent } from \"../types.js\";\nimport { sanitizeCapturedValue } from \"./mcp-payloads.js\";\n\ntype SanitizedRecord = Record<string, unknown>;\n\nfunction isRecord(value: unknown): value is SanitizedRecord {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * Sanitizes an event by redacting non-text content blocks from responses\n * and large base64-encoded strings from parameters.\n *\n * This is a synchronous operation that returns a new object without mutating the original.\n * It should run after customer redaction in the event pipeline.\n */\nexport function sanitizeEvent<T extends Event | UnredactedEvent>(event: T): T {\n const result = { ...event };\n\n if (result.response != null) {\n result.response = sanitizeResponse(result.response);\n }\n\n if (result.parameters != null) {\n result.parameters = sanitizeParameters(result.parameters);\n }\n\n return result;\n}\n\n/**\n * Sanitizes response content blocks by replacing non-text content types\n * with informative redaction messages.\n */\nfunction sanitizeResponse(response: unknown): unknown {\n if (response == null || typeof response !== \"object\") {\n return sanitizeCapturedValue(response);\n }\n\n const sanitized = sanitizeCapturedValue(response);\n if (!isRecord(sanitized)) {\n return sanitized;\n }\n\n const result: SanitizedRecord = { ...sanitized };\n const content = result.content;\n if (Array.isArray(content)) {\n result.content = content.map(sanitizeContentBlock);\n }\n\n if (\n result.structuredContent != null &&\n typeof result.structuredContent === \"object\"\n ) {\n result.structuredContent = sanitizeCapturedValue(result.structuredContent);\n }\n\n return result;\n}\n\n/**\n * Sanitizes a single content block based on its type discriminator.\n */\nfunction sanitizeContentBlock(block: unknown): unknown {\n if (block == null || typeof block !== \"object\") {\n return block;\n }\n\n if (!isRecord(block)) {\n return block;\n }\n\n switch (block.type) {\n case \"text\":\n return sanitizeCapturedValue(block);\n\n case \"image\":\n return {\n type: \"text\",\n text: \"[image content redacted - not supported by PostHog MCP analytics]\",\n };\n\n case \"audio\":\n return {\n type: \"text\",\n text: \"[audio content redacted - not supported by PostHog MCP analytics]\",\n };\n\n case \"resource\":\n return sanitizeResourceBlock(block);\n\n case \"resource_link\":\n return sanitizeCapturedValue(block);\n\n default:\n return {\n type: \"text\",\n text: `[unsupported content type \"${block.type}\" redacted - not supported by PostHog MCP analytics]`,\n };\n }\n}\n\n/**\n * Sanitizes an embedded resource content block.\n * BlobResourceContents (has `blob` field) are redacted.\n * TextResourceContents (has `text` field) pass through.\n */\nfunction sanitizeResourceBlock(block: SanitizedRecord): unknown {\n if (isRecord(block.resource) && \"blob\" in block.resource) {\n return {\n type: \"text\",\n text: \"[binary resource content redacted - not supported by PostHog MCP analytics]\",\n };\n }\n return sanitizeCapturedValue(block);\n}\n\n/**\n * Recursively scans parameters for large base64-encoded strings and replaces them.\n * Uses a size gate (10KB) to avoid regex testing on small strings.\n */\nfunction sanitizeParameters(obj: unknown): unknown {\n return sanitizeCapturedValue(obj);\n}\n","","import packageJson from \"../../package.json\" with { type: \"json\" };\nimport type {\n CompatibleRequestHandlerExtra,\n MCPAnalyticsData,\n MCPServerLike,\n ServerClientInfoLike,\n SessionInfo,\n} from \"../types.js\";\nimport { INACTIVITY_TIMEOUT_IN_MINUTES } from \"./constants.js\";\nimport { deterministicPrefixedId, newPrefixedId } from \"./ids.js\";\nimport { getServerTrackingData, setServerTrackingData } from \"./internal.js\";\n\nexport function newSessionId(): string {\n return newPrefixedId(\"ses\");\n}\n\n/**\n * Creates a deterministic SDK session ID from an MCP sessionId.\n * The same inputs will always produce the same session ID, enabling correlation across server restarts.\n *\n * @param mcpSessionId - The session ID from the MCP protocol\n * @returns An SDK session ID with \"ses\" prefix derived deterministically from the inputs\n */\nexport function deriveSessionIdFromMCPSession(mcpSessionId: string): string {\n return deterministicPrefixedId(\"ses\", mcpSessionId);\n}\n\n/**\n * Gets or generates a session ID for the server.\n * Prioritizes MCP protocol sessionId over PostHog MCP analytics-generated sessionId.\n *\n * @param server - The MCP server instance\n * @param extra - Optional extra data containing MCP sessionId\n * @returns The session ID to use for events\n */\nexport function getServerSessionId(\n server: MCPServerLike,\n extra?: CompatibleRequestHandlerExtra\n): string {\n const data = getServerTrackingData(server);\n\n if (!data) {\n throw new Error(\"Server tracking data not found\");\n }\n\n const mcpSessionId = extra?.sessionId;\n\n // If MCP sessionId is provided\n if (mcpSessionId) {\n // Derive deterministic SDK session ID from MCP sessionId\n data.sessionId = deriveSessionIdFromMCPSession(mcpSessionId);\n data.lastMcpSessionId = mcpSessionId;\n data.sessionSource = \"mcp\";\n setServerTrackingData(server, data);\n // If MCP sessionId hasn't changed, continue using the existing derived ID\n setLastActivity(server);\n return data.sessionId;\n }\n\n // No MCP sessionId provided - handle PostHog MCP analytics-generated sessions\n // If we had an MCP sessionId before but it disappeared, keep using the last derived ID\n if (data.sessionSource === \"mcp\" && data.lastMcpSessionId) {\n setLastActivity(server);\n return data.sessionId;\n }\n\n // For PostHog MCP analytics-generated sessions, apply timeout logic\n const now = Date.now();\n const timeoutMs = INACTIVITY_TIMEOUT_IN_MINUTES * 60 * 1000;\n // If last activity timed out\n if (now - data.lastActivity.getTime() > timeoutMs) {\n data.sessionId = newSessionId();\n data.sessionSource = \"generated\";\n setServerTrackingData(server, data);\n }\n setLastActivity(server);\n\n return data.sessionId;\n}\n\nexport function setLastActivity(server: MCPServerLike): void {\n const data = getServerTrackingData(server);\n\n if (!data) {\n throw new Error(\"Server tracking data not found\");\n }\n\n data.lastActivity = new Date();\n setServerTrackingData(server, data);\n}\n\nexport function getSessionInfo(\n server: MCPServerLike,\n data: MCPAnalyticsData | undefined\n): SessionInfo {\n let clientInfo: ServerClientInfoLike | undefined = {\n name: undefined,\n version: undefined,\n };\n if (!data?.sessionInfo.clientName) {\n clientInfo = server.getClientVersion();\n }\n const actorInfo = data?.identifiedSessions.get(data.sessionId);\n\n const sessionInfo: SessionInfo = {\n ipAddress: undefined, // grab from django\n sdkLanguage: \"TypeScript\", // hardcoded for now\n sdkVersion: packageJson.version,\n serverName: server._serverInfo?.name,\n serverVersion: server._serverInfo?.version,\n clientName: clientInfo?.name,\n clientVersion: clientInfo?.version,\n identifyActorGivenId: actorInfo?.userId,\n identifyActorName: actorInfo?.userName,\n identifyActorData: actorInfo?.userData || {},\n };\n\n if (!data) {\n return sessionInfo;\n }\n\n data.sessionInfo = sessionInfo;\n setServerTrackingData(server, data);\n return data.sessionInfo;\n}\n","import type {\n ErrorData,\n Event,\n StackFrame,\n UnredactedEvent,\n} from \"../types.js\";\n\n// --- Constants ---\nexport const MAX_DEPTH = 10;\nexport const MAX_BREADTH = 100;\nexport const MAX_STRING_LENGTH = 32_768; // 32KB\nexport const MAX_EVENT_BYTES = 102_400; // 100KB\n\n// --- Field-level limit constants ---\nconst MAX_USER_INTENT_LENGTH = 2048;\nconst MAX_ERROR_MESSAGE_LENGTH = 2048;\nconst MAX_RESOURCE_NAME_LENGTH = 256;\nconst MAX_METADATA_LENGTH = 256;\nconst MAX_STACK_FRAMES = 50;\nconst MAX_CONTENT_TEXT_LENGTH = 32_768;\n\n// --- Truncation markers ---\nconst TRUNCATION_SUFFIX = \"...\";\n\ntype MutableEvent = Partial<Event | UnredactedEvent> & Record<string, unknown>;\ntype MutableRecord = Record<string, unknown>;\n\n/**\n * Recursively normalizes a value, handling:\n * - String truncation (> MAX_STRING_LENGTH)\n * - Non-serializable values (functions, symbols, undefined, BigInt, NaN, Infinity)\n * - Date objects -> ISO string\n * - Circular reference detection\n * - Depth limiting\n * - Breadth limiting\n */\nexport function normalize(\n input: unknown,\n depth: number = MAX_DEPTH,\n maxBreadth: number = MAX_BREADTH,\n maxStringLength: number = MAX_STRING_LENGTH\n): unknown {\n const memo = new WeakSet<object>();\n return visit(input, depth, maxBreadth, maxStringLength, memo);\n}\n\nfunction visit(\n value: unknown,\n remainingDepth: number,\n maxBreadth: number,\n maxStringLength: number,\n memo: WeakSet<object>\n): unknown {\n // null\n if (value === null) {\n return null;\n }\n\n // undefined\n if (value === undefined) {\n return \"[undefined]\";\n }\n\n // boolean\n if (typeof value === \"boolean\") {\n return value;\n }\n\n // number (including NaN, Infinity)\n if (typeof value === \"number\") {\n if (Number.isNaN(value)) {\n return \"[NaN]\";\n }\n if (!Number.isFinite(value)) {\n return value > 0 ? \"[Infinity]\" : \"[-Infinity]\";\n }\n return value;\n }\n\n // bigint\n if (typeof value === \"bigint\") {\n return `[BigInt: ${value}]`;\n }\n\n // string\n if (typeof value === \"string\") {\n if (value.length > maxStringLength) {\n return value.slice(0, maxStringLength) + TRUNCATION_SUFFIX;\n }\n return value;\n }\n\n // symbol\n if (typeof value === \"symbol\") {\n const desc = value.description;\n return desc ? `[Symbol(${desc})]` : \"[Symbol()]\";\n }\n\n // function\n if (typeof value === \"function\") {\n const name = value.name || \"<anonymous>\";\n return `[Function: ${name}]`;\n }\n\n // Date\n if (value instanceof Date) {\n return Number.isNaN(value.getTime())\n ? \"[Invalid Date]\"\n : value.toISOString();\n }\n\n // Objects and arrays from here — need depth/breadth/circular checks\n if (typeof value === \"object\") {\n // Circular reference detection\n if (memo.has(value)) {\n return \"[Circular ~]\";\n }\n\n // Depth limit\n if (remainingDepth <= 0) {\n return Array.isArray(value) ? \"[Array]\" : \"[Object]\";\n }\n\n memo.add(value);\n\n let result: unknown;\n if (Array.isArray(value)) {\n result = visitArray(\n value,\n remainingDepth - 1,\n maxBreadth,\n maxStringLength,\n memo\n );\n } else {\n result = visitObject(\n value as Record<string, unknown>,\n remainingDepth - 1,\n maxBreadth,\n maxStringLength,\n memo\n );\n }\n\n memo.delete(value);\n return result;\n }\n\n // Fallback: coerce to string\n return String(value);\n}\n\nfunction visitArray(\n arr: unknown[],\n remainingDepth: number,\n maxBreadth: number,\n maxStringLength: number,\n memo: WeakSet<object>\n): unknown[] {\n const result: unknown[] = [];\n for (let i = 0; i < arr.length; i++) {\n if (i >= maxBreadth) {\n result.push(\"[MaxProperties ~]\");\n break;\n }\n result.push(\n visit(arr[i], remainingDepth, maxBreadth, maxStringLength, memo)\n );\n }\n return result;\n}\n\nfunction visitObject(\n obj: Record<string, unknown>,\n remainingDepth: number,\n maxBreadth: number,\n maxStringLength: number,\n memo: WeakSet<object>\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n const keys = Object.keys(obj);\n let count = 0;\n\n for (const key of keys) {\n if (count >= maxBreadth) {\n result[\"...\"] = \"[MaxProperties ~]\";\n break;\n }\n // Skip undefined values — matches JSON.stringify behavior (omits undefined properties)\n if (obj[key] === undefined) {\n continue;\n }\n result[key] = visit(\n obj[key],\n remainingDepth,\n maxBreadth,\n maxStringLength,\n memo\n );\n count++;\n }\n\n return result;\n}\n\n// --- Field-level truncation helpers ---\n\nfunction truncateString(\n str: string | undefined,\n maxLength: number\n): string | undefined {\n if (str == null) {\n return str;\n }\n if (str.length <= maxLength) {\n return str;\n }\n return str.slice(0, maxLength) + TRUNCATION_SUFFIX;\n}\n\nfunction truncateStackFrames(\n frames: StackFrame[] | undefined\n): StackFrame[] | undefined {\n if (!frames || frames.length <= MAX_STACK_FRAMES) {\n return frames;\n }\n const half = Math.floor(MAX_STACK_FRAMES / 2);\n return [...frames.slice(0, half), ...frames.slice(-half)];\n}\n\nfunction truncateResponseContent(response: unknown): unknown {\n if (response == null || typeof response !== \"object\") {\n return response;\n }\n const result: MutableRecord = { ...(response as MutableRecord) };\n if (Array.isArray(result.content)) {\n result.content = result.content.map((block: unknown) => {\n if (\n block != null &&\n typeof block === \"object\" &&\n \"type\" in block &&\n \"text\" in block &&\n block?.type === \"text\" &&\n typeof block.text === \"string\" &&\n block.text.length > MAX_CONTENT_TEXT_LENGTH\n ) {\n return {\n ...(block as MutableRecord),\n text:\n block.text.slice(0, MAX_CONTENT_TEXT_LENGTH) + TRUNCATION_SUFFIX,\n };\n }\n return block;\n });\n }\n return result;\n}\n\n/**\n * Calculates the UTF-8 byte size of a JSON-serialized value.\n */\nconst textEncoder = new TextEncoder();\n\nfunction jsonByteSize(value: unknown): number {\n return textEncoder.encode(JSON.stringify(value)).length;\n}\n\n/**\n * Finds and truncates the largest string values in an object to fit within a byte budget.\n * Last-resort mechanism when depth reduction alone isn't enough.\n * Iterates until the result fits or no further reduction is possible.\n */\nfunction truncateLargestFields<T>(obj: T, maxBytes: number): T {\n const result = structuredClone(obj);\n\n for (let attempt = 0; attempt < 10; attempt++) {\n const currentSize = jsonByteSize(result);\n if (currentSize <= maxBytes) {\n return result;\n }\n\n const excess = currentSize - maxBytes;\n\n // Find all string values and their sizes, sorted largest first\n const stringPaths: Array<{ path: string[]; length: number }> = [];\n collectStringPaths(result, [], stringPaths);\n stringPaths.sort((a, b) => b.length - a.length);\n\n if (stringPaths.length === 0) {\n break; // no strings left to truncate\n }\n\n // Distribute the reduction across the largest strings\n let remaining = excess + 200; // buffer for JSON overhead from added \"...\" suffixes\n let truncated = false;\n\n for (const { path, length } of stringPaths) {\n if (remaining <= 0) {\n break;\n }\n const reduction = Math.min(remaining, Math.floor(length * 0.5));\n if (reduction < 10) {\n continue; // not worth truncating tiny strings\n }\n const newLength = length - reduction;\n const currentValue = getNestedValue(result, path);\n if (typeof currentValue !== \"string\") {\n continue;\n }\n setNestedValue(\n result,\n path,\n currentValue.slice(0, newLength) + TRUNCATION_SUFFIX\n );\n remaining -= reduction;\n truncated = true;\n }\n\n if (!truncated) {\n break; // no progress possible\n }\n }\n\n return result;\n}\n\nfunction collectStringPaths(\n obj: unknown,\n currentPath: string[],\n results: Array<{ path: string[]; length: number }>\n): void {\n if (typeof obj === \"string\" && obj.length > 100) {\n results.push({ path: [...currentPath], length: obj.length });\n return;\n }\n if (Array.isArray(obj)) {\n for (const [i, item] of obj.entries()) {\n collectStringPaths(item, [...currentPath, String(i)], results);\n }\n return;\n }\n if (obj != null && typeof obj === \"object\") {\n for (const [key, value] of Object.entries(obj)) {\n collectStringPaths(value, [...currentPath, key], results);\n }\n }\n}\n\nfunction getNestedValue(obj: unknown, path: string[]): unknown {\n let current: unknown = obj;\n for (const key of path) {\n if (current == null || typeof current !== \"object\") {\n return;\n }\n current = (current as MutableRecord)[key];\n }\n return current;\n}\n\nfunction setNestedValue(obj: unknown, path: string[], value: unknown): void {\n let current: unknown = obj;\n for (let i = 0; i < path.length - 1; i++) {\n if (current == null || typeof current !== \"object\") {\n return;\n }\n current = (current as MutableRecord)[path[i]];\n }\n const finalKey = path.at(-1);\n if (\n finalKey !== undefined &&\n current != null &&\n typeof current === \"object\"\n ) {\n (current as MutableRecord)[finalKey] = value;\n }\n}\n\n/**\n * Ensures an event fits within MAX_EVENT_BYTES by progressively reducing\n * normalization depth, then truncating largest string fields as a last resort.\n */\nfunction truncateToSize(event: MutableEvent): MutableEvent {\n // Check if already within budget\n if (jsonByteSize(event) <= MAX_EVENT_BYTES) {\n return event;\n }\n\n // Progressive depth reduction\n for (let depth = MAX_DEPTH - 1; depth >= 1; depth--) {\n const reduced: MutableEvent = { ...event };\n if (reduced.parameters != null) {\n reduced.parameters = normalize(reduced.parameters, depth);\n }\n if (reduced.response != null) {\n reduced.response = normalize(reduced.response, depth);\n }\n if (reduced.identifyActorData != null) {\n reduced.identifyActorData = normalize(\n reduced.identifyActorData,\n depth\n ) as Event[\"identifyActorData\"];\n }\n if (reduced.error != null) {\n reduced.error = normalize(reduced.error, depth) as Event[\"error\"];\n }\n\n if (jsonByteSize(reduced) <= MAX_EVENT_BYTES) {\n return reduced;\n }\n }\n\n // Last resort: truncate largest string fields\n const minimal: MutableEvent = { ...event };\n if (minimal.parameters != null) {\n minimal.parameters = normalize(minimal.parameters, 1);\n }\n if (minimal.response != null) {\n minimal.response = normalize(minimal.response, 1);\n }\n if (minimal.identifyActorData != null) {\n minimal.identifyActorData = normalize(\n minimal.identifyActorData,\n 1\n ) as Event[\"identifyActorData\"];\n }\n if (minimal.error != null) {\n minimal.error = normalize(minimal.error, 1) as Event[\"error\"];\n }\n\n return truncateLargestFields(minimal, MAX_EVENT_BYTES);\n}\n\n/**\n * Applies layered truncation to an event:\n * 1. Field-level string limits (userIntent, resourceName, metadata fields, error.message)\n * 2. Error frame limiting (first 25 + last 25 if > 50)\n * 3. Response content text limits (32KB per text block)\n * 4. Recursive normalization on user-controlled fields\n * 5. Size-targeted truncation (progressive depth reduction + last-resort string truncation)\n */\nexport function truncateEvent<T extends Event | UnredactedEvent>(event: T): T {\n const result: MutableEvent = { ...event };\n\n // Layer 1: Field-level string limits\n result.userIntent = truncateString(result.userIntent, MAX_USER_INTENT_LENGTH);\n result.resourceName = truncateString(\n result.resourceName,\n MAX_RESOURCE_NAME_LENGTH\n );\n result.serverName = truncateString(result.serverName, MAX_METADATA_LENGTH);\n result.serverVersion = truncateString(\n result.serverVersion,\n MAX_METADATA_LENGTH\n );\n result.clientName = truncateString(result.clientName, MAX_METADATA_LENGTH);\n result.clientVersion = truncateString(\n result.clientVersion,\n MAX_METADATA_LENGTH\n );\n\n // Error field limits\n if (result.error != null && typeof result.error === \"object\") {\n const error = { ...(result.error as Partial<ErrorData>) };\n error.message = truncateString(error.message, MAX_ERROR_MESSAGE_LENGTH);\n if (error.frames !== undefined) {\n error.frames = truncateStackFrames(error.frames);\n }\n result.error = error as ErrorData;\n }\n\n // Response content text limits\n result.response = truncateResponseContent(result.response);\n\n // Layer 2: Recursive normalization on user-controlled fields\n if (result.parameters != null) {\n result.parameters = normalize(result.parameters);\n }\n if (result.response != null) {\n result.response = normalize(result.response);\n }\n if (result.identifyActorData != null) {\n result.identifyActorData = normalize(\n result.identifyActorData\n ) as Event[\"identifyActorData\"];\n }\n if (result.error != null) {\n result.error = normalize(result.error) as Event[\"error\"];\n }\n\n // Layer 3: Size-targeted normalization\n return truncateToSize(result) as T;\n}\n","import { PostHog } from \"posthog-node\";\nimport type {\n Event,\n MCPAnalyticsOptions,\n MCPServerLike,\n PostHogCaptureClient,\n UnredactedEvent,\n} from \"../types.js\";\nimport { getMCPCompatibleErrorMessage } from \"./compatibility.js\";\nimport { newPrefixedId } from \"./ids.js\";\nimport { getServerTrackingData } from \"./internal.js\";\nimport { writeToLog } from \"./logging.js\";\nimport { buildPostHogCaptureEvents } from \"./posthog-events.js\";\nimport { redactEvent } from \"./redaction.js\";\nimport { sanitizeEvent } from \"./sanitization.js\";\nimport { getSessionInfo } from \"./session.js\";\nimport { truncateEvent } from \"./truncation.js\";\n\ninterface QueuedEvent {\n enableAITracing?: boolean;\n event: UnredactedEvent;\n posthogClient?: PostHogCaptureClient;\n}\n\nclass EventQueue {\n private readonly queue: QueuedEvent[] = [];\n private processing = false;\n private readonly maxQueueSize = 10_000; // Prevent unbounded growth\n private readonly concurrency = 5; // Max parallel requests\n private activeRequests = 0;\n private host = \"https://us.i.posthog.com\";\n private posthogOptions: NonNullable<MCPAnalyticsOptions[\"posthogOptions\"]> =\n {};\n private readonly posthogClients = new Map<string, PostHogCaptureClient>();\n\n configure(host: string): void {\n this.host = host;\n this.posthogClients.clear();\n }\n\n configurePostHogOptions(\n posthogOptions: NonNullable<MCPAnalyticsOptions[\"posthogOptions\"]>\n ): void {\n this.posthogOptions = {\n ...this.posthogOptions,\n ...posthogOptions,\n };\n if (posthogOptions.host) {\n this.host = posthogOptions.host;\n }\n this.posthogClients.clear();\n }\n\n add(\n event: UnredactedEvent,\n posthogClient?: PostHogCaptureClient,\n enableAITracing = false\n ): void {\n // Drop oldest events if queue is full (or implement your preferred strategy)\n if (this.queue.length >= this.maxQueueSize) {\n writeToLog(\"Event queue full, dropping oldest event\");\n this.queue.shift();\n }\n\n this.queue.push({ enableAITracing, event, posthogClient });\n this.process();\n }\n\n private async process(): Promise<void> {\n if (this.processing) {\n return;\n }\n\n this.processing = true;\n\n while (this.queue.length > 0 && this.activeRequests < this.concurrency) {\n const queuedEvent = this.queue.shift();\n if (!queuedEvent) {\n continue;\n }\n const { enableAITracing, event, posthogClient } = queuedEvent;\n\n if (event.redactionFn) {\n try {\n const redactedEvent = await redactEvent(event, event.redactionFn);\n event.redactionFn = undefined;\n Object.assign(event, redactedEvent);\n } catch (error) {\n writeToLog(`Failed to redact event: ${error}`);\n continue;\n }\n }\n\n try {\n Object.assign(event, sanitizeEvent(event));\n } catch (error) {\n writeToLog(`Failed to sanitize event: ${error}`);\n continue;\n }\n try {\n Object.assign(event, truncateEvent(event));\n } catch (error) {\n writeToLog(`Failed to truncate event: ${error}`);\n continue;\n }\n\n event.id = event.id || newPrefixedId(\"evt\");\n this.activeRequests++;\n try {\n this.sendEvent(event as Event, posthogClient, enableAITracing);\n } finally {\n this.activeRequests--;\n this.process();\n }\n }\n\n this.processing = false;\n }\n\n private sendEvent(\n event: Event,\n posthogClientOverride?: PostHogCaptureClient,\n enableAITracing = false\n ): void {\n const posthogClient = this.getPostHogClient(\n event.apiKey,\n posthogClientOverride\n );\n if (posthogClient) {\n try {\n for (const captureEvent of buildPostHogCaptureEvents(event, {\n enableAITracing,\n })) {\n posthogClient.capture({\n distinctId: captureEvent.distinct_id,\n event: captureEvent.event,\n properties: captureEvent.properties,\n timestamp: new Date(captureEvent.timestamp),\n });\n }\n writeToLog(\n `Queued PostHog event ${event.id} | ${event.eventType} | ${event.duration} ms | ${event.identifyActorGivenId || \"anonymous\"}`\n );\n writeToLog(`Event details: ${JSON.stringify(event)}`);\n } catch (error) {\n writeToLog(\n `Failed to queue PostHog event ${event.id}: ${getMCPCompatibleErrorMessage(error)}`\n );\n throw error;\n }\n }\n }\n\n private getPostHogClient(\n apiKey?: string,\n posthogClient?: PostHogCaptureClient\n ): PostHogCaptureClient | undefined {\n if (posthogClient) {\n return posthogClient;\n }\n\n if (!apiKey) {\n return;\n }\n\n const existingClient = this.posthogClients.get(apiKey);\n if (existingClient) {\n return existingClient;\n }\n\n const client = new PostHog(apiKey, {\n ...this.posthogOptions,\n host: this.host,\n });\n this.posthogClients.set(apiKey, client);\n return client;\n }\n\n private delay(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n // Get queue stats for monitoring\n getStats() {\n return {\n queueLength: this.queue.length,\n activeRequests: this.activeRequests,\n isProcessing: this.processing,\n };\n }\n\n // Graceful shutdown - wait for active requests\n async destroy(): Promise<void> {\n // Stop accepting new events\n this.add = () => {\n writeToLog(\"Queue is shutting down, event dropped\");\n };\n\n // Wait for queue to drain (with timeout)\n const timeout = 5000; // 5 seconds\n const start = Date.now();\n\n while (\n (this.queue.length > 0 || this.activeRequests > 0) &&\n Date.now() - start < timeout\n ) {\n await this.delay(100);\n }\n\n if (this.queue.length > 0) {\n writeToLog(\n `Shutting down with ${this.queue.length} events still in queue`\n );\n }\n\n const shutdowns: Promise<void>[] = [];\n for (const client of this.posthogClients.values()) {\n if (client.shutdown) {\n shutdowns.push(client.shutdown(timeout));\n } else if (client.flush) {\n shutdowns.push(client.flush());\n }\n }\n await Promise.allSettled(shutdowns);\n }\n}\n\nexport const eventQueue = new EventQueue();\n\n// Register graceful shutdown handlers if available (Node.js only)\n// Edge environments (Cloudflare Workers, etc.) don't have process signals\ntry {\n if (typeof process !== \"undefined\" && typeof process.once === \"function\") {\n process.once(\"SIGINT\", () => eventQueue.destroy());\n process.once(\"SIGTERM\", () => eventQueue.destroy());\n process.once(\"beforeExit\", () => eventQueue.destroy());\n }\n} catch {\n // process.once not available in this environment - graceful shutdown handlers not registered\n}\n\nexport function publishEvent(\n server: MCPServerLike,\n eventInput: UnredactedEvent\n): void {\n const data = getServerTrackingData(server);\n if (!data) {\n writeToLog(\n \"Warning: Server tracking data not found. Event will not be published.\"\n );\n return;\n }\n\n if (!data.options.enableTracing) {\n return;\n }\n\n const sessionInfo = getSessionInfo(server, data);\n\n // Calculate duration if not provided\n const duration =\n eventInput.duration ||\n (eventInput.timestamp\n ? Date.now() - eventInput.timestamp.getTime()\n : undefined);\n\n // Build complete Event object with all fields explicit\n const fullEvent: UnredactedEvent = {\n // Core fields (id will be generated later in the queue)\n id: eventInput.id || \"\",\n sessionId: eventInput.sessionId || data.sessionId,\n apiKey: data.apiKey,\n\n // Event metadata\n eventType: eventInput.eventType || \"\",\n timestamp: eventInput.timestamp || new Date(),\n duration,\n\n // Session context from sessionInfo\n ipAddress: sessionInfo.ipAddress,\n sdkLanguage: sessionInfo.sdkLanguage,\n sdkVersion: sessionInfo.sdkVersion,\n serverName: sessionInfo.serverName,\n serverVersion: sessionInfo.serverVersion,\n clientName: sessionInfo.clientName,\n clientVersion: sessionInfo.clientVersion,\n\n // Actor information from sessionInfo\n identifyActorGivenId: sessionInfo.identifyActorGivenId,\n identifyActorName: sessionInfo.identifyActorName,\n identifyActorData: sessionInfo.identifyActorData,\n\n // Event-specific data from input\n resourceName: eventInput.resourceName,\n parameters: eventInput.parameters,\n response: eventInput.response,\n userIntent: eventInput.userIntent,\n isError: eventInput.isError,\n error: eventInput.error,\n\n // Preserve redaction function\n redactionFn: eventInput.redactionFn,\n\n // Customer-defined metadata\n tags: eventInput.tags,\n properties: eventInput.properties,\n };\n\n if (data.options.posthogClient) {\n eventQueue.add(\n fullEvent,\n data.options.posthogClient,\n data.options.enableAITracing\n );\n } else {\n eventQueue.add(fullEvent, undefined, data.options.enableAITracing);\n }\n}\n","import { createRequire } from \"node:module\";\nimport type { ChainedErrorData, ErrorData, StackFrame } from \"../types.js\";\n\n// Lazy-loaded fs module for context_line extraction (Node.js only)\n// Edge environments don't have filesystem access\nlet fsModule: typeof import(\"node:fs\") | null = null;\nlet fsInitAttempted = false;\n\nfunction getFsSync(): typeof import(\"node:fs\") | null {\n if (!fsInitAttempted) {\n fsInitAttempted = true;\n try {\n // Use createRequire for ESM compatibility\n // Works in Node.js ESM/CJS, fails gracefully in Workers/edge environments\n const require = createRequire(import.meta.url);\n fsModule = require(\"node:fs\");\n } catch {\n fsModule = null;\n }\n }\n return fsModule;\n}\n\n// Maximum number of exceptions to capture in a cause chain\nconst MAX_EXCEPTION_CHAIN_DEPTH = 10;\n\n// Maximum number of stack frames to capture per exception\nconst MAX_STACK_FRAMES = 50;\n\nconst LOCATION_WITH_LINE_COLUMN_REGEX = /^(.+):(\\d+):(\\d+)$/;\nconst WINDOWS_DRIVE_PREFIX_REGEX = /^[A-Za-z]:/;\nconst WINDOWS_ABSOLUTE_PATH_REGEX = /^[A-Za-z]:\\\\/;\nconst WINDOWS_ABSOLUTE_SLASH_PATH_REGEX = /^[A-Za-z]:[/]/;\nconst UNIX_USER_HOME_REGEX = /^\\/Users\\/[^/]+\\//;\nconst LINUX_USER_HOME_REGEX = /^\\/home\\/[^/]+\\//;\nconst WINDOWS_USER_HOME_REGEX = /^[A-Za-z]:[\\\\/]Users[\\\\/][^\\\\/]+[\\\\/]/;\nconst DEPLOYMENT_PREFIX_REGEXES = [\n /^\\/var\\/www\\/[^/]+\\//, // Apache/nginx: /var/www/myapp/\n /^\\/var\\/task\\//, // AWS Lambda: /var/task/\n /^\\/usr\\/src\\/app\\//, // Docker: /usr/src/app/\n /^\\/app\\//, // Heroku, Docker, generic: /app/\n /^\\/opt\\/[^/]+\\//, // Optional software: /opt/myapp/\n /^\\/srv\\/[^/]+\\//, // Service data: /srv/myapp/\n];\n\ninterface ErrorWithCause extends Error {\n cause?: unknown;\n}\n\ninterface CallToolContentPart {\n text?: unknown;\n type?: unknown;\n}\n\ninterface CallToolResult {\n content: unknown[];\n isError: unknown;\n}\n\n/**\n * Captures detailed exception information including stack traces and cause chains.\n *\n * This function extracts error metadata (type, message, stack trace) and recursively\n * unwraps Error.cause chains. It parses V8 stack traces into structured frames and\n * detects whether each frame is user code (in_app: true) or library code (in_app: false).\n *\n * @param error - The error to capture (can be Error, string, object, or any value)\n * @param contextStack - Optional Error object to use for stack context (for validation errors)\n * @returns ErrorData object with structured error information\n */\nexport function captureException(\n error: unknown,\n contextStack?: Error\n): ErrorData {\n // Handle CallToolResult objects (SDK 1.21.0+ converts errors to these)\n if (isCallToolResult(error)) {\n return captureCallToolResultError(error, contextStack);\n }\n\n // Handle non-Error objects\n if (!(error instanceof Error)) {\n return {\n message: stringifyNonError(error),\n type: undefined,\n platform: \"javascript\",\n };\n }\n\n const errorData: ErrorData = {\n message: error.message || \"\",\n type: error.name || error.constructor?.name || undefined,\n platform: \"javascript\",\n };\n\n // Capture stack trace if available\n if (error.stack) {\n errorData.stack = error.stack;\n errorData.frames = parseV8StackTrace(error.stack);\n }\n\n // Unwrap Error.cause chain\n const chainedErrors = unwrapErrorCauses(error);\n if (chainedErrors.length > 0) {\n errorData.chained_errors = chainedErrors;\n }\n\n return errorData;\n}\n\n/**\n * Parses V8 stack trace string into structured StackFrame array.\n *\n * V8 stack traces have the format:\n * Error: message\n * at functionName (filename:line:col)\n * at Object.method (filename:line:col)\n * ...\n *\n * This function handles various V8 format variations including:\n * - Regular functions: \"at functionName (file:10:5)\"\n * - Anonymous functions: \"at file:10:5\"\n * - Async functions: \"at async functionName (file:10:5)\"\n * - Object methods: \"at Object.method (file:10:5)\"\n * - Native code: \"at Array.map (native)\"\n *\n * @param stackTrace - Raw V8 stack trace string from Error.stack\n * @returns Array of parsed StackFrame objects (limited to MAX_STACK_FRAMES)\n */\nfunction parseV8StackTrace(stackTrace: string): StackFrame[] {\n const frames: StackFrame[] = [];\n const lines = stackTrace.split(\"\\n\");\n\n for (const line of lines) {\n // Skip the first line (error message) and empty lines\n if (!line.trim().startsWith(\"at \")) {\n continue;\n }\n\n const frame = parseV8StackFrame(line.trim());\n if (frame) {\n addContextToFrame(frame);\n frames.push(frame);\n }\n\n // Limit number of frames\n if (frames.length >= MAX_STACK_FRAMES) {\n break;\n }\n }\n\n return frames;\n}\n\n/**\n * Adds context_line to a stack frame by reading the source file.\n *\n * This function extracts the line of code where the error occurred by:\n * 1. Reading the source file using abs_path\n * 2. Extracting the line at the specified line number\n * 3. Setting the context_line field on the frame\n *\n * Only extracts context for user code (in_app: true)\n * If the file cannot be read or the line number is invalid, context_line remains undefined.\n *\n * @param frame - The StackFrame to add context to (modified in place)\n * @returns The modified StackFrame\n */\nfunction addContextToFrame(frame: StackFrame): StackFrame {\n if (!(frame.in_app && frame.abs_path && frame.lineno)) {\n return frame;\n }\n\n // Get fs module lazily - returns null in edge environments\n const fs = getFsSync();\n if (!fs) {\n return frame; // File reading not available in this environment\n }\n\n try {\n const source = fs.readFileSync(frame.abs_path, \"utf8\");\n const lines = source.split(\"\\n\");\n const lineIndex = frame.lineno - 1; // Convert to 0-based index\n\n if (lineIndex >= 0 && lineIndex < lines.length) {\n frame.context_line = lines[lineIndex];\n }\n } catch {\n // File not found or not readable - silently skip\n }\n\n return frame;\n}\n\n/**\n * Parses a location string from a V8 stack frame.\n *\n * Handles different location formats:\n * - \"fileName:lineNumber:columnNumber\" - normal file location\n * - \"eval at functionName (location)\" - eval'd code (recursively unwraps)\n * - \"native\" - V8 internal code\n * - \"unknown location\" - location unavailable\n *\n * @param location - Location string from stack frame\n * @returns Object with filename, abs_path, and optional lineno/colno, or null if unparseable\n */\nfunction parseLocation(location: string): {\n filename: string;\n abs_path: string;\n lineno?: number;\n colno?: number;\n} | null {\n // Handle special cases first\n if (location === \"native\") {\n return { filename: \"native\", abs_path: \"native\" };\n }\n\n if (location === \"unknown location\") {\n return { filename: \"<unknown>\", abs_path: \"<unknown>\" };\n }\n\n // Handle eval locations\n if (location.startsWith(\"eval at \")) {\n return parseEvalOrigin(location);\n }\n\n // Handle normal location format: fileName:lineNumber:columnNumber\n const match = location.match(LOCATION_WITH_LINE_COLUMN_REGEX);\n if (match) {\n const [, filename, lineStr, colStr] = match;\n return {\n filename: makeRelativePath(filename),\n abs_path: filename,\n lineno: Number.parseInt(lineStr, 10),\n colno: Number.parseInt(colStr, 10),\n };\n }\n\n return null;\n}\n\n/**\n * Recursively unwraps eval location chains to extract the underlying file location.\n *\n * Eval locations have the format: \"eval at functionName (location), <anonymous>:line:col\"\n * where location can be another eval or a file location.\n *\n * V8 formats:\n * - \"eval at Bar.z (myscript.js:10:3)\" → extract myscript.js:10:3\n * - \"eval at Foo (eval at Bar (file.js:10:3)), <anonymous>:5:2\" → extract file.js:10:3\n *\n * @param evalLocation - Eval location string starting with \"eval at \"\n * @returns Object with extracted file location, or null if unparseable\n */\nfunction parseEvalOrigin(evalLocation: string): {\n filename: string;\n abs_path: string;\n lineno?: number;\n colno?: number;\n} | null {\n // V8 format: \"eval at functionName (parentLocation), <anonymous>:line:col\"\n // or simpler: \"eval at functionName (parentLocation)\"\n //\n // Strategy: Find balanced parentheses to extract the parent location,\n // then recursively parse it to find the actual file.\n\n // First, check if there's a comma separating eval chain from eval code location\n // Format: \"eval at FUNC (...), <anonymous>:line:col\"\n // We want to extract just the \"eval at FUNC (...)\" part\n let evalChainPart = evalLocation;\n const commaIndex = findCommaAfterBalancedParens(evalLocation);\n if (commaIndex !== -1) {\n evalChainPart = evalLocation.slice(0, commaIndex);\n }\n\n const innerLocation = extractTrailingParenthesizedContent(evalChainPart);\n if (!(innerLocation && evalChainPart.startsWith(\"eval at \"))) {\n return null;\n }\n\n // Recursively parse the inner location\n if (innerLocation.startsWith(\"eval at \")) {\n return parseEvalOrigin(innerLocation);\n }\n\n // Base case: parse as normal location\n const locationMatch = innerLocation.match(LOCATION_WITH_LINE_COLUMN_REGEX);\n if (locationMatch) {\n const [, filename, lineStr, colStr] = locationMatch;\n return {\n filename: makeRelativePath(filename),\n abs_path: filename,\n lineno: Number.parseInt(lineStr, 10),\n colno: Number.parseInt(colStr, 10),\n };\n }\n\n return null;\n}\n\n/**\n * Finds the index of the comma that appears after balanced parentheses.\n *\n * For \"eval at f (eval at g (x)), <anonymous>:1:2\", returns the index of the comma\n * after the closing \")\" and before \"<anonymous>\".\n *\n * @param str - String to search\n * @returns Index of comma, or -1 if not found\n */\nfunction findCommaAfterBalancedParens(str: string): number {\n let depth = 0;\n let foundOpenParen = false;\n\n for (let i = 0; i < str.length; i++) {\n if (str[i] === \"(\") {\n depth++;\n foundOpenParen = true;\n } else if (str[i] === \")\") {\n depth--;\n if (depth === 0 && foundOpenParen) {\n // Found the closing paren of the eval at (...) part\n for (let j = i + 1; j < str.length; j++) {\n if (str[j] === \",\") {\n return j;\n }\n if (str[j] !== \" \") {\n // Non-comma, non-space character found, no comma separator\n return -1;\n }\n }\n return -1;\n }\n }\n }\n\n return -1;\n}\n\nfunction extractTrailingParenthesizedContent(value: string): string | null {\n const trimmedValue = value.trim();\n if (!trimmedValue.endsWith(\")\")) {\n return null;\n }\n\n const openingParenIndex = findMatchingOpeningParen(trimmedValue);\n if (openingParenIndex === -1) {\n return null;\n }\n\n return trimmedValue.slice(openingParenIndex + 1, -1);\n}\n\nfunction findMatchingOpeningParen(value: string): number {\n let depth = 0;\n\n for (let index = value.length - 1; index >= 0; index--) {\n const char = value[index];\n if (char === \")\") {\n depth++;\n } else if (char === \"(\") {\n depth--;\n if (depth === 0) {\n return index;\n }\n }\n }\n\n return -1;\n}\n\n/**\n * Parses a single V8 stack frame line into a StackFrame object.\n *\n * Handles multiple V8 stack frame formats:\n * - \"at functionName (filename:line:col)\"\n * - \"at filename:line:col\" (top-level code)\n * - \"at async functionName (filename:line:col)\"\n * - \"at Object.method (filename:line:col)\"\n * - \"at Module._compile (node:internal/...)\" (internal modules)\n * - \"at functionName (eval at ...)\" (eval'd code)\n * - \"at functionName (native)\" (native code)\n *\n * @param line - Single line from V8 stack trace (trimmed, starts with \"at \")\n * @returns Parsed StackFrame or null if line cannot be parsed\n */\nfunction parseV8StackFrame(line: string): StackFrame | null {\n // Remove \"at \" prefix\n const withoutAt = line.slice(3);\n\n // Try to extract function name and location\n // Format 1: \"functionName (location)\"\n // Location can be: filename:line:col, eval at ..., native, unknown location\n const location = extractTrailingParenthesizedContent(withoutAt);\n if (location) {\n const openingParenIndex = findMatchingOpeningParen(withoutAt.trim());\n const functionName = withoutAt.slice(0, openingParenIndex).trim();\n const parsedLocation = parseLocation(location);\n\n if (functionName && parsedLocation) {\n return {\n function: functionName,\n filename: parsedLocation.filename,\n abs_path: parsedLocation.abs_path,\n lineno: parsedLocation.lineno,\n colno: parsedLocation.colno,\n in_app: isInApp(parsedLocation.abs_path),\n };\n }\n }\n\n // Format 2: \"location\" (no function name, top-level code)\n // Try to parse as location directly\n const parsedLocation = parseLocation(withoutAt);\n if (parsedLocation) {\n return {\n function: \"<anonymous>\",\n filename: parsedLocation.filename,\n abs_path: parsedLocation.abs_path,\n lineno: parsedLocation.lineno,\n colno: parsedLocation.colno,\n in_app: isInApp(parsedLocation.abs_path),\n };\n }\n\n // Format 3: Unparseable\n // Fallback for formats we don't recognize\n return {\n function: withoutAt,\n filename: \"<unknown>\",\n in_app: false,\n };\n}\n\n/**\n * Determines if a file path represents user code (in_app: true) or library code (in_app: false).\n *\n * Library code is identified by:\n * - Paths containing \"/node_modules/\"\n * - Node.js internal modules (e.g., \"node:internal/...\")\n * - Native code\n *\n * @param filename - File path from stack frame\n * @returns true if user code, false if library code\n */\nfunction isInApp(filename: string): boolean {\n // Exclude node_modules\n if (\n filename.includes(\"/node_modules/\") ||\n filename.includes(\"\\\\node_modules\\\\\")\n ) {\n return false;\n }\n\n // Exclude Node.js internal modules (node:internal/...)\n if (filename.startsWith(\"node:\")) {\n return false;\n }\n\n // Exclude native code\n if (filename === \"native\" || filename === \"<unknown>\") {\n return false;\n }\n\n return true;\n}\n\n/**\n * Normalizes URL schemes to regular file paths.\n *\n * Handles file:// URLs commonly seen in ESM modules and local testing:\n * - \"file:///Users/john/project/src/index.ts\" → \"/Users/john/project/src/index.ts\"\n * - \"file:///C:/projects/app/src/index.ts\" → \"C:/projects/app/src/index.ts\"\n *\n * @param filename - File path that may be a file:// URL\n * @returns Clean file path without URL scheme\n */\nfunction normalizeUrl(filename: string): string {\n // Handle file:// URLs (common in ESM modules and local testing)\n if (filename.startsWith(\"file://\")) {\n let result = filename.slice(7); // Remove \"file://\"\n\n // Ensure Unix paths start with /\n if (!(result.startsWith(\"/\") || WINDOWS_DRIVE_PREFIX_REGEX.test(result))) {\n result = `/${result}`;\n }\n\n return result;\n }\n\n return filename;\n}\n\n/**\n * Normalizes Node.js internal module paths for consistent error grouping.\n *\n * Examples:\n * - \"node:internal/modules/cjs/loader\" → \"node:internal\"\n * - \"node:fs/promises\" → \"node:fs\"\n * - \"node:fs\" → \"node:fs\" (unchanged)\n *\n * @param filename - File path that may be a Node.js internal module\n * @returns Simplified module path or original filename\n */\nfunction normalizeNodeInternals(filename: string): string {\n if (filename.startsWith(\"node:internal\")) {\n return \"node:internal\";\n }\n\n if (filename.startsWith(\"node:\")) {\n // Extract just the module name: node:fs/promises → node:fs\n const parts = filename.split(\"/\");\n return parts[0];\n }\n\n return filename;\n}\n\n/**\n * Strips user-specific and system path prefixes.\n *\n * Removes prefixes like:\n * - /Users/username/ → ~/\n * - /home/username/ → ~/\n * - C:\\Users\\username\\ → ~\\\n * - C:/Users/username/ → ~/ (mixed separators)\n *\n * @param path - File path to normalize\n * @returns Path with system prefixes removed\n */\nfunction stripSystemPrefixes(path: string): string {\n let result = path;\n\n // Unix/macOS: /Users/username/\n result = result.replace(UNIX_USER_HOME_REGEX, \"~/\");\n\n // Linux: /home/username/\n result = result.replace(LINUX_USER_HOME_REGEX, \"~/\");\n\n // Windows: C:\\Users\\username\\ or C:/Users/username/ (with any separator)\n result = result.replace(WINDOWS_USER_HOME_REGEX, \"~/\");\n\n return result;\n}\n\n/**\n * Normalizes node_modules paths to be consistent across deployments.\n *\n * Extracts only the package-relative portion of the path:\n * - /Users/john/project/node_modules/express/lib/router.js → node_modules/express/lib/router.js\n * - /app/node_modules/@scope/pkg/index.js → node_modules/@scope/pkg/index.js\n *\n * @param path - File path that may contain node_modules\n * @returns Normalized node_modules path or original path\n */\nfunction normalizeNodeModules(path: string): string {\n // Find the last occurrence of /node_modules/ or \\node_modules\\\n const unixIndex = path.lastIndexOf(\"/node_modules/\");\n const winIndex = path.lastIndexOf(\"\\\\node_modules\\\\\");\n\n if (unixIndex !== -1) {\n return path.slice(unixIndex + 1); // +1 to exclude leading slash\n }\n\n if (winIndex !== -1) {\n return path.slice(winIndex + 1).replace(/\\\\/g, \"/\");\n }\n\n return path;\n}\n\n/**\n * Strips common deployment-specific path prefixes.\n *\n * Removes prefixes like:\n * - /var/www/app/ → \"\"\n * - /app/ → \"\"\n * - /opt/project/ → \"\"\n * - /var/task/ → \"\" (AWS Lambda)\n * - /usr/src/app/ → \"\" (Docker)\n *\n * @param path - File path to normalize\n * @returns Path with deployment prefixes removed\n */\nfunction stripDeploymentPaths(path: string): string {\n let result = path;\n\n for (const prefix of DEPLOYMENT_PREFIX_REGEXES) {\n result = result.replace(prefix, \"\");\n }\n\n return result;\n}\n\n/**\n * Finds project-relative path using common project boundary markers.\n *\n * Looks for markers like /src/, /lib/, /dist/, /build/ and extracts the path\n * from that marker onwards:\n * - /Users/john/project/src/components/Button.tsx → src/components/Button.tsx\n * - /app/dist/index.js → dist/index.js\n *\n * Priority order: looks for primary markers first (src, lib, dist, build),\n * then secondary markers. Uses the highest-priority marker found.\n *\n * @param path - File path to search for project boundaries\n * @returns Project-relative path or original path if no marker found\n */\nfunction findProjectPath(path: string): string {\n // Project boundary markers in priority order\n // Primary markers (most likely to be project root)\n const primaryMarkers = [\"/src/\", \"/lib/\", \"/dist/\", \"/build/\"];\n\n // Secondary markers (could be subdirectories)\n const secondaryMarkers = [\n \"/app/\",\n \"/components/\",\n \"/pages/\",\n \"/api/\",\n \"/utils/\",\n \"/services/\",\n \"/modules/\",\n ];\n\n // Check primary markers first\n for (const marker of primaryMarkers) {\n const index = path.lastIndexOf(marker);\n if (index !== -1) {\n return path.slice(index + 1); // +1 to remove leading slash\n }\n }\n\n // If no primary marker, check secondary markers\n for (const marker of secondaryMarkers) {\n const index = path.lastIndexOf(marker);\n if (index !== -1) {\n return path.slice(index + 1);\n }\n }\n\n return path;\n}\n\n/**\n * Converts absolute file paths to normalized relative paths for consistent error grouping.\n *\n * This function performs comprehensive path normalization to ensure errors from the same\n * code location group together regardless of deployment environment, user directories,\n * or system-specific paths. The original absolute path is always preserved in abs_path.\n *\n * Normalization steps:\n * 1. Normalize URL schemes (file://, etc.) - must be first to strip URL prefixes\n * 2. Preserve special paths (already relative, Node internals, etc.)\n * 3. Normalize path separators to forward slashes (for consistent processing)\n * 4. Normalize Node.js internal modules (node:internal/*, node:fs/*)\n * 5. Normalize node_modules paths to package-relative format\n * 6. Strip user home directories (/Users/*, /home/*, C:\\Users\\*)\n * 7. Strip deployment-specific paths (/var/www/*, /app/, AWS Lambda, Docker)\n * 8. Strip current working directory\n * 9. Find project boundaries (/src/, /lib/, /dist/, etc.)\n * 10. Remove leading slashes for clean relative paths\n *\n * @param filename - Absolute or relative file path from stack trace\n * @returns Normalized relative path for error grouping\n *\n * @example\n * makeRelativePath('/Users/john/project/src/index.ts')\n * // Returns: 'src/index.ts'\n *\n * @example\n * makeRelativePath('/home/ubuntu/app/node_modules/express/lib/router.js')\n * // Returns: 'node_modules/express/lib/router.js'\n *\n * @example\n * makeRelativePath('/var/www/myapp/dist/server.js')\n * // Returns: 'dist/server.js'\n *\n * @example\n * makeRelativePath('node:internal/modules/cjs/loader')\n * // Returns: 'node:internal'\n *\n * @example\n * makeRelativePath('C:\\\\Users\\\\John\\\\projects\\\\myapp\\\\src\\\\index.ts')\n * // Returns: 'src/index.ts'\n */\nfunction makeRelativePath(filename: string): string {\n let result = filename;\n\n // Step 1: Normalize URL schemes (file://, etc.)\n result = normalizeUrl(result);\n\n // Step 2: Handle already-relative paths and special cases\n if (!(result.startsWith(\"/\") || WINDOWS_ABSOLUTE_PATH_REGEX.test(result))) {\n // Already relative or special path (native, <unknown>, etc.)\n // Still normalize Node internals\n if (result.startsWith(\"node:\")) {\n return normalizeNodeInternals(result);\n }\n return result;\n }\n\n // Step 3: Normalize path separators early for consistent processing\n result = result.replace(/\\\\/g, \"/\");\n\n // Step 4: Normalize Node.js internal modules (should be rare at this point)\n if (result.startsWith(\"node:\")) {\n return normalizeNodeInternals(result);\n }\n\n // Step 5: Handle node_modules specially - preserve package structure\n if (result.includes(\"/node_modules/\")) {\n return normalizeNodeModules(result);\n }\n\n // Step 6: Strip user home directories\n result = stripSystemPrefixes(result);\n\n // Step 7: Strip deployment-specific paths\n result = stripDeploymentPaths(result);\n\n // Step 8: Strip current working directory (if available)\n // process.cwd() may not be available in edge environments\n let cwd: string | null = null;\n try {\n if (typeof process !== \"undefined\" && typeof process.cwd === \"function\") {\n cwd = process.cwd();\n }\n } catch {\n // process.cwd() not available in this environment\n }\n\n if (cwd && result.startsWith(cwd)) {\n result = result.slice(cwd.length + 1); // +1 to remove leading /\n }\n\n // Step 9: Find project boundaries if still absolute-looking\n // Also apply to tilde paths that might have project markers after the tilde\n if (\n result.startsWith(\"/\") ||\n WINDOWS_ABSOLUTE_SLASH_PATH_REGEX.test(result)\n ) {\n result = findProjectPath(result);\n } else if (result.startsWith(\"~\")) {\n // For tilde paths, strip the tilde and find markers in the remaining path\n const withoutTilde = result.slice(2); // Remove ~/\n const absoluteWithoutTilde = `/${withoutTilde}`;\n const projectPath = findProjectPath(absoluteWithoutTilde);\n // If a marker was found (path changed), use it; otherwise keep the tilde version\n if (projectPath !== absoluteWithoutTilde) {\n result = projectPath;\n }\n }\n\n // Step 10: Remove leading slash if present (prefer relative paths)\n if (result.startsWith(\"/\")) {\n result = result.slice(1);\n }\n\n return result;\n}\n\n/**\n * Recursively unwraps Error.cause chain and returns array of chained errors.\n *\n * Error.cause is a standard JavaScript feature that allows chaining errors:\n * const cause = new Error(\"Root cause\");\n * const error = new Error(\"Wrapper error\", { cause });\n *\n * This function extracts all errors in the cause chain up to MAX_EXCEPTION_CHAIN_DEPTH.\n *\n * @param error - Error object to unwrap\n * @returns Array of ChainedErrorData objects representing the error chain\n */\nfunction unwrapErrorCauses(error: Error): ChainedErrorData[] {\n const chainedErrors: ChainedErrorData[] = [];\n const seenErrors = new Set<Error>();\n let currentError: unknown = (error as ErrorWithCause).cause;\n let depth = 0;\n\n while (currentError && depth < MAX_EXCEPTION_CHAIN_DEPTH) {\n // If cause is not an Error, stringify it and stop\n if (!(currentError instanceof Error)) {\n chainedErrors.push({\n message: stringifyNonError(currentError),\n type: undefined,\n });\n break;\n }\n\n // Check for circular reference\n if (seenErrors.has(currentError)) {\n break;\n }\n seenErrors.add(currentError);\n\n const chainedErrorData: ChainedErrorData = {\n message: currentError.message || \"\",\n type: currentError.name || currentError.constructor?.name || \"Error\",\n };\n\n if (currentError.stack) {\n chainedErrorData.stack = currentError.stack;\n chainedErrorData.frames = parseV8StackTrace(currentError.stack);\n }\n\n chainedErrors.push(chainedErrorData);\n\n // Move to next cause in chain\n currentError = (currentError as ErrorWithCause).cause;\n depth++;\n }\n\n return chainedErrors;\n}\n\n/**\n * Detects if a value is a CallToolResult object (SDK 1.21.0+ error format).\n *\n * SDK 1.21.0+ converts errors to CallToolResult format:\n * { content: [{ type: \"text\", text: \"error message\" }], isError: true }\n *\n * @param value - Value to check\n * @returns True if value is a CallToolResult object\n */\nfunction isCallToolResult(value: unknown): value is CallToolResult {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"isError\" in value &&\n \"content\" in value &&\n Array.isArray((value as { content?: unknown }).content)\n );\n}\n\nfunction isTextContentPart(value: unknown): value is { text: string } {\n if (value === null || typeof value !== \"object\") {\n return false;\n }\n\n const contentPart = value as CallToolContentPart;\n return contentPart.type === \"text\" && typeof contentPart.text === \"string\";\n}\n\n/**\n * Extracts error information from CallToolResult objects.\n *\n * SDK 1.21.0+ converts errors to CallToolResult, losing original stack traces.\n * This extracts the error message from the content array.\n *\n * @param result - CallToolResult object with error\n * @param _contextStack - Optional Error object for stack context (unused, kept for compatibility)\n * @returns ErrorData with extracted message (no stack trace)\n */\nfunction captureCallToolResultError(\n result: CallToolResult,\n _contextStack?: Error\n): ErrorData {\n // Extract message from content array\n const message =\n result.content\n .filter(isTextContentPart)\n .map((contentPart) => contentPart.text)\n .join(\" \")\n .trim() || \"Unknown error\";\n\n const errorData: ErrorData = {\n message,\n type: undefined, // Can't determine actual type from CallToolResult\n platform: \"javascript\",\n // No stack or frames - SDK stripped the original error information\n };\n\n return errorData;\n}\n\n/**\n * Converts non-Error objects to string representation for error messages.\n *\n * In JavaScript, anything can be thrown (not just Error objects):\n * throw \"string error\";\n * throw { code: 404 };\n * throw null;\n *\n * This function handles these cases by converting them to meaningful strings.\n *\n * @param value - Non-Error value that was thrown\n * @returns String representation of the value\n */\nfunction stringifyNonError(value: unknown): string {\n if (value === null) {\n return \"null\";\n }\n\n if (value === undefined) {\n return \"undefined\";\n }\n\n if (typeof value === \"string\") {\n return value;\n }\n\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value);\n }\n\n // Try to stringify objects with fallback\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n","import type { MCPAnalyticsOptions } from \"../types.js\";\nimport { DEFAULT_CONTEXT_PARAMETER_DESCRIPTION } from \"./constants.js\";\nimport { writeToLog } from \"./logging.js\";\n\ninterface JsonSchema {\n additionalProperties?: boolean;\n allOf?: unknown;\n anyOf?: unknown;\n oneOf?: unknown;\n properties?: Record<string, unknown>;\n required?: string[];\n type?: string;\n}\n\nexport interface ContextInjectableTool {\n inputSchema?: JsonSchema;\n name?: string;\n [key: string]: unknown;\n}\n\nexport function isContextEnabled(\n context: MCPAnalyticsOptions[\"context\"]\n): boolean {\n return context !== false;\n}\n\nexport function getContextDescription(\n context: MCPAnalyticsOptions[\"context\"]\n): string | undefined {\n return typeof context === \"object\" ? context.description : undefined;\n}\n\n/**\n * Adds a context parameter to a tool's JSON Schema.\n * This function is called AFTER the MCP SDK has converted Zod schemas to JSON Schema,\n * so we only need to handle JSON Schema format.\n *\n * Skips injection (with warning) for:\n * - Tools that already have a 'context' parameter\n * - Complex schemas (oneOf/allOf/anyOf) that can't safely have properties added\n * - Schemas with additionalProperties: false\n */\nexport function addContextParameterToTool<TTool extends ContextInjectableTool>(\n tool: TTool,\n contextDescriptionOverride?: string\n): TTool {\n // Create a shallow copy of the tool to avoid modifying the original\n const modifiedTool = { ...tool };\n const toolName = tool.name || \"unknown\";\n const schema = modifiedTool.inputSchema as JsonSchema | undefined;\n\n // Check if tool already has context parameter - skip to avoid collision\n if (schema?.properties?.context) {\n writeToLog(\n `WARN: Tool \"${toolName}\" already has 'context' parameter. Skipping context injection.`\n );\n return modifiedTool;\n }\n\n // Skip complex schemas that can't safely have properties added at root level\n if (schema?.oneOf || schema?.allOf || schema?.anyOf) {\n writeToLog(\n `WARN: Tool \"${toolName}\" has complex schema (oneOf/allOf/anyOf). Skipping context injection.`\n );\n return modifiedTool;\n }\n\n // Note: If additionalProperties is false, we'll need to remove that constraint\n // when adding context, otherwise the schema would be invalid. We handle this\n // after the deep copy below.\n\n if (!modifiedTool.inputSchema) {\n modifiedTool.inputSchema = {\n type: \"object\",\n properties: {},\n required: [],\n };\n }\n\n const contextDescription =\n contextDescriptionOverride || DEFAULT_CONTEXT_PARAMETER_DESCRIPTION;\n\n // Deep copy the inputSchema to avoid mutations\n modifiedTool.inputSchema = JSON.parse(\n JSON.stringify(modifiedTool.inputSchema)\n ) as JsonSchema;\n\n const inputSchema = modifiedTool.inputSchema as JsonSchema;\n\n // Ensure properties object exists\n if (!inputSchema.properties) {\n inputSchema.properties = {};\n }\n\n // Handle additionalProperties: false - must remove this constraint since we're adding context\n // The MCP SDK adds this constraint when converting Zod schemas to JSON Schema\n if (inputSchema.additionalProperties === false) {\n inputSchema.additionalProperties = undefined;\n }\n\n // Add context property\n inputSchema.properties.context = {\n type: \"string\",\n description: contextDescription,\n };\n\n // Add context to required array\n if (Array.isArray(inputSchema.required)) {\n if (!inputSchema.required.includes(\"context\")) {\n inputSchema.required.push(\"context\");\n }\n } else {\n inputSchema.required = [\"context\"];\n }\n\n return modifiedTool;\n}\n\nexport function addContextParameterToTools<TTool extends ContextInjectableTool>(\n tools: TTool[],\n contextDescriptionOverride?: string\n): TTool[] {\n return tools.map((tool) => {\n // Skip get_more_tools - it has its own special context parameter\n if (tool.name === \"get_more_tools\") {\n return tool;\n }\n return addContextParameterToTool(tool, contextDescriptionOverride);\n });\n}\n","import {\n ListToolsRequestSchema,\n type ListToolsResult,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type { MCPServerLike, UnredactedEvent } from \"../types.js\";\nimport { getMCPCompatibleErrorMessage } from \"./compatibility.js\";\nimport {\n addContextParameterToTools,\n getContextDescription,\n isContextEnabled,\n} from \"./context-parameters.js\";\nimport { publishEvent } from \"./event-queue.js\";\nimport { MCPAnalyticsEventType } from \"./event-types.js\";\nimport { getServerTrackingData } from \"./internal.js\";\nimport { writeToLog } from \"./logging.js\";\nimport { getServerSessionId } from \"./session.js\";\n\nexport const GET_MORE_TOOLS_NAME = \"get_more_tools\" as const;\n\ntype ReportMissingToolDescriptor = ListToolsResult[\"tools\"][number];\n\nexport function getReportMissingToolDescriptor(): ReportMissingToolDescriptor {\n return {\n name: GET_MORE_TOOLS_NAME,\n description:\n \"Check for additional tools whenever your task might benefit from specialized capabilities - even if existing tools could work as a fallback.\",\n inputSchema: {\n type: \"object\",\n properties: {\n context: {\n type: \"string\",\n description:\n \"A description of your goal and what kind of tool would help accomplish it.\",\n },\n },\n required: [\"context\"],\n },\n };\n}\n\nexport function handleReportMissing(args: { context: string }) {\n writeToLog(`Missing tool reported: ${JSON.stringify(args)}`);\n\n return {\n content: [\n {\n type: \"text\" as const,\n text: \"Unfortunately, we have shown you the full tool list. We have noted your feedback and will work to improve the tool list in the future.\",\n },\n ],\n };\n}\n\nexport function setupMCPAnalyticsTools(server: MCPServerLike): void {\n // Store reference to original handlers - need to use the method name, not the schema\n const handlers = server._requestHandlers;\n\n const originalListToolsHandler = handlers.get(\"tools/list\");\n const originalCallToolHandler = handlers.get(\"tools/call\");\n\n if (!(originalListToolsHandler && originalCallToolHandler)) {\n writeToLog(\n \"Warning: Original tool handlers not found. Your tools may not be setup before PostHog MCP analytics .track().\"\n );\n return;\n }\n\n // Override tools list to include get_more_tools and add context parameter\n try {\n server.setRequestHandler(ListToolsRequestSchema, async (request, extra) => {\n let tools: ListToolsResult[\"tools\"] = [];\n const data = getServerTrackingData(server);\n const event: UnredactedEvent = {\n sessionId: getServerSessionId(server, extra),\n parameters: {\n request,\n extra,\n },\n eventType: MCPAnalyticsEventType.mcpToolsList,\n timestamp: new Date(),\n redactionFn: data?.options.redactSensitiveInformation,\n };\n try {\n const originalResponse = (await originalListToolsHandler(\n request,\n extra\n )) as ListToolsResult;\n tools = originalResponse.tools || [];\n } catch (error) {\n // If original handler fails, start with empty tools\n writeToLog(\n `Warning: Original list tools handler failed, this suggests an error PostHog MCP analytics did not cause - ${error}`\n );\n event.error = { message: getMCPCompatibleErrorMessage(error) };\n event.isError = true;\n event.duration =\n (event.timestamp && Date.now() - event.timestamp.getTime()) || 0;\n publishEvent(server, event);\n throw error;\n }\n\n if (!data) {\n writeToLog(\n \"Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.\"\n );\n return { tools };\n }\n\n if (tools.length === 0) {\n writeToLog(\n \"Warning: No tools found in the original list. This is likely due to the tools not being registered before PostHog MCP analytics.track().\"\n );\n event.error = { message: \"No tools were sent to MCP client.\" };\n event.isError = true;\n event.duration =\n (event.timestamp && Date.now() - event.timestamp.getTime()) || 0;\n publishEvent(server, event);\n return { tools };\n }\n\n // Add context parameter to all existing tools when context capture is enabled\n if (isContextEnabled(data.options.context)) {\n tools = addContextParameterToTools(\n tools,\n getContextDescription(data.options.context)\n );\n }\n\n // Add report_missing tool if enabled\n if (data.options.reportMissing) {\n const alreadyPresent = tools.some(\n (tool) => tool?.name === GET_MORE_TOOLS_NAME\n );\n if (!alreadyPresent) {\n tools.push(getReportMissingToolDescriptor());\n }\n }\n\n event.response = { tools };\n event.isError = false;\n event.duration =\n (event.timestamp && Date.now() - event.timestamp.getTime()) || 0;\n publishEvent(server, event);\n return { tools };\n });\n } catch (error) {\n writeToLog(`Warning: Failed to override list tools handler - ${error}`);\n }\n}\n","import {\n CallToolRequestSchema,\n InitializeRequestSchema,\n ListToolsRequestSchema,\n type ListToolsResult,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport type {\n HighLevelMCPServerLike,\n MCPAnalyticsOptions,\n MCPServerLike,\n UnredactedEvent,\n} from \"../types.js\";\nimport { getMCPCompatibleErrorMessage } from \"./compatibility.js\";\nimport {\n addContextParameterToTools,\n getContextDescription,\n isContextEnabled,\n} from \"./context-parameters.js\";\nimport { publishEvent } from \"./event-queue.js\";\nimport { MCPAnalyticsEventType } from \"./event-types.js\";\nimport { captureException } from \"./exceptions.js\";\nimport {\n getServerTrackingData,\n handleIdentify,\n resolveEventProperties,\n resolveEventTags,\n} from \"./internal.js\";\nimport { writeToLog } from \"./logging.js\";\nimport { buildCapturedMcpParameters } from \"./mcp-payloads.js\";\nimport { getServerSessionId } from \"./session.js\";\nimport {\n GET_MORE_TOOLS_NAME,\n getReportMissingToolDescriptor,\n handleReportMissing,\n} from \"./tools.js\";\n\ntype MCPRequestHandler = NonNullable<\n MCPServerLike[\"_requestHandlers\"] extends Map<string, infer THandler>\n ? THandler\n : never\n>;\ntype MCPRequest = Parameters<MCPRequestHandler>[0];\ntype MCPRequestExtra = Parameters<MCPRequestHandler>[1];\ntype MCPServerWithCapabilities = MCPServerLike & {\n _capabilities?: {\n tools?: unknown;\n };\n};\n\nfunction isToolResultError(result: unknown): boolean {\n return (\n !!result &&\n typeof result === \"object\" &&\n \"isError\" in result &&\n result.isError === true\n );\n}\n\n// Track if we've already set up list tools tracing per server instance\nconst listToolsTracingSetup = new WeakMap<MCPServerLike, boolean>();\n\nexport function setupListToolsTracing(\n highLevelServer: HighLevelMCPServerLike\n): void {\n const server = highLevelServer.server;\n\n // Check if server supports tools capability\n if (!(server as MCPServerWithCapabilities)._capabilities?.tools) {\n // Server doesn't support tools yet, skip setup\n return;\n }\n\n // Check if we've already set up tracing for this server instance\n if (listToolsTracingSetup.get(server)) {\n return;\n }\n\n const handlers = server._requestHandlers;\n const originalListToolsHandler = handlers.get(\"tools/list\");\n\n // No handler to override yet\n if (!originalListToolsHandler) {\n return;\n }\n\n try {\n server.setRequestHandler(\n ListToolsRequestSchema,\n async (request, extra) =>\n await handleListToolsRequest(\n server,\n originalListToolsHandler,\n request,\n extra\n )\n );\n\n // Mark as setup successful for this server instance\n listToolsTracingSetup.set(server, true);\n } catch (error) {\n writeToLog(`Warning: Failed to override list tools handler - ${error}`);\n }\n}\n\nasync function handleListToolsRequest(\n server: MCPServerLike,\n originalListToolsHandler: MCPRequestHandler,\n request: MCPRequest,\n extra: MCPRequestExtra\n): Promise<{ tools: ListToolsResult[\"tools\"] }> {\n const data = getServerTrackingData(server);\n const event: UnredactedEvent = {\n sessionId: getServerSessionId(server, extra),\n parameters: buildCapturedMcpParameters(request),\n eventType: MCPAnalyticsEventType.mcpToolsList,\n timestamp: new Date(),\n redactionFn: data?.options.redactSensitiveInformation,\n };\n\n if (data) {\n await applyResolvedMetadata(event, data, request, extra);\n }\n\n const tools = await getTracedToolsList(\n server,\n originalListToolsHandler,\n request,\n extra,\n event\n );\n\n if (!data) {\n writeToLog(\n \"Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.\"\n );\n return { tools };\n }\n\n if (tools.length === 0) {\n writeToLog(\n \"Warning: No tools found in the original list. This is likely due to the tools not being registered before PostHog MCP analytics.track().\"\n );\n event.error = { message: \"No tools were sent to MCP client.\" };\n event.isError = true;\n event.duration = getEventDuration(event);\n publishEvent(server, event);\n return { tools };\n }\n\n event.response = { tools };\n event.isError = false;\n event.duration = getEventDuration(event);\n publishEvent(server, event);\n return { tools };\n}\n\nasync function getTracedToolsList(\n server: MCPServerLike,\n originalListToolsHandler: MCPRequestHandler,\n request: MCPRequest,\n extra: MCPRequestExtra,\n event: UnredactedEvent\n): Promise<ListToolsResult[\"tools\"]> {\n try {\n const data = getServerTrackingData(server);\n const originalResponse = (await originalListToolsHandler(\n request,\n extra\n )) as ListToolsResult;\n let tools = originalResponse.tools || [];\n\n if (data && isContextEnabled(data.options.context)) {\n tools = addContextParameterToTools(\n tools,\n getContextDescription(data.options.context)\n );\n }\n\n if (data?.options.reportMissing) {\n const alreadyPresent = tools.some(\n (tool) => tool?.name === GET_MORE_TOOLS_NAME\n );\n if (!alreadyPresent) {\n tools.push(getReportMissingToolDescriptor());\n }\n }\n return tools;\n } catch (error) {\n writeToLog(\n `Warning: Original list tools handler failed, this suggests an error PostHog MCP analytics did not cause - ${error}`\n );\n event.error = { message: getMCPCompatibleErrorMessage(error) };\n event.isError = true;\n event.duration = getEventDuration(event);\n publishEvent(server, event);\n throw error;\n }\n}\n\nexport function setupInitializeTracing(\n highLevelServer: HighLevelMCPServerLike\n): void {\n const server = highLevelServer.server;\n const handlers = server._requestHandlers;\n const originalInitializeHandler = handlers.get(\"initialize\");\n\n if (originalInitializeHandler) {\n server.setRequestHandler(\n InitializeRequestSchema,\n async (request, extra) => {\n const data = getServerTrackingData(server);\n if (!data) {\n writeToLog(\n \"Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.\"\n );\n return await originalInitializeHandler(request, extra);\n }\n\n const sessionId = getServerSessionId(server, extra);\n\n // Try to identify the session\n await handleIdentify(server, data, request, extra);\n\n const event: UnredactedEvent = {\n sessionId,\n resourceName: request.params?.name || \"Unknown Tool Name\",\n eventType: MCPAnalyticsEventType.mcpInitialize,\n parameters: buildCapturedMcpParameters(request),\n timestamp: new Date(),\n redactionFn: data.options.redactSensitiveInformation,\n };\n\n const resolvedTags = await resolveEventTags(data, request, extra);\n if (resolvedTags) {\n event.tags = resolvedTags;\n }\n const resolvedProperties = await resolveEventProperties(\n data,\n request,\n extra\n );\n if (resolvedProperties) {\n event.properties = resolvedProperties;\n }\n\n const result = await originalInitializeHandler(request, extra);\n event.response = result;\n publishEvent(server, event);\n return result;\n }\n );\n }\n}\n\nexport function setupToolCallTracing(server: MCPServerLike): void {\n try {\n const handlers = server._requestHandlers;\n\n const originalCallToolHandler = handlers.get(\"tools/call\");\n const originalInitializeHandler = handlers.get(\"initialize\");\n\n if (originalInitializeHandler) {\n server.setRequestHandler(\n InitializeRequestSchema,\n async (request, extra) => {\n const data = getServerTrackingData(server);\n if (!data) {\n writeToLog(\n \"Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.\"\n );\n return await originalInitializeHandler(request, extra);\n }\n\n const sessionId = getServerSessionId(server, extra);\n\n // Try to identify the session\n await handleIdentify(server, data, request, extra);\n\n const event: UnredactedEvent = {\n sessionId,\n resourceName: request.params?.name || \"Unknown Tool Name\",\n eventType: MCPAnalyticsEventType.mcpInitialize,\n parameters: buildCapturedMcpParameters(request),\n timestamp: new Date(),\n redactionFn: data.options.redactSensitiveInformation,\n };\n\n const resolvedTags = await resolveEventTags(data, request, extra);\n if (resolvedTags) {\n event.tags = resolvedTags;\n }\n const resolvedProperties = await resolveEventProperties(\n data,\n request,\n extra\n );\n if (resolvedProperties) {\n event.properties = resolvedProperties;\n }\n\n const result = await originalInitializeHandler(request, extra);\n event.response = result;\n publishEvent(server, event);\n return result;\n }\n );\n }\n\n server.setRequestHandler(\n CallToolRequestSchema,\n async (request, extra) =>\n await handleToolCallRequest(\n server,\n originalCallToolHandler,\n request,\n extra\n )\n );\n } catch (error) {\n writeToLog(`Warning: Failed to setup tool call tracing - ${error}`);\n throw error;\n }\n}\n\nasync function handleToolCallRequest(\n server: MCPServerLike,\n originalCallToolHandler: MCPRequestHandler | undefined,\n request: MCPRequest,\n extra: MCPRequestExtra\n): Promise<unknown> {\n const data = getServerTrackingData(server);\n if (!data) {\n writeToLog(\n \"Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.\"\n );\n return await originalCallToolHandler?.(request, extra);\n }\n\n const event: UnredactedEvent = {\n sessionId: getServerSessionId(server, extra),\n resourceName: request.params?.name || \"Unknown Tool Name\",\n parameters: buildCapturedMcpParameters(request),\n eventType: MCPAnalyticsEventType.mcpToolsCall,\n timestamp: new Date(),\n redactionFn: data.options.redactSensitiveInformation,\n };\n\n try {\n await handleIdentify(server, data, request, extra);\n await applyResolvedMetadata(event, data, request, extra);\n setToolCallContext(event, data.options.context, request);\n\n const result = await executeToolCall(\n server,\n originalCallToolHandler,\n request,\n extra,\n event\n );\n if (isToolResultError(result)) {\n event.isError = true;\n event.error = captureException(result);\n }\n\n event.response = result;\n publishEvent(server, event);\n return result;\n } catch (error) {\n event.isError = true;\n event.error = captureException(error);\n publishEvent(server, event);\n throw error;\n }\n}\n\nasync function executeToolCall(\n server: MCPServerLike,\n originalCallToolHandler: MCPRequestHandler | undefined,\n request: MCPRequest,\n extra: MCPRequestExtra,\n event: UnredactedEvent\n): Promise<unknown> {\n if (request.params?.name === \"get_more_tools\") {\n const context = getContextArgument(request) || \"\";\n event.userIntent = context;\n return handleReportMissing({ context });\n }\n\n if (originalCallToolHandler) {\n return await originalCallToolHandler(request, extra);\n }\n\n event.isError = true;\n event.error = {\n message: `Tool call handler not found for ${request.params?.name || \"unknown\"}`,\n };\n event.duration = getEventDuration(event) || undefined;\n publishEvent(server, event);\n throw new Error(`Unknown tool: ${request.params?.name || \"unknown\"}`);\n}\n\nasync function applyResolvedMetadata(\n event: UnredactedEvent,\n data: NonNullable<ReturnType<typeof getServerTrackingData>>,\n request: MCPRequest,\n extra: MCPRequestExtra\n): Promise<void> {\n const resolvedTags = await resolveEventTags(data, request, extra);\n if (resolvedTags) {\n event.tags = resolvedTags;\n }\n const resolvedProperties = await resolveEventProperties(data, request, extra);\n if (resolvedProperties) {\n event.properties = resolvedProperties;\n }\n}\n\nfunction setToolCallContext(\n event: UnredactedEvent,\n context: MCPAnalyticsOptions[\"context\"],\n request: MCPRequest\n): void {\n if (\n !(isContextEnabled(context) && request.params?.name !== \"get_more_tools\")\n ) {\n return;\n }\n\n const contextArgument = getContextArgument(request);\n if (contextArgument) {\n event.userIntent = contextArgument;\n }\n}\n\nfunction getContextArgument(request: MCPRequest): string | undefined {\n const context = request.params?.arguments?.context;\n return typeof context === \"string\" ? context : undefined;\n}\n\nfunction getEventDuration(event: UnredactedEvent): number {\n return event.timestamp ? Date.now() - event.timestamp.getTime() : 0;\n}\n","/**\n * MCP SDK Compatibility Helpers\n *\n * Internal utilities for handling differences between MCP SDK versions.\n * These helpers abstract away SDK-internal details like:\n * - Tool callback/handler property names (changed in SDK 1.24)\n * - Zod schema internal structures (v3 vs v4)\n */\n\nimport type { RegisteredTool, ToolCallback } from \"../types.js\";\n\n// --- Tool function property utilities for MCP SDK version compatibility ---\n// MCP SDK 1.23 and earlier use \"callback\", 1.24+ uses \"handler\"\n\nexport type ToolFunctionKey = \"callback\" | \"handler\";\n\n/**\n * Returns the tool function (callback/handler) from a RegisteredTool.\n * Supports both MCP SDK 1.23- (callback) and 1.24+ (handler).\n */\nexport function getToolFunction(tool: RegisteredTool): ToolCallback {\n if (\"handler\" in tool && typeof tool.handler === \"function\") {\n return tool.handler;\n }\n if (\"callback\" in tool && typeof tool.callback === \"function\") {\n return tool.callback;\n }\n throw new Error(\"Tool has neither callback nor handler property\");\n}\n\n/**\n * Returns the property key name used for the tool function (\"callback\" or \"handler\").\n * This preserves the original property name when wrapping tools.\n */\nexport function getToolFunctionKey(tool: RegisteredTool): ToolFunctionKey {\n if (\"handler\" in tool && typeof tool.handler === \"function\") {\n return \"handler\";\n }\n return \"callback\";\n}\n\n/**\n * Returns true if the tool has a callback or handler property.\n */\nexport function hasToolFunction(tool: unknown): tool is RegisteredTool {\n if (!tool || typeof tool !== \"object\") {\n return false;\n }\n const t = tool as Record<string, unknown>;\n return (\n (\"handler\" in t && typeof t.handler === \"function\") ||\n (\"callback\" in t && typeof t.callback === \"function\")\n );\n}\n\n/**\n * Creates a new tool object with the wrapped function, preserving the original property name.\n * This ensures MCP SDK 1.24+ gets back a tool with \"handler\" and 1.23- gets \"callback\".\n */\nexport function createWrappedTool(\n originalTool: RegisteredTool,\n wrappedFunction: ToolCallback\n): RegisteredTool {\n const key = getToolFunctionKey(originalTool);\n return {\n ...originalTool,\n [key]: wrappedFunction,\n } as RegisteredTool;\n}\n\n// --- Zod schema internal property helpers ---\n// These access internal properties to extract method names from MCP SDK schemas\n// No Zod import needed - we introspect the internal structure directly\n\ninterface ZodV3Internal {\n _def?: {\n value?: unknown;\n values?: unknown[]; // For enums - some Zod versions store literal values here\n shape?: Record<string, unknown> | (() => Record<string, unknown>);\n };\n shape?: Record<string, unknown> | (() => Record<string, unknown>);\n}\n\ninterface ZodV4Internal {\n _zod?: {\n def?: {\n value?: unknown;\n values?: unknown[]; // For enums - some Zod versions store literal values here\n shape?: Record<string, unknown> | (() => Record<string, unknown>);\n };\n };\n}\n\nexport function isZ4Schema(schema: unknown): boolean {\n if (!schema || typeof schema !== \"object\") {\n return false;\n }\n return !!(schema as ZodV4Internal)._zod;\n}\n\nexport function getObjectShape(\n schema: unknown\n): Record<string, unknown> | undefined {\n if (!schema || typeof schema !== \"object\") {\n return;\n }\n\n let rawShape:\n | Record<string, unknown>\n | (() => Record<string, unknown>)\n | undefined;\n\n if (isZ4Schema(schema)) {\n const v4Schema = schema as ZodV4Internal;\n rawShape = v4Schema._zod?.def?.shape;\n } else {\n const v3Schema = schema as ZodV3Internal;\n // Try .shape first, then fall back to _def.shape (some v3 schema types store it there)\n rawShape = v3Schema.shape ?? v3Schema._def?.shape;\n }\n\n if (!rawShape) {\n return;\n }\n\n if (typeof rawShape === \"function\") {\n try {\n return rawShape();\n } catch {\n return;\n }\n }\n\n return rawShape;\n}\n\nexport function getLiteralValue(schema: unknown): unknown {\n if (!schema || typeof schema !== \"object\") {\n return;\n }\n\n if (isZ4Schema(schema)) {\n const v4Schema = schema as ZodV4Internal;\n const def = v4Schema._zod?.def;\n if (def?.value !== undefined) {\n return def.value;\n }\n // Fallback: values array (for enums)\n if (Array.isArray(def?.values) && def.values.length > 0) {\n return def.values[0];\n }\n } else {\n const v3Schema = schema as ZodV3Internal;\n const def = v3Schema._def;\n if (def?.value !== undefined) {\n return def.value;\n }\n // Fallback: values array (for enums)\n if (Array.isArray(def?.values) && def.values.length > 0) {\n return def.values[0];\n }\n }\n\n // Final fallback: direct .value property (some Zod versions)\n const directValue = (schema as { value?: unknown }).value;\n if (directValue !== undefined) {\n return directValue;\n }\n\n return;\n}\n","import type { CallToolResult } from \"@modelcontextprotocol/sdk/types.js\";\nimport type {\n CompatibleRequestHandlerExtra,\n HighLevelMCPServerLike,\n MCPServerLike,\n RegisteredTool,\n UnredactedEvent,\n} from \"../types.js\";\nimport { isContextEnabled } from \"./context-parameters.js\";\nimport { publishEvent } from \"./event-queue.js\";\nimport { MCPAnalyticsEventType } from \"./event-types.js\";\nimport { captureException } from \"./exceptions.js\";\nimport {\n getServerTrackingData,\n handleIdentify,\n resolveEventProperties,\n resolveEventTags,\n} from \"./internal.js\";\nimport { writeToLog } from \"./logging.js\";\nimport { buildCapturedMcpParameters } from \"./mcp-payloads.js\";\nimport {\n createWrappedTool,\n getLiteralValue,\n getObjectShape,\n getToolFunction,\n hasToolFunction,\n} from \"./mcp-sdk-compat.js\";\nimport { getServerSessionId } from \"./session.js\";\nimport { handleReportMissing } from \"./tools.js\";\nimport { setupInitializeTracing, setupListToolsTracing } from \"./tracing.js\";\n\ntype MCPRequestHandler = NonNullable<\n MCPServerLike[\"_requestHandlers\"] extends Map<string, infer THandler>\n ? THandler\n : never\n>;\ntype MCPRequest = Parameters<MCPRequestHandler>[0];\ntype MCPRequestExtra = Parameters<MCPRequestHandler>[1];\n\n// WeakMap to track which callbacks have already been wrapped\nconst wrappedCallbacks = new WeakMap<object, boolean>();\n\n// Symbol to mark tools that have already been processed\nconst MCP_ANALYTICS_PROCESSED = Symbol(\"__posthog_mcp_analytics_processed__\");\n\ntype ProcessedRegisteredTool = RegisteredTool & {\n [MCP_ANALYTICS_PROCESSED]?: boolean;\n};\n\nfunction isToolResultError(result: unknown): boolean {\n return (\n !!result &&\n typeof result === \"object\" &&\n \"isError\" in result &&\n result.isError === true\n );\n}\n\nfunction isCallbackUpdate(value: unknown): value is { callback: unknown } {\n return (\n !!value &&\n typeof value === \"object\" &&\n \"callback\" in value &&\n typeof value.callback === \"function\"\n );\n}\n\nfunction addTracingToToolRegistry(\n tools: Record<string, RegisteredTool>,\n server: HighLevelMCPServerLike\n): Record<string, RegisteredTool> {\n return Object.fromEntries(\n Object.entries(tools).map(([name, tool]) => [\n name,\n addTracingToToolCallbackInternal(tool, name, server),\n ])\n );\n}\n\nfunction setupListenerToRegisteredTools(server: HighLevelMCPServerLike): void {\n try {\n const data = getServerTrackingData(server.server as MCPServerLike);\n if (!data) {\n writeToLog(\"Warning: Cannot setup listener - no tracking data found\");\n return;\n }\n\n // Create a proxy handler for the _registeredTools object\n const handler: ProxyHandler<Record<string, RegisteredTool>> = {\n set(\n target: Record<string, RegisteredTool>,\n property: string | symbol,\n value: RegisteredTool\n ): boolean {\n try {\n // Check if this is a tool being registered (has callback or handler property)\n if (\n typeof property === \"string\" &&\n value &&\n typeof value === \"object\" &&\n hasToolFunction(value)\n ) {\n // Check if tool has already been processed\n if ((value as ProcessedRegisteredTool)[MCP_ANALYTICS_PROCESSED]) {\n writeToLog(\n `Tool ${String(property)} already processed, skipping proxy wrapping`\n );\n // Just set the value without processing\n return Reflect.set(target, property, value);\n }\n\n // Check if callback/handler is already wrapped\n if (wrappedCallbacks.has(getToolFunction(value))) {\n writeToLog(\n `Tool ${String(property)} callback already wrapped, skipping proxy wrapping`\n );\n // Just set the value without processing\n return Reflect.set(target, property, value);\n }\n\n // Apply tracing to the callback (context injection happens in setupListToolsTracing)\n const nextValue = addTracingToToolCallbackInternal(\n value,\n property,\n server\n );\n\n // After adding a tool, try to set up list tools tracing\n // This handles the case where track() is called before tools are registered\n setupListToolsTracing(server);\n\n // If the tool has an update method, wrap it to handle callback updates\n if (typeof nextValue.update === \"function\") {\n const originalUpdate = nextValue.update;\n nextValue.update = function (...updateArgs: unknown[]) {\n // If callback is being updated, wrap the new callback\n // Note: MCP SDK's update() method API uses \"callback\" property in its interface\n if (updateArgs[0]) {\n const updateObj = updateArgs[0];\n if (isCallbackUpdate(updateObj)) {\n const wrappedTool = addTracingToToolCallbackInternal(\n { callback: updateObj.callback } as RegisteredTool,\n property,\n server\n );\n updateObj.callback = getToolFunction(wrappedTool);\n }\n }\n return originalUpdate.apply(this, updateArgs);\n };\n }\n return Reflect.set(target, property, nextValue);\n }\n\n // Use Reflect to perform the actual property set\n return Reflect.set(target, property, value);\n } catch (error) {\n writeToLog(\n `Warning: Error in proxy set handler for tool ${String(property)} - ${error}`\n );\n // Fall back to default behavior on error\n return Reflect.set(target, property, value);\n }\n },\n\n get(\n target: Record<string, RegisteredTool>,\n property: string | symbol\n ): unknown {\n return Reflect.get(target, property);\n },\n\n deleteProperty(\n target: Record<string, RegisteredTool>,\n property: string | symbol\n ): boolean {\n return Reflect.deleteProperty(target, property);\n },\n\n has(\n target: Record<string, RegisteredTool>,\n property: string | symbol\n ): boolean {\n return Reflect.has(target, property);\n },\n };\n\n // Replace _registeredTools with a proxied version\n const originalTools = server._registeredTools || {};\n server._registeredTools = new Proxy(originalTools, handler);\n\n writeToLog(\"Successfully set up listener for new tool registrations\");\n } catch (error) {\n writeToLog(\n `Warning: Failed to setup listener for registered tools - ${error}`\n );\n }\n}\n\nfunction addTracingToToolCallbackInternal(\n tool: RegisteredTool,\n toolName: string,\n _server: HighLevelMCPServerLike\n): RegisteredTool {\n const originalCallback = getToolFunction(tool);\n\n if (wrappedCallbacks.has(originalCallback)) {\n writeToLog(`Tool ${toolName} callback already wrapped, skipping re-wrap`);\n return tool;\n }\n\n if ((tool as ProcessedRegisteredTool)[MCP_ANALYTICS_PROCESSED]) {\n writeToLog(`Tool ${toolName} already processed, skipping re-wrap`);\n return tool;\n }\n\n const wrappedCallback = async (\n ...params: unknown[]\n ): Promise<CallToolResult> => {\n let args: unknown;\n let extra: CompatibleRequestHandlerExtra;\n\n if (params.length === 2) {\n args = params[0];\n extra = params[1] as CompatibleRequestHandlerExtra;\n } else {\n args = undefined;\n extra = params[0] as CompatibleRequestHandlerExtra;\n }\n\n const removeContextFromArgs = (args: unknown): unknown => {\n if (args && typeof args === \"object\" && \"context\" in args) {\n const { context: _context, ...argsWithoutContext } = args;\n return argsWithoutContext;\n }\n return args;\n };\n\n const cleanedArgs =\n toolName === \"get_more_tools\" ? args : removeContextFromArgs(args);\n\n try {\n if (cleanedArgs === undefined) {\n const handler = originalCallback as (\n extra: CompatibleRequestHandlerExtra\n ) => Promise<CallToolResult>;\n return await handler(extra);\n }\n const handler = originalCallback as (\n args: unknown,\n extra: CompatibleRequestHandlerExtra\n ) => Promise<CallToolResult>;\n return await handler(cleanedArgs, extra);\n } catch (error) {\n if (error instanceof Error) {\n extra.__mcp_analytics_error = error;\n }\n throw error;\n }\n };\n\n // Mark the original callback as wrapped\n wrappedCallbacks.set(originalCallback, true);\n\n // Mark the wrapped callback as well (in case it gets re-wrapped)\n wrappedCallbacks.set(wrappedCallback, true);\n\n // Create a new tool object with the wrapped callback, preserving the property name\n const wrappedTool = createWrappedTool(tool, wrappedCallback);\n\n // Mark the tool as processed\n (wrappedTool as ProcessedRegisteredTool)[MCP_ANALYTICS_PROCESSED] = true;\n\n return wrappedTool;\n}\n\nfunction setupToolsCallHandlerWrapping(server: HighLevelMCPServerLike): void {\n const lowLevelServer = server.server as MCPServerLike;\n\n // Check if tools/call handler already exists\n const existingHandler = lowLevelServer._requestHandlers.get(\"tools/call\");\n if (existingHandler) {\n const wrappedHandler = createToolsCallWrapper(\n existingHandler,\n lowLevelServer\n );\n lowLevelServer._requestHandlers.set(\"tools/call\", wrappedHandler);\n }\n\n // Intercept future calls to setRequestHandler for tools registered after track()\n const originalSetRequestHandler =\n lowLevelServer.setRequestHandler.bind(lowLevelServer);\n\n lowLevelServer.setRequestHandler = ((\n requestSchema: unknown,\n handler: MCPRequestHandler\n ) => {\n const shape = getObjectShape(requestSchema);\n const method = shape?.method ? getLiteralValue(shape.method) : undefined;\n\n // Only wrap tools/call handler\n if (method === \"tools/call\") {\n const wrappedHandler = createToolsCallWrapper(handler, lowLevelServer);\n return originalSetRequestHandler(requestSchema, wrappedHandler);\n }\n\n // Pass through all other handlers unchanged\n return originalSetRequestHandler(requestSchema, handler);\n }) as MCPServerLike[\"setRequestHandler\"];\n}\n\nfunction createToolsCallWrapper(\n originalHandler: MCPRequestHandler,\n server: MCPServerLike\n): MCPRequestHandler {\n return async (request: MCPRequest, extra: MCPRequestExtra) =>\n await handleWrappedToolsCall(originalHandler, server, request, extra);\n}\n\nasync function handleWrappedToolsCall(\n originalHandler: MCPRequestHandler,\n server: MCPServerLike,\n request: MCPRequest,\n extra: MCPRequestExtra\n): Promise<unknown> {\n const startTime = new Date();\n const tracing = await initializeToolCallEvent(\n server,\n request,\n extra,\n startTime\n );\n\n if (request?.params?.name === \"get_more_tools\") {\n return await executeReportMissingTool(server, request, tracing, startTime);\n }\n\n return await executeOriginalTool(\n originalHandler,\n server,\n request,\n extra,\n tracing,\n startTime\n );\n}\n\nasync function initializeToolCallEvent(\n server: MCPServerLike,\n request: MCPRequest,\n extra: MCPRequestExtra,\n startTime: Date\n): Promise<{ event: UnredactedEvent | null; shouldPublishEvent: boolean }> {\n try {\n const data = getServerTrackingData(server);\n if (!data) {\n writeToLog(\n \"Warning: PostHog MCP analytics is unable to find server tracking data. Please ensure you have called track(server, options) before using tool calls.\"\n );\n return { event: null, shouldPublishEvent: false };\n }\n\n const event: UnredactedEvent = {\n sessionId: getServerSessionId(server, extra),\n resourceName: request.params?.name || \"Unknown Tool\",\n parameters: buildCapturedMcpParameters(request),\n eventType: MCPAnalyticsEventType.mcpToolsCall,\n timestamp: startTime,\n redactionFn: data.options.redactSensitiveInformation,\n };\n\n await handleIdentify(server, data, request, extra);\n event.sessionId = data.sessionId;\n await applyResolvedMetadata(event, data, request, extra);\n\n const contextArgument = getContextArgument(request);\n if (isContextEnabled(data.options.context) && contextArgument) {\n event.userIntent = contextArgument;\n }\n\n return { event, shouldPublishEvent: true };\n } catch (error) {\n writeToLog(\n `Warning: PostHog MCP analytics tracing failed for tool ${request.params?.name}, falling back to original handler - ${error}`\n );\n return { event: null, shouldPublishEvent: false };\n }\n}\n\nasync function applyResolvedMetadata(\n event: UnredactedEvent,\n data: NonNullable<ReturnType<typeof getServerTrackingData>>,\n request: MCPRequest,\n extra: MCPRequestExtra\n): Promise<void> {\n const resolvedTags = await resolveEventTags(data, request, extra);\n if (resolvedTags) {\n event.tags = resolvedTags;\n }\n const resolvedProperties = await resolveEventProperties(data, request, extra);\n if (resolvedProperties) {\n event.properties = resolvedProperties;\n }\n}\n\nasync function executeReportMissingTool(\n server: MCPServerLike,\n request: MCPRequest,\n tracing: { event: UnredactedEvent | null; shouldPublishEvent: boolean },\n startTime: Date\n): Promise<unknown> {\n try {\n const context = getContextArgument(request) || \"\";\n const result = await handleReportMissing({\n context,\n });\n publishSuccessfulToolEvent(server, tracing, result, startTime, {\n userIntent: context,\n });\n return result;\n } catch (error) {\n publishFailedToolEvent(server, tracing, error, startTime);\n throw error;\n }\n}\n\nasync function executeOriginalTool(\n originalHandler: MCPRequestHandler,\n server: MCPServerLike,\n request: MCPRequest,\n extra: MCPRequestExtra,\n tracing: { event: UnredactedEvent | null; shouldPublishEvent: boolean },\n startTime: Date\n): Promise<unknown> {\n try {\n const result = await originalHandler(request, extra);\n publishSuccessfulToolEvent(server, tracing, result, startTime, {\n capturedError: extra?.__mcp_analytics_error,\n clearCapturedError: () => {\n if (extra) {\n extra.__mcp_analytics_error = undefined;\n }\n },\n });\n return result;\n } catch (error) {\n publishFailedToolEvent(server, tracing, error, startTime);\n throw error;\n }\n}\n\nfunction getContextArgument(request: MCPRequest): string | undefined {\n const context = request.params?.arguments?.context;\n return typeof context === \"string\" ? context : undefined;\n}\n\nfunction publishSuccessfulToolEvent(\n server: MCPServerLike,\n tracing: { event: UnredactedEvent | null; shouldPublishEvent: boolean },\n result: unknown,\n startTime: Date,\n options: {\n capturedError?: unknown;\n clearCapturedError?: () => void;\n userIntent?: string;\n } = {}\n): void {\n if (!(tracing.event && tracing.shouldPublishEvent)) {\n return;\n }\n\n if (options.userIntent) {\n tracing.event.userIntent = options.userIntent;\n }\n if (isToolResultError(result)) {\n tracing.event.isError = true;\n tracing.event.error = captureException(options.capturedError || result);\n options.clearCapturedError?.();\n }\n\n tracing.event.response = result;\n tracing.event.duration = Date.now() - startTime.getTime();\n publishEvent(server, tracing.event);\n}\n\nfunction publishFailedToolEvent(\n server: MCPServerLike,\n tracing: { event: UnredactedEvent | null; shouldPublishEvent: boolean },\n error: unknown,\n startTime: Date\n): void {\n if (!(tracing.event && tracing.shouldPublishEvent)) {\n return;\n }\n\n tracing.event.isError = true;\n tracing.event.error = captureException(error);\n tracing.event.duration = Date.now() - startTime.getTime();\n publishEvent(server, tracing.event);\n}\n\nexport function setupTracking(server: HighLevelMCPServerLike): void {\n try {\n const _mcpAnalyticsData = getServerTrackingData(server.server);\n\n // Setup handler wrapping before any tools are registered\n setupToolsCallHandlerWrapping(server);\n\n setupInitializeTracing(server);\n\n // Modify existing callbacks to include tracing and publishing events\n // This now includes get_more_tools if it was added\n server._registeredTools = addTracingToToolRegistry(\n server._registeredTools,\n server\n );\n\n setupListToolsTracing(server);\n\n // Proxy the high level server's registered tools to ensure new tools are injected with tracing\n // Note: Context parameter injection now happens in setupListToolsTracing (after JSON Schema conversion)\n setupListenerToRegisteredTools(server);\n } catch (error) {\n writeToLog(`Warning: Failed to setup tool call tracing - ${error}`);\n }\n}\n","// Import our minimal interface from types\n\n// Import from modules\nimport {\n isCompatibleServerType,\n isHighLevelServer,\n} from \"./modules/compatibility.js\";\nimport {\n eventQueue,\n publishEvent as publishEventToQueue,\n} from \"./modules/event-queue.js\";\nimport { MCPAnalyticsEventType } from \"./modules/event-types.js\";\nimport { captureException } from \"./modules/exceptions.js\";\nimport {\n getServerTrackingData,\n setServerTrackingData,\n} from \"./modules/internal.js\";\nimport { writeToLog } from \"./modules/logging.js\";\nimport {\n deriveSessionIdFromMCPSession,\n getSessionInfo,\n newSessionId,\n} from \"./modules/session.js\";\nimport { setupMCPAnalyticsTools } from \"./modules/tools.js\";\nimport { setupToolCallTracing } from \"./modules/tracing.js\";\nimport { setupTracking } from \"./modules/tracing-v2.js\";\nimport { validateTags } from \"./modules/validation.js\";\nimport type {\n CustomEventData,\n HighLevelMCPServerLike,\n MCPAnalyticsData,\n MCPAnalyticsOptions,\n MCPServerLike,\n UnredactedEvent,\n UserIdentity,\n} from \"./types.js\";\n\n/**\n * Integrates PostHog MCP into an MCP server to track tool usage patterns and user interactions.\n *\n * @param server - The MCP server instance to track. Must be a compatible MCP server implementation.\n * @param options - Configuration to customize tracking behavior.\n * @param options.apiKey - PostHog project API key (`phc_...`). Optional when using an injected `posthogClient`.\n * @param options.host - Custom PostHog ingestion host. Defaults to `https://us.i.posthog.com`.\n * @param options.reportMissing - Adds a \"get_more_tools\" tool that allows LLMs to automatically report missing functionality. Defaults to false.\n * @param options.enableAITracing - Emits `$ai_span` events for tool calls so MCP activity appears in PostHog LLM analytics. Defaults to false.\n * @param options.enableTracing - Enables tracking of tool calls and usage patterns.\n * @param options.context - Enables the required \"context\" parameter on tools to capture user intent. Pass false to disable, or an object with a custom description.\n * @param options.identify - Async function to identify users and attach custom data to their sessions.\n * @param options.redactSensitiveInformation - Function to redact sensitive data before sending to PostHog.\n * @param options.eventTags - Callback invoked on every auto-captured event (tool calls, tool lists, initialize) to attach string key-value tags. Tags are intended to be indexed and queryable in PostHog — use them for structured metadata you'll want to filter or group by (e.g., trace IDs, environments, regions). Tags are validated client-side: keys must be ≤32 chars matching `[a-zA-Z0-9$_.:\\- ]`, values must be strings ≤200 chars with no newlines, max 50 entries per event. Invalid entries are silently dropped with a warning logged to `~/posthog-mcp-analytics.log`. If the callback throws or returns null, tags are omitted. Receives the same `(request, extra)` arguments as `identify`.\n * @param options.eventProperties - Callback invoked on every auto-captured event to attach flexible JSON metadata (device info, feature flags, nested context). No constraints beyond standard JSON types. If the callback throws or returns null, properties are omitted. Receives the same `(request, extra)` arguments as `identify`.\n * @param options.posthogClient - Optional existing posthog-node compatible client. If provided, MCP events are captured with that client instead of creating a new one.\n * @param options.posthogOptions - Optional posthog-node options used when the SDK creates its own client.\n *\n * @returns The tracked server instance.\n *\n * @remarks\n * Analytics data and debug information are logged to `~/posthog-mcp-analytics.log` since console logs interfere\n * with STDIO-based MCP servers.\n *\n * Do not call `track()` multiple times on the same server instance as this will cause unexpected behavior.\n *\n * @example\n * ```typescript\n * import { track } from \"@posthog/mcp\";\n *\n * const mcpServer = new Server({ name: \"my-mcp-server\", version: \"1.0.0\" });\n *\n * // Track the server with PostHog MCP\n * track(mcpServer, { apiKey: \"phc_abc123xyz\" });\n *\n * // Register your tools\n * mcpServer.setRequestHandler(ListToolsRequestSchema, async () => ({\n * tools: [{ name: \"my_tool\", description: \"Does something useful\" }]\n * }));\n * ```\n *\n * @example\n * ```typescript\n * // With user identification\n * track(mcpServer, {\n * apiKey: \"phc_abc123xyz\",\n * identify: async (request, extra) => {\n * const user = await getUserFromToken(request.params.arguments.token);\n * return {\n * userId: user.id,\n * userData: { plan: user.plan, company: user.company }\n * };\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With custom context description\n * track(mcpServer, {\n * apiKey: \"phc_abc123xyz\",\n * context: {\n * description: \"Explain why you're calling this tool and what business objective it helps achieve\"\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With sensitive data redaction\n * track(mcpServer, {\n * apiKey: \"phc_abc123xyz\",\n * redactSensitiveInformation: async (text) => {\n * return text.replace(/api_key_\\w+/g, \"[REDACTED]\");\n * }\n * });\n * ```\n *\n * @example\n * ```typescript\n * // With event tags and properties\n * track(mcpServer, {\n * apiKey: \"phc_abc123xyz\",\n * eventTags: async (request, extra) => ({\n * trace_id: extra?.requestContext?.traceId,\n * env: process.env.NODE_ENV,\n * region: \"us-east-1\",\n * }),\n * eventProperties: async (request, extra) => ({\n * device: \"desktop\",\n * app_version: \"2.1.0\",\n * feature_flags: [\"dark_mode\", \"beta_ui\"],\n * }),\n * });\n * ```\n *\n * @example\n * ```typescript\n */\nfunction track<TServer>(\n server: TServer,\n options: MCPAnalyticsOptions = {}\n): TServer {\n try {\n const validatedServer = isCompatibleServerType(server);\n const lowLevelServer = getLowLevelServer(validatedServer);\n\n configureIngestion(options);\n\n // Check if server is already being tracked\n const existingData = getServerTrackingData(lowLevelServer);\n if (existingData) {\n writeToLog(\n \"[SESSION DEBUG] track() - Server already being tracked, skipping initialization\"\n );\n return validatedServer as TServer;\n }\n\n if (!(options.apiKey || options.posthogClient)) {\n writeToLog(\n \"Warning: No PostHog API key or PostHog client configured. Events will not be sent anywhere.\"\n );\n }\n\n const mcpAnalyticsData = buildTrackingData(lowLevelServer, options);\n\n setServerTrackingData(lowLevelServer, mcpAnalyticsData);\n setupTrackedServer(validatedServer, lowLevelServer, mcpAnalyticsData);\n\n return validatedServer as TServer;\n } catch (error) {\n writeToLog(`Warning: Failed to track server - ${error}`);\n return server;\n }\n}\n\nfunction getLowLevelServer(\n server: MCPServerLike | HighLevelMCPServerLike\n): MCPServerLike {\n return isHighLevelServer(server)\n ? (server as HighLevelMCPServerLike).server\n : (server as MCPServerLike);\n}\n\nfunction configureIngestion(options: MCPAnalyticsOptions): void {\n const host = options.host || process.env.POSTHOG_MCP_ANALYTICS_HOST;\n if (options.posthogOptions) {\n eventQueue.configurePostHogOptions(options.posthogOptions);\n }\n if (host) {\n eventQueue.configure(host);\n }\n}\n\nfunction buildTrackingData(\n lowLevelServer: MCPServerLike,\n options: MCPAnalyticsOptions\n): MCPAnalyticsData {\n return {\n apiKey: options.apiKey || \"\",\n sessionId: newSessionId(),\n lastActivity: new Date(),\n identifiedSessions: new Map<string, UserIdentity>(),\n sessionInfo: getSessionInfo(lowLevelServer, undefined),\n options: {\n reportMissing: options.reportMissing ?? false,\n enableAITracing: options.enableAITracing ?? false,\n enableTracing: options.enableTracing ?? true,\n context: options.context,\n identify: options.identify,\n redactSensitiveInformation: options.redactSensitiveInformation,\n eventTags: options.eventTags,\n eventProperties: options.eventProperties,\n host: options.host,\n posthogClient: options.posthogClient,\n posthogOptions: options.posthogOptions,\n },\n sessionSource: \"generated\", // Changes to \"mcp\" if MCP sessionId is provided in requests\n };\n}\n\nfunction setupTrackedServer(\n validatedServer: MCPServerLike | HighLevelMCPServerLike,\n lowLevelServer: MCPServerLike,\n mcpAnalyticsData: MCPAnalyticsData\n): void {\n if (isHighLevelServer(validatedServer)) {\n const highLevelServer = validatedServer as HighLevelMCPServerLike;\n setupTracking(highLevelServer);\n } else {\n if (mcpAnalyticsData.options.reportMissing) {\n try {\n setupMCPAnalyticsTools(lowLevelServer);\n } catch (error) {\n writeToLog(`Warning: Failed to setup report missing tool - ${error}`);\n }\n }\n\n if (mcpAnalyticsData.options.enableTracing) {\n try {\n // Pass the low-level server to the current tracing module\n setupToolCallTracing(lowLevelServer);\n } catch (error) {\n writeToLog(`Warning: Failed to setup tool call tracing - ${error}`);\n }\n }\n }\n}\n\n/**\n * Publishes a custom event to PostHog MCP with flexible session management.\n *\n * @param serverOrSessionId - Either a tracked MCP server instance or a MCP session ID string\n * @param eventData - Event data to include with the custom event. `apiKey` is required when publishing against a raw session ID.\n *\n * @returns Promise that resolves when the event is queued for publishing\n *\n * @example\n * ```typescript\n * // With a tracked server\n * await publishCustomEvent(\n * server,\n * {\n * resourceName: \"custom-action\",\n * parameters: { action: \"user-feedback\", rating: 5 },\n * message: \"User provided feedback\"\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * // With a MCP session ID\n * await publishCustomEvent(\n * \"user-session-12345\",\n * {\n * apiKey: \"phc_abc123xyz\",\n * isError: true,\n * error: { message: \"Custom error occurred\", code: \"ERR_001\" }\n * }\n * );\n * ```\n *\n * @example\n * ```typescript\n * await publishCustomEvent(\n * server,\n * {\n * resourceName: \"feature-usage\",\n * }\n * );\n * ```\n */\nexport function publishCustomEvent(\n serverOrSessionId: unknown,\n eventData: CustomEventData = {}\n): Promise<void> {\n try {\n publishCustomEventSync(serverOrSessionId, eventData);\n return Promise.resolve();\n } catch (error) {\n return Promise.reject(error);\n }\n}\n\nfunction publishCustomEventSync(\n serverOrSessionId: unknown,\n eventData: CustomEventData\n): void {\n const target = resolveCustomEventTarget(serverOrSessionId, eventData);\n\n // Build the event object\n const event: UnredactedEvent = {\n // Core fields\n sessionId: target.sessionId,\n apiKey: target.apiKey,\n\n // Fixed event type for custom events\n eventType: MCPAnalyticsEventType.custom,\n\n // Timestamp\n timestamp: new Date(),\n\n // Event data from parameters\n resourceName: eventData?.resourceName,\n parameters: eventData?.parameters,\n response: eventData?.response,\n userIntent: eventData?.message,\n duration: eventData?.duration,\n isError: eventData?.isError,\n error: resolveCustomEventError(eventData?.error),\n };\n\n // Wire up customer-defined metadata\n if (eventData?.tags) {\n event.tags = validateTags(eventData.tags);\n }\n if (eventData?.properties && Object.keys(eventData.properties).length > 0) {\n event.properties = eventData.properties;\n }\n\n // If we have a tracked server, use the publishEvent function\n // Otherwise, add directly to the event queue\n publishResolvedCustomEvent(target, event);\n\n writeToLog(\n `Published custom event for session ${target.sessionId} with type '${MCPAnalyticsEventType.custom}'`\n );\n}\n\nfunction resolveCustomEventError(error: unknown): UnredactedEvent[\"error\"] {\n if (error === undefined || error === null) {\n return error;\n }\n\n if (\n typeof error === \"object\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error as UnredactedEvent[\"error\"];\n }\n\n return captureException(error);\n}\n\ninterface CustomEventTarget {\n apiKey: string;\n lowLevelServer: MCPServerLike | null;\n posthogClient?: MCPAnalyticsOptions[\"posthogClient\"];\n sessionId: string;\n}\n\nfunction resolveCustomEventTarget(\n serverOrSessionId: unknown,\n eventData: CustomEventData\n): CustomEventTarget {\n if (typeof serverOrSessionId === \"string\") {\n return resolveSessionIdTarget(serverOrSessionId, eventData);\n }\n\n if (serverOrSessionId && typeof serverOrSessionId === \"object\") {\n return resolveTrackedServerTarget(serverOrSessionId);\n }\n\n throw new Error(\n \"First parameter must be either an MCP server object or a session ID string\"\n );\n}\n\nfunction resolveSessionIdTarget(\n sessionIdInput: string,\n eventData: CustomEventData\n): CustomEventTarget {\n const apiKey = eventData.apiKey || \"\";\n if (!(apiKey || eventData.posthogClient)) {\n throw new Error(\n \"apiKey or posthogClient is required when publishing with a session ID\"\n );\n }\n\n return {\n apiKey,\n lowLevelServer: null,\n posthogClient: eventData.posthogClient,\n sessionId: deriveSessionIdFromMCPSession(sessionIdInput),\n };\n}\n\nfunction resolveTrackedServerTarget(server: object): CustomEventTarget {\n const lowLevelServer = getLowLevelServerFromUnknownObject(server);\n const trackingData = getServerTrackingData(lowLevelServer);\n\n if (!trackingData) {\n throw new Error(\n \"Server is not tracked. Please call track() first or provide a session ID string.\"\n );\n }\n\n return {\n apiKey: trackingData.apiKey,\n lowLevelServer,\n posthogClient: trackingData.options.posthogClient,\n sessionId: trackingData.sessionId,\n };\n}\n\nfunction getLowLevelServerFromUnknownObject(server: object): MCPServerLike {\n return \"server\" in server &&\n server.server &&\n typeof server.server === \"object\"\n ? (server.server as MCPServerLike)\n : (server as MCPServerLike);\n}\n\nfunction publishResolvedCustomEvent(\n target: CustomEventTarget,\n event: UnredactedEvent\n): void {\n if (target.lowLevelServer && getServerTrackingData(target.lowLevelServer)) {\n publishEventToQueue(target.lowLevelServer, event);\n return;\n }\n\n if (target.posthogClient) {\n eventQueue.add(event, target.posthogClient);\n return;\n }\n\n eventQueue.add(event);\n}\n\nexport type {\n CustomEventData,\n MCPAnalyticsContextOptions,\n MCPAnalyticsOptions,\n RedactFunction,\n UserIdentity,\n} from \"./types.js\";\n\nexport type IdentifyFunction = MCPAnalyticsOptions[\"identify\"];\n\n// biome-ignore lint/performance/noBarrelFile: the package entrypoint intentionally defines the public SDK API.\nexport { PostHogMCPAnalyticsProperty } from \"./modules/constants.js\";\nexport { track };\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@posthog/mcp",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "PostHog SDK for MCP servers",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
8
|
+
"types": "dist/index.d.mts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.mts",
|
|
13
|
+
"default": "./dist/index.mjs"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsdown",
|
|
23
|
+
"dev": "tsdown --watch",
|
|
24
|
+
"test": "vitest",
|
|
25
|
+
"test:compatibility": "vitest run src/tests/mcp-version-compatibility.test.ts",
|
|
26
|
+
"check": "ultracite check --error-on-warnings .",
|
|
27
|
+
"fix": "ultracite fix .",
|
|
28
|
+
"typecheck": "tsgo --noEmit",
|
|
29
|
+
"typecheck:tsc6": "tsc6 --noEmit",
|
|
30
|
+
"bump": "changeset version",
|
|
31
|
+
"prepare": "husky",
|
|
32
|
+
"verify": "pnpm check && pnpm typecheck && pnpm test && pnpm build",
|
|
33
|
+
"prepublishOnly": "pnpm verify"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"ai-agents",
|
|
37
|
+
"analytics",
|
|
38
|
+
"mcp",
|
|
39
|
+
"mcp-server",
|
|
40
|
+
"model-context-protocol",
|
|
41
|
+
"observability",
|
|
42
|
+
"posthog"
|
|
43
|
+
],
|
|
44
|
+
"author": "PostHog",
|
|
45
|
+
"license": "MIT",
|
|
46
|
+
"repository": {
|
|
47
|
+
"type": "git",
|
|
48
|
+
"url": "git+https://github.com/PostHog/mcp-analytics.git"
|
|
49
|
+
},
|
|
50
|
+
"bugs": {
|
|
51
|
+
"url": "https://github.com/PostHog/mcp-analytics/issues"
|
|
52
|
+
},
|
|
53
|
+
"homepage": "https://github.com/PostHog/mcp-analytics#readme",
|
|
54
|
+
"files": [
|
|
55
|
+
"dist",
|
|
56
|
+
"README.md",
|
|
57
|
+
"LICENSE"
|
|
58
|
+
],
|
|
59
|
+
"publishConfig": {
|
|
60
|
+
"access": "public"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=22.22.0"
|
|
64
|
+
},
|
|
65
|
+
"packageManager": "pnpm@10.33.2",
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@biomejs/biome": "2.4.14",
|
|
68
|
+
"@changesets/cli": "^2.29.8",
|
|
69
|
+
"@modelcontextprotocol/sdk": "~1.24.2",
|
|
70
|
+
"@types/node": "^22.15.21",
|
|
71
|
+
"@typescript/native-preview": "beta",
|
|
72
|
+
"@vitest/coverage-v8": "^4.0.14",
|
|
73
|
+
"@vitest/ui": "^4.0.14",
|
|
74
|
+
"husky": "^9.1.7",
|
|
75
|
+
"tsdown": "^0.21.10",
|
|
76
|
+
"typescript": "npm:@typescript/typescript6@^6.0.0",
|
|
77
|
+
"ultracite": "7.6.3",
|
|
78
|
+
"vitest": "^4.0.14",
|
|
79
|
+
"zod": "^3.25 || ^4.0"
|
|
80
|
+
},
|
|
81
|
+
"peerDependencies": {
|
|
82
|
+
"@modelcontextprotocol/sdk": ">=1.11"
|
|
83
|
+
},
|
|
84
|
+
"pnpm": {
|
|
85
|
+
"overrides": {
|
|
86
|
+
"js-yaml": ">=4.1.1",
|
|
87
|
+
"tmp": ">=0.2.4",
|
|
88
|
+
"vite": ">=6.4.1",
|
|
89
|
+
"body-parser": ">=2.2.1",
|
|
90
|
+
"brace-expansion": "2.0.2"
|
|
91
|
+
},
|
|
92
|
+
"overridesComments": {
|
|
93
|
+
"js-yaml": "Fixes GHSA-mh29-5h37-fv8m (prototype pollution in merge) - via @changesets/cli",
|
|
94
|
+
"tmp": "Fixes GHSA-52f5-9888-hmc6 (symlink attack) - via @changesets/cli",
|
|
95
|
+
"vite": "Fixes GHSA-93m4-6634-74q7 and other vite security issues - via vitest",
|
|
96
|
+
"body-parser": "Fixes GHSA-wqch-xfxh-vrr4 (DoS via url encoding) - via @modelcontextprotocol/sdk",
|
|
97
|
+
"brace-expansion": "Fixes GHSA-v6h2-p8h4-qcjw (ReDoS vulnerability) - via eslint"
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
"dependencies": {
|
|
101
|
+
"posthog-node": "^5.33.3"
|
|
102
|
+
}
|
|
103
|
+
}
|