Skip to main content
Glama

OPNSense MCP Server

base.ts6.45 kB
// Core Resource Model for MCP-based IaC Platform // This provides the foundation for all MCP servers to implement IaC patterns import crypto from 'crypto'; /** * Resource states following standard IaC lifecycle */ export enum ResourceState { Pending = 'pending', // Resource defined but not created Creating = 'creating', // Resource creation in progress Created = 'created', // Resource exists and is active Updating = 'updating', // Resource update in progress Deleting = 'deleting', // Resource deletion in progress Deleted = 'deleted', // Resource has been deleted Failed = 'failed' // Resource operation failed } /** * Standard validation result */ export interface ValidationResult { valid: boolean; errors: string[]; warnings?: string[]; } /** * Resource metadata for tracking */ export interface ResourceMetadata { createdAt?: Date; updatedAt?: Date; version: number; checksum?: string; } /** * Base class for all IaC resources across MCP servers */ export abstract class Resource { public readonly id: string; public readonly type: string; public readonly name: string; public state: ResourceState = ResourceState.Pending; public outputs: Record<string, any> = {}; public metadata: ResourceMetadata; constructor( type: string, name: string, public properties: Record<string, any>, public dependencies: string[] = [] ) { this.id = this.generateId(type, name); this.type = type; this.name = name; this.metadata = { version: 1, createdAt: new Date() }; } /** * Generate unique resource ID */ private generateId(type: string, name: string): string { const hash = crypto.createHash('sha256') .update(`${type}:${name}`) .digest('hex') .substring(0, 8); return `${type}:${name}:${hash}`; } /** * Validate resource configuration */ abstract validate(): ValidationResult; /** * Convert to API-specific payload */ abstract toApiPayload(): any; /** * Update resource state from API response */ abstract fromApiResponse(response: any): void; /** * Get resource references (for dependency resolution) */ getReferences(): string[] { const refs: string[] = []; // Scan properties for ${resource.output} patterns const scanValue = (value: any): void => { if (typeof value === 'string') { const matches = value.matchAll(/\$\{([^}]+)\}/g); for (const match of matches) { refs.push(match[1].split('.')[0]); } } else if (typeof value === 'object' && value !== null) { Object.values(value).forEach(scanValue); } }; Object.values(this.properties).forEach(scanValue); return [...new Set(refs)]; } /** * Resolve references in properties */ resolveReferences(resources: Map<string, Resource>): void { const resolveValue = (value: any): any => { if (typeof value === 'string') { return value.replace(/\$\{([^}]+)\}/g, (match, ref) => { const [resourceName, outputKey] = ref.split('.'); const resource = resources.get(resourceName); if (resource && outputKey && resource.outputs[outputKey]) { return resource.outputs[outputKey]; } return match; }); } else if (Array.isArray(value)) { return value.map(resolveValue); } else if (typeof value === 'object' && value !== null) { const resolved: any = {}; for (const [key, val] of Object.entries(value)) { resolved[key] = resolveValue(val); } return resolved; } return value; }; // Create new properties object with resolved references const resolved: any = {}; for (const [key, value] of Object.entries(this.properties)) { resolved[key] = resolveValue(value); } this.properties = resolved; } /** * Get resource display info */ getDisplayInfo(): string { return `${this.type} "${this.name}" [${this.state}]`; } /** * Clone resource with new properties */ clone(newProperties?: Partial<Record<string, any>>): Resource { const ResourceClass = this.constructor as any; return new ResourceClass( this.name, { ...this.properties, ...newProperties } ); } } /** * Resource action for execution planning */ export interface ResourceAction { type: 'create' | 'update' | 'delete' | 'read'; resource: Resource; reason?: string; requiresRecreate?: boolean; } /** * Deployment plan containing all actions */ export interface DeploymentPlan { id: string; name: string; actions: ResourceAction[]; summary: { create: number; update: number; delete: number; unchanged: number; }; } /** * Deployment result */ export interface DeploymentResult { success: boolean; plan: DeploymentPlan; appliedActions: ResourceAction[]; failedActions: Array<{ action: ResourceAction; error: string; }>; duration: number; } /** * Resource registry for dynamic resource creation */ export class ResourceRegistry { private resources = new Map<string, typeof Resource>(); /** * Register a resource type */ register(type: string, resourceClass: typeof Resource): void { this.resources.set(type, resourceClass); } /** * Create a resource instance */ create(type: string, name: string, properties: any): Resource { const ResourceClass = this.resources.get(type); if (!ResourceClass) { throw new Error(`Unknown resource type: ${type}`); } return new (ResourceClass as any)(name, properties); } /** * Check if resource type is registered */ has(type: string): boolean { return this.resources.has(type); } /** * Get all registered types */ getTypes(): string[] { return Array.from(this.resources.keys()); } } /** * Cross-MCP resource reference */ export interface CrossMCPReference { server: string; resourceId: string; outputKey: string; } /** * Resolve cross-MCP references */ export function parseCrossMCPReference(ref: string): CrossMCPReference | null { // Format: ${server:resource.output} const match = ref.match(/\$\{([^:]+):([^.]+)\.([^}]+)\}/); if (match) { return { server: match[1], resourceId: match[2], outputKey: match[3] }; } 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/vespo92/OPNSenseMCP'

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