Skip to main content
Glama
jim-coyne

Hyperfabric MCP Server

fabricsDeleteFabricConnection

Remove a specific connection from a fabric in Hyperfabric infrastructure management by providing fabric and connection identifiers.

Instructions

Delete a specific connection.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
fabricIdYesThe fabric id or name.
connectionIdYesThe connection id or port name.

Implementation Reference

  • This is the core handler function that executes the API call for any tool, including 'fabricsDeleteFabricConnection'. It matches the toolName to the corresponding OpenAPI path/method, builds the request from arguments, and makes the HTTP call to the Hyperfabric API.
    private async executeApiCall(toolName: string, args: any): Promise<any> {
      // Validate inputs for port configuration tools to prevent misuse
      if (toolName === 'nodesSetPorts' || toolName === 'nodesUpdatePort') {
        // Ensure no executable content or shell commands in arguments
        const argsStr = JSON.stringify(args);
        if (/(\$\(|`|eval|exec|system|spawn|child_process)/.test(argsStr)) {
          throw new Error('Security: Invalid arguments detected. Port configuration tools only accept network settings (speed, MTU, VLAN, etc.)');
        }
      }
      
      // Extract the original method and path from the tool name
      // This is a simplified approach - in a production system you'd want a more robust mapping
      
      if (!this.openApiSpec?.paths) {
        throw new Error("OpenAPI spec not loaded");
      }
    
      // Find the corresponding operation
      let foundOperation: { method: string; path: string; operation: OpenAPIOperation } | null = null;
      
      for (const [pathKey, pathItem] of Object.entries(this.openApiSpec.paths)) {
        for (const [method, operation] of Object.entries(pathItem)) {
          if (typeof operation !== 'object' || !operation) continue;
          
          const op = operation as OpenAPIOperation;
          const expectedToolName = this.generateToolName(method, pathKey, op);
          
          if (expectedToolName === toolName) {
            foundOperation = { method, path: pathKey, operation: op };
            break;
          }
        }
        if (foundOperation) break;
      }
    
      if (!foundOperation) {
        throw new Error(`No operation found for tool: ${toolName}`);
      }
    
      // Build the URL by replacing path parameters
      let url = foundOperation.path;
      const queryParams: Record<string, string> = {};
      
      // Handle path and query parameters
      if (foundOperation.operation.parameters) {
        for (const param of foundOperation.operation.parameters) {
          const value = args[param.name];
          if (value !== undefined) {
            if (param.in === 'path') {
              url = url.replace(`{${param.name}}`, encodeURIComponent(value));
            } else if (param.in === 'query') {
              queryParams[param.name] = value;
            }
          }
        }
      }
    
      // Prepare the request
      const requestConfig: any = {
        method: foundOperation.method.toUpperCase(),
        url,
        params: queryParams,
      };
    
      // Handle request body for POST/PUT/PATCH
      if (['post', 'put', 'patch'].includes(foundOperation.method.toLowerCase())) {
        // Check if args has a requestBody property (legacy format)
        if (args.requestBody) {
          requestConfig.data = args.requestBody;
        } else {
          // Build request body from exposed properties
          // This handles cases where schema properties are exposed directly (e.g., fabrics, nodes, etc.)
          const requestBody: Record<string, any> = {};
          const pathItem = this.openApiSpec?.paths?.[foundOperation.path];
          const operation = (pathItem as any)?.[foundOperation.method];
          
          if (operation?.requestBody) {
            const requestBodyDef = this.resolveSchemaRef(operation.requestBody);
            const schema = this.deepResolveSchema(requestBodyDef.content?.['application/json']?.schema);
            
            // Collect all properties that are part of the request body schema
            if (schema?.properties) {
              for (const propName of Object.keys(schema.properties)) {
                if (args.hasOwnProperty(propName)) {
                  requestBody[propName] = args[propName];
                }
              }
            }
          }
          
          if (Object.keys(requestBody).length > 0) {
            requestConfig.data = requestBody;
          }
        }
      }
    
      logger.debug(`Making API call: ${requestConfig.method} ${url}`);
      
      try {
        const response = await this.httpClient.request(requestConfig);
        return {
          status: response.status,
          statusText: response.statusText,
          data: response.data
        };
      } catch (error) {
        if (axios.isAxiosError(error)) {
          throw new Error(`API call failed: ${error.response?.status} ${error.response?.statusText} - ${JSON.stringify(error.response?.data)}`);
        }
        throw error;
      }
    }
  • Generates the inputSchema (JSON Schema) for each tool based on the OpenAPI operation's parameters and requestBody schema. For 'fabricsDeleteFabricConnection', this would define the required path/query params like fabricId, connectionId etc.
    private createToolFromOperation(
      name: string,
      method: string,
      path: string,
      operation: OpenAPIOperation
    ): Tool | null {
      let description = operation.summary || operation.description || `${method.toUpperCase()} ${path}`;
      
      // Add security context for network port configuration operations
      if (name === 'nodesSetPorts' || name === 'nodesUpdatePort') {
        description += '\n\n[SAFE OPERATION] This tool configures network fabric port settings (speed, MTU, VLAN, etc.) via REST API. It does NOT execute code or commands on the system.';
      }
      
      // Enhance description for create/update operations
      if (['post', 'put', 'patch'].includes(method.toLowerCase())) {
        if (method.toLowerCase() === 'post') {
          description += '\n\nTo use this tool, pass the required fields as direct arguments (e.g., fabrics=[{name:"my-fabric", description:"...", ...}])';
        } else if (method.toLowerCase() === 'put') {
          description += '\n\nTo use this tool, pass the resource ID and the fields to update as arguments';
        } else if (method.toLowerCase() === 'patch') {
          description += '\n\nTo use this tool, pass the resource ID and the fields to patch as arguments';
        }
      }
      
      const properties: Record<string, any> = {};
      const required: string[] = [];
    
      // Process parameters
      if (operation.parameters) {
        for (const param of operation.parameters) {
          if (param.in === 'path' || param.in === 'query') {
            properties[param.name] = {
              type: param.schema?.type || 'string',
              description: param.description || ''
            };
            
            if (param.required) {
              required.push(param.name);
            }
          }
        }
      }
    
      // Process request body for POST/PUT/PATCH requests
      if (operation.requestBody && ['post', 'put', 'patch'].includes(method.toLowerCase())) {
        // Resolve the requestBody reference if it exists
        const requestBody = this.resolveSchemaRef(operation.requestBody);
        const content = requestBody.content;
        
        if (content?.['application/json']?.schema) {
          let schema = content['application/json'].schema;
          // Deeply resolve schema references
          schema = this.deepResolveSchema(schema);
          
          if (schema.properties) {
            // Expose the request body properties directly
            for (const [propName, propSchema] of Object.entries(schema.properties)) {
              const propDef = propSchema as any;
              properties[propName] = this.deepResolveSchema(propDef, 0);
              
              if (schema.required?.includes(propName)) {
                required.push(propName);
              }
            }
          }
        }
      }
    
      return {
        name,
        description,
        inputSchema: {
          type: 'object',
          properties,
          required
        }
      };
    }
  • src/main.ts:134-158 (registration)
    Dynamically generates and registers all Tool objects (including 'fabricsDeleteFabricConnection' if operationId matches in OpenAPI spec) by iterating over paths/operations and calling createToolFromOperation.
    private generateTools(): void {
      if (!this.openApiSpec?.paths) {
        logger.error("No paths found in OpenAPI spec");
        return;
      }
    
      this.tools = [];
    
      for (const [pathKey, pathItem] of Object.entries(this.openApiSpec.paths)) {
        for (const [method, operation] of Object.entries(pathItem)) {
          if (typeof operation !== 'object' || !operation) continue;
          
          const op = operation as OpenAPIOperation;
          const toolName = this.generateToolName(method, pathKey, op);
          const tool = this.createToolFromOperation(toolName, method, pathKey, op);
          
          if (tool) {
            this.tools.push(tool);
            logger.debug(`Generated tool: ${toolName}`);
          }
        }
      }
    
      logger.info(`Generated ${this.tools.length} tools from OpenAPI spec`);
    }
  • src/main.ts:292-335 (registration)
    Sets up the MCP server request handlers: ListTools returns the list of generated tools, CallTool dispatches to executeApiCall based on tool name.
    private setupHandlers(): void {
      this.server.setRequestHandler(ListToolsRequestSchema, async () => {
        return { tools: this.tools };
      });
    
      this.server.setRequestHandler(CallToolRequestSchema, async (request: any) => {
        const { name, arguments: args } = request.params;
        
        logger.info(`Calling tool: ${name}`);
        logger.debug(`Tool arguments: ${JSON.stringify(args, null, 2)}`);
        
        try {
          // Find the tool definition
          const tool = this.tools.find(t => t.name === name);
          if (!tool) {
            throw new Error(`Tool ${name} not found`);
          }
    
          // Execute the API call
          const result = await this.executeApiCall(name, args);
          
          return {
            content: [
              {
                type: "text",
                text: JSON.stringify(result, null, 2)
              }
            ]
          };
        } catch (error) {
          logger.error(`Error executing tool ${name}:`, error);
          
          return {
            content: [
              {
                type: "text",
                text: `Error: ${error instanceof Error ? error.message : String(error)}`
              }
            ],
            isError: true
          };
        }
      });
    }
  • Helper used to generate tool names from OpenAPI operations (uses operationId if present) and to match toolName back to operation during execution.
    private generateToolName(method: string, path: string, operation: OpenAPIOperation): string {
      if (operation.operationId) {
        return operation.operationId;
      }
    
      // Generate a name from the method and path
      const pathParts = path.split('/').filter(part => part && !part.startsWith('{'));
      const nameBase = pathParts.join('_').replace(/[^a-zA-Z0-9_]/g, '_');
      return `${method}_${nameBase}`;
    }

Tool Definition Quality

Score is being calculated. Check back soon.

Install Server

Other Tools

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/jim-coyne/hyperfabric_MCP'

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