Orchestrating Fortigate Guest Management with FastMCP, Gemini API, and Next.js

By Michael Elias on February 9, 2026

·

29 views

A colleague of mine reached out asking if I could help build a web UI to interact with their Fortigate firewall to manage Guest user access. The goal was to create an interface for a receptionist or help desk personnel to list users, add users, delete users, and change passwords.

The requirements were straightforward: a secure interface limited strictly to Fortigate commands without offering any other AI capabilities. I chose Node.js as the main component, FastMCP to present a limited Fortigate toolbox, the Gemini LLM to prompt the user, and Nginx as the proxy.

As in my other posts at The Factory System, I turned to Gemini to help orchestrate the build. After several prompts as the "Prompt Engineer" persona, I landed on this final system prompt:

The Architectural Blueprint

The core philosophy of this build was "limited scope." The AI isn't a general-purpose assistant; it’s a dedicated infrastructure tool. I used Node.js as the primary orchestrator, FastMCP (a Python-based framework) to expose the FortiGate "toolbox," and Nginx to wrap everything in a production-ready proxy.

High-level architecture diagram of a Universal FastMCP UI connecting Next.js, Gemini LLM, and FortiGate Firewall.

Figure 1: The Universal FastMCP UI Architecture—orchestrating the flow from user intent to FortiGate execution.

As I’ve explored in my previous post on AI-Powered Automation, I turned to Gemini to help orchestrate the build. I used a System Implementation Prompt to define a specific persona: a senior full-stack engineer specialized in MCP and secure system design.

System Implementation Prompt
Persona: You are a senior full-stack software engineer with expertisein building AI-powered applications, specifically using the ModelContext Protocol (MCP), Next.js for web interfaces, and Python forbackend services. You have experience with secure system design,including API integrations and process management.
Objective: Implement the "Universal FastMCP UI" system asdescribed in the architectural document. The goal is to create asecure, interactive web-based chat interface that allows a user tomanage a FortiGate Firewall's guest users by interacting with aGemini large language model. The system must prioritize securitywith a "human-in-the-loop" confirmation for all sensitive actions.

Core Components & Requirements:

1.FastMCP Server (Python):
Create a Python application using the FastMCPframework and FastAPI.
Expose a set of tools for FortiGate guest management:create_guest_user, delete_guest_user, list_guest_users,and update_guest_user_password.
Implement the FortiGate API interaction using httpx forauthenticated API calls.
The server must run on http://127.0.0.1:8000/mcp and useFastMCP's 
Streamable HTTP Transport (SSE overPOST).

2.Full-Stack UI Application (Next.js):
Backend API (/api/chat):
Develop a Next.js API Route using TypeScript.
Act as an orchestrator between the frontend, theGemini API, and the FastMCP server.
Receive chat messages, fetch tool definitions fromthe FastMCP server, and construct requests to theGemini API (gemini-2.5-flash).
Handle streaming responses (SSE) from the GeminiAPI. Critically, intercept functionCall responses totrigger the frontend confirmation flow.
Securely manage the GEMINI_API_KEY.

The prompt generated a comprehensive action plan, which guided every step of the installation and configuration.

Action Plan
Here is a detailed, phased action plan to build and deploy theUniversal FastMCP UI.

Phase 1: Setup & Environment

1.Project Scaffolding:
Initialize a new Next.js project (fastmcp-ui) with TypeScriptand Tailwind CSS.
Initialize a new Python project (fastmcp-server) with avirtual environment.

2.Dependency Installation:
Next.js: Install necessary packages: eventsource-parser,@headlessui/react (for modal), clsx, tailwind-merge.
Python: Install necessary packages: fastmcp, fastapi,uvicorn, httpx, pydantic.

3.Environment Variables:
Create a .env.local file in the fastmcp-ui project for GEMINI_API_KEY.
Create a .env file in the fastmcp project forFORTIGATE_IP and FORTIGATE_API_KEY. (this acctually changed to /etc/default/fastmcp for a systemctl startup script)

Phase 2: Core Backend - FastMCP Server

1.Tool Definition:

After reviewing the plan, I let Gemini orchestrate the build while keeping a cautious eye on every step. I have learned on my AI journey that hallucinations are more the norm than the exception; every step must be scrutinized. While there was some trial and error with the JS and Python code, it was much faster than developing by hand.

