Skip to main content
Glama
ODATANO

@odatano/nightgate-mcp

Official
by ODATANO

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
NIGHTGATE_TOKENNoAgent-grant token (ngat_...) or plain bearer token
NIGHTGATE_BASE_URLNoNIGHTGATE host apphttp://localhost:4004
NIGHTGATE_PASSWORDNoBasic auth password
NIGHTGATE_USERNAMENoBasic auth username
NIGHTGATE_TIMEOUT_MSNoPer-request timeout30000
NIGHTGATE_SERVICE_PATHNoOData 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

CapabilityDetails
tools
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
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 salt (feed it back as fieldSalt / claim salt), the full opening (salt seed + all 16 slots, needed for the cross-root proofs) and schemaId (anchor it alongside the root). STORE the opening with the document: losing the salt seed makes the anchored root unprovable, publishing it makes leaf hashes guessable. Pass saltSeed to reproduce an EXISTING anchored root byte-for-byte; omit it for a fresh document. The returned fields carry witness material (scaled values / digests / salts): treat as sensitive. Store canonicalDocument at your storageRef; re-serializing with different key order will not re-hash equal.

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 next what to do. 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.

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: next says what to do. 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.

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: next says what to do. 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.

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, spendable, the most ONE swap half can give (what its largest coins hold, up to maxInputs coins), and pending, what the halves built here bring back once their swaps land (the change and the wanted coins). While a half can still land the wallet is worth balance plus pending; a half can give only from balance, and revert_swap_offer moves a dropped half back into it. Also lists the halves built here that are not handed over yet (pendingHalves, with those of an earlier process marked restored) and the coins the SDK holds reserved (reserved, each with its ttl); one posted with post_swap_offer carries offerId and boardStatus and leaves the list once its offer filled. A maker half whose offer expired or was retired 15 minutes ago and that went into no job is released here on its own (released). The wallet syncs its shielded coins only; a first sync from genesis takes about 5 minutes, during which the answer is { synced: false, syncingSeconds }: call again. Spends nothing.

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 give and creates want (and the change) for this wallet. Returns the offer file (offer, text starting with swapoffer1, about 25 000 characters) to publish, its id, and the terms read back from the built transaction. Anyone holding the wanted token can take the offer; the first swap that lands consumes it. The coins stay reserved until the swap lands: withdraw an offer that is not going to be used with revert_swap_offer. An offer refers to a recent chain state and expires with it, so publish it promptly. give.amount may not exceed spendable of get_swap_wallet. Proving takes about 200 s in-process, 11 to 17 s on a proof server (NIGHTGATE_PROOF_SERVER_URL). Spends no fee.

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 expect, builds and proves the mirror half from this server's wallet (it spends what the offer wants and creates what the offer gives). With submit: true the two halves go to the sponsor at once and the tool waits until the swap landed ({ status, txHash, transactionHash, result.swap, id, terms }). Without it the answer carries both halves for sponsor_swap. ALWAYS pass expect with the terms you agreed to: an offer is text from someone else. With offerId the board entry is read first and the call refuses, before proving, when it is not open or carries another offer than offer. A sponsor that refuses the swap leaves the proven half held under halfId: send it again with sponsor_swap({ halfId, offerId? }) or release its coins with revert_swap_offer. If the offer was taken by somebody else first, the job fails: revert_swap_offer.

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 halfId alone for an offer this server took (take_swap_offer keeps both halves); with offerId the maker half comes from the board, next to takerHalf or the halfId of the taken offer. 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: next says what to do. 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.

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: next says what to do. 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.

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: next says what to do. 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.

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: next says what to do. 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.

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: next says what to do. 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.

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

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

TDQS

A4/5.0

Scored across 28 tools

Disambiguation3/5

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.

Naming Consistency4/5

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.

Tool Count3/5

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.

Completeness4/5

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.

Maintenance

ActivityActive
ResponsivenessUnresponsive