Skip to main content
Glama
PasarGuard MCP

PasarGuard MCP

PasarGuard MCP

PasarGuard MCP is a local Model Context Protocol server for managing one or more PasarGuard panels through their REST APIs. It is intentionally limited to panel operations. It does not install servers, manage Vultr, SSH into nodes, manage Cloudflare/Fastly, or change provider infrastructure.

The server supports both reading and writing. Writes use a two-step plan/apply workflow: the MCP reads the current object, creates a short-lived confirmation token, and only applies the saved change after the user confirms it. Update plans preserve fields that were not changed, which is important because PasarGuard core and host updates expect complete valid objects.

Install

cd projects/pasarguard-mcp
python3 -m venv .venv
.venv/bin/python -m pip install -e '.[dev]'

Python 3.11 or newer is required.

Related MCP server: Caddy MCP

Configure panels

Static configuration is optional. The MCP can also load a credential file from a chat-driven tool call; see the next section.

Copy config/panels.example.json to a file outside Git, for example ~/.config/pasarguard-mcp/panels.json, and set the password in an environment variable:

export PASARGUARD_MCP_CONFIG="$HOME/.config/pasarguard-mcp/panels.json"
export PASARGUARD_EXAMPLE_PASSWORD='your-panel-password'

The configuration accepts multiple named panels:

{
  "panels": {
    "main": {
      "base_url": "https://panel.example.com",
      "username": "admin",
      "password_env": "PASARGUARD_MAIN_PASSWORD",
      "verify_tls": true,
      "timeout": 30
    },
    "staging": {
      "base_url": "https://staging-panel.example.com",
      "username_env": "PASARGUARD_STAGING_USERNAME",
      "password_env": "PASARGUARD_STAGING_PASSWORD"
    }
  }
}

An existing bearer token can be configured with token_env instead of username/password. Do not commit panel URLs, credentials, tokens, node API keys, certificates, or exported panel objects to this repository.

The local state directory stores confirmation plans and before-snapshots with mode 0700/0600. Override it with PASARGUARD_MCP_STATE_DIR when needed.

MCP client configuration

For a stdio MCP client, use the installed executable:

{
  "mcpServers": {
    "pasarguard": {
      "command": "/absolute/path/to/projects/pasarguard-mcp/.venv/bin/pasarguard-mcp",
      "env": {
        "PASARGUARD_MCP_CONFIG": "/absolute/path/to/panels.json",
        "PASARGUARD_MAIN_PASSWORD": "set-this-in-your-local-client-config"
      }
    }
  }
}

Prefer the client's secret/environment mechanism where it provides one. The MCP server never prints passwords or bearer tokens to stdout.

Chat-based credential files

You can tell Codex where an existing local credential file is instead of putting it in the MCP setup. Ask it to use the load_panel_credentials tool, for example:

Use the PasarGuard credentials in
/Users/me/workspace/memory/30-clients/example/credentials.local.md for the
panel named example. Keep them session-only and test the connection.

The tool reads the file locally and extracts only recognized fields. Supported formats are .env, .md, and .markdown; common keys include PANEL_URL, PASARGUARD_BASE_URL, username, password, and token. The password is never returned by the tool and is kept only in the MCP process by default.

If a Markdown file contains multiple named accounts, select the intended credential block explicitly. For example, a file with a flowship_super_admin block should be loaded with credential_name=flowship_super_admin. The parser strips one matching pair of Markdown backticks or quote characters around values. This matters for entries such as Password: \...`; sending the backticks as part of the password causes PasarGuard to return HTTP 401. When multiple complete credential blocks exist, omitting credential_name` now fails safely instead of merging the username from one account with the password or URL from another.

The tool accepts persist=true only when you explicitly want the profile written to the protected local JSON config. The default is persist=false. Use absolute local paths and keep credential files outside Git repositories.

