Skip to main content
Glama

XcodeBuildMCP

plugin-registry.ts3.38 kB
import type { PluginMeta, WorkflowGroup, WorkflowMeta } from './plugin-types.ts'; import { WORKFLOW_LOADERS, WorkflowName, WORKFLOW_METADATA } from './generated-plugins.ts'; export async function loadPlugins(): Promise<Map<string, PluginMeta>> { const plugins = new Map<string, PluginMeta>(); // Load all workflows and collect all their tools const workflowGroups = await loadWorkflowGroups(); for (const [, workflow] of workflowGroups.entries()) { for (const tool of workflow.tools) { if (tool?.name && typeof tool.handler === 'function') { plugins.set(tool.name, tool); } } } return plugins; } /** * Load workflow groups with metadata validation using generated loaders */ export async function loadWorkflowGroups(): Promise<Map<string, WorkflowGroup>> { const workflows = new Map<string, WorkflowGroup>(); for (const [workflowName, loader] of Object.entries(WORKFLOW_LOADERS)) { try { // Dynamic import with code-splitting const workflowModule = (await loader()) as { workflow?: WorkflowMeta; [key: string]: unknown; }; if (!workflowModule.workflow) { throw new Error(`Workflow metadata missing in ${workflowName}/index.js`); } // Validate required fields const workflowMeta = workflowModule.workflow as WorkflowMeta; if (!workflowMeta.name || typeof workflowMeta.name !== 'string') { throw new Error( `Invalid workflow.name in ${workflowName}/index.js: must be a non-empty string`, ); } if (!workflowMeta.description || typeof workflowMeta.description !== 'string') { throw new Error( `Invalid workflow.description in ${workflowName}/index.js: must be a non-empty string`, ); } workflows.set(workflowName, { workflow: workflowMeta, tools: await loadWorkflowTools(workflowModule), directoryName: workflowName, }); } catch (error) { throw new Error( `Failed to load workflow '${workflowName}': ${error instanceof Error ? error.message : 'Unknown error'}`, ); } } return workflows; } /** * Load workflow tools from the workflow module */ async function loadWorkflowTools(workflowModule: Record<string, unknown>): Promise<PluginMeta[]> { const tools: PluginMeta[] = []; // Load individual tool files from the workflow module for (const [key, value] of Object.entries(workflowModule)) { if (key !== 'workflow' && value && typeof value === 'object') { const tool = value as PluginMeta; if (tool.name && typeof tool.handler === 'function') { tools.push(tool); } } } return tools; } /** * Get workflow metadata by directory name using generated loaders */ export async function getWorkflowMetadata(directoryName: string): Promise<WorkflowMeta | null> { try { // First try to get from generated metadata (fast path) const metadata = WORKFLOW_METADATA[directoryName as WorkflowName]; if (metadata) { return metadata; } // Fall back to loading the actual module const loader = WORKFLOW_LOADERS[directoryName as WorkflowName]; if (loader) { const workflowModule = (await loader()) as { workflow?: WorkflowMeta }; return workflowModule.workflow ?? null; } return null; } catch { return null; } }

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/cameroncooke/XcodeBuildMCP'

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