Documentation Index
Fetch the complete documentation index at: https://docs.tryheimdall.com/llms.txt
Use this file to discover all available pages before exploring further.
Installation
Install the Heimdall JavaScript SDK from npm:
Or with yarn:
Basic Usage
Initialize the Client
import { HeimdallClient, traceMCPTool } from 'hmdl';
// Initialize with explicit configuration
const client = new HeimdallClient({
endpoint: "http://localhost:4318",
orgId: "your-org-id",
projectId: "your-project-id",
serviceName: "my-mcp-server",
environment: "development"
});
You can also configure the client using environment variables and initialize without arguments:const client = new HeimdallClient();
Use traceMCPTool to wrap your MCP tool functions:
const searchDocuments = traceMCPTool(
async (query: string, limit: number = 10) => {
const results = await performSearch(query, limit);
return {
results,
query,
total: results.length
};
},
{
name: "search-documents",
paramNames: ["query", "limit"]
}
);
// Call your tool normally
const result = await searchDocuments("machine learning", 5);
Important: Unlike Python, JavaScript cannot introspect parameter names at runtime. Use the paramNames option to display inputs as named objects:
- With
paramNames: {"query": "machine learning", "limit": 5}
- Without
paramNames: ["machine learning", 5]
Flush Traces
Always flush traces before your application exits:
// At the end of your application
await client.flush();
Configuration Options
The traceMCPTool function accepts the following options:
const myTool = traceMCPTool(
async (arg1: string, arg2: number) => {
return { result: "data" };
},
{
name: "my-tool", // Custom span name (required)
paramNames: ["arg1", "arg2"], // Parameter names for display
captureInput: true, // Capture input arguments (default: true)
captureOutput: true // Capture return value (default: true)
}
);
General Tracing with observe
For non-MCP functions or when you need more control:
import { observe } from 'hmdl';
const fetchUser = observe(
async (userId: string) => {
// Fetch user from database
return { id: userId, name: "John" };
},
{ name: "fetch-user-data" }
);
const processPayment = observe(
async (cardNumber: string, amount: number) => {
// Process payment
return true;
},
{
name: "process-payment",
captureOutput: false // Don't capture sensitive output
}
);
Error Handling
Errors are automatically captured and the span is marked as failed:
const riskyOperation = traceMCPTool(
async (data: string) => {
if (!data) {
throw new Error("Data cannot be empty");
}
return { processed: data };
},
{ name: "risky-operation", paramNames: ["data"] }
);
try {
await riskyOperation("");
} catch (error) {
// Error is captured in the trace
}
await client.flush(); // Don't forget to flush!
Complete Example
Here’s a complete example of an MCP server instrumented with Heimdall:
import { HeimdallClient, traceMCPTool, observe } from 'hmdl';
// Configure via environment variables
process.env.HEIMDALL_ENDPOINT = "http://localhost:4318";
process.env.HEIMDALL_ORG_ID = "my-org";
process.env.HEIMDALL_PROJECT_ID = "my-project";
// Initialize client
const client = new HeimdallClient({
serviceName: "document-mcp-server",
environment: "production"
});
// Your MCP tools
const searchDocuments = traceMCPTool(
async (query: string, limit: number = 10) => {
const results = await db.search(query, limit);
return { results, count: results.length };
},
{ name: "search-documents", paramNames: ["query", "limit"] }
);
const getDocument = traceMCPTool(
async (docId: string) => {
const doc = await db.get(docId);
if (!doc) {
throw new Error(`Document ${docId} not found`);
}
return doc;
},
{ name: "get-document", paramNames: ["docId"] }
);
const createDocument = traceMCPTool(
async (title: string, content: string) => {
const doc = await db.create({ title, content });
return { id: doc.id, created: true };
},
{ name: "create-document", paramNames: ["title", "content"] }
);
// Internal helper with tracing
const validateQuery = observe(
(query: string): boolean => {
return query.length >= 3;
},
{ name: "validate-query" }
);
// Main execution
async function main() {
try {
// Run your MCP server logic
const result = await searchDocuments("test query", 5);
console.log(result);
} finally {
// Always flush before exit
await client.flush();
}
}
main();
TypeScript Support
The SDK is written in TypeScript and provides full type definitions. Your traced functions maintain their original type signatures:
// Type inference works correctly
const search = traceMCPTool(
async (query: string, limit: number): Promise<SearchResult> => {
// ...
},
{ name: "search", paramNames: ["query", "limit"] }
);
// search is typed as: (query: string, limit: number) => Promise<SearchResult>
Next Steps
Environment Variables
Configure Heimdall using environment variables.
SDK Options
Explore all available configuration options.