Skip to main content
Glama

marzban-mcp

An MCP server that lets AI agents manage a Marzban panel — built on marzban-sdk.

Users, subscriptions, nodes, and the core config — through Claude, Cursor, or any MCP-compatible client.

npm version npm downloads Docker image license

Documentation · Client Setup · Tools


Point an AI agent at your panel and it can actually run it — not just read about it. No custom integration code, just an entry in your MCP config.

Install

npm install -g marzban-mcp

You don't usually need to install it yourself — your MCP client runs it via npx (see below). Prefer a container? A multi-arch image is published at ilmar7786/marzban-mcp:

docker pull ilmar7786/marzban-mcp

Related MCP server: io.github.antonio-mello-ai/mcp-pfsense

Quick start

Add it to your client's MCP config with your panel's URL and an admin login. Every client reads roughly the same shape:

{
  "mcpServers": {
    "marzban": {
      "command": "npx",
      "args": ["-y", "marzban-mcp"],
      "env": {
        "MARZBAN_BASE_URL": "https://panel.example.com",
        "MARZBAN_USERNAME": "admin",
        "MARZBAN_PASSWORD": "secret"
      }
    }
  }
}

Claude Desktop, Claude Code, Cursor and other MCP clients all read the same mcpServers block — just from a different config file. Restart the client and the tools below become available.

Features

  • 🔒 Env-only credentials — the panel URL, username and password are never accepted as a tool argument, so a compromised or confused model can't redirect the server elsewhere.

  • 🎯 Profile-gated tools — a tool outside the active profile never appears in tools/list at all, not just hidden behind a hint.

  • Confirmation on every destructive call — the first call only describes the consequences and returns a one-time token; nothing runs until a human-approved second call repeats it, and confirming one call never authorizes a different target or a wider version of the same call.

  • 🔁 A retried destructive call doesn't run twice — an identical repeat within 5 minutes returns the recorded result of the first one instead of restarting the core again; a call whose outcome was never observed says so plainly rather than guessing.

  • 🙈 Credentials masked by defaultproxies, subscription_url and links stay hidden unless you explicitly opt in.

  • 🧭 21 tools, 3 prompts — full user lifecycle, config, hosts, nodes, system stats and subscriptions, plus ready-made investigations that chain several tools together.

  • 🛠️ Built on marzban-sdk — the same auth, retry and reconnect behavior as the SDK itself, just exposed as MCP tools.

Configuration

Variable

Required

Description

MARZBAN_BASE_URL

Yes

Your panel's URL, e.g. https://panel.example.com

MARZBAN_USERNAME

Yes

Admin username

MARZBAN_PASSWORD

Yes

Admin password — also used to silently re-authenticate on expiry

Everything else — profile, output format, verbosity, tool allow/deny filters, log level, link masking — is optional and documented in Configuration.

Tools

21 tools, namespaced marzban_<area>_<action>: Users (11) · Config (5) · System & nodes (3) · Subscription (2). Three prompts — expiring_users_audit, node_diagnostics, traffic_report — chain those tools into ready-made investigations. Full list at Tools & Prompts.

Safety model

A profile isn't a hint — a tool outside it never appears in tools/list, so a model can't call what it can't see. readonly exposes only lists and lookups; standard (default) adds full user CRUD, renewals and status changes; full adds destructive tools — delete, reset traffic, rewrite config, restart the core.

Destructive tools also gate on confirmation: the first call never runs anything — it describes exactly what would happen and returns a one-time token. Only a second call, with that token attached, executes. MARZBAN_MCP_CONFIRM controls how often this is required: auto (default, once per tool and exact arguments, for 5 minutes — a different target or a wider call always needs its own confirmation), always (every call), or off (unattended environments only — no safety net once set).

Confirmation decides whether a call may run; it doesn't decide whether it has already run. So each destructive call is also remembered for 5 minutes: an identical repeat — the kind a client sends after a timeout — returns the recorded result of the first one, with a note saying so, and never reaches the panel. When a request went out and no answer came back, the outcome is reported as unknown, with instructions to check the state with a read-only tool rather than retry. A fresh confirmation still runs the operation for real, and restarting the server clears the memory.

Documentation

Full setup guides and the complete tool/prompt reference live at ilmar7786.github.io/marzban-sdk:

Contributing

