validate_event_payload
Validate tracking implementation payloads against event specifications to identify errors, warnings, and valid fields for analytics data accuracy.
Instructions
Validate a tracking implementation payload against the event spec. Returns errors, warnings, and valid fields.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| event_name | Yes | Name of the event to validate against | |
| payload | Yes | The payload object to validate |
Implementation Reference
- src/mcp-server/tools.js:63-156 (handler)The main handler function for the 'validate_event_payload' tool. It retrieves the event specification, expands its properties, validates the provided payload by checking field presence, types, and constraints (enum, regex), collects errors and warnings for invalid or unknown fields and missing required properties, and returns validation results.handler: async (args) => { const event = eventsMap.get(args.event_name); if (!event) { throw new NotFoundError('Event', args.event_name); } const expanded = getExpandedProperties(event); const errors = []; const warnings = []; const validFields = []; // Collect all expected properties const expectedProps = new Map(); for (const group of expanded.property_groups) { for (const prop of group.properties) { expectedProps.set(prop.name, prop); } } for (const prop of expanded.additional_properties) { expectedProps.set(prop.name, prop); } // Check provided fields for (const [key, value] of Object.entries(args.payload)) { const prop = expectedProps.get(key); if (!prop) { warnings.push({ field: key, issue: 'Unknown property not in spec' }); continue; } // Remove from expected (field was provided, even if invalid) expectedProps.delete(key); // Type validation const actualType = Array.isArray(value) ? 'array' : typeof value; const expectedType = prop.type === 'timestamp' ? 'string' : prop.type; if (expectedType !== actualType && expectedType !== 'unknown') { errors.push({ field: key, issue: 'Type mismatch', expected: prop.type, got: actualType }); continue; } // Constraint validation if (prop.constraints && prop.constraints !== '-') { if (prop.constraints.startsWith('enum:')) { const allowedValues = prop.constraints.substring(5).split(',').map(s => s.trim()); if (!allowedValues.includes(value)) { errors.push({ field: key, issue: 'Invalid enum value', expected: allowedValues, got: value }); continue; } } else if (prop.constraints.startsWith('regex:')) { const pattern = prop.constraints.substring(6).trim(); try { const regex = new RegExp(pattern); if (!regex.test(value)) { errors.push({ field: key, issue: 'Regex validation failed', expected: pattern, got: value }); continue; } } catch (e) { // Invalid regex pattern in spec } } } validFields.push(key); } // Check for missing properties for (const [name] of expectedProps) { warnings.push({ field: name, issue: 'Missing property' }); } return { valid: errors.length === 0, errors, warnings, valid_fields: validFields }; }
- src/mcp-server/tools.js:49-62 (schema)Input schema defining the expected parameters: event_name (string, required) and payload (object, required).inputSchema: { type: 'object', properties: { event_name: { type: 'string', description: 'Name of the event to validate against' }, payload: { type: 'object', description: 'The payload object to validate' } }, required: ['event_name', 'payload'] },
- src/mcp-server/tools.js:47-157 (registration)The tool definition object within the exported 'tools' object, which is imported into index.js and registered dynamically via setRequestHandler for ListToolsRequestSchema and CallToolRequestSchema.validate_event_payload: { description: 'Validate a tracking implementation payload against the event spec. Returns errors, warnings, and valid fields.', inputSchema: { type: 'object', properties: { event_name: { type: 'string', description: 'Name of the event to validate against' }, payload: { type: 'object', description: 'The payload object to validate' } }, required: ['event_name', 'payload'] }, handler: async (args) => { const event = eventsMap.get(args.event_name); if (!event) { throw new NotFoundError('Event', args.event_name); } const expanded = getExpandedProperties(event); const errors = []; const warnings = []; const validFields = []; // Collect all expected properties const expectedProps = new Map(); for (const group of expanded.property_groups) { for (const prop of group.properties) { expectedProps.set(prop.name, prop); } } for (const prop of expanded.additional_properties) { expectedProps.set(prop.name, prop); } // Check provided fields for (const [key, value] of Object.entries(args.payload)) { const prop = expectedProps.get(key); if (!prop) { warnings.push({ field: key, issue: 'Unknown property not in spec' }); continue; } // Remove from expected (field was provided, even if invalid) expectedProps.delete(key); // Type validation const actualType = Array.isArray(value) ? 'array' : typeof value; const expectedType = prop.type === 'timestamp' ? 'string' : prop.type; if (expectedType !== actualType && expectedType !== 'unknown') { errors.push({ field: key, issue: 'Type mismatch', expected: prop.type, got: actualType }); continue; } // Constraint validation if (prop.constraints && prop.constraints !== '-') { if (prop.constraints.startsWith('enum:')) { const allowedValues = prop.constraints.substring(5).split(',').map(s => s.trim()); if (!allowedValues.includes(value)) { errors.push({ field: key, issue: 'Invalid enum value', expected: allowedValues, got: value }); continue; } } else if (prop.constraints.startsWith('regex:')) { const pattern = prop.constraints.substring(6).trim(); try { const regex = new RegExp(pattern); if (!regex.test(value)) { errors.push({ field: key, issue: 'Regex validation failed', expected: pattern, got: value }); continue; } } catch (e) { // Invalid regex pattern in spec } } } validFields.push(key); } // Check for missing properties for (const [name] of expectedProps) { warnings.push({ field: name, issue: 'Missing property' }); } return { valid: errors.length === 0, errors, warnings, valid_fields: validFields }; } },