URL, credential, filtering, and output normalization

  • Dashboard URLs are normalized to the PasarGuard site root. For example, https://flowshipnet.com/dashboard/ becomes https://flowshipnet.com before API paths are appended.

  • Markdown ## through ###### headings are selectable credential blocks in addition to named list blocks. This supports files where a section such as ## PasarGuard Panel (production) directly contains URL, username, and password fields.

  • List query keys that correspond to returned item fields are also enforced locally with exact matching. This protects callers when a panel silently ignores a filter such as inbound_tag. Pagination/control keys that are not item fields remain upstream-only.

  • PasarGuard's /api/hosts endpoint returns a bare top-level JSON list, unlike the wrapped node/core/group/user endpoints. The MCP normalizes bare lists to an object keyed by the resource, such as {"hosts": [...], "total": N}. FastMCP otherwise emits one text content block per list item, which makes a large host inventory easy for downstream tool renderers to split or truncate. The normalized object produces one coherent structured block.

  • Apply responses are compact receipts. Full updated core objects are not returned, and recursive redaction covers Reality privateKey/shortIds in read results. Verification should use the read tools after apply.

Tool groups

Read operations:

  • list_panels, load_panel_credentials, test_panel

  • get_panel_inventory

  • list_panel_resource, get_panel_resource

  • get_node_realtime_stats, get_panel_system_status

Write planning operations:

  • Nodes: create, update, delete, reconnect, sync, reset usage, update core

  • Cores: create and update, with explicit optional node restart on updates

  • Hosts: create and update

  • Groups: create and update

  • Users: create and update by numeric ID

  • All supported resources can be planned for deletion

Write execution and recovery:

  • apply_change applies one still-valid confirmation token.

  • inspect_change shows a safe summary without the stored payload.

  • plan_rollback creates a new confirmation plan from an applied update's before-snapshot.

The normal sequence is:

  1. Inspect the panel or resource.

  2. Call the relevant plan_* tool.

  3. Show the returned summary and ask the user for confirmation.

  4. Call apply_change with the returned token.

  5. Verify the resulting resource and node status.

API compatibility

The implementation follows the current public PasarGuard panel API layout, including POST /api/admin/token, /api/nodes, /api/cores, /api/hosts, /api/groups, /api/users, node action endpoints, and ID-based user routes under /api/user/by-id/{user_id}. The panel API can evolve, so endpoint changes should be updated in src/pasarguard_mcp/server.py and covered by tests before release.

Development

.venv/bin/python -m pytest
.venv/bin/python -m compileall -q src tests
.venv/bin/ruff check src tests

Tests use an in-memory HTTP transport and never contact a real panel.

Scoped direct-API fallback

When the hosted MCP approval gateway is unavailable, the repository includes scripts/apply_reality_expansion.py. It uses the same PasarGuardClient, loads session credentials from the Lexo, Flowship, and VSL247 credential files, checks every requested port/tag for collisions, saves each core once with restart_nodes=false so its inbound tags exist, updates the groups, then saves each core once with restart_nodes=true. Without --apply it only reads and validates the live state; --verify-only reads back the current core/group/node state; --restart-cores panel:id,... performs targeted restart-enabled saves when a previous request timed out. It never creates hosts.

The hosted connector and local elevated execution were both blocked by an external HTTP 403 approval-gateway response on 2026-08-18; until that gate is available, do not report the planned ports as live.

For a targeted Microsoft REALITY target/SNI repair across the same four panel cores, use scripts/repair_reality_sni.py. It validates the exact inbound tag, port, transport, and old/new SNI before changing only target and serverNames, then sends one complete-core PUT with restart_nodes=true per target and verifies the read-back. Run without --apply for a dry-run, --verify-only for current state, or --apply for the authorized repair.

Security boundary

This is an operations tool with write access. Run it locally over stdio, use a least-privileged PasarGuard administrator when possible, keep TLS verification enabled, and review every plan before applying it. Credential-file loading extracts only known fields and does not return passwords. The MCP deliberately does not provide a generic arbitrary-URL request tool.

Available Tools

22 tools
apply_changeA

Apply one previously planned change after explicit user confirmation.

Inputs: change_id (required), confirmation_token (required). Returns: object

get_node_realtime_statsC

Get current realtime statistics for a PasarGuard node.

Inputs: panel (required), node_id (required).

get_panel_inventoryB

Fetch a compact panel inventory: nodes, cores, hosts, groups, users, and system status.

Inputs: panel (required). Returns: object

get_panel_resourceC

Get a node, core, host, group, or user by numeric ID.

Inputs: panel (required), resource (required), resource_id (required), include_sensitive.

get_panel_system_statusC

Get panel system statistics and worker health.

Inputs: panel (required). Returns: object