This package lives in the marzban-sdk monorepo — see the root CONTRIBUTING.md for how to submit a patch. Running the server locally in watch mode, poking it with the MCP Inspector, or wiring a client to your own build? See ARCHITECTURE.md § Local development & manual testing. Found a bug or have an idea? Open an issue.

License

MIT © ilmar7786

Available Tools

15 tools
marzban_config_getGet core configA
Read-only

Reads the Xray core configuration. Defaults to a structural summary (inbound/outbound tags, ports, protocols, routing rule count) — the full config can be tens of KB and this is usually all that's needed. Pass section (e.g. "inbounds") for one key's raw JSON, or section: "raw" for the entire config.

ParametersJSON Schema
NameRequiredDescriptionDefault
sectionNoReturn this one top-level key's raw JSON instead of the summary (e.g. "inbounds", "routing"). Use "raw" for the entire config. Omit for a structural summary — prefer that over "raw" unless you specifically need the full JSON.

Output Schema

ParametersJSON Schema
NameRequiredDescription
dataYes
modeYes
sectionYes
summaryYes

TDQS

A4.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false. The description adds meaningful context beyond the annotations: the default response is a truncated structural summary due to the config's large size, and section/raw override that behavior. This goes beyond the schema's basic parameter semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences: default behavior, parameter option, and raw caveat. Front-loaded with the core purpose and immediately guides the agent to the best default call. Every sentence carries operational value.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only, optional-parameter tool with 100% schema coverage and an output schema, the description covers the default behavior, the override options, and the rationale. An agent can call this correctly without further documentation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and the schema already documents the section values including 'raw' and omission behavior. The description adds practical selection guidance (prefer summary over raw unless full JSON needed) and clarifies output scale, which enhances the schema without repeating it verbatim.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Reads) and resource (Xray core configuration), and distinguishes the default structural summary from full raw output. This clearly differentiates it from sibling tools that target hosts, nodes, subscriptions, inbounds, or users.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises when to omit the parameter vs pass a section, and explicitly cautions against using "raw" unless full JSON is truly needed. The schema description echoes this guidance, reinforcing the decision rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_hosts_getGet proxy hostsA
Read-only

Lists proxy host settings grouped by inbound tag. Flags host fields (remark/address/host/sni/path) that reference an unknown {VARIABLE} template token — almost always a typo, since Marzban leaves unknown tokens un-substituted rather than erroring.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
hostsYes
warningsYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the operation as read-only and non-destructive. The description goes beyond this by explaining the grouping behavior and, importantly, that unknown template tokens are flagged rather than causing an error because Marzban leaves them un-substituted. This gives an agent useful insight into output semantics that annotations cannot convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences carry all the essential information without redundancy. The core listing behavior is front-loaded, and the secondary token-flagging behavior is added in a compact, useful second sentence.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only tool with an output schema available, the description is complete. It explains what is returned, how results are grouped, and what the notable edge-case behavior is. There are no outstanding gaps an agent would need filled to invoke it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, and the schema coverage is 100%, so there are no parameter semantics to document. The baseline of 4 applies here: the description appropriately focuses on the returned data and behavior rather than inventing parameter guidance.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Lists'), a concrete resource ('proxy host settings'), and a distinguishing organizing principle ('grouped by inbound tag'). It also adds a second specific behavior (flagging unknown `{VARIABLE}` tokens) that makes the tool's purpose unmistakable and separates it from generic config or inbound tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description makes the tool's purpose clear, so an agent can infer it is the right choice for inspecting proxy host settings. However, it does not explicitly state when not to use it or which sibling tools should be preferred for related concerns such as general config, inbound management, or node status.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_nodes_listList nodesA
Read-only

Lists all connected nodes with their status and Xray version, plus bandwidth usage (uplink/downlink) over the given period. start/end (ISO datetimes) narrow the usage window; omit both for all-time.

ParametersJSON Schema
NameRequiredDescriptionDefault
endNoISO datetime. Omit for no upper bound.
startNoISO datetime. Omit for no lower bound.

Output Schema

