A Model Context Protocol (MCP) server for validating HED (Hierarchical Event Descriptor) data. This server provides comprehensive HED validation tools through the standardized MCP interface, making HED validation accessible to any MCP-compatible client.
HED (Hierarchical Event Descriptor) is:
- A standardized vocabulary for describing experimental events
- A hierarchical system that allows for precise event annotation
- Widely used in BIDS (Brain Imaging Data Structure) datasets
- Essential for reproducible neuroscience research
Model Context Protocol (MCP) is:
- A standardized protocol for tool and resource sharing
- Enables AI assistants and applications to access external capabilities
- Provides a consistent interface across different implementations
- Facilitates integration between diverse software systems
- HED string validation: Validate individual HED tag strings against schema specifications
- TSV file validation: Validate entire BIDS TSV files containing HED annotations
- JSON sidecar validation: Parse and validate HED sidecar JSON files
- File system access: Read files from local filesystem paths
- Multi-schema support: Support for standard HED schemas and library schemas
- Definition processing: Handle HED definitions for enhanced validation
- Warning detection: Optional warning detection in addition to error reporting
- Schema caching: Intelligent caching system for optimal performance
- Multiple interfaces: MCP server (stdio/WebSocket) + HTTP REST API
- Browser compatibility: Full browser support with multiple integration options
- Understanding HED
- Installation
- Quick Start
- Server Architecture
- Available Tools
- Usage Examples
- Working with HED Data
- Browser Usage
- Configuration
- Advanced Features
- Performance Optimization
- Integration Guide
- Development
- Troubleshooting
- Testing
- Contributing
- License
HED uses a hierarchical tag structure where tags are organized from general to specific:
Event # General event type
Event/Sensory-event # More specific
Sensory-event # Same as Event/Sensory-event
The hierarchical structure is used for search generality -- allowing a search for Event to pick up Event/Sensory-event as well as Sensory-event.
Note: All tags in the HED vocabulary are unique. It is recommended that you annotate using just the tag, not the full path.
- Path notation: Tags use forward slashes to indicate hierarchy
- Grouping: Parentheses group related tags:
(Red, Large) - Definitions: Custom definitions can be used for complex concepts
- Extension: Custom subtags can be added for specialization
Sensory-event, Property/Sensory-property/Visual/Color/Red
(Event/Sensory-event, (Property/Sensory-property/Visual/Color/Red, Property/Physical-property/Size/Large))
Def/StimulusOnset, Property/Sensory-property/Visual/Color/Blue
HED schemas evolve over time. Use the latest version whenever possible:
- Standard HED:
8.4.0- Basic vocabulary - Library schemas:
lang_1.1.0- Language-related tagsscore_2.1.0- EEG features based on SCORE standard
Before using the HED MCP Server, ensure you have:
- Node.js 18+: Download from nodejs.org
- Basic understanding of HED: Familiarity with HED concepts is helpful
- MCP-compatible client: Such as the MCP Inspector or custom client
npm installnpm run buildThis creates the distribution files in the dist/ directory.
npx @modelcontextprotocol/inspector node dist/server.jsHED MCP Server (src)
βββ server.ts # Main MCP server (stdio/WebSocket modes)
βββ tools/ # Validation functions
β βββ validateHedString.ts
β βββ validateHedTsv.ts
β βββ validateHedSidecar.ts
β βββ getFileFromPath.ts
βββ resources/ # Schema Information
β βββ hedSchema.ts
βββ utils/ # Utilities
β βββ schemaCache.ts # Schema caching system
β βββ definitionProcessor.ts
β βββ fileReader.ts
β βββ issueFormatter.ts
β βββ mcpToZod.ts
βββ types/ # TypeScript definitions
Examples (examples/)
βββ http-server.ts # HTTP REST API server example
βββ hed-validator.html # Browser validation interface
βββ hed-demo.html # Interactive demo and guide
βββ mcp-client.js # MCP protocol client example
βββ ... # Additional examples and utilities
βββ index.ts
- Client request β MCP server
- Schema loading β Cache or load from network
- Data processing β Parse and validate
- Issue formatting β Standardize error/Warning format
- Response β Return to client
The server implements intelligent caching:
- Schema caching: Avoids reloading schemas for repeated operations
- Definition caching: Reuses processed definitions
- Memory management: Automatic cleanup of unused cache entries
The fastest way to test the server is using the MCP Inspector:
npx @modelcontextprotocol/inspector node dist/server.jsThis opens a web interface where you can interact with the server and test all available tools.
Test the server directly:
# Standard MCP server (stdio mode)
npm start
# WebSocket mode
node dist/server.js --websocket --port=8080
# HTTP REST API server
npm run start:httpOr test with the included client:
node test-mcp-client.js- Open the MCP Inspector in your browser
- Initialize the server - this happens automatically
- List available tools to see what's available
- Try a simple validation with
validateHedString
| Tool | Description | Required parameters | Optional parameters |
|---|---|---|---|
validateHedString |
Validates HED tag strings | hedString, hedVersion |
checkForWarnings, definitions |
validateHedTsv |
Validates TSV files with HED | filePath, hedVersion |
checkForWarnings, fileData, jsonData, definitions |
validateHedSidecar |
Validates HED sidecar JSON files | filePath, hedVersion |
checkForWarnings, fileData |
getFileFromPath |
Reads files from filesystem | filePath |
Purpose: Validates individual HED tag strings
When to use:
- Testing specific HED constructs
- Interactive validation during annotation
- Validating programmatically generated HED strings
Parameters:
hedString(required): The HED string to validatehedVersion(required): Schema version (e.g., "8.4.0")checkForWarnings(optional): Include warnings in resultsdefinitions(optional): Array of definition strings
Best practices:
- Use specific schema versions in production
- Enable warnings during development
- Group related definitions together
Purpose: Validates TSV files containing HED annotations
When to use:
- Validating BIDS event files
- Checking TSV files before publication
- Automated dataset validation
Parameters:
filePath(required): Path to TSV filehedVersion(required): Schema versioncheckForWarnings(optional): Include warningsfileData(optional): Inline TSV datajsonData(optional): Sidecar data as JSON stringdefinitions(optional): Definition strings
Best practices:
- Use
fileDatafor small datasets to avoid file I/O - Include sidecar data via
jsonDatafor complete validation - Process files in batches for large datasets
Purpose: Validates HED sidecar JSON files
When to use:
- Validating BIDS sidecar files
- Checking JSON structure and HED content
- Converting between sidecar formats
Parameters:
filePath(required): Path to JSON sidecar filehedVersion(required): Schema versioncheckForWarnings(optional): Include warningsfileData(optional): Inline JSON data
Best practices:
- Validate sidecar files before TSV files
- Use parsed output for debugging sidecar structure
- Check both structure and HED content validity
Purpose: Retrieves files from the local filesystem
When to use:
- Reading configuration files
- Accessing data files for validation
- File system operations
Parameters:
filePath(required): Absolute path to the file
Best practices:
- Use absolute file paths
- Check file permissions and existence
- Handle file encoding properly (UTF-8 recommended)
{
"method": "tools/call",
"params": {
"name": "validateHedString",
"arguments": {
"hedString": "Event/Sensory-event, Red, Blue, (Green, Large)",
"hedVersion": "8.4.0",
"checkForWarnings": true
}
}
}{
"method": "tools/call",
"params": {
"name": "validateHedTsv",
"arguments": {
"filePath": "/tests/data/sub-002_ses-1_task-FacePerception_run-1_events.tsv",
"hedVersion": "8.4.0",
"checkForWarnings": true,
"definitions": [
"(Definition/Fixation, (Sensory-event, Visual-presentation, (Image, Cross))",
"(Definition/ButtonPress, (Press, Mouse-button))"
]
}
}
}{
"method": "tools/call",
"params": {
"name": "validateHedSidecar",
"arguments": {
"filePath": "/tests/data/task-FacePerception_events.json",
"hedVersion": "8.4.0",
"checkForWarnings": false
}
}
}{
"method": "tools/call",
"params": {
"name": "getFileFromPath",
"arguments": {
"filePath": "/path/to/data/events.tsv"
}
}
}- Schema Selection: Choose appropriate HED schema version
- Definition Setup: Prepare any custom definitions
- Data Validation: Run appropriate validation tool
- Issue Resolution: Address errors and warnings
- Quality Assurance: Final validation with warnings enabled
// 1. First validate sidecar files
{
"name": "validateHedSidecar",
"arguments": {
"filePath": "/data/task-rest_events.json",
"hedVersion": "8.4.0",
"checkForWarnings": true
}
}
// 2. Then validate TSV files with sidecar data
{
"name": "validateHedTsv",
"arguments": {
"filePath": "/data/sub-01_task-rest_events.tsv",
"hedVersion": "8.4.0",
"jsonData": "{...sidecar content...}",
"checkForWarnings": true
}
}// Test individual HED strings during annotation
{
"name": "validateHedString",
"arguments": {
"hedString": "Event/Sensory-event, (Red, Large)",
"hedVersion": "8.4.0",
"checkForWarnings": true
}
}// Test definitions before using in datasets
{
"name": "validateHedString",
"arguments": {
"hedString": "Def/MyStimulus, Blue",
"hedVersion": "8.4.0",
"definitions": [
"(Definition/MyStimulus, (Event/Sensory-event, (Onset)))"
],
"checkForWarnings": true
}
}-
TAG_INVALID: Tag not found in schema
- Check spelling and capitalization
- Verify tag exists in specified schema version
- Consider using extension tags if appropriate
-
DEFINITION_INVALID: Malformed definition
- Ensure proper parentheses around definition content
- Check that definition name follows conventions
- Verify definition content is valid HED
-
SCHEMA_LOAD_FAILED: Invalid schema version
- Verify schema version exists
- Check network connectivity for schema download
- Use stable, released schema versions
-
FILE_READ_ERROR: Cannot read specified file
- Verify file path and permissions
- Check file exists and is readable
- Consider using inline data for virtual files
-
TAG_EXTENDED: Extension tag used
- Consider using more specific standard tags
- Acceptable for novel experimental paradigms
- Document extensions for reproducibility
-
DEFINITION_WARNING: Definition issues
- Non-critical definition problems
- May indicate style or convention issues
- Review definition structure and content
- Specificity: Use most specific appropriate tags
- Consistency: Apply same annotation patterns throughout dataset
- Completeness: Annotate all relevant aspects of events
- Accuracy: Ensure annotations match actual experimental events
- All files validate without errors
- Warnings reviewed and addressed where appropriate
- Definitions properly documented
- Schema version appropriate for dataset
- Annotations consistent across similar events
The HED MCP server can be used in browsers through several approaches. All browser files are located in the examples/ directory.
Open examples/hed-validator.html for a full-featured web interface:
- Multiple validation modes: String, TSV, and Sidecar validation
- Modern UI: Clean, responsive design with professional styling
- Real-time feedback: Instant validation results with detailed error reporting
- Multiple HED versions: Support for different schema versions and libraries
# Serve the examples locally
npx serve examples/
# Or open directly in browser
open examples/hed-validator.htmlView examples/hed-demo.html for:
- Live examples: Pre-configured validation scenarios
- Integration guide: Complete API documentation and code examples
- Developer tools: Quick validation form for testing
Include the modern browser client in your web application:
<link rel="stylesheet" href="examples/hed-validator.css">
<script src="examples/hed-validator-client.js"></script>
<script>
// Create validator client (auto-detects server availability)
const validator = new HEDValidatorClient();
// Validate HED string
const result = await validator.validateString('Event/Sensory-event, Red');
// Or create a pre-built validation form
HEDValidatorClient.createValidationForm('my-container');
</script>For complete server-based validation, run the HTTP API server:
npm run build
node dist/examples/http-server.jsThe browser client automatically detects and uses the server at http://localhost:3000/api/hed/.
Quick Start: Open examples/hed-validator.html to immediately start validating HED data in your browser!
<!DOCTYPE html>
<html>
<head>
<title>HED Validator</title>
</head>
<body>
<textarea id="hedInput" placeholder="Enter HED string..."></textarea>
<button onclick="validateHED()">Validate</button>
<div id="results"></div>
<script>
async function validateHED() {
const hedString = document.getElementById('hedInput').value;
try {
const response = await fetch('/api/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
hedString,
hedVersion: '8.4.0',
checkForWarnings: true
})
});
const result = await response.json();
displayResults(result);
} catch (error) {
console.error('Validation failed:', error);
}
}
function displayResults(result) {
const resultsDiv = document.getElementById('results');
if (result.errors.length === 0) {
resultsDiv.innerHTML = '<p style="color: green;">β
Valid HED string!</p>';
} else {
resultsDiv.innerHTML = '<p style="color: red;">β Validation errors:</p>';
result.errors.forEach(error => {
resultsDiv.innerHTML += `<p>β’ ${error.message}</p>`;
});
}
if (result.warnings.length > 0) {
resultsDiv.innerHTML += '<p style="color: orange;">β οΈ Warnings:</p>';
result.warnings.forEach(warning => {
resultsDiv.innerHTML += `<p>β’ ${warning.message}</p>`;
});
}
}
</script>
</body>
</html>Add to your MCP client configuration:
{
"servers": {
"hed-mcp": {
"command": "node",
"args": ["dist/server.js"],
"cwd": "/path/to/hed-mcp-typescript"
}
}
}Run the server in WebSocket mode for browser-based MCP clients:
node dist/server.js --websocket --port=8080The server respects standard Node.js environment variables:
NODE_ENV: Set todevelopmentfor verbose loggingDEBUG: Enable debug output for troubleshooting
Enable debug logging:
DEBUG=* node dist/server.jsOr in MCP client configuration:
{
"servers": {
"hed-mcp": {
"command": "node",
"args": ["dist/server.js"],
"env": {
"DEBUG": "*"
}
}
}
}- Naming: Use descriptive, unique names
- Structure: Keep definitions simple and focused
- Reusability: Design for reuse across similar experiments
- Documentation: Document purpose and usage
// Simple stimulus definition
"(Definition/RedCircle, (Event/Sensory-event, (Red, Circle)))"
// Complex behavioral definition
"(Definition/CorrectResponse, (Action/Move, Agent/Human, (Correct-action, (Voluntary))))"
// Hierarchical definitions
"(Definition/VisualStimulus, (Event/Sensory-event, Property/Sensory-property/Visual))"
"(Definition/RedVisualStimulus, (Def/VisualStimulus, Red))"The server automatically caches loaded schemas to improve performance:
// Schemas are cached by version string
const schema1 = await schemaCache.getOrCreateSchema('8.4.0');
const schema2 = await schemaCache.getOrCreateSchema('8.4.0'); // Uses cacheProcess definitions once and reuse:
// Define once, use multiple times
const definitions = [
"(Definition/Fixation, (Event/Sensory-event, (Onset)))",
"(Definition/Response, (Action/Move, Agent/Human))"
];
// Use in multiple validations
for (const hedString of hedStrings) {
const result = await validate({
hedString,
hedVersion: '8.4.0',
definitions // Reuse same definitions
});
}// Efficient batch processing
const server = new MCPServer();
await server.connect();
try {
const results = await Promise.all(
files.map(file =>
server.call('validateHedTsv', {
filePath: file,
hedVersion: '8.4.0'
})
)
);
} finally {
await server.disconnect();
}- Monitor memory usage with large datasets
- Process files in batches if memory constrained
- Clear unused schema cache entries
- Use streaming for very large files
- Reuse server connections for multiple operations
- Cache schemas and definitions between operations
- Use inline data to avoid file I/O overhead
- Disable warnings for production validation
import { MCPClient } from '@modelcontextprotocol/client';
const client = new MCPClient({
server: {
command: 'node',
args: ['dist/server.js'],
cwd: '/path/to/hed-mcp-typescript'
}
});
await client.connect();async function safeValidation(hedString, hedVersion) {
try {
const response = await client.call('tools/call', {
name: 'validateHedString',
arguments: { hedString, hedVersion }
});
const result = JSON.parse(response.content[0].text);
return {
success: result.errors.length === 0,
errors: result.errors,
warnings: result.warnings
};
} catch (error) {
return {
success: false,
errors: [{
code: 'CLIENT_ERROR',
message: error.message,
severity: 'error'
}],
warnings: []
};
}
}import asyncio
import json
from mcp_client import MCPClient
class HEDValidator:
def __init__(self, server_path):
self.client = MCPClient(server_path)
async def __aenter__(self):
await self.client.connect()
return self
async def __aexit__(self, exc_type, exc_val, exc_tb):
await self.client.disconnect()
async def validate_string(self, hed_string, hed_version="8.4.0", check_warnings=True):
"""Validate a HED string."""
response = await self.client.call('tools/call', {
'name': 'validateHedString',
'arguments': {
'hedString': hed_string,
'hedVersion': hed_version,
'checkForWarnings': check_warnings
}
})
return json.loads(response['content'][0]['text'])
async def validate_file(self, file_path, hed_version="8.4.0", definitions=None):
"""Validate a TSV file."""
args = {
'filePath': file_path,
'hedVersion': hed_version,
'checkForWarnings': True
}
if definitions:
args['definitions'] = definitions
response = await self.client.call('tools/call', {
'name': 'validateHedTsv',
'arguments': args
})
return json.loads(response['content'][0]['text'])
# Usage example
async def main():
async with HEDValidator('/path/to/hed-mcp-typescript/dist/server.js') as validator:
# Validate a HED string
result = await validator.validate_string(
"Event/Sensory-event, Red, Blue",
hed_version="8.4.0"
)
if result['errors']:
print("Validation errors found:")
for error in result['errors']:
print(f" - {error['message']}")
else:
print("HED string is valid!")
if __name__ == "__main__":
asyncio.run(main())#!/bin/bash
# validate-dataset.sh - Validate all HED files in a BIDS dataset
DATASET_DIR="$1"
HED_VERSION="8.4.0"
echo "Validating BIDS dataset: $DATASET_DIR"
# Validate sidecar files
find "$DATASET_DIR" -name "*_events.json" | while read file; do
echo "Validating sidecar: $file"
# Call validateHedSidecar via MCP client
validate_sidecar "$file" "$HED_VERSION"
done
# Validate TSV files
find "$DATASET_DIR" -name "*_events.tsv" | while read file; do
echo "Validating TSV: $file"
# Call validateHedTsv via MCP client
validate_tsv "$file" "$HED_VERSION"
done
echo "Dataset validation complete!"src/
βββ server.ts # Main MCP server (stdio/WebSocket)
βββ tools/ # MCP tools (validation functions)
β βββ validateHedString.ts
β βββ validateHedTsv.ts
β βββ validateHedSidecar.ts
β βββ getFileFromPath.ts
βββ resources/ # MCP resources (schema info)
β βββ hedSchema.ts
βββ utils/ # Utility functions
β βββ mcpToZod.ts
β βββ definitionProcessor.ts
β βββ fileReader.ts
β βββ issueFormatter.ts
β βββ schemaCache.ts
βββ types/ # TypeScript type definitions
βββ index.ts
npm run build # Build the TypeScript project
npm run dev # Build in watch mode
npm run test # Run the test suite
npm run test:watch # Run tests in watch mode
npm run test:coverage # Generate test coverage report
npm run clean # Clean build artifacts
npm start # Run stdio MCP server
npm run start:http # Run HTTP API server-
Clone and install:
git clone <repository-url> cd hed-mcp-typescript npm install
-
Start development:
npm run dev # Builds in watch mode -
Test your changes:
npm test -
Test with inspector:
npx @modelcontextprotocol/inspector node dist/server.js
Symptoms: Server exits immediately or shows connection errors
Solutions:
- Check Node.js version (requires 18+)
- Verify build completed successfully:
npm run build - Check for port conflicts
- Review error messages in console
Symptoms: SCHEMA_LOAD_FAILED errors
Solutions:
- Verify internet connectivity for schema downloads
- Use exact schema version strings
- Check schema cache directory permissions
- Try clearing cache: delete node_modules and reinstall
Symptoms: FILE_READ_ERROR when accessing files
Solutions:
- Verify file paths are absolute
- Check file permissions and existence
- Use inline data (
fileData) for testing - Ensure proper file encoding (UTF-8)
Symptoms: Different results from same input
Solutions:
- Ensure consistent schema versions
- Clear schema cache if needed
- Check for concurrent validation conflicts
- Verify definition ordering and consistency
- Monitor memory usage with large datasets
- Process files in batches if memory constrained
- Clear unused schema cache entries
- Use streaming for very large files
- Reuse server connections for multiple operations
- Cache schemas and definitions between operations
- Use inline data to avoid file I/O overhead
- Disable warnings for production validation
For detailed API documentation, see API.md.
Key concepts:
- FormattedIssue: Standardized error/warning format
- HedValidationResult: Standard validation response format
- Schema Caching: Automatic caching of loaded HED schemas
- Definition Support: Process and use HED definitions during validation
The project includes comprehensive tests covering:
- Unit tests: Individual function testing
- Integration tests: Tool interaction testing
- Data validation: Real HED data file testing
# Run all tests
npm test
# Run with coverage
npm run test:coverage
# Run in watch mode during development
npm run test:watch
# Run only integration tests
npm test -- --testPathPattern=integrationTest files are located in tests/data/:
sub-002_ses-1_task-FacePerception_run-1_events.tsvtask-FacePerception_events.jsonparticipants_bad.jsonparticipants_bad.tsv
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and add tests
- Run the test suite:
npm test - Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
- Use TypeScript strict mode
- Follow existing naming conventions
- Add JSDoc comments for public APIs
- Ensure all tests pass before submitting
This project is licensed under the ISC License - see the LICENSE file for details.