Skip to main content
Glama

OPNSense MCP Server

network.ts7.5 kB
// OPNSense Network Resources Implementation import { Resource, ValidationResult } from '../base.js'; /** * VLAN Properties */ export interface VlanProperties { interface: string; tag: number; description?: string; pcp?: number; // Priority Code Point (0-7) } /** * OPNSense VLAN Resource */ export class Vlan extends Resource { constructor(name: string, properties: VlanProperties) { super('opnsense:network:vlan', name, properties); } validate(): ValidationResult { const errors: string[] = []; const props = this.properties as VlanProperties; if (!props.interface) { errors.push('Interface is required'); } if (!props.tag || props.tag < 1 || props.tag > 4094) { errors.push('VLAN tag must be between 1 and 4094'); } if (props.pcp !== undefined && (props.pcp < 0 || props.pcp > 7)) { errors.push('Priority Code Point must be between 0 and 7'); } return { valid: errors.length === 0, errors }; } toApiPayload(): any { const props = this.properties as VlanProperties; return { vlan: { if: props.interface, tag: props.tag.toString(), descr: props.description || `VLAN ${props.tag}`, pcp: (props.pcp || 0).toString() } }; } fromApiResponse(response: any): void { if (response.uuid) { this.outputs.uuid = response.uuid; this.outputs.vlanif = response.vlanif; // e.g., "igc3_vlan150" this.outputs.tag = this.properties.tag; } } } /** * Interface Assignment Properties */ export interface InterfaceProperties { device: string; // Physical device or VLAN interface description?: string; enabled?: boolean; blockPrivate?: boolean; blockBogons?: boolean; // IPv4 Configuration ipv4Type?: 'none' | 'static' | 'dhcp'; ipv4Address?: string; ipv4Subnet?: number; // IPv6 Configuration ipv6Type?: 'none' | 'static' | 'dhcp6' | 'slaac'; ipv6Address?: string; ipv6Prefix?: number; } /** * OPNSense Interface Assignment Resource */ export class Interface extends Resource { constructor(name: string, properties: InterfaceProperties) { super('opnsense:network:interface', name, properties); } validate(): ValidationResult { const errors: string[] = []; const props = this.properties as InterfaceProperties; if (!props.device) { errors.push('Device is required'); } // Validate IPv4 configuration if (props.ipv4Type === 'static') { if (!props.ipv4Address) { errors.push('IPv4 address is required for static configuration'); } if (!props.ipv4Subnet || props.ipv4Subnet < 0 || props.ipv4Subnet > 32) { errors.push('IPv4 subnet must be between 0 and 32'); } } // Validate IPv6 configuration if (props.ipv6Type === 'static') { if (!props.ipv6Address) { errors.push('IPv6 address is required for static configuration'); } if (!props.ipv6Prefix || props.ipv6Prefix < 0 || props.ipv6Prefix > 128) { errors.push('IPv6 prefix must be between 0 and 128'); } } return { valid: errors.length === 0, errors }; } toApiPayload(): any { const props = this.properties as InterfaceProperties; const payload: any = { interface: { if: props.device, descr: props.description || this.name, enable: props.enabled !== false ? '1' : '0', blockpriv: props.blockPrivate ? '1' : '0', blockbogons: props.blockBogons ? '1' : '0' } }; // IPv4 configuration if (props.ipv4Type) { payload.interface.ipaddr = props.ipv4Type; if (props.ipv4Type === 'static') { payload.interface.ipaddr = props.ipv4Address; payload.interface.subnet = props.ipv4Subnet; } } // IPv6 configuration if (props.ipv6Type) { payload.interface.ipaddrv6 = props.ipv6Type; if (props.ipv6Type === 'static') { payload.interface.ipaddrv6 = props.ipv6Address; payload.interface.subnetv6 = props.ipv6Prefix; } } return payload; } fromApiResponse(response: any): void { if (response.interface) { this.outputs.name = this.name; this.outputs.device = response.interface.if; if (response.interface.ipaddr) { this.outputs.ipv4Address = response.interface.ipaddr; } if (response.interface.ipaddrv6) { this.outputs.ipv6Address = response.interface.ipaddrv6; } } } } /** * Static Route Properties */ export interface StaticRouteProperties { network: string; gateway: string; interface?: string; description?: string; disabled?: boolean; } /** * OPNSense Static Route Resource */ export class StaticRoute extends Resource { constructor(name: string, properties: StaticRouteProperties) { super('opnsense:network:route', name, properties); } validate(): ValidationResult { const errors: string[] = []; const props = this.properties as StaticRouteProperties; if (!props.network) { errors.push('Network is required'); } if (!props.gateway) { errors.push('Gateway is required'); } // Validate network format if (props.network && !/^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/.test(props.network)) { errors.push('Network must be in CIDR format (e.g., 192.168.1.0/24)'); } return { valid: errors.length === 0, errors }; } toApiPayload(): any { const props = this.properties as StaticRouteProperties; return { route: { network: props.network, gateway: props.gateway, interface: props.interface || '', descr: props.description || this.name, disabled: props.disabled ? '1' : '0' } }; } fromApiResponse(response: any): void { if (response.uuid) { this.outputs.uuid = response.uuid; } } } /** * NAT Rule Properties */ export interface NatRuleProperties { interface: string; source: string; destination?: string; target?: string; targetPort?: string; protocol?: string; description?: string; noNat?: boolean; // For NAT exclusions } /** * OPNSense NAT Rule Resource */ export class NatRule extends Resource { constructor(name: string, properties: NatRuleProperties) { super('opnsense:network:nat', name, properties); } validate(): ValidationResult { const errors: string[] = []; const props = this.properties as NatRuleProperties; if (!props.interface) { errors.push('Interface is required'); } if (!props.source) { errors.push('Source is required'); } if (!props.noNat && !props.target) { errors.push('Target is required for NAT rules'); } return { valid: errors.length === 0, errors }; } toApiPayload(): any { const props = this.properties as NatRuleProperties; return { rule: { interface: props.interface, source: props.source, destination: props.destination || 'any', target: props.noNat ? '' : props.target, target_port: props.targetPort || '', protocol: props.protocol || 'any', descr: props.description || this.name, no_nat: props.noNat ? '1' : '0' } }; } fromApiResponse(response: any): void { if (response.uuid) { this.outputs.uuid = response.uuid; } } }

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