ParametersJSON Schema
NameRequiredDescription
nodesYes
usageYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral context by specifying that it lists only connected nodes, includes status and Xray version, and that bandwidth usage is scoped to the given period, defaulting to all-time when both parameters are omitted.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The main purpose and return contents are front-loaded, and the parameter semantics are stated compactly and clearly.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only list operation with zero required parameters and an existing output schema, the description covers the essential behavior, parameter semantics, and default period. Nothing critical is missing for an agent to select and invoke this tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3, and the description goes further by explaining that start/end narrow the bandwidth usage window rather than filtering nodes, and explicitly stating that omitting both parameters gives all-time usage. This adds meaning beyond the schema's generic 'no lower/upper bound' phrasing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Lists'), names the resource ('all connected nodes'), and enumerates exactly what is returned: status, Xray version, and bandwidth usage over a period. This clearly differentiates it from sibling tools like marzban_system_stats or marzban_hosts_get, which target different resources or aggregates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear parameter usage guidance ('omit both for all-time') but does not explicitly state when to prefer this tool over sibling tools or mention any exclusions. The use case is implied rather than directly contrasted with alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_subscription_infoGet subscription infoA
Read-only

Reads subscription status/usage/expiry using the token from a subscription URL (the same public, unauthenticated endpoint client apps use) — for diagnosing a broken subscription link without needing the username. For an admin-side lookup by username, use marzban_users_get instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
subscriptionTokenYesThe opaque token from a user's subscription URL (the path segment after "/sub/") — not an admin/session token.

Output Schema

ParametersJSON Schema
NameRequiredDescription
linksNo
expireNo
statusYes
proxiesYes
usernameYes
next_planNo
online_atNo
created_atYes
data_limitNodata_limit can be 0 or greater
used_trafficYes
sub_updated_atNo
on_hold_timeoutNo
subscription_urlNo
sub_last_user_agentNo
lifetime_used_trafficNo
on_hold_expire_durationNo
data_limit_reset_strategyNo

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare readOnlyHint and destructiveHint, and the description adds meaningful behavioral context beyond that: it calls 'the same public, unauthenticated endpoint client apps use,' clarifying that no admin authentication is needed. It does not contradict the annotations, and the remaining details about invalid-token behavior are not essential given the output schema.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loads the core purpose and scope, and then immediately provides the routing alternative. Every sentence earns its place with no redundant filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read-only tool with full schema coverage and an output schema, the description is complete: it explains the use case, the required token source, the authentication context, and the alternative admin-side tool. Nothing needed for correct invocation is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema description covers 100% of the parameter and already fully explains that subscriptionToken is the opaque token from the subscription URL path segment after '/sub/' and not an admin/session token. The tool description adds little new meaning beyond restating 'using the token from a subscription URL,' so the schema-carried baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: it 'Reads subscription status/usage/expiry' using a subscription token. It clearly distinguishes this from admin-side user lookups by stating it works 'without needing the username' and directly names the sibling alternative marzban_users_get.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly tells when to use the tool: 'for diagnosing a broken subscription link without needing the username.' It also gives a direct alternative and route when that condition does not hold: 'For an admin-side lookup by username, use marzban_users_get instead.'

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_system_inboundsList inboundsA
Read-only

Lists configured inbound proxies grouped by protocol, with tag, network, TLS mode, and port for each. For the raw Xray inbound JSON (routing, stream settings, etc.) use marzban_config_get with section: "inbounds" instead.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription

No output parameters

TDQS

A4.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the read-only safety profile is covered. The description adds scoping detail about what is included (configured inbound proxies, grouped by protocol) and that it is not raw JSON, but does not disclose additional behavioral traits such as response size or potential filtering.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences with no filler. The primary purpose and returned fields are upfront, and the alternative tool is mentioned in the second sentence without distracting from the main definition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a parameterless read-only list operation with annotations, an output schema, and a clear sibling alternative, the description is fully sufficient. Nothing essential is missing for an agent to select and invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are zero parameters, so the schema has no parameter semantics to document. The description instead clarifies the shape and scope of the returned data, which is useful context and matches the baseline for a parameterless tool.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the specific verb 'Lists' and a precise resource ('configured inbound proxies'), then details the returned fields (tag, network, TLS mode, port) and grouping by protocol. It also explicitly distinguishes itself from the raw Xray inbound JSON returned by marzban_config_get.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives a clear when-to-use this tool versus the alternative: use this for a structured summary, use marzban_config_get with section 'inbounds' when raw Xray JSON is needed. This explicit routing removes ambiguity for the agent.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_system_statsGet system statsA
Read-only

