Skip to main content
Glama

Worksona MCP Server

Official
by worksona
registry.ts•8.56 kB
import { glob } from 'glob'; import * as fs from 'fs-extra'; import * as path from 'path'; import { WorksonaAgent, AgentSuggestion, AgentStats } from './types'; export class AgentRegistry { private agents = new Map<string, WorksonaAgent>(); private categories = new Map<string, string[]>(); private loadingPromise: Promise<void> | null = null; constructor(private worksonaAgentsPath: string) { // Validate path exists if (!fs.existsSync(worksonaAgentsPath)) { throw new Error(`Worksona agents path does not exist: ${worksonaAgentsPath}`); } } async loadAllAgents(): Promise<void> { if (this.loadingPromise) { return this.loadingPromise; } this.loadingPromise = this.performLoad(); return this.loadingPromise; } private async performLoad(): Promise<void> { console.error('šŸ” Discovering Worksona agents...'); try { // Find all metadata.json files const metadataFiles = await glob('**/metadata.json', { cwd: this.worksonaAgentsPath, absolute: true, ignore: ['**/node_modules/**', '**/dist/**', '**/.git/**'] }); console.error(`šŸ“ Found ${metadataFiles.length} agent definitions`); let loadedCount = 0; for (const metadataPath of metadataFiles) { try { await this.loadAgent(metadataPath); loadedCount++; } catch (error) { console.error(`āš ļø Failed to load agent from ${metadataPath}:`, error); } } console.error(`āœ… Loaded ${loadedCount} agents across ${this.categories.size} categories`); this.printAgentSummary(); } catch (error) { console.error('āŒ Failed to load agents:', error); throw error; } } private async loadAgent(metadataPath: string): Promise<void> { const metadata = await fs.readJSON(metadataPath); const agentDir = path.dirname(metadataPath); const agentMdPath = path.join(agentDir, 'agent.md'); // Load agent prompt content let prompt = ''; if (await fs.pathExists(agentMdPath)) { prompt = await fs.readFile(agentMdPath, 'utf-8'); } // Normalize metadata structure - handle both array and object formats let capabilities; if (Array.isArray(metadata.capabilities)) { capabilities = { primary: metadata.capabilities, secondary: [] }; } else if (metadata.capabilities && typeof metadata.capabilities === 'object') { capabilities = { primary: metadata.capabilities.primary || [], secondary: metadata.capabilities.secondary || [], frameworks: metadata.capabilities.frameworks }; } else { capabilities = { primary: [], secondary: [] }; } // Create agent definition const agent: WorksonaAgent = { name: metadata.name, version: metadata.version || '1.0.0', description: metadata.description || 'No description available', category: this.extractCategory(agentDir), subcategory: metadata.subcategory, capabilities, requirements: metadata.requirements || { tools: [] }, coordination: metadata.coordination, prompt, examples: metadata.examples, triggers: metadata.triggers, quality: metadata.quality }; // Register agent this.agents.set(agent.name, agent); // Update category index if (!this.categories.has(agent.category)) { this.categories.set(agent.category, []); } this.categories.get(agent.category)!.push(agent.name); } private extractCategory(agentPath: string): string { // Extract category from path: /path/to/agents/software-engineering/frontend-developer const parts = agentPath.split(path.sep); const agentsIndex = parts.findIndex(part => part === 'agents'); return parts[agentsIndex + 1] || 'uncategorized'; } getAgent(name: string): WorksonaAgent | undefined { return this.agents.get(name); } getAllAgents(): WorksonaAgent[] { return Array.from(this.agents.values()); } getAgentsByCategory(category: string): WorksonaAgent[] { const agentNames = this.categories.get(category) || []; return agentNames.map(name => this.agents.get(name)!).filter(Boolean); } getCategories(): string[] { return Array.from(this.categories.keys()); } findAgentsByCapability(capability: string): WorksonaAgent[] { return this.getAllAgents().filter(agent => agent.capabilities.primary.includes(capability) || agent.capabilities.secondary?.includes(capability) ); } suggestAgentsForRequest(request: string, maxSuggestions = 5): AgentSuggestion[] { const requestWords = request.toLowerCase().split(/\\s+/); const suggestions: AgentSuggestion[] = []; for (const agent of this.getAllAgents()) { let score = 0; let reasons: string[] = []; // Check trigger keywords if (agent.triggers?.keywords) { for (const keyword of agent.triggers.keywords) { if (requestWords.some(word => word.includes(keyword.toLowerCase()) || keyword.toLowerCase().includes(word))) { score += 15; reasons.push(`matches keyword "${keyword}"`); } } } // Check trigger patterns if (agent.triggers?.patterns) { for (const pattern of agent.triggers.patterns) { const regex = new RegExp(pattern.replace('*', '.*'), 'i'); if (regex.test(request)) { score += 20; reasons.push(`matches pattern "${pattern}"`); } } } // Check description and capability words const agentText = (agent.description + ' ' + agent.capabilities.primary.join(' ') + ' ' + (agent.capabilities.secondary?.join(' ') || '')).toLowerCase(); const agentWords = agentText.split(/\\s+/); let wordMatches = 0; for (const word of requestWords) { if (word.length > 3 && agentWords.some(agentWord => agentWord.includes(word) || word.includes(agentWord))) { wordMatches++; } } if (wordMatches > 0) { score += wordMatches * 3; reasons.push(`${wordMatches} word match(es)`); } // Enterprise grade agents get slight boost if (agent.quality?.enterpriseGrade) { score += 2; } if (score > 5) { suggestions.push({ agent, score, reason: reasons.join(', ') }); } } return suggestions .sort((a, b) => b.score - a.score) .slice(0, maxSuggestions); } getAgentStats(): AgentStats { const categoryCounts: Record<string, number> = {}; const capabilityCounts: Record<string, number> = {}; for (const [category, agents] of this.categories.entries()) { categoryCounts[category] = agents.length; } for (const agent of this.getAllAgents()) { // Safely iterate over capabilities if (agent.capabilities.primary && Array.isArray(agent.capabilities.primary)) { for (const capability of agent.capabilities.primary) { capabilityCounts[capability] = (capabilityCounts[capability] || 0) + 1; } } if (agent.capabilities.secondary && Array.isArray(agent.capabilities.secondary)) { for (const capability of agent.capabilities.secondary) { capabilityCounts[capability] = (capabilityCounts[capability] || 0) + 1; } } } return { totalAgents: this.agents.size, categoryCounts, capabilityCounts }; } // Find agents that work well together findCoordinatingAgents(primaryAgent: string): WorksonaAgent[] { const agent = this.getAgent(primaryAgent); if (!agent?.coordination?.worksWellWith) { return []; } return agent.coordination.worksWellWith .map(name => this.getAgent(name)) .filter(Boolean) as WorksonaAgent[]; } private printAgentSummary(): void { console.error('\\nšŸ“Š Agent Registry Summary:'); for (const [category, agents] of this.categories.entries()) { console.error(` ${category}: ${agents.length} agents`); } } // Validation method validateAgent(agent: WorksonaAgent): string[] { const errors: string[] = []; if (!agent.name) errors.push('Agent name is required'); if (!agent.description) errors.push('Agent description is required'); if (!agent.capabilities.primary.length) errors.push('At least one primary capability is required'); if (!agent.prompt) errors.push('Agent prompt is required'); return errors; } }

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/worksona/-worksona-mcp-server'

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