Skip to main content
Glama

HomeAssistant MCP

index.ts6.37 kB
import { EventEmitter } from "events"; // Resource types export enum ResourceType { DEVICE = "device", AREA = "area", USER = "user", AUTOMATION = "automation", SCENE = "scene", SCRIPT = "script", GROUP = "group", } // Resource state interface export interface ResourceState { id: string; type: ResourceType; state: any; attributes: Record<string, any>; lastUpdated: number; context?: Record<string, any>; } // Resource relationship types export enum RelationType { CONTAINS = "contains", CONTROLS = "controls", TRIGGERS = "triggers", DEPENDS_ON = "depends_on", GROUPS = "groups", } // Resource relationship interface export interface ResourceRelationship { sourceId: string; targetId: string; type: RelationType; metadata?: Record<string, any>; } // Context manager class export class ContextManager extends EventEmitter { private resources: Map<string, ResourceState> = new Map(); private relationships: ResourceRelationship[] = []; private stateHistory: Map<string, ResourceState[]> = new Map(); private historyLimit = 100; constructor() { super(); } // Resource management public addResource(resource: ResourceState): void { this.resources.set(resource.id, resource); this.emit("resource_added", resource); } public updateResource(id: string, update: Partial<ResourceState>): void { const resource = this.resources.get(id); if (resource) { // Store current state in history this.addToHistory(resource); // Update resource const updatedResource = { ...resource, ...update, lastUpdated: Date.now(), }; this.resources.set(id, updatedResource); this.emit("resource_updated", updatedResource); } } public removeResource(id: string): void { const resource = this.resources.get(id); if (resource) { this.resources.delete(id); // Remove related relationships this.relationships = this.relationships.filter( (rel) => rel.sourceId !== id && rel.targetId !== id, ); this.emit("resource_removed", resource); } } // Relationship management public addRelationship(relationship: ResourceRelationship): void { this.relationships.push(relationship); this.emit("relationship_added", relationship); } public removeRelationship( sourceId: string, targetId: string, type: RelationType, ): void { const index = this.relationships.findIndex( (rel) => rel.sourceId === sourceId && rel.targetId === targetId && rel.type === type, ); if (index !== -1) { const removed = this.relationships.splice(index, 1)[0]; this.emit("relationship_removed", removed); } } // History management private addToHistory(state: ResourceState): void { const history = this.stateHistory.get(state.id) || []; history.push({ ...state }); if (history.length > this.historyLimit) { history.shift(); } this.stateHistory.set(state.id, history); } public getHistory(id: string): ResourceState[] { return this.stateHistory.get(id) || []; } // Context queries public getResource(id: string): ResourceState | undefined { return this.resources.get(id); } public getResourcesByType(type: ResourceType): ResourceState[] { return Array.from(this.resources.values()).filter( (resource) => resource.type === type, ); } public getRelatedResources( id: string, type?: RelationType, depth: number = 1, ): ResourceState[] { const related = new Set<ResourceState>(); const visited = new Set<string>(); const traverse = (currentId: string, currentDepth: number) => { if (currentDepth > depth || visited.has(currentId)) return; visited.add(currentId); this.relationships .filter( (rel) => (rel.sourceId === currentId || rel.targetId === currentId) && (!type || rel.type === type), ) .forEach((rel) => { const relatedId = rel.sourceId === currentId ? rel.targetId : rel.sourceId; const relatedResource = this.resources.get(relatedId); if (relatedResource) { related.add(relatedResource); traverse(relatedId, currentDepth + 1); } }); }; traverse(id, 0); return Array.from(related); } // Context analysis public analyzeResourceUsage(id: string): { dependencies: string[]; dependents: string[]; groups: string[]; usage: { triggerCount: number; controlCount: number; groupCount: number; }; } { const dependencies = this.relationships .filter( (rel) => rel.sourceId === id && rel.type === RelationType.DEPENDS_ON, ) .map((rel) => rel.targetId); const dependents = this.relationships .filter( (rel) => rel.targetId === id && rel.type === RelationType.DEPENDS_ON, ) .map((rel) => rel.sourceId); const groups = this.relationships .filter((rel) => rel.targetId === id && rel.type === RelationType.GROUPS) .map((rel) => rel.sourceId); const usage = { triggerCount: this.relationships.filter( (rel) => rel.sourceId === id && rel.type === RelationType.TRIGGERS, ).length, controlCount: this.relationships.filter( (rel) => rel.sourceId === id && rel.type === RelationType.CONTROLS, ).length, groupCount: groups.length, }; return { dependencies, dependents, groups, usage }; } // Event subscriptions public subscribeToResource( id: string, callback: (state: ResourceState) => void, ): () => void { const handler = (resource: ResourceState) => { if (resource.id === id) { callback(resource); } }; this.on("resource_updated", handler); return () => this.off("resource_updated", handler); } public subscribeToType( type: ResourceType, callback: (state: ResourceState) => void, ): () => void { const handler = (resource: ResourceState) => { if (resource.type === type) { callback(resource); } }; this.on("resource_updated", handler); return () => this.off("resource_updated", handler); } } // Export context manager instance export const contextManager = new ContextManager();

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jango-blockchained/advanced-homeassistant-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server