inspect_changeA

Inspect a local plan summary without exposing its stored credentials or full payload.

Inputs: change_id (required). Returns: object

list_panel_resourceC

List one PasarGuard panel resource. Query supports the panel's normal filters/pagination.

Inputs: panel (required), resource (required), query.

list_panelsA

List configured PasarGuard panel profiles without exposing credentials.

Inputs: no named parameters. Returns: result

plan_create_coreC

Plan creating a core configuration using the panel's CoreCreate body.

Inputs: core (required), panel (required). Returns: object

plan_create_groupC

Plan creating a group using the panel's GroupCreate body.

Inputs: group (required), panel (required). Returns: object

plan_create_hostC

Plan creating a subscription host using the panel's CreateHost body.

Inputs: host (required), panel (required). Returns: object

plan_create_nodeB

Plan adding a node. Apply only after asking the user to confirm the returned token.

Inputs: node (required), panel (required). Returns: object

plan_create_userC

Plan creating a PasarGuard user. The body follows the panel's UserCreate model.

Inputs: user (required), panel (required). Returns: object

plan_delete_resourceB

Plan deleting a panel resource. This is intentionally separate from update tools.

Inputs: panel (required), resource (required), resource_id (required). Returns: object

plan_node_actionC

Plan a node action that may reconnect, sync, reset usage, or update its core.

Inputs: panel (required), action (required), node_id (required), flush_users. Returns: object

plan_rollbackB

Plan restoring a previously applied update from its local before-snapshot.

Inputs: change_id (required). Returns: object

plan_update_coreC

Plan a core update. The full current core is merged with patch and restart_nodes is explicit.

Inputs: panel (required), patch (required), core_id (required), restart_nodes. Returns: object

plan_update_groupC

Plan a partial group update.

Inputs: panel (required), patch (required), group_id (required). Returns: object

plan_update_hostA

Plan a partial host update while preserving required fields from the current host.

Inputs: panel (required), patch (required), host_id (required). Returns: object

plan_update_nodeA

Plan a partial node update; the MCP fetches and preserves the complete current object.

Inputs: panel (required), patch (required), node_id (required). Returns: object

plan_update_userC

Plan a user update through the current ID-based PasarGuard route.

Inputs: panel (required), patch (required), user_id (required). Returns: object

test_panelC

Authenticate to a panel and return the current admin identity.

Inputs: panel (required). Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3/5.0

    Scored across 22 tools

    Disambiguation4/5

    Most tools target distinct resource-action pairs (e.g., plan_create_node vs. plan_update_core), and read tools are clearly separated from planning tools. Some ambiguity exists between plan_node_action and plan_update_core since plan_node_action can also update a core, and plan_delete_resource is generic, but descriptions mitigate this.

    Naming Consistency4/5

    The naming follows a consistent verb_noun pattern (e.g., plan_create_node, get_panel_inventory, apply_change). Minor inconsistencies include 'list_panel_resource' (singular generic) and 'plan_rollback' not matching the plan_create/update pattern, but overall the convention is predictable.

    Tool Count3/5

    With 22 tools, the server is on the heavier side, which can be overwhelming but is justified by the breadth of PasarGuard management. The count is within the 'heavy' range (16-25) rather than extreme, so it earns a middle score.

    Completeness4/5

    The tool surface covers create, read, update, delete, planning, applying, rollback, and monitoring for core PasarGuard resources. Minor gaps exist, such as no explicit tool to list planned changes or cancel a plan, but these are workarounds via inspect_change and apply_change.

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      C
      maintenance
      MCP server for Proxmox VE and Proxmox Datacenter Manager, covering every API endpoint via six consolidated tools for list, describe, and call operations with a read-only safety gate.
      6
      6 npm
      2
      AGPL 3.0
    • A
      license
      B
      quality
      C
      maintenance
      Local MCP server for inspecting and managing an allowlisted Discord server via Discord's REST API, with safety modes, idempotent JSON blueprints, and destructive-operation safeguards.
      27
      1
      MIT
    • A
      license
      B
      quality
      D
      maintenance
      MCP server for interacting with a self-hosted Appsmith instance via its REST API, enabling read/update/create of pages, queries, JS objects, widgets, datasources, and applications with lazy session management and destructive-operation gating.
      30
      MIT