npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@alexbuzo/dzengi-mcp

v0.1.1

Published

Safe Dzengi MCP server for read-only and explicitly guarded trading workflows

Readme

@alexbuzo/dzengi-mcp

Safe, local Model Context Protocol (MCP) access to Dzengi market, account, order, and position data. Trading tools are separate, explicitly guarded mutations; the server is read-only until its policy gates are enabled.

Financial-risk warning: trading digital assets and leveraged products can lose money quickly, including more than the amount initially committed. This package is infrastructure, not investment advice or a trading strategy. Review every order, account, symbol, quantity, price, leverage, and stop value yourself. Start with demo and read-only API keys. Never give an agent more permission than you can afford to use.

1. Scope and safety boundary

The package runs a Node.js 20+ stdio MCP server against the official Dzengi REST adapter. It exposes curated typed tools, not an arbitrary HTTP proxy. Public market reads work without credentials; signed account reads and every mutation require credentials at call time. dzengi_list_instruments reads the public exchangeInfo catalog without credentials, but automatically uses the account-scoped catalog when both DZENGI_API_KEY and DZENGI_API_SECRET are configured. Supplying only one credential keeps this read fully public and never sends a partial credential pair.

The server does not implement withdrawals, deposits, transfers, funding, or account-management operations. It cannot move funds. An account response may contain broker metadata such as canWithdraw or canDeposit, but those flags do not add a funding tool to this server. It also does not run a trading strategy, store credentials remotely, or maintain WebSocket subscriptions.

Stdout is reserved for MCP protocol frames. Startup and audit diagnostics go to stderr, and secrets, signatures, authorization headers, and complete signed URLs are redacted. Successful tool results are recursively sanitized and bounded to 1 MiB of UTF-8 JSON; an oversized result is returned as a safe validation error instead of a partial response.

Broker HTTP response bodies are separately bounded to 2 MiB of decompressed bytes before JSON parsing. An oversized or malformed read is returned as a safe HTTP error; a dispatched mutation is reported as having an unknown outcome and is never retried.

The transport rejects redirects (redirect: "error") for every broker request, so an API key or signed query cannot be forwarded to another origin. A read redirect is a safe HTTP failure; a redirect rejection after mutation dispatch is an unknown outcome that requires reconciliation. Swagger's cancel endpoints may return 204 No Content, which is accepted as an empty success result; other empty 2xx responses remain malformed.

2. Install from npm or source

The npm package name is @alexbuzo/dzengi-mcp and its executable is dzengi-mcp. Run the package from an environment that supplies configuration through environment variables:

npx -y @alexbuzo/[email protected]

Run this published-package command outside the source checkout. Inside a checkout with the same package name and version, npm can select the local package without installing its executable, producing dzengi-mcp: command not found. Set the MCP launcher's working directory to a neutral directory, or use the source-checkout commands below. After changing source code, rebuild and launch node /absolute/path/to/dzengi-mcp/dist/index.js to use those changes; an npx command pinned to a published version still runs that published version.

For a source checkout:

git clone https://github.com/abuzo/DzengiMcp.git dzengi-mcp
cd dzengi-mcp
npm ci
cp .env.example .env
npm run build
npm start

.env is for local development only and is ignored by Git. Do not commit it, paste credentials into this README, or put secrets in a Codex TOML file.

The default environment is the official demo adapter at https://demo-api-adapter.dzengi.com with API v1. Live uses https://api-adapter.dzengi.com; demo API v2 is rejected by configuration.

3. Create a restricted Dzengi API key

Follow Dzengi's API Get Started guide: sign in, open Settings > API integrations > Generate new key, enable 2FA, set permissions, bind an IP address, and set an expiration date.

Use separate keys for demo and live. Begin with the smallest read-only permissions needed for market/account inspection. Add trade permission only after the demo workflow is understood. Disable withdrawal, deposit, transfer, or other funding permissions if the Dzengi account UI offers them; this server does not need them. Bind the key to the narrowest stable egress IP, enable 2FA on the account, set a short expiration, and record the expiry owner and date. Keep the API secret in an environment manager or OS keychain, never in source, shell history, logs, screenshots, tool arguments, or a Codex configuration value. Rotate and revoke keys on the schedule in section 10.

4. Start with demo, read-only

The safe baseline is:

DZENGI_ENV=demo
DZENGI_API_VERSION=1
DZENGI_ALLOW_TRADE=false
DZENGI_ALLOW_LIVE_TRADING=false
DZENGI_REQUIRE_CONFIRMATION=true
DZENGI_MAX_LEVERAGE=1

Credentials are not needed for public reads. After building from source, check the executable and protocol boundary without contacting a trading endpoint:

npm run build
npm run verify:stdio

Use dzengi_get_runtime_status, dzengi_get_server_time, dzengi_list_instruments, and dzengi_get_ticker first. Signed account reads will return AUTH_REQUIRED until both credential variables are supplied. With the baseline gates, all six mutation tools remain denied even if a client asks for confirm: true.

5. Configure Codex without embedding values

Codex forwards the names below from the environment in which it starts the server. The TOML contains names, not API keys or secrets:

[mcp_servers.dzengi]
command = "npx"
args = ["-y", "@alexbuzo/[email protected]"]
env_vars = [
  "DZENGI_ENV",
  "DZENGI_API_KEY",
  "DZENGI_API_SECRET",
  "DZENGI_ALLOW_TRADE",
  "DZENGI_ALLOW_LIVE_TRADING",
  "DZENGI_MAX_ORDER_NOTIONAL",
  "DZENGI_MAX_LEVERAGE",
  "DZENGI_ALLOWED_SYMBOLS"
]
default_tools_approval_mode = "writes"

This follows the Codex MCP configuration guide. Set the forwarded values in the local process environment or your approved secret manager. Codex approvals are a client-side safety layer; the server's trade flags, confirmation requirement, allowlist, notional limit, leverage limit, and live dual gate remain authoritative. A stricter per-tool approval policy is encouraged for new deployments.

Configuration reference

All names below are read by loadConfig; blank optional values are omitted.

| Variable | Default / accepted values | Purpose | | --- | --- | --- | | DZENGI_ENV | demo or live (default demo) | Selects the official adapter host. | | DZENGI_API_VERSION | 1 or 2; defaults to 1 for demo and 2 for live | Demo v2 is rejected. | | DZENGI_API_KEY | blank | Signed-request key; public reads do not need it. | | DZENGI_API_SECRET | blank | HMAC secret; never returned in status or errors. | | DZENGI_ALLOW_TRADE | false (strict true/false) | Master mutation gate. | | DZENGI_ALLOW_LIVE_TRADING | false (strict true/false) | Required in addition to the master gate for live. | | DZENGI_REQUIRE_CONFIRMATION | true (strict true/false) | Requires confirm: true on every mutation; live trading enforces true at startup. | | DZENGI_MAX_ORDER_NOTIONAL | blank or positive plain decimal | Maximum order notional; mandatory when live trading is enabled. | | DZENGI_MAX_LEVERAGE | 1, up to 1000 | Maximum requested leverage. | | DZENGI_ALLOWED_SYMBOLS | blank or comma-separated symbols | Optional trimmed, case-sensitive allowlist; copy symbols exactly from dzengi_list_instruments, including case and punctuation. | | DZENGI_RECV_WINDOW_MS | 5000, integer 1..60000 | Signed request timing window. | | DZENGI_TIMEOUT_MS | 10000, integer 100..120000 | HTTP timeout. | | DZENGI_READ_RETRIES | 2, integer 0..5 | Bounded retries for transient reads only. | | DZENGI_BASE_URL | blank (derived from DZENGI_ENV) | Official host override; custom hosts require the next flag. Signed reads and mutations send the API key and HMAC signature to the configured host. | | DZENGI_ALLOW_CUSTOM_BASE_URL | false (strict true/false) | Explicitly permits a non-official, fully trusted host. Custom non-loopback hosts must use HTTPS. | | DZENGI_AUDIT_LOG_PATH | blank | Optional append-only JSONL mutation audit path; it must resolve to a regular file (stdout/stderr descriptor aliases and special files are rejected), and newly created files use mode 600. | | DZENGI_LOG_LEVEL | info; debug, info, warn, or error | Secret-free stderr verbosity. |

DZENGI_LOG_LEVEL controls lifecycle information only: debug and info show startup information, while warn and error suppress it. Startup and shutdown errors always remain on stderr. Mutation audit events are independent of this filter and continue to be emitted to stderr and the configured audit file when enabled. Runtime status reports only whether audit logging is enabled; it never returns the configured local audit path. Its baseUrl status is the configured endpoint origin only; endpoint paths are not returned.

Only set DZENGI_BASE_URL to an endpoint you fully trust: signed reads and every mutation send X-MBX-APIKEY and a query HMAC signature to that host. Keep the default official host unless a trusted test or gateway endpoint is required.

Changing any environment value, especially either trade flag, takes effect only after the MCP process is restarted because configuration is loaded once.

6. Tool catalog

There are exactly 22 curated tools. Read tools have read-only MCP annotations; mutations have destructive/write annotations and always require a caller-owned clientRequestId plus a boolean confirm field.

Read-only market and runtime tools

| Tool | What it does | | --- | --- | | dzengi_get_runtime_status | Reports environment, API version, configured endpoint origin, gates, limits, credential-presence booleans, and the audit-enabled flag; it never exposes endpoint paths or the local audit path. | | dzengi_get_server_time | Reads server time and refreshes the local clock offset. | | dzengi_list_instruments | Reads account-scoped exchangeInfo when both credentials are configured, otherwise public exchangeInfo, with bounded local pagination (offset, limit). | | dzengi_get_ticker | Reads an optional-symbol 24-hour ticker. | | dzengi_get_order_book | Reads bounded depth for a required symbol and optional limit. | | dzengi_get_candles | Reads bounded candles for symbol, interval, and optional time/price filters. | | dzengi_get_trading_fees | Reads optional-symbol fee information. | | dzengi_get_trading_limits | Reads optional-symbol broker limits. | | dzengi_get_leverage_settings | Reads signed leverage settings for an exact symbol whose marketType is LEVERAGE. A rejected request for a known SPOT instrument returns a descriptive validation error; symbols are never converted. |

Read-only account and lifecycle tools

| Tool | What it does | | --- | --- | | dzengi_get_account | Reads signed account permissions and balances; optional showZeroBalance. | | dzengi_list_open_orders | Reads open orders, optionally filtered by symbol. | | dzengi_get_order | Reads a signed order by required symbol and orderId. | | dzengi_list_positions | Reads current leverage positions. | | dzengi_list_trades | Reads bounded signed trades for required symbol and optional time/limit filters. | | dzengi_list_position_history | Reads bounded position history with optional symbol, from, to, and limit. | | dzengi_preflight_order | Validates a proposed order against current metadata and policy without placing it. |

Guarded mutation tools

| Tool | Financial operation and additional fields | | --- | --- | | dzengi_place_order | Places a MARKET, LIMIT, or STOP order. Required: symbol, type, side, quantity; optional: price, accountId, leverage, expireTimestamp, newOrderRespType, stopLoss, takeProfit, stopDistance, profitDistance, trailingStopLoss, guaranteedStopLoss. | | dzengi_cancel_order | Cancels by required symbol and orderId; it never assumes USD. | | dzengi_edit_order | Edits an exchange order by required safety-only symbol and orderId; provide price and/or expireTimestamp. | | dzengi_update_order | Updates a leverage order by required safety-only symbol and orderId; provide at least one of newPrice, expireTimestamp, stopLoss, takeProfit, stopDistance, profitDistance, trailingStopLoss, or guaranteedStopLoss. | | dzengi_close_position | Closes a leverage position by required safety-only symbol and positionId. | | dzengi_update_position | Updates position protection by required safety-only symbol and positionId; provide at least one stop/protection field. |

Every mutation is sent at most once by the transport. An ID must never be reused: while an entry remains in the bounded in-memory cache (up to 24 hours and 1,024 completed entries), an identical request replays and a different financial payload is rejected. Restart, TTL expiry, or capacity eviction removes that local protection, so callers must reconcile before any new request.

Lifecycle mutations use symbol for allowlist and signed ownership checks, then omit it from the broker mutation payload. The signed order lookup is already scoped by the exact {symbol, orderId} query, so a single matching order record may omit symbol; explicit mismatches and ambiguous records still fail closed. Position records must include the exact symbol. Order edits with a replacement price also re-check the associated quantity against the configured notional cap. Use the exact canonical symbol, including case and punctuation, returned by dzengi_list_instruments for all symbol-bearing tools.

7. Enable demo mutations deliberately

Only do this with a demo account after the read-only checks pass. Replace every REPLACE_WITH_... value; these are intentionally fake placeholders, not credentials or live symbols:

export DZENGI_ENV=demo
export DZENGI_API_VERSION=1
export DZENGI_API_KEY=REPLACE_WITH_DEMO_API_KEY
export DZENGI_API_SECRET=REPLACE_WITH_DEMO_API_SECRET
export DZENGI_ALLOW_TRADE=true
export DZENGI_ALLOW_LIVE_TRADING=false
export DZENGI_REQUIRE_CONFIRMATION=true
export DZENGI_MAX_ORDER_NOTIONAL=10
export DZENGI_MAX_LEVERAGE=1
export DZENGI_ALLOWED_SYMBOLS=REPLACE_WITH_DEMO_SYMBOL
npm run build
npm start

The server still requires confirm: true on each mutation and a new clientRequestId. Keep the notional and allowlist as small as practical. A demo key should have no funding permission and should be bound and expired like a live key.

8. Enable live mutations only with all gates

Live trading requires every item below at startup:

  1. DZENGI_ENV=live and a live API key/secret;
  2. DZENGI_ALLOW_TRADE=true;
  3. DZENGI_ALLOW_LIVE_TRADING=true;
  4. a positive DZENGI_MAX_ORDER_NOTIONAL;
  5. a deliberate DZENGI_MAX_LEVERAGE and, preferably, a narrow DZENGI_ALLOWED_SYMBOLS list;
  6. DZENGI_REQUIRE_CONFIRMATION=true (enforced at startup) and confirm: true per mutation; and
  7. Codex write approval enabled for the client session.

Example shape, with deliberately fake credential placeholders:

export DZENGI_ENV=live
export DZENGI_API_VERSION=2
export DZENGI_API_KEY=REPLACE_WITH_LIVE_API_KEY
export DZENGI_API_SECRET=REPLACE_WITH_LIVE_API_SECRET
export DZENGI_ALLOW_TRADE=true
export DZENGI_ALLOW_LIVE_TRADING=true
export DZENGI_REQUIRE_CONFIRMATION=true
export DZENGI_MAX_ORDER_NOTIONAL=10
export DZENGI_MAX_LEVERAGE=1
export DZENGI_ALLOWED_SYMBOLS=REPLACE_WITH_LIVE_SYMBOL
npm run build
npm start

The example limit is not a recommendation; choose a limit appropriate to the account and risk policy. Configuration rejects live trading without DZENGI_MAX_ORDER_NOTIONAL. Restart after every gate or credential change, then inspect dzengi_get_runtime_status before considering a write.

DZENGI_MAX_ORDER_NOTIONAL is measured in quote currency as quantity × limit or stop price (or the current market reference price for a market order). It is a pre-dispatch cap, not a guarantee against execution price or slippage.

9. Preflight, place, and reconcile

Dzengi's native exchangeInfo reports the price increment in top-level tickSize and may omit minPrice/maxPrice entirely. Preflight checks this increment without treating absent optional price bounds as an API error. Declared but incomplete price filters and malformed explicit bounds still produce warnings. Quantity filters, broker minimum notional, configured caps, and confirmation requirements continue to apply independently.

Use an obviously fake symbol in documentation examples and replace it only with a symbol returned by dzengi_list_instruments:

{
  "tool": "dzengi_preflight_order",
  "arguments": {
    "symbol": "REPLACE_WITH_DEMO_SYMBOL",
    "type": "LIMIT",
    "side": "BUY",
    "quantity": "0.01",
    "price": "1.00",
    "confirm": true
  }
}

Placement must consume a fresh report with allowed: true. The mutation adds the explicit confirmation and a new request ID; it is not a shell command and must be issued through the MCP client:

{
  "tool": "dzengi_place_order",
  "arguments": {
    "clientRequestId": "REPLACE_WITH_NEW_UUID",
    "confirm": true,
    "symbol": "REPLACE_WITH_DEMO_SYMBOL",
    "type": "LIMIT",
    "side": "BUY",
    "quantity": "0.01",
    "price": "1.00"
  }
}

An order mutation can cross the broker boundary before a timeout, network failure, malformed response, or HTTP 5xx is observed. The server then returns MUTATION_OUTCOME_UNKNOWN with reconciliation guidance. Do not retry the mutation. Inspect, in order as applicable:

  • dzengi_list_open_orders for the symbol;
  • dzengi_get_order with the known symbol and orderId;
  • dzengi_list_trades for fills; and
  • dzengi_list_positions for position state.

On the same running process, repeating the identical clientRequestId returns the cached unknown result without dispatching again. A different financial payload under that ID is rejected. The local guard is memory-only: it does not survive a process restart and is not a broker idempotency guarantee. Never reuse a mutation ID after restart; reconcile broker state first and choose a new ID only for a deliberately new action.

10. Emergency disablement and credential rotation

The emergency kill switch is to set both trade gates false and restart the process:

export DZENGI_ALLOW_TRADE=false
export DZENGI_ALLOW_LIVE_TRADING=false
npm start

Stop the existing process first (Ctrl-C for a foreground process). Changing the variables without restarting does not change the active policy. Verify dzengi_get_runtime_status shows both gates disabled. If a key may have been exposed, revoke it in Dzengi immediately; do not rely on the process restart alone.

For rotation, generate a new key with the same least-privilege permissions, IP binding, 2FA, and expiry policy; update the external secret store or local environment; restart; run a public read and (if appropriate) a signed read; then revoke the old key. Never print either value while checking the change.

Audit file operations

DZENGI_AUDIT_LOG_PATH is optional. When set, the server appends one secret-free JSONL start/terminal pair per mutation attempt; it does not persist ordinary read responses or unrestricted broker payloads. Treat the file as sensitive operational data even though credentials and signatures are redacted. Create an owner-only directory and file before starting the server:

umask 077
install -d -m 700 /var/lib/dzengi-mcp/audit
touch /var/lib/dzengi-mcp/audit/mutations.jsonl
chmod 600 /var/lib/dzengi-mcp/audit/mutations.jsonl
export DZENGI_AUDIT_LOG_PATH=/var/lib/dzengi-mcp/audit/mutations.jsonl

The writer is append-only at the application level. The configured path is read once at startup, while each event opens the configured path for an append; the process does not automatically follow a renamed rotation target. To rotate safely, stop the server (and let any in-flight write finish), move the old file to an owner-only archive, create a new 600 file, update DZENGI_AUDIT_LOG_PATH, and restart. Verify the new process's runtime status and that a deliberately chosen test mutation/readiness check writes to the new path; never use a live trade as a logging test. Set an operator-owned retention period, protect backups, and use the organization's approved secure-deletion procedure when records expire. Audit files are local state and must never be committed, included in an npm tarball, or shipped to a support ticket without redaction.

Rollback to a known-good release

Select a previously verified package version and pin it instead of relying on latest. For example, the Codex entry can temporarily use an owner-approved version tag:

[mcp_servers.dzengi]
command = "npx"
args = ["-y", "@alexbuzo/[email protected]"]

Stop the existing MCP process or supervisor unit, restore the known-good environment file and safety gates (start with both trade gates false), and restart the pinned version. Verify dzengi_get_runtime_status, then a public read such as dzengi_get_server_time; perform dzengi_get_account only when a signed read is appropriate and credentials have been checked independently. Do not use a mutation to validate a rollback. If compromise is possible, revoke the affected key, issue a replacement with the same least-privilege/IP/ 2FA/expiry policy, update the secret store, and restart again. npm publication and version promotion remain manual owner actions.

11. Errors and unknown outcomes

MCP failures are structured and set isError: true; the text and structured representations contain the same safe error projection. The stable codes are:

| Code | Meaning | | --- | --- | | CONFIG_ERROR | Invalid environment, unsupported API version, unsafe host, or missing live limit. | | VALIDATION_ERROR | Tool input, precision, required-field, account-selection, or preflight validation failed. | | POLICY_DENIED | Trade gate, live gate, confirmation, symbol allowlist, notional, or leverage policy denied the mutation. | | AUTH_REQUIRED | A signed read or mutation was requested without both credentials. | | RATE_LIMITED | Broker or local pacing rejected the request; read retries remain bounded. | | DZENGI_HTTP_ERROR | A non-success HTTP response or transport failure was classified as an HTTP error. | | DZENGI_API_ERROR | Dzengi returned a non-success API envelope or malformed success payload. | | MUTATION_OUTCOME_UNKNOWN | A dispatched mutation may have succeeded; reconcile before any new action. |

Only idempotent reads retry bounded transient statuses (408, 429, 500, 502, 503, 504). Writes are never automatically retried, including after timestamp, timeout, network, malformed-response, or 5xx failures. The shared limiter stays below Dzengi's documented 10 requests/second limit and applies a separate margin for openOrders.

12. Development, tests, and owner release commands

Requirements: Node.js 20 or newer and npm. The offline development gate is:

npm ci
npm test
npm run typecheck
npm run lint
npm run build
npm run verify:stdio
npm run verify:pack

npm run verify runs the test, type, lint, build, stdio, and package gates in one command. npm run dev runs the TypeScript entry point for local work; npm run clean removes dist. npm run update:openapi refreshes the checked- in official Swagger snapshot and npm run check:openapi checks for drift; both are maintainer commands that need network access and their source snapshots are not shipped in the npm payload. npm run format formats the repository.

Before an owner release, inspect the dry-run package and then use the existing owner npm commands:

npm pack --dry-run
npm publish --access public

This repository's Task 11 verification does not publish. The package's prepack build and prepublishOnly test/type/lint/build hooks provide an additional release guard; npm run verify:pack invokes dry-run packing with --ignore-scripts so the verifier cannot recursively invoke those hooks.

13. Official documentation

When broker behavior and this README differ, verify the official Dzengi documentation and the checked-in Swagger snapshot before changing a limit or endpoint. The package intentionally favors a fail-closed result over guessing.