I allowed Gemini to resolve and install the necessary dependencies:

  • eventsource-parser
  • headlessui/react
  • clsx & tailwind-merge
  • FastMCP (my new favorite toy)
  • FastAPI & Uvicorn
  • Httpx & Pydantic

The Engine: fortigate_guest_manager.py and FastMCP

We created a dedicated API key on the Fortigate with limited permissions to stay within scope. We stored the GEMINI_API_KEY in .env.local and created /etc/default/fastmcp to hold the Fortinet API key and IP address.

The FastMCP server leverages httpx to make REST API calls to the Fortigate. This is the main engine responsible for exposing the following tools:

  • create_guest_user
  • delete_guest_user
  • list_guest_users
  • update_guest_user_password

The FastMCP Server (The Engine)

//ortigate_guest_manager.py
import os
from datetime import datetime, timedelta
from typing import List, Dict, Any

from fastmcp import FastMCP
import httpx

# Environment variables for FortiGate configuration
FORTIGATE_IP = os.getenv("FORTIGATE_IP")
FORTIGATE_API_KEY = os.getenv("FORTIGATE_API_KEY")

if not FORTIGATE_IP or not FORTIGATE_API_KEY:
    raise ValueError(
        "FORTIGATE_IP and FORTIGATE_API_KEY environment variables must be set."
    )

# Initialize FastMCP
mcp = FastMCP("FortiGate Guest Manager")

To manage the service, I created a system init script:

[Unit]
Description=FastMCP FortiGate Guest Manager
After=network.target

[Service]
User=gemini
Group=gemini
WorkingDirectory=/gemini/fastmcp/examples
EnvironmentFile=/etc/default/fastmcp
ExecStart=/home/gemini/.pyenv/shims/uvicorn fortigate_guest_manager:create_app --factory --host 0.0.0.0 --port 8000
Restart=always

[Install]
WantedBy=multi-user.target
[eliasm@centos7a ~]$ cat /etc/systemd/system/fastmcp.service
[Unit]
Description=FastMCP FortiGate Guest Manager
After=network.target

[Service]

I then asked Gemini for a Python test script to ensure the tools were being presented correctly. As you can see in the image below, the results returned the four defined tools and their arguments.

Terminal output showing available FastMCP tools for guest user management.

Validation of tool discovery showing the four guest management tools.

//tool __debug__
import httpx
import json
import asyncio

# --- Configuration ---
MCP_SERVER_URL = "http://127.0.0.1:8000/mcp"
HEADERS = {
    "Content-Type": "application/json",
    "Accept": "application/json, text/event-stream",
}

async def test_mcp_server():
    """
    Initializes a session and lists tools from the FastMCP server,
    then prints only the name and description of each tool.
    """
    session_id = None
    print(f"--- 1. Initializing session with {MCP_SERVER_URL} ---")

The Orchestrator: McpClient and route.ts

With the engine running, we moved to the Next.js backend. This involved creating an McpClient to handle initialization and an API route to orchestrate between FastMCP and Gemini.

The McpClient

//mcp-client.ts
import { createParser } from 'eventsource-parser';

export type Tool = {
  name: string;
  description?: string;
  inputSchema: any;
};

export class McpClient {
  private baseUrl: string;
  private sessionId: string | null = null;

  constructor(baseUrl: string) {
    this.baseUrl = baseUrl;
  }

  private async post(url: string, body: any) {
    const response = await fetch(url, {
      method: 'POST',

The API Route (route.ts)

The route.ts is the orchestrator. It handles POST requests, connects to the Python server via McpClient, and manages the LLM flow and text stream.

//route.ts
import { NextRequest, NextResponse } from 'next/server';
import { McpClient } from '@/lib/mcp-client';

// export const runtime = 'edge'; // Commenting out to ensure broad compatibility with node features if needed

export async function POST(req: NextRequest) {
  try {
    console.log('Backend: Received chat request');
    const { messages, toolConfirmation } = await req.json();
    const apiKey = process.env.GEMINI_API_KEY;

    if (!apiKey) {
      console.error('Backend: Missing API Key');
      return NextResponse.json({ error: 'Missing API Key' }, { status: 500 });
    }

    // 1. Initialize MCP Client and Fetch Tools
    const mcpUrl = 'http://127.0.0.1:8000/mcp';
    console.log('Backend: Connecting to MCP at', mcpUrl);

How the Gemini API Works

Interaction with the Gemini API from route.ts is 100% server-side. The user's browser has no direct access to the API, enforcing strict security.

  1. Frontend: User sends a message via the React interface.
  2. Request: Frontend POSTs to /api/chat.
  3. Backend: route.ts retrieves the API key and formats the history.
  4. Fetch: A server-to-server call is made to the Google Generative AI endpoint.
  5. Stream: Gemini sends back Server-Sent Events (SSE), which are piped directly to the frontend for a real-time "typing" effect.

Frontend and Deployment

The React UI provides a simple chat window and buttons to generate prompts. We included logic to prompt for Human-in-the-Loop confirmation before execution.

A web UI showing a 'Confirmation Required' modal before executing a firewall tool.

The UI requires explicit confirmation before the AI executes a tool.

We built the app using npm run build and managed the process using PM2 for clustering and load balancing.

Systemd for PM2

##fastmcp-ui.service

[Unit]
Description=PM2 Process Manager for fastmcp-ui
Documentation=https://pm2.keymetrics.io/
After=network.target

[Service]
Type=simple
User=gemini
Group=gemini
WorkingDirectory=/gemini/fastmcp-ui
##fastmcp-ui.service
Environment=PM2_HOME=/home/gemini/.pm2

# Using pm2-runtime which is designed for this use case
ExecStart=/usr/bin/pm2-runtime start /gemini/fastmcp-ui/ecosystem.config.js
ExecReload=/usr/bin/pm2 reload fastmcp-ui
ExecStop=/usr/bin/pm2 stop fastmcp-ui

PM2 dashboard showing active fastmcp-ui clusters on a Linux server.

Monitoring the fastmcp-ui processes with PM2 to ensure 24/7 availability.

Finally, Nginx proxies connections from port 443 to the backend on port 3000

server {
    listen 80;
    server_name localhost;

    # Redirect HTTP to HTTPS
    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name localhost;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;

The Proof is in the Pudding

The primary chat interface of the AI portal featuring a dark theme and quick-action guest management buttons

The primary chat interface of the AI portal featuring a dark theme and quick-action guest management buttons

A user interface prompt showing the "Human-in-the-Loop" security confirmation required before the AI executes a command

A user interface prompt showing the "Human-in-the-Loop" security confirmation required before the AI executes a command

A chat interaction showing the AI processing a request to create a guest user with a 10-day expiration period

A chat interaction showing the AI processing a request to create a guest user with a 10-day expiration period

Screenshot showing the AI refusing to answer general knowledge questions to demonstrate strict scope enforcement

Screenshot showing the AI refusing to answer general knowledge questions to demonstrate strict scope enforcement

Screenshot of the FortiOS administrative dashboard confirming the account 'eliasm' was created successfully

Summary: Orchestrating a Secure Fortigate Guest Portal

This project details the creation of a specialized Infrastructure AI Assistant designed to bridge the gap between non-technical staff and complex firewall management. By integrating a Next.js frontend, a FastMCP Python engine, and the Gemini API, we built a scoped web interface that allows users to manage Fortigate guest accounts—listing, adding, deleting, and updating passwords—entirely through natural language.

Key Technical Milestones:

  • Scoped Orchestration: Used a targeted System Prompt and Action Plan to ensure the Gemini LLM remains a dedicated infrastructure tool, strictly refusing out-of-scope queries to maintain security.
  • The FastMCP Engine: Developed fortigate_guest_manager.py to translate AI intents into precise FortiOS REST API calls via httpx, exposing critical management tools to the LLM.
  • Secure Architecture: Implemented a server-side-only communication flow where the Gemini API is never exposed to the client-side browser, proxied through a Next.js backend and Nginx.
  • Human-in-the-Loop: Built safety guardrails into the React UI, requiring explicit user confirmation before any automated firewall changes are executed.
  • Production Reliability: Leveraged PM2 for process management and systemd for service persistence, ensuring the entire stack remains resilient and scalable.

The final result is a robust, "sandboxed" management portal that simplifies administrative tasks while upholding enterprise security best practices

Michael Elias is a Senior Principal Operations Engineer at Dun & Bradstreet with a history of entrepreneurship in the ISP and consulting spaces. A veteran of the dot-com era with certifications from Cisco, Red Hat, and Fortinet, Michael specializes in high-compliance infrastructure and enterprise architecture.

- Michael Elias (Read full bio)

Subscribe to this Post

Get notified when there are updates or new content related to "Orchestrating Fortigate Guest Management with FastMCP, Gemini API, and Next.js".

Comments

Loading comments...

Leave a Comment

Note: All comments are moderated and will appear after approval.