Reports panel-wide stats: CPU/memory usage, user counts by status, and bandwidth totals/speeds, plus the Xray core version and whether it is currently running.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
coreYes
systemYes

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds useful behavioral context by stating exactly what the tool reports, including live Xray running state, which goes beyond the basic annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single sentence that front-loads the main purpose and then packs the key reportable items into a compact list. Every phrase adds information without redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a zero-parameter, read-only stats endpoint with an output schema present, the description is fully sufficient. It tells the agent what category of data to expect, and the annotations cover the operational risk profile.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no parameter semantics to document. The description correctly does not invent any parameters, and the schema's empty properties are consistent with that.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Reports panel-wide stats', then enumerates the concrete data categories covered (CPU/memory, user counts, bandwidth, Xray core status). This clearly distinguishes it from siblings like marzban_system_inbounds or marzban_users_list.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for obtaining an overall panel health/statistics overview, but it does not explicitly state when to prefer it over alternatives or mention any exclusions. There is no direct comparison to sibling tools such as marzban_system_inbounds.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_activateActivate userA

Sets a user's status to active.

ParametersJSON Schema
NameRequiredDescriptionDefault
usernameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
adminNo
linksNo
expireNo
statusYes
proxiesYes
inboundsNo
usernameYes
next_planNo
online_atNo
created_atYes
data_limitNodata_limit can be 0 or greater
used_trafficYes
sub_updated_atNo
on_hold_timeoutNo
subscription_urlNo
excluded_inboundsNo
auto_delete_in_daysNo
sub_last_user_agentNo
lifetime_used_trafficNo
on_hold_expire_durationNo
data_limit_reset_strategyNo

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate this is not read-only and not destructive. The description adds that the affected behavior is a status change to active, which is useful contextual detail, but it does not disclose edge cases such as idempotency, prerequisites, or effects on expired or held users.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single tightly-worded sentence with no filler. Every word contributes meaning, and the core action is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple single-parameter status mutation with annotations and an output schema, the description is mostly sufficient. The main gap is the absence of usage-routing context, but the operation itself is described completely enough to invoke correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, and the description does not compensate: it never mentions the username parameter or explains that it identifies the target user. The schema's pattern and constraints partially cover meaning, but the description adds no parameter-level semantics.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Sets') and resource ('a user's status') with a clear outcome ('to active'). This unambiguously distinguishes the operation from siblings like marzban_users_deactivate, since the semantic opposite is explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is given on when to use this tool versus alternatives such as marzban_users_deactivate, marzban_users_hold, or marzban_users_update. The intended use is only implied by the wording, not stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_createCreate userA

Creates a new user. dataLimit accepts a human size ("10GB"), expire a relative duration ("30d") or absolute date — both default to unlimited when omitted. templateId fills dataLimit/inbounds/expire from a user template; any field also given explicitly overrides the template value.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNo
expireNoe.g. "30d". Omit for no expiration.
statusNoDefaults to active.
proxiesNoProtocol name -> settings, e.g. {"vless": {"id": "<uuid>"}} or {"shadowsocks": {}} to auto-generate credentials. Omit to leave unchanged on update. On create there is no server default — omitting this (without templateId) errors; provide at least one protocol with a matching inbound configured on the panel.
inboundsNoProtocol name -> inbound tags to restrict this user to. Omit for all inbounds.
usernameYes
dataLimitNoe.g. "10GB". Omit or 0 for unlimited.
templateIdNoCreate from a user template instead of specifying proxies/inbounds by hand.
onHoldExpireDurationNoSeconds the user may stay on_hold before expiring, counted from their first connection. Only meaningful when status is on_hold.
dataLimitResetStrategyNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
adminNo
linksNo
expireNo
statusYes
proxiesYes
inboundsNo
usernameYes
next_planNo
online_atNo
created_atYes
data_limitNodata_limit can be 0 or greater
used_trafficYes
sub_updated_atNo
on_hold_timeoutNo
subscription_urlNo
excluded_inboundsNo
auto_delete_in_daysNo
sub_last_user_agentNo
lifetime_used_trafficNo
on_hold_expire_durationNo
data_limit_reset_strategyNo

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With annotations only marking readOnlyHint=false and destructiveHint=false, the description adds meaningful behavioral context: default-unlimited behavior for dataLimit and expire, support for human-readable sizes and relative or absolute durations, and template override semantics. It does not contradict the annotations and goes beyond what the schema states.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences with no filler. It front-loads the core action, then packs the most important parameter semantics into compact, readable sentences. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (10 parameters, nested objects) and the presence of a rich schema and output schema, the description covers the key cross-cutting behaviors: defaults, value formats, and template override logic. It relies on the schema for per-parameter details like the proxies-on-create requirement, which is acceptable since the schema describes it explicitly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 70%, so the schema handles most parameters, but the description adds value by clarifying formats ('10GB', '30d', absolute date), the unlimited-by-default behavior, and how templateId merges with explicitly provided fields. This meaningfully supplements the schema rather than repeating it.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: 'Creates a new user.' It clearly identifies the action, but it does not explicitly differentiate from sibling tools like marzban_users_update or marzban_users_list, so the sibling-distinguishing bar for a 5 is not fully met.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage by saying 'Creates a new user,' and it gives useful context about templateId and explicit override behavior. However, it does not state when to prefer this tool over an alternative, such as using marzban_users_update for existing users, nor does it mention any exclusions or prerequisites.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_deactivateDeactivate userB

Sets a user's status to disabled, immediately blocking their access without deleting them.

ParametersJSON Schema
NameRequiredDescriptionDefault
usernameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
adminNo
linksNo
expireNo
statusYes
proxiesYes
inboundsNo
usernameYes
next_planNo
online_atNo
created_atYes
data_limitNodata_limit can be 0 or greater
used_trafficYes
sub_updated_atNo
on_hold_timeoutNo
subscription_urlNo
excluded_inboundsNo
auto_delete_in_daysNo
sub_last_user_agentNo
lifetime_used_trafficNo
on_hold_expire_durationNo
data_limit_reset_strategyNo

TDQS

B3.4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds that the action is immediate and non-destructive ('without deleting them'), which complements the annotations (readOnlyHint=false, destructiveHint=false). However, it does not mention reversibility, impact on active sessions, or any side effects, leaving some behavioral gaps.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single, focused sentence that front-loads the action and adds the key clarifying detail about deletion. No unnecessary words or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter tool with an output schema, the description is mostly adequate but lacks usage guidance and any parameter clarification. The output schema covers return values, so that is not a gap, but the missing usage context prevents a higher score.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description does not reference the 'username' parameter, and the schema provides no description (0% coverage). While the parameter name is self-explanatory, the description fails to compensate for the schema's lack of explanation, such as format or purpose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific action ('Sets a user's status to disabled'), identifies the resource ('user'), and explicitly clarifies it does not delete the user, distinguishing it from deletion-like operations. This also implicitly contrasts with the sibling 'activate' tool.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No guidance is provided on when to use this tool versus alternatives such as 'activate' or 'hold'. It does not mention conditions for disabling a user or suggest re-enabling via the activate tool, leaving the agent to infer usage from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_extendExtend user subscriptionA

