@odatano/nightgate-mcp
OfficialServer Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| NIGHTGATE_TOKEN | No | Agent-grant token (ngat_...) or plain bearer token | |
| NIGHTGATE_BASE_URL | No | NIGHTGATE host app | http://localhost:4004 |
| NIGHTGATE_PASSWORD | No | Basic auth password | |
| NIGHTGATE_USERNAME | No | Basic auth username | |
| NIGHTGATE_TIMEOUT_MS | No | Per-request timeout | 30000 |
| NIGHTGATE_SERVICE_PATH | No | OData service path | /api/v1/nightgate |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| verify_attestationA | Verify against LIVE Midnight contract state that an attester's record of a payload hash stands in an AttestationVault (crawler-free, no txHash needed). A record is ONE attester's attestation of ONE payload (ledger key recordKey(attesterId, payloadHash)): name it by attesterId + payloadHash, or by a bound documentId, which resolves to exactly one record and reveals its attester. Optionally also checks that the anchored content root / schema id match. Returns verified:false (not an error) when absent; the result carries attesterId, payloadHash, recordKey and documentId. bindingRegistered is only about documentId lookups: true when the vault registrar assigned that id to this attester. A record anchored without a document id reports false, and that is fine. Free: it reads the public verify service. |
| verify_predicateA | Verify against LIVE Midnight contract state that a ZK claim was recorded true on-chain. Id-free: works for proofs NIGHTGATE never saw. Numeric predicates (lessOrEqual / greaterOrEqual) need threshold (the SAME scaled integer the circuit hashed; a scaling mismatch yields verified:false) and optionally fieldKey for field-bound proofs. bytesEquality needs fieldKey + expectedDigest; setMembership needs fieldKey + setRoot (recompute it from the published list via prepare_membership_set). Every claim is bound to ONE attester's record of the document, so attesterId is part of the coordinates. Free: it reads the public verify service. |
| prepare_document_proofA | Turn a structured document into everything the proof tools need: canonical JSON and its payloadHash (what anchor_document anchors), a Merkle contentRoot over an ORDERED list of up to 16 proof fields, and per-field inclusion paths ready for the proveField* calls of submit_vault_call. kind "uint" (default) scales a numeric value; kind "bytes" (NIGHTGATE >= 0.16.0) enters a STRING field as the digest of the exact string, feeding the equality/membership proofs. Keep the field order stable across anchor and proof: it is part of the tree identity. Compute-only and synchronous, nothing is stored server-side. Leaves are SALTED: the response carries a per-field |
| prepare_membership_setA | Build the canonical depth-6 membership-set tree over a public allow-list (NIGHTGATE >= 0.16.0). Deterministic rule (digest each exact string, dedupe, sort ascending, pad by repeating the last member digest), so ANYONE recomputes the same setRoot from the published list alone: use the root to verify_predicate a setMembership claim. With value/valueDigest it additionally returns the member inclusion path (witness material, treat as sensitive); a non-member is a clean 400. Compute-only and synchronous. |
| anchor_documentA | Anchor a document hash on Midnight in one call: builds the attest transaction here with the caller seed, a sponsor pays the fee, and the tool waits until it landed (about 1 to 2 minutes; the first call also downloads the prover keys). The record belongs to this seed (attesterId). Only the hash and the hash of the metadata go on-chain; keep the document yourself. With contentRoot and schemaId from prepare_document_proof it also anchors the content root, which the field claims of submit_vault_call need. Returns { status, attesterId, payloadHash, contractAddress, metadataJson, txHash, transactionHash, timings, check }; check is the verify_attestation call that shows the record on-chain. If the call was cut off or came back pending, run it again with the same arguments: it picks up the job it started and submits nothing new (the answer says deduplicated). A second, separate call with the same arguments needs a new idempotencyKey. |
| submit_vault_callA | Run any AttestationVault call in one go: build, prove and sign it here with the caller seed, a sponsor pays, and the tool waits until it landed. Same calls and params as build_sponsorable_transaction: the ZK claims over a hidden field (proveFieldPredicate, proveFieldEquality, proveFieldMembership), the claims across two documents (proveFieldsUnchangedExcept, proveFieldsDiffer), disclosure (grantDisclosure, revokeDisclosure), passports and anchoring. The witness from prepare_document_proof is used here and never sent. Returns { status, attesterId, contractAddress, txHash, transactionHash, timings, check }; check is the free verify call that shows the effect on-chain. A failed job says in |
| build_sponsorable_transactionA | Build, prove and sign an AttestationVault call LOCALLY and hand back the bytes, for a sponsor on another server or a later hand-over; submit_vault_call does build and submit in one go. The caller seed (NIGHTGATE_SEED_HEX, else the seed file) stays here, the attestation secret is derived from it, nothing secret leaves this machine. The fee-unpaid transaction stays in this process under the returned txId (its sha256; characters and bytes alongside), or is written to outFile: UNBOUND by default (hand the txId to sponsor_unbound_transaction, parallel channel) or bound with bind:true (sponsor_finalized_transaction). The on-chain effect carries the attester id of THIS builder (returned). Proving takes 20-60 s in-process (the first call also fetches the prover keys from the NIGHTGATE /zk-config); NIGHTGATE_PROOF_SERVER_URL switches to a proof server. Needs @odatano/nightgate-tx installed next to the MCP server. params by call: attest {payloadHash, metadataHash}; anchorContentRoot {payloadHash, contentRoot, schemaId}; grantDisclosure {payloadHash, grantee, level 0|1|2}; revokeDisclosure {payloadHash, grantee}; registerPassport {passportId, ownerId}; bindPassport {passportId, payloadHash}. The owner-gated calls address THIS builder's own record of the payload (the circuit derives recordKey(attesterId, payloadHash) from the caller). ZK CLAIMS, proven here with no wallet on the server and no witness ever sent to it, address a record explicitly: pass payloadHash (this builder's record) or payloadHash + attesterId (another attester's record) or recordKey directly: proveFieldPredicate {payloadHash, fieldKey, threshold, op 0=lessOrEqual|1=greaterOrEqual} plus merkleProof {fieldValue, fieldSalt, siblings, dirs}; proveFieldEquality {payloadHash, fieldKey, expectedDigest} plus merkleProof {fieldSalt, siblings, dirs}; proveFieldMembership {payloadHash, fieldKey, setRoot} plus merkleProof {fieldDigest, fieldSalt, siblings, dirs, setProof}; proveFieldsUnchangedExcept {payloadHashA, payloadHashB, allowedMask} and proveFieldsDiffer {payloadHashA, payloadHashB, k} (optionally attesterIdA / attesterIdB, or recordKeyA / recordKeyB), both plus docPair {schema, openingA, openingB}. Every witness field comes straight out of prepare_document_proof. All hashes 64 hex. The built bytes are valid for the transaction TTL (~30 min) and against the contract state at build time: if the sponsor job ends CHAIN_EXECUTION_FAILED, build again. |
| get_attester_identityA | The attester id this MCP server builds under (derived from the caller seed via the txbuilder), plus the network, the shielded address and the two public shielded keys (what a sender needs to create a coin for this wallet). Use it to check verify_attestation results against the identity that will appear on-chain; builds nothing and submits nothing. |
| sponsor_finalized_transactionA | Cross-server fee sponsoring, phase 2 (NIGHTGATE 0.17.0): submit a FINALIZED, fee-unpaid transaction that was built, proven and signed elsewhere (e.g. with the @odatano/nightgate-tx txbuilder, so the caller's key never left its machine). The sponsor session pays the dust; the on-chain effect carries the BUILDER's identity, not the sponsor's. The server enforces its contract/circuit allow-list and rejects anything outside it. The transaction expires with its TTL (default 30 min), so hand it over promptly. This is the SERIAL channel (one tx per sponsor wallet at a time); for parallel submission build with bind:false and use sponsor_unbound_transaction. The server picks the wallet that pays. The tool also waits for the block (about a minute more) and then carries the instance's signed receipt; if that wait runs out, receipt is null and the same call again fetches it. The tool waits until the job settled (about 1 minute) and returns { status, txHash, transactionHash, result }. failed: |
| sponsor_unbound_transactionA | Cross-server fee sponsoring, PARALLEL channel (NIGHTGATE 0.18.0): submit an UNBOUND (pre-binding) proven+signed caller transaction, built with the @odatano/nightgate-tx txbuilder's buildSponsorable({ bind: false }) (the caller's key never left its machine). The sponsor locks one free dust backing, merges its dust spend, binds and submits; only the dust build takes the per-wallet lock, so ONE sponsor wallet sponsors N transactions at once (N = its registered dust backings; live: several in the same block). Same allow-list policy and grant surface as sponsor_finalized_transaction; do not mix both channels on one sponsor wallet. Contract state is account-style: two sponsored calls against the SAME contract in one block conflict, the loser lands on-chain but its call does not apply and the job ends failed with errorCode CHAIN_EXECUTION_FAILED (the transaction hash is in the error); then REBUILD the transaction against the current contract state and sponsor again (never resubmit the same bytes). The tool waits until the job settled (about 1 minute) and returns { status, txHash, transactionHash, result }. failed: |
| get_swap_walletA | The shielded wallet this MCP server swaps from (the caller seed): address, public keys, and per token type the balance of the free coins, their number, |
| read_swap_offerA | A swap settles two shielded tokens between two wallets without a contract: each side builds one half (it spends the coin it gives and creates the coin it wants), the two mirrored halves merge into one transaction, and a sponsor pays the fee. This reads what an offer gives and wants FROM THE TRANSACTION it carries, never from what its maker says: gives / wants (token type and amount, from the maker's side), the coins it carries, and whether it is bound. Refuses anything that is not a plain swap half (a contract call, unshielded value, more than one token type given or wanted). Needs no wallet and no network. Check the terms here before take_swap_offer. |
| build_swap_offerA | A swap settles two shielded tokens between two wallets without a contract: each side builds one half (it spends the coin it gives and creates the coin it wants), the two mirrored halves merge into one transaction, and a sponsor pays the fee. This builds and proves ONE half from this server's wallet: it spends |
| take_swap_offerA | A swap settles two shielded tokens between two wallets without a contract: each side builds one half (it spends the coin it gives and creates the coin it wants), the two mirrored halves merge into one transaction, and a sponsor pays the fee. This takes an offer: it reads the offer's terms from the transaction, refuses when they differ from |
| revert_swap_offerA | Release the coins of a swap half this wallet built (build_swap_offer, take_swap_offer or send_token) that is not going to be used. Until then, or until the swap lands, the coins count as spent in this wallet. By id for a half listed by get_swap_wallet, also one restored from an earlier process; by offerId for a board offer this wallet posted, from the board's copy of the half, which works after a restart and needs the offer closed (expired or retired; retire_swap_offer first while it is open). It does not recall an offer somebody already holds: to make a published offer worthless, spend its coins in another swap. A half whose swap landed leaves the list; its coins are spent. |
| sponsor_swapA | A swap settles two shielded tokens between two wallets without a contract: each side builds one half (it spends the coin it gives and creates the coin it wants), the two mirrored halves merge into one transaction, and a sponsor pays the fee. This hands the two halves to the sponsor, which checks them, merges them, pays the dust and submits: each half carries an offer and nothing else, gives exactly one token type and wants exactly one other, both on the sponsor's token allow-list and never NIGHT, at most 4 inputs and 2 outputs per half, and the halves mirror each other in types and amounts. A half may be bound or unbound and is passed as offer file text or base64. Off on a server by default (NIGHTGATE_SPONSOR_ALLOW_SWAPS); an agent grant needs sponsorSwap in its allowedActions. Job result { txHash, transactionHash, swap: { gives, wants } }. An offer fills once: if it was taken first by somebody else the job fails. Pass both halves, or |
| post_swap_offerA | Post a maker half on the server's offer board, so takers find it with list_swap_offers instead of receiving the offer file out of band. The server checks it like a half it would sponsor (one token type given, one wanted, both on its list, never NIGHT) and records its terms; the half itself stays signed by the maker. The offer closes when a swap that spends one of its inputs lands, on expiry, or by retire_swap_offer. Needs postSwapOffer in an agent grant's allowedActions. Returns { offerId, status, terms }. With directed: true only a taker who knows the returned takerSecret can have the swap sponsored: hand that secret to your counterparty, it is shown once (needs NIGHTGATE 0.39.0). |
| list_swap_offersA | Offers on the server's board. Without status: the open ones, newest first. status filled | retired | expired | all reads the closed ones instead, ordered by last change; since keeps offers changed after that instant, so status all + since polled repeatedly is the board's change feed. With waitMs the server holds an empty answer until an offer matches or the time is up, so a watcher makes one call per change instead of one per interval. Filters are exact 64-hex token types and one tag. Each row: offerId, the offer half (feed it to read_swap_offer or take_swap_offer), gives/wants type and amount, tags, expiresAt, postedAt, status, filledTxHash, closedAt, changedAt. Never the poster or the half's nullifiers. Every token may read the board. |
| my_swap_offersA | The offers this caller posted on the board (a token: its grant's), open and closed, ordered by last change: what is still open, what filled (filledTxHash), what expired or was retired. status narrows to one state, since to offers changed after an instant, waitMs holds an empty answer until one of them changes. Each row: offerId, the offer half (feed it to read_swap_offer or take_swap_offer), gives/wants type and amount, tags, expiresAt, postedAt, status, filledTxHash, closedAt, changedAt. Never the poster or the half's nullifiers. |
| get_swap_offerA | One board offer by id, open or closed, in the board's shape: status, filledTxHash once a swap spent it, closedAt, changedAt. The way to follow an offer after post_swap_offer or after taking one. Unknown id: 404. Each row: offerId, the offer half (feed it to read_swap_offer or take_swap_offer), gives/wants type and amount, tags, expiresAt, postedAt, status, filledTxHash, closedAt, changedAt. Never the poster or the half's nullifiers. |
| get_board_statusA | Counts of the server's offer board and its sponsors, no credentials needed: openOffers, offersFilledToday and swapsToday (UTC day), sponsorsConfigured and sponsorsReady (at tip with a spendable dust note; 0 means a sponsor_swap would wait or fail now), asOf. Computed at most every 10 s. |
| retire_swap_offerA | Take an offer off the board. Only its poster may; the coins behind the half stay reserved until revert_swap_offer releases the half built here (or until the 15-minute release of get_swap_wallet). Returns { offerId, status }: retired, or the status of an offer already closed (expired, retired, filled), so a lapsed offer answers expired instead of an error (NIGHTGATE 0.40.0). |
| derive_token_typeA | Derive the raw token type a minting contract produces (compute-only, no wallet, no chain access). A custom token is addressed by rawTokenType(domainSeparator, contractAddress); without it the minted balance cannot be transferred. domainSeparator is the plain string the contract pads (Compact pad(32, "...")) or 64 hex for the padded bytes; defaults to the bundled test token's. The result feeds sendNight(tokenTypeHex). |
| mint_tokenA | Mint a shielded token with a name of your own on a token-factory deployment. This process is the issuer: its issuer secret derives from the caller seed, the mint is built, proven and signed here, and a sponsor pays; the seed never leaves this process. The factory has to be on the sponsor's contract list and mint on its circuit list. The same name from another issuer is another token. The answer names the token ({ tokenType, domain, issuerKey }); a landed mint makes the type known to the sponsor (swaps, offer board). The recipient defaults to this wallet (get_attester_identity); another wallet takes both of its keys. The tool waits until the job settled (about 1 minute) and returns { status, txHash, transactionHash, result }. failed: |
| burn_tokenA | Burn an amount of a factory token this wallet holds: the coins leave circulation and the factory's supply ledger drops. Built, proven and signed here, a sponsor pays; the factory has to be on the sponsor's contract list and burn on its circuit list. Names the token by its name and issuer: without issuerKey the token is one this wallet minted. The tool waits until the job settled (about 1 minute) and returns { status, txHash, transactionHash, result }. failed: |
| send_tokenA | Send an amount of a shielded token from this wallet to another shielded address, with the sponsor paying the fee: a payout, a salary, an invoice settlement. The transfer is built and proven here from the wallet's coins (at most maxInputs of them); only the fee-unpaid bytes go to the server, which records the declared type and amount and submits. The recipient needs nothing but its address. Needs sponsorTransfer in the grant, the type on the sponsor's list and NIGHTGATE 0.39.0. The tool also waits for the block (about a minute more) and then carries the instance's signed receipt; if that wait runs out, receipt is null and the same call again fetches it. The tool waits until the job settled (about 1 minute) and returns { status, txHash, transactionHash, result }. failed: |
| call_contractA | Call a circuit on any contract whose lineage package is installed next to this server (laid out like @odatano/contract-: contract.json, the compiled class, the proving files). The call is built, proven and signed here from the caller seed and a sponsor pays, so the caller holds neither NIGHT nor DUST. Arguments are JSON in circuit order; tagged values: {"$bytes":""}, {"$uint":""}, and {"$coin":{"tokenType","amount"}} for a shielded coin the circuit receives, funded from this wallet, the one get_swap_wallet shows (a gateway key syncs it through the gateway, a direct instance needs NIGHTGATE_INDEXER_HTTP_URL and _WS_URL; the tool waits up to 20 s for its sync, a first sync from genesis takes about 5 minutes). {"$night":""} is a NIGHT amount the circuit takes from this wallet (receiveUnshielded, a deposit or a stake): the wallet syncs its NIGHT coins and pays them in, the sponsor adds only the fee; set payUnshielded when the amount is no argument. Needs allowUnshieldedOffers on the grant; one pay-in runs at a time. A payout the circuit makes to this wallet (sendUnshielded, a claim or a refund) needs nothing extra: NIGHTGATE 0.40.0 sponsors it. A call that funds anything is bound and goes through the serial sponsor channel, one without through the parallel one. Witnesses come from the package when its contract.json names a witnesses module (createWitnesses gets a secret derived from the seed for that package; the private state they return is kept once the call landed). The contract has to be sponsorable (its address and circuit on the sponsor's policy). The answer waits for the block; a call the chain refused gives its coins back. The tool waits until the job settled (about 1 minute) and returns { status, txHash, transactionHash, result }. failed: |
| get_usageA | What this key has left and what it spent. With a gateway key (oda_...): unitsLeft, validUntil, status, usage today and over 30 days, and the last calls with the units each one cost (ledger). Free. With an agent grant of a direct instance: jobs by kind and status and the limits { jobsPerHour, jobsPerDay, classes }. Read it before a burst and after a 429 (the error carries retryAfterSeconds). |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
TDQS
Scored across 28 tools
The set covers several broad domains and most tools have distinct purposes, but there is meaningful overlap between board/offer reading tools (get_swap_offer vs read_swap_offer), swap lifecycle tools, and transaction-building/submitting/sponsoring variants. The very long descriptions help, but an agent can still hesitate between submit_vault_call, build_sponsorable_transaction, call_contract, and anchor_document for related attestation/contract work.
Most tool names follow a predictable snake_case verb_noun pattern such as get_swap_wallet, build_swap_offer, post_swap_offer, verify_attestation, and prepare_document_proof. Minor deviations like my_swap_offers and read_swap_offer are readable but slightly break the pattern.
The server genuinely spans attestation, ZK predicates, shielded swaps, token minting/burning/transfers, sponsoring, and contract calls, so many tools are justified. However, 28 tools is heavy, and the ten or so swap-related tools plus multiple sponsoring/build abstractions make the surface feel larger than necessary.
Coverage is strong: swaps have build/read/post/list/get/take/sponsor/retire/revert lifecycle tools, attestation has prepare/anchor/verify/prove operations, and token and sponsoring flows are well represented. Minor gaps include no obvious way to list or enumerate all attestations and no generic job-status/query tool beyond result payloads.