Skip to main content
Glama

Targetprocess MCP Server

operation-registry.ts9.76 kB
import { SemanticOperation, FeatureModule, OperationRegistry as IOperationRegistry, ExecutionContext } from './interfaces/semantic-operation.interface.js'; /** * Central registry for managing semantic operations and feature modules. * Provides discovery, filtering, and lifecycle management for operations. */ export class OperationRegistry implements IOperationRegistry { private operations = new Map<string, SemanticOperation>(); private features = new Map<string, FeatureModule>(); private personalityFilters = new Map<string, Set<string>>(); constructor() { this.setupDefaultPersonalities(); } /** * Register a standalone operation */ register(operation: SemanticOperation): void { if (this.operations.has(operation.metadata.id)) { throw new Error(`Operation ${operation.metadata.id} is already registered`); } this.operations.set(operation.metadata.id, operation); this.updatePersonalityFilters(operation); } /** * Register a feature module (multiple related operations) */ registerFeature(feature: FeatureModule): void { if (this.features.has(feature.metadata.id)) { throw new Error(`Feature ${feature.metadata.id} is already registered`); } this.features.set(feature.metadata.id, feature); // Register all operations from the feature Object.entries(feature.operations).forEach(([operationId, operation]) => { this.operations.set(operationId, operation); this.updatePersonalityFilters(operation); }); } /** * Get an operation by ID */ getOperation(id: string): SemanticOperation | undefined { return this.operations.get(id); } /** * Get all operations available for a specific personality */ getOperationsForPersonality(personality: string): SemanticOperation[] { const allowedOperations = this.personalityFilters.get(personality) || new Set(); return Array.from(this.operations.values()).filter(operation => operation.metadata.requiredPersonalities.includes(personality) || operation.metadata.requiredPersonalities.includes('all') || allowedOperations.has(operation.metadata.id) ); } /** * Find operation by natural language intent analysis */ findOperationByIntent(query: string, context: ExecutionContext): SemanticOperation | undefined { const normalizedQuery = query.toLowerCase(); const availableOps = this.getOperationsForPersonality(context.personality.mode); // Score operations based on query matching const scoredOps = availableOps.map(op => ({ operation: op, score: this.calculateIntentScore(op, normalizedQuery, context) })).filter(({ score }) => score > 0); // Sort by score and return best match scoredOps.sort((a, b) => b.score - a.score); return scoredOps[0]?.operation; } /** * Get all registered operations */ getAllOperations(): SemanticOperation[] { return Array.from(this.operations.values()); } /** * Get all registered features */ getAllFeatures(): FeatureModule[] { return Array.from(this.features.values()); } /** * Initialize a feature (if it has initialization logic) */ async initializeFeature(featureId: string, context: ExecutionContext): Promise<void> { const feature = this.features.get(featureId); if (feature?.initialize) { await feature.initialize(context); } } /** * Cleanup a feature when unloading */ async cleanupFeature(featureId: string): Promise<void> { const feature = this.features.get(featureId); if (feature?.cleanup) { await feature.cleanup(); } } /** * Get operations by category */ getOperationsByCategory(category: string): SemanticOperation[] { return Array.from(this.operations.values()).filter( op => op.metadata.category === category ); } /** * Search operations by tags */ searchOperationsByTags(tags: string[]): SemanticOperation[] { return Array.from(this.operations.values()).filter(op => op.metadata.tags?.some(tag => tags.includes(tag)) ); } /** * Validate that an operation can execute in the current context */ canExecuteOperation(operationId: string, context: ExecutionContext): boolean { const operation = this.getOperation(operationId); if (!operation) return false; // Check personality restrictions if (!this.getOperationsForPersonality(context.personality.mode).includes(operation)) { return false; } // Check operation-specific validation return operation.canExecute ? operation.canExecute(context) : true; } /** * Get operation suggestions based on current context and conversation state */ getSuggestedOperations(context: ExecutionContext, limit: number = 5): SemanticOperation[] { const availableOps = this.getOperationsForPersonality(context.personality.mode); // Score operations based on context relevance const scoredOps = availableOps.map(op => ({ operation: op, score: this.calculateContextRelevance(op, context) })); // Sort by relevance and return top suggestions scoredOps.sort((a, b) => b.score - a.score); return scoredOps.slice(0, limit).map(({ operation }) => operation); } private setupDefaultPersonalities(): void { // Developer personality - focused on task management and technical workflows this.personalityFilters.set('developer', new Set([ 'show-my-tasks', 'start-working-on', 'update-progress', 'complete-task', 'log-time', 'resolve-blocker', 'show-impediments' ])); // Product Manager personality - focused on planning and backlog management this.personalityFilters.set('product-manager', new Set([ 'manage-backlog', 'prioritize-features', 'plan-iteration', 'show-team-capacity', 'track-release-progress', 'review-feedback' ])); // Project Manager personality - focused on coordination and reporting this.personalityFilters.set('project-manager', new Set([ 'show-team-tasks', 'track-project-health', 'generate-status-report', 'identify-risks', 'manage-dependencies' ])); // QA/Tester personality - focused on testing workflows this.personalityFilters.set('tester', new Set([ 'show-test-assignments', 'create-test-run', 'log-defect', 'update-test-results', 'review-test-coverage' ])); // Administrator personality - has access to all operations this.personalityFilters.set('administrator', new Set()); // Default personality - basic operations for general users this.personalityFilters.set('default', new Set([ 'search-work-items' // Semantic operation for searching ])); } private updatePersonalityFilters(operation: SemanticOperation): void { // Add operation to appropriate personality filters operation.metadata.requiredPersonalities.forEach(personality => { if (personality !== 'all') { const filterSet = this.personalityFilters.get(personality) || new Set(); filterSet.add(operation.metadata.id); this.personalityFilters.set(personality, filterSet); } }); } private calculateIntentScore( operation: SemanticOperation, query: string, context: ExecutionContext ): number { let score = 0; // Match against operation name (high weight) if (operation.metadata.name.toLowerCase().includes(query)) { score += 10; } // Match against operation description if (operation.metadata.description.toLowerCase().includes(query)) { score += 5; } // Match against examples (very high weight) const exampleMatches = operation.metadata.examples.filter(example => example.toLowerCase().includes(query) || query.includes(example.toLowerCase()) ); score += exampleMatches.length * 15; // Match against tags if (operation.metadata.tags?.some(tag => query.includes(tag.toLowerCase()))) { score += 3; } // Context-specific scoring score += this.calculateContextRelevance(operation, context) * 2; return score; } private calculateContextRelevance( operation: SemanticOperation, context: ExecutionContext ): number { let relevance = 0; // Boost operations relevant to current workspace state if (context.workspace.currentProject) { if (operation.metadata.category === 'project-workflow') relevance += 3; } if (context.workspace.currentIteration) { if (operation.metadata.category === 'iteration-workflow') relevance += 3; } // Boost operations based on recent conversation context if (context.conversation.previousOperations.length > 0) { const lastOperation = context.conversation.previousOperations[context.conversation.previousOperations.length - 1]; // Suggest logical next steps if (lastOperation === 'show-my-tasks' && operation.metadata.id === 'start-working-on') { relevance += 5; } if (lastOperation === 'start-working-on' && operation.metadata.id === 'update-progress') { relevance += 5; } } // Boost operations matching mentioned entities if (context.conversation.mentionedEntities.length > 0) { const entityTypes = context.conversation.mentionedEntities.map(e => e.type.toLowerCase()); if (entityTypes.includes('task') && operation.metadata.category === 'task-workflow') { relevance += 4; } if (entityTypes.includes('bug') && operation.metadata.category === 'bug-workflow') { relevance += 4; } } return relevance; } } export const operationRegistry = new OperationRegistry();

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/aaronsb/apptio-target-process-mcp'

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