Renews a user: adds addDuration to their current expiration (or to now, if they have none or it already passed) and/or addData on top of their current data limit. If the user was expired or limited, status is moved back to active. Use this instead of marzban_users_update for renewals — it reads the current expire/limit first so the increment is relative, not an absolute overwrite.

ParametersJSON Schema
NameRequiredDescriptionDefault
addDataNoExtra data allowance to add on top of the current limit, e.g. "10GB".
usernameYes
addDurationNoRelative duration to add to the current expiration, e.g. "30d".

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
userYes

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only state readOnly=false and destructive=false; the description adds the important behavioral details: fallback to now when no expiration exists or it already passed, additive data increments, and reactivation of expired/limited users. This is meaningful context beyond what annotations provide, and it contradicts nothing.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two compact sentences front-load the core behavior, then give routing guidance. Every sentence earns its place, and there is no redundant restatement of the title or schema.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values do not need to be explained. The description covers fallback behavior, relative increments, status side effects, and sibling routing. The main gap is that the schema only requires username, while the description does not explicitly state that at least one of addDuration or addData should normally be supplied for the call to be meaningful.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents addData and addDuration with examples, and the description adds crucial relational meaning: increments are relative to current values rather than absolute overwrites, and expiration falls back to now if absent/passed. The required username is left undescribed, but its pattern makes it self-evident.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names the resource (a user subscription), the action (renews/extend), and the exact semantics (adds relative duration and/or data). It also explicitly distinguishes the tool from marzban_users_update, so an agent can tell them apart without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives an explicit when-to-use rule: 'Use this instead of marzban_users_update for renewals,' and explains why — it reads current expiration/limit first so the increment is relative rather than an absolute overwrite. This clearly routes the agent away from the closest sibling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_getGet userA
Read-only

Fetches one user by username, with a computed summary: data left, days left, usage percent, and whether they are effectively expired (covers the case where status has not caught up with an already-past expire yet).

ParametersJSON Schema
NameRequiredDescriptionDefault
usernameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
userYes
summaryYes

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds meaningful behavioral context beyond that, including the computed summary fields and the nuance about 'effectively expired' covering status lag.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the core action and resource, followed by the key computed output details. There is no filler or redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple, has one well-constrained parameter, an output schema, and annotations covering read-only safety. The description adds the only extra context an agent might need, namely the computed summary semantics, making it complete for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The description only restates that the user is fetched by username, which adds little beyond the input schema's property name. Since schema description coverage is 0%, the description was expected to compensate by explaining parameter meaning or matching behavior, but it does not.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb ('Fetches'), a specific resource ('one user by username'), and adds the distinguishing computed summary details, which clearly sets it apart from sibling tools like marzban_users_list that handle multiple users. It is not a tautology of the title.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'one user by username' gives clear context that this tool is for single-user lookup rather than listing or mutating users. However, it does not explicitly name alternatives or state when not to use this tool, relying on the sibling-tool names to imply the distinction.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_holdPut user on holdA

Sets a user's status to on_hold — inactive until their first connection, at which point the on-hold timer starts. Useful for provisioning an account ahead of time without starting its clock.

ParametersJSON Schema
NameRequiredDescriptionDefault
usernameYes
onHoldExpireDurationNoSeconds the user may stay on_hold before expiring, counted from their first connection.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
adminNo
linksNo
expireNo
statusYes
proxiesYes
inboundsNo
usernameYes
next_planNo
online_atNo
created_atYes
data_limitNodata_limit can be 0 or greater
used_trafficYes
sub_updated_atNo
on_hold_timeoutNo
subscription_urlNo
excluded_inboundsNo
auto_delete_in_daysNo
sub_last_user_agentNo
lifetime_used_trafficNo
on_hold_expire_durationNo
data_limit_reset_strategyNo

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds meaningful behavioral context beyond the annotations: it explains the on_hold state transition and the first-connection timer trigger. It doesn't cover reversibility or what happens when the timer expires, but the core behavior is transparent.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two front-loaded sentences with no filler. The core state change comes first, followed by the use case.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the state change and use case, but leaves an important gap: onHoldExpireDuration is optional and the description does not state what happens when it is omitted (e.g., default hold behavior or no expiry). Output schema covers return values, so that is not a concern.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema already documents onHoldExpireDuration, and the description reinforces its timing semantics. Username has no schema description and is not elaborated, though its role is obvious from the tool name and 'a user's status'. Overall only marginal added meaning beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Sets'), a resource ('a user's status'), and the precise semantic (on_hold, inactive until first connection, then timer starts). This clearly distinguishes it from sibling tools like activate/deactivate, which target different user states.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear use case: provisioning an account ahead of time without starting its clock. It does not explicitly name alternatives or when-not-to-use, so it stops short of a full routing rule.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_listList usersA
Read-only

Lists users, optionally filtered by status or a search term (matches username/note). Paginated — default 25, max 100 per call; prefer search over paging through everyone. For one known username, use marzban_users_get instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNoDefault 25, max 100.
offsetNo
searchNoMatches username or note (server-side substring search).
statusNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteYes
totalYes
usersYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover readOnlyHint=true and destructiveHint=false. The description adds pagination defaults (25, max 100) and clarifies that search matches username/note, which is beyond the annotations. It does not detail the response envelope or error behavior, but the output schema exists, so a 4 is appropriate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with zero filler: purpose, filter options, pagination limits, and routing to the sibling. The most critical information (what the tool lists and its filters) is front-loaded, and every clause contributes.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only list tool with an output schema, annotations covering safety, and clear sibling differentiation, the description supplies all needed operational context: filtering, pagination, and search guidance. Nothing an agent needs to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 50% (limit and search have descriptions). The description reinforces these and adds the pagination preference, but it adds little for offset (no semantics) and status (only says 'optionally filtered', enum is in schema). It partially compensates for the coverage gap but does not fully explain each parameter's role.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a clear verb+resource ('Lists users') and immediately specifies the filtering options (status, search term). It explicitly differentiates from the sibling marzban_users_get by noting the single-user alternative, so an agent can reliably pick the right tool without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete guidance on when to prefer search over paging ('prefer `search` over paging through everyone') and names the exact alternative for a known username ('use marzban_users_get instead'). This is explicit when-to-use and when-not-to-use guidance with a sibling reference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_updateUpdate userA

Partially updates a user — only fields you provide are changed, everything else is left as-is. For status changes prefer marzban_users_activate/deactivate/hold (clearer intent, no need to know the raw status enum). For renewing an expiring/expired user prefer marzban_users_extend.

ParametersJSON Schema
NameRequiredDescriptionDefault
noteNo
expireNoe.g. "30d" or an absolute date. 0 means unlimited.
proxiesNoProtocol name -> settings, e.g. {"vless": {"id": "<uuid>"}} or {"shadowsocks": {}} to auto-generate credentials. Omit to leave unchanged on update. On create there is no server default — omitting this (without templateId) errors; provide at least one protocol with a matching inbound configured on the panel.
inboundsNoProtocol name -> inbound tags to restrict this user to. Omit for all inbounds.
usernameYes
dataLimitNoe.g. "10GB". 0 means unlimited.
dataLimitResetStrategyNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNo
adminNo
linksNo
expireNo
statusYes
proxiesYes
inboundsNo
usernameYes
next_planNo
online_atNo
created_atYes
data_limitNodata_limit can be 0 or greater
used_trafficYes
sub_updated_atNo
on_hold_timeoutNo
subscription_urlNo
excluded_inboundsNo
auto_delete_in_daysNo
sub_last_user_agentNo
lifetime_used_trafficNo
on_hold_expire_durationNo
data_limit_reset_strategyNo

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint=false, destructiveHint=false), the description discloses that updates are partial and non-destructive to omitted fields. It also clarifies that status changes via this tool would require raw enum knowledge, which is useful behavioral context not present in annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: the first states the core behavior, the second and third route to siblings. No filler or repetition of schema details. The most important information is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the critical usage nuance (partial update) and sibling routing for a complex nested-parameter tool. An output schema exists, so return values need no explanation. It does not discuss edge cases like proxy replacement semantics, but the schema's proxy description already covers some of that.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 57%, with descriptions for expire, proxies, inbounds, and dataLimit. The description adds the crucial cross-cutting semantic that all parameters are optional and only provided ones change, but it does not individually clarify note or dataLimitResetStrategy beyond the schema. This is adequate but not fully compensating.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Partially updates a user'. It clearly defines the core behavior (only provided fields are changed) and distinguishes this tool from sibling tools by naming the specialized alternatives for status and renewal operations.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly tells the agent when to prefer marzban_users_activate/deactivate/hold and marzban_users_extend, with reasons. This is direct routing guidance that leaves little to inference and prevents misuse.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

marzban_users_usageGet user traffic usageA
Read-only

Reports how much data a user has used: total, lifetime total, their current limit, and a breakdown by node. start/end (ISO datetimes) narrow the per-node breakdown to a period; omit both for all-time.

ParametersJSON Schema
NameRequiredDescriptionDefault
endNoISO datetime. Omit for no upper bound.
startNoISO datetime. Omit for no lower bound.
usernameYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
byNodeYes
usernameYes
dataLimitYes
usedTrafficYes
lifetimeUsedTrafficYes

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is established. The description adds meaningful behavioral context beyond the annotations: it discloses that the report includes per-node breakdowns and that the breakdown can be filtered by period, which helps the agent set expectations without needing to inspect output structure further.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two tightly written sentences deliver all essential information with no filler. The main purpose is front-loaded, followed immediately by parameter usage guidance, and every clause earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only usage query with an output schema already present, the description covers everything needed to invoke it correctly: what is reported, which parameters affect the report, and what happens when the optional parameters are omitted. No critical behavioral or invocation details are missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema already documents start and end as optional ISO datetimes, covering 67% of parameters, and the description reinforces this with the specific rule 'omit both for all-time.' This adds semantic context about how the two time parameters interact, which is valuable beyond the individual schema descriptions. The username parameter is only constrained by schema pattern, but the description's focus on usage makes its role clear.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Reports') and names the resource ('data a user has used'), then enumerates exactly what is returned: total, lifetime total, current limit, and per-node breakdown. This makes the tool's purpose unmistakable and distinct from sibling tools like marzban_users_get or marzban_users_list, which focus on user configuration rather than traffic statistics.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly explains how to use the optional start/end parameters and explicitly states the all-time behavior when both are omitted. It does not name alternative sibling tools or specify when not to use this tool, but the usage context is evident from the description and the readOnly annotation, so the guidance is adequate.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

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

  1. 9 tool updatesv0.2.3
    • Changedmarzban_subscription_info5 fields changed
      • removedOutput schema / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_activate5 fields changed
      • removedOutput schema / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_create6 fields changed
      • changedInput schema / properties / proxies / description
        Previous value: -"Protocol name -> settings, e.g. {\"vless\": {\"id\": \"<uuid>\"}}. Omit to leave unchanged (update) or use server defaults (create)."New value: +"Protocol name -> settings, e.g. {\"vless\": {\"id\": \"<uuid>\"}} or {\"shadowsocks\": {}} to auto-generate credentials. Omit to leave unchanged on update. On create there is no server default — omitting this (without templateId) errors; provide at least one protocol with a matching inbound configured on the panel."
      • removedOutput schema / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_deactivate5 fields changed
      • removedOutput schema / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_extend5 fields changed
      • removedOutput schema / properties / user / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / user / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / user / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / user / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / user / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_get5 fields changed
      • removedOutput schema / properties / user / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / user / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / user / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / user / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / user / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_hold5 fields changed
      • removedOutput schema / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_list5 fields changed
      • removedOutput schema / properties / users / items / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / users / items / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / users / items / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / users / items / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / users / items / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
    • Changedmarzban_users_update6 fields changed
      • changedInput schema / properties / proxies / description
        Previous value: -"Protocol name -> settings, e.g. {\"vless\": {\"id\": \"<uuid>\"}}. Omit to leave unchanged (update) or use server defaults (create)."New value: +"Protocol name -> settings, e.g. {\"vless\": {\"id\": \"<uuid>\"}} or {\"shadowsocks\": {}} to auto-generate credentials. Omit to leave unchanged on update. On create there is no server default — omitting this (without templateId) errors; provide at least one protocol with a matching inbound configured on the panel."
      • removedOutput schema / properties / created_at / format
        Removed value: -"date-time"
      • removedOutput schema / properties / created_at / pattern
        Removed value: -"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$"
      • changedOutput schema / properties / on_hold_timeout / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / online_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • changedOutput schema / properties / sub_updated_at / anyOf
        Previous value: -[
        -  {
        -    "anyOf": [
        -      {
        -        "format": "date-time",
        -        "pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|))$",
        -        "type": "string"
        -      },
        -      {
        -        "type": "null"
        -      }
        -    ]
        -  },
        -  {
        -    "type": "null"
        -  }
        -]New value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
  2. 15 tool updatesv0.2.2
    • First observedmarzban_config_get
    • First observedmarzban_hosts_get
    • First observedmarzban_nodes_list
    • First observedmarzban_subscription_info
    • First observedmarzban_system_inbounds
    • First observedmarzban_system_stats
    • First observedmarzban_users_activate
    • First observedmarzban_users_create
    • First observedmarzban_users_deactivate
    • First observedmarzban_users_extend
    • First observedmarzban_users_get
    • First observedmarzban_users_hold
    • First observedmarzban_users_list
    • First observedmarzban_users_update
    • First observedmarzban_users_usage

TDQS

A3.9/5.0

Scored across 15 tools

Disambiguation4/5

Most tools have clearly distinct purposes, especially across user actions and system views. The descriptions explicitly disambiguate users_get vs users_list vs subscription_info and config_get vs hosts_get vs system_inbounds, though hosts_get and system_inbounds could still cause mild confusion.

Naming Consistency4/5

The dominant pattern is marzban_<resource>_<verb>, e.g. users_create, users_get, hosts_get, nodes_list. A few tools break this pattern—subscription_info, system_inbounds, system_stats, users_usage—but the naming remains predictable and readable overall.

Tool Count5/5

At 15 tools, the set is at the upper end of the well-scoped range but still feels justified for a panel administration server. Each tool covers a meaningful operation, and the many user-management tools map to distinct lifecycle actions.

Completeness3/5

The set covers user creation, retrieval, update, status changes, renewal, usage, subscription diagnosis, nodes, config, inbounds, and system stats. However, there is no delete-user tool, and no obvious way to generate or reset a subscription URL, leaving clear lifecycle gaps.

Maintenance

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers