Skip to main content
Glama

hq-mcp

An MCP server that gives an AI agent read access to a VPN business: billing in SHM and the panel in Remnawave, stitched together so questions that span both systems can be answered in one call.

Sixteen tools, all read-only. No mutations ship in this release.

Why composite tools instead of endpoint proxies

The obvious design is one tool per HTTP endpoint — roughly 150 of them. That was tried and abandoned, for two reasons.

A raw proxy tool voids every allowlist you write. If the model can call GET <any path>, then the list of operations you decided to forbid is decoration: the forbidden path is one string away. The tools here call named routes and a build-time scanner fails the suite if a source file hardcodes a forbidden one.

And an endpoint is not a question. "Why does this client have no working config" touches four SHM routes and two panel routes, and the interesting part is the join — a service that is ACTIVE in billing while the panel has no user for it is invisible to either system alone. Tools like client_overview, sync_audit and provisioning_diagnose exist because that seam is where the bugs live.

Related MCP server: xendit-mcp

The design rule that shaped everything

An empty answer must never be mistaken for a proven absence.

Most of the work in this repository is that one sentence applied over and over. When a backend fails, the tool degrades: the failure lands in degraded, a partial_result warning says which half is missing, and any finding that depended on the missing half is suppressed rather than computed from what survived. When a list is truncated, the server-side total comes back with it, so "there is no such service" cannot rest on an unannounced window.

This is not theoretical caution. During development, one tool read 1124 panel records, discarded every one of them because a field had been renamed upstream, and then reported 690 clients as needing to be re-provisioned — a destructive recommendation, stated confidently, derived from an empty set. The fix was not only the renamed field: it was that a bucket computed from unusable input must refuse to be a finding.

Install

Requires Node 20+ and pnpm.

pnpm install
pnpm build
cp .env.example .env    # then fill it in

Point Claude Code at it:

{
  "mcpServers": {
    "hq": {
      "command": "node",
      "args": ["/absolute/path/to/hq-mcp/apps/stdio/dist/index.js"],
      "env": { "HQ_MCP_MODE": "ro" }
    }
  }
}

The server reads its configuration from the environment. A missing or malformed variable fails at startup naming the variable and what it expects, rather than surfacing later as a confusing tool error.

Start here: call platform_probe first. It reports what the two backends actually are — versions read from the live systems, which undocumented features work, which tunnels are open — because published API specs lag deployments and this project has been bitten by trusting them.

The tools

Tool

Answers

platform_probe

What is live right now: versions, capabilities, tunnels

client_resolve

Who is this — by telegram id, email, login, id

client_search

Find clients by a fragment

client_overview

One client across both systems in a single call

billing_ledger

Payments, bonuses, charges, and two independent reconciliations

service_inspect

One client's services: status, expiry, queued tasks

catalog_read

Tariffs, price list, categories, the event map

spool_inspect

The provisioning queue: stuck, failed, and the real depth

provisioning_diagnose

"Paid, but there is no config" — per service, not per client

subscription_inspect

Traffic, devices, subscription fetch history

sync_audit

Batch reconciliation of billing against the panel

country_health

Nodes, hosts and bandwidth for one country

infra_map

Nodes, hosts, inbounds, squads and the gaps between them

config_read

Billing configuration, secrets masked

abuse_report

The anti-abuse hook's findings

sql_query

Read-only SQL — preflight only, see below

Safety model

Two profiles. human is a trusted operator and gets specific, actionable refusals — including the exact ssh command when a tunnel is closed. bot is an untrusted channel: every refusal collapses into one uniform message, so the tool registry cannot be enumerated by probing for which names answer differently.

A forbidden class, separate from merely dangerous. Key generation, token and auth routes, template and settings writes, bulk and restart-all operations, mass-mail jobs, ready-to-use subscription links, marking a provisioning task successful by hand, and deleting payments or bonuses. These are not gated — they are absent, and a build-time scanner keeps them absent.

Secrets are masked on the way out, by key name, in both directions and on both the success and the failure path — including the backend response fragments that HTTP clients like to splice into error messages.

sql_query does not execute anything. It validates and refuses, and says so in its own source. The lexical check it performs is a cheap first filter and explicitly not a security boundary; the module lists the bypasses that pass it, with tests pinning them open, so nobody mistakes the filter for a guarantee. Before execution is ever wired, the preconditions are stated in the same file: a read-only role, a read-only transaction, a statement timeout, and a column denylist.

Limitations worth knowing

  • Read-only. The mutation and HTTP-transport releases are designed but not built.

  • Two tools need a tunnel into a private network and refuse without one. They stay visible on purpose: a tool that vanishes teaches the model that the capability does not exist, when the truth is that a port is closed.

  • sync_audit reads both systems to completion and is the one expensive call here — it has its own request allowance for that reason.

  • The panel's page size is measured at runtime rather than assumed, because the API declares no maximum and the effective one has changed between releases.

Development

pnpm test          # unit tests
pnpm typecheck
pnpm test:guards   # the capture script's production-refusal guards

Tests run against fixtures shaped like real responses. Where a defect was only visible against a live system, the test that pins it says so.

License

MIT.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    A read-only MCP server for securely accessing Xendit payment platform data. It enables querying balances, invoices, transactions, disbursements, refunds, and virtual account payments while preventing any money-moving operations.
    13
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    MCP server for the DataGate billing platform API, providing read-only tools to manage customers, invoices, products, agreements, sites, and payments.
    13
    MIT

View all related MCP servers

Related MCP Connectors

  • Read-only MCP server for ClassQuill, a tutoring-business-management platform.

  • A paid remote MCP for hosted MCP server, built to return verdicts, receipts, usage logs, and audit-r

  • A paid remote MCP for AI SDK data query MCP, built to return verdicts, receipts, usage logs, and aud

View all MCP Connectors

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/qwertyhq/hq-mcp'

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