Skip to main content
Glama
component.ops.ts7.72 kB
import { KuzuDBClient } from '../../db/kuzu'; import { ToolHandlerContext } from '../../mcp/types/sdk-custom'; import { ComponentRepository, RepositoryRepository } from '../../repositories'; import { Component, ComponentInput } from '../../types'; // Helper function to parse timestamps from BaseEntity (Date | undefined) to string | null function parseBaseEntityTimestamp(timestamp: Date | undefined): string | null { if (timestamp instanceof Date) { return timestamp.toISOString(); } return null; } /** * Creates or updates a component in a repository. * * @param mcpContext - The MCP server request context. * @param repositoryName - The name of the repository. * @param branch - The branch of the repository. * @param componentData - Data for the component to be upserted. * @param repositoryRepo - Instance of RepositoryRepository. * @param componentRepo - Instance of ComponentRepository. * @returns A Promise resolving to the upserted Component object or null if repository not found. */ export async function upsertComponentOp( mcpContext: ToolHandlerContext, repositoryName: string, branch: string, componentData: ComponentInput, repositoryRepo: RepositoryRepository, componentRepo: ComponentRepository, ): Promise<Component | null> { const logger = mcpContext.logger; const repository = await repositoryRepo.findByName(repositoryName, branch); if (!repository || !repository.id) { logger.warn( `[component.ops.upsertComponentOp] Repository not found: ${repositoryName}/${branch}`, ); return null; } const inputForRepo: ComponentInput = { id: componentData.id, name: componentData.name, kind: componentData.kind, status: componentData.status || 'active', depends_on: componentData.depends_on || componentData.dependsOn || undefined, branch: branch, }; logger.debug( `[component.ops.upsertComponentOp] Calling componentRepo.upsertComponent for ${inputForRepo.id} in repo ${repository.id}`, { inputForRepo }, ); const upsertedComponent = await componentRepo.upsertComponent(repository.id, inputForRepo); if (!upsertedComponent) { logger.warn( `[component.ops.upsertComponentOp] componentRepo.upsertComponent returned null for ${componentData.id} in ${repositoryName}:${branch}`, ); return null; } logger.info( `[component.ops.upsertComponentOp] Component ${upsertedComponent.id} upserted successfully in ${repositoryName}:${branch}.`, ); return normalizeComponent(upsertedComponent, repositoryName, branch); } /** * Retrieves all upstream dependencies for a component. * * @param mcpContext - The MCP server request context. * @param repositoryName - The name of the repository. * @param branch - The branch of the repository. * @param componentId - The ID (yaml_id) of the component. * @param repositoryRepo - Instance of RepositoryRepository. * @param componentRepo - Instance of ComponentRepository. * @returns A Promise resolving to an array of dependent Component objects. */ export async function getComponentDependenciesOp( mcpContext: ToolHandlerContext, repositoryName: string, branch: string, componentId: string, repositoryRepo: RepositoryRepository, componentRepo: ComponentRepository, ): Promise<Component[]> { const logger = mcpContext.logger; logger.debug( `[component.ops.getComponentDependenciesOp] For component ${componentId} in ${repositoryName}:${branch}`, ); const dependencies = await componentRepo.getComponentDependencies( repositoryName, componentId, branch, ); logger.debug( `[component.ops.getComponentDependenciesOp] Found ${dependencies.length} dependencies for ${componentId}.`, ); return dependencies.map((comp) => normalizeComponent(comp, repositoryName, branch)); } /** * Retrieves all downstream dependents of a component. * * @param mcpContext - The MCP server request context. * @param repositoryName - The name of the repository. * @param branch - The branch of the repository. * @param componentId - The ID (yaml_id) of the component. * @param repositoryRepo - Instance of RepositoryRepository. * @param componentRepo - Instance of ComponentRepository. * @returns A Promise resolving to an array of dependent Component objects. */ export async function getComponentDependentsOp( mcpContext: ToolHandlerContext, repositoryName: string, branch: string, componentId: string, repositoryRepo: RepositoryRepository, componentRepo: ComponentRepository, ): Promise<Component[]> { const logger = mcpContext.logger; logger.debug( `[component.ops.getComponentDependentsOp] For component ${componentId} in ${repositoryName}:${branch}`, ); const dependents = await componentRepo.getComponentDependents( repositoryName, componentId, branch, ); logger.debug( `[component.ops.getComponentDependentsOp] Found ${dependents.length} dependents for ${componentId}.`, ); return dependents.map((comp) => normalizeComponent(comp, repositoryName, branch)); } /** * Retrieves all active components for a repository and branch. * * @param mcpContext - The MCP server request context. * @param repositoryName - The name of the repository. * @param branch - The branch of the repository. * @param repositoryRepo - Instance of RepositoryRepository. * @param componentRepo - Instance of ComponentRepository. * @returns A Promise resolving to an array of active Component objects. */ export async function getActiveComponentsOp( mcpContext: ToolHandlerContext, repositoryName: string, branch: string, repositoryRepo: RepositoryRepository, componentRepo: ComponentRepository, ): Promise<Component[]> { const logger = mcpContext.logger; logger.debug(`[component.ops.getActiveComponentsOp] For ${repositoryName}:${branch}`); const repository = await repositoryRepo.findByName(repositoryName, branch); if (!repository || !repository.id) { logger.warn( `[component.ops.getActiveComponentsOp] Repository not found: ${repositoryName}/${branch}`, ); return []; } const activeComponents = await componentRepo.getActiveComponents(repository.id, branch); logger.debug( `[component.ops.getActiveComponentsOp] Found ${activeComponents.length} active components for ${repositoryName}:${branch}.`, ); return activeComponents.map((comp) => normalizeComponent(comp, repositoryName, branch)); } /** * Helper function to ensure component has repository and branch fields populated */ function normalizeComponent( component: Component, repositoryName: string, branch: string, ): Component { return { ...component, repository: repositoryName, branch: branch, }; } export async function deleteComponentOp( mcpContext: ToolHandlerContext, kuzuClient: KuzuDBClient, repositoryRepo: RepositoryRepository, repositoryName: string, branch: string, componentId: string, ): Promise<boolean> { const logger = mcpContext.logger; const repository = await repositoryRepo.findByName(repositoryName, branch); if (!repository || !repository.id) { logger.warn( `[component.ops.deleteComponentOp] Repository ${repositoryName}:${branch} not found.`, ); return false; } const graphUniqueId = `${repositoryName}:${branch}:${componentId}`; const deleteQuery = ` MATCH (c:Component {graph_unique_id: $graphUniqueId}) DETACH DELETE c RETURN 1 as deletedCount `; const result = await kuzuClient.executeQuery(deleteQuery, { graphUniqueId }); const deletedCount = result[0]?.deletedCount || 0; logger.info( `[component.ops.deleteComponentOp] Deleted ${deletedCount} component(s) with ID ${componentId}`, ); return deletedCount > 0; }

Latest Blog Posts

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/Jakedismo/KuzuMem-MCP'

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