@purplesquirrel/hedera-mcp 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0
4
+
5
+ Initial release — comprehensive build-only MCP server for Hedera (Hashgraph).
6
+
7
+ - 51 tools across Account, Token (HTS), Consensus (HCS), Smart Contract (EVM), File, Schedule, and Network services.
8
+ - Keyless reads via the Mirror Node REST API.
9
+ - Build-only writes: transactions are frozen and returned as unsigned base64 for offline signing. The server never holds keys or executes.
10
+ - `hedera_decode_transaction` for reviewing built transactions before signing.
11
+ - Supports mainnet / testnet / previewnet via `HEDERA_NETWORK`.
12
+ - Verified: `tsc` clean against `@hashgraph/sdk` 2.81.0; MCP stdio smoke test passes (live testnet Mirror Node read + build-only write round-trip).
13
+ - **Live execution verified on testnet:** build-only output signed externally and submitted — `create_topic` and `submit_message` both `SUCCESS`, confirmed independently via Mirror Node. The server held no key at any point.
14
+ - Added `gen-key.mjs` (throwaway ECDSA keypair → `.env`) and `resolve-account.mjs` (resolve auto-created account id from a faucet-funded EVM address) for reproducible verification.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Matthew Karsten
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,127 @@
1
+ # hedera-mcp
2
+
3
+ ![hedera-mcp](./logo.svg)
4
+
5
+ **Comprehensive Model Context Protocol server for Hedera (Hashgraph).** Full coverage of every core Hedera service — Account, Token (HTS), Consensus (HCS), Smart Contract (EVM), File, Schedule, and Network — exposed as **51 MCP tools** any AI agent (Claude, Cursor, etc.) can call.
6
+
7
+ > **Build-only. Never holds keys.** Reads hit the public Mirror Node REST API (no auth). Writes return an *unsigned, frozen* transaction (base64) for you to sign and submit with your own wallet/SDK/CLI. This server never sees a private key and never executes anything.
8
+
9
+ ---
10
+
11
+ ## Why this exists
12
+
13
+ The official Hedera Agent Kit ships a preconfigured MCP server, but its tool surface is intentionally small (balance, transfer, deploy). This server fills the gap with **end-to-end coverage** of the Hedera API, organized for developer education and agent-driven onboarding — so a developer can go from "certified" to "shipping their first HTS token / HCS topic / contract" inside a single AI session.
14
+
15
+ | Service | Official starter MCP | **hedera-mcp** |
16
+ |---|---|---|
17
+ | Account | balance | create, transfer, update, delete, allowances, info, balances, NFTs |
18
+ | Token (HTS) | transfer, deploy | create FT/NFT, mint, burn, transfer, associate, freeze, KYC, pause, wipe, delete, info |
19
+ | Consensus (HCS) | — | create/update/delete topic, submit + read messages |
20
+ | Smart contract | — | deploy, execute, eth_call read, info |
21
+ | File | — | create, append, delete, info |
22
+ | Schedule | — | create, sign, delete, info |
23
+ | Network | — | tx lookup, nodes, fees, supply, exchange rate, decode |
24
+
25
+ ## Security model
26
+
27
+ - **Reads** → public Mirror Node REST. No keys, no account required.
28
+ - **Writes** → the tool constructs the transaction, freezes it for offline signing, and returns base64 bytes plus a human summary. You inspect it (`hedera_decode_transaction`), then sign and submit yourself.
29
+ - The only optional environment input is `HEDERA_OPERATOR_ID` — an **account id**, used as the default payer/treasury when building. Never a key.
30
+
31
+ This mirrors the posture of [goat-network-mcp](https://github.com/ExpertVagabond/goat-network-mcp): safe to run anywhere, safe to give to an autonomous agent.
32
+
33
+ ## Install
34
+
35
+ ```bash
36
+ npm install
37
+ npm run build
38
+ ```
39
+
40
+ ## Configure (Claude Desktop / Claude Code)
41
+
42
+ ```json
43
+ {
44
+ "mcpServers": {
45
+ "hedera": {
46
+ "command": "node",
47
+ "args": ["/absolute/path/to/hedera-mcp/dist/index.js"],
48
+ "env": {
49
+ "HEDERA_NETWORK": "testnet",
50
+ "HEDERA_OPERATOR_ID": "0.0.1234"
51
+ }
52
+ }
53
+ }
54
+ }
55
+ ```
56
+
57
+ | Env var | Default | Notes |
58
+ |---|---|---|
59
+ | `HEDERA_NETWORK` | `testnet` | `mainnet` \| `testnet` \| `previewnet` |
60
+ | `HEDERA_OPERATOR_ID` | _(unset)_ | Optional default payer/treasury **account id** (not a key) |
61
+ | `HEDERA_MIRROR_URL` | per-network | Override Mirror Node REST base (e.g. a private/HGraph node) |
62
+
63
+ ## Build-only workflow
64
+
65
+ ```
66
+ agent calls hedera_create_fungible_token
67
+
68
+
69
+ hedera-mcp builds + freezes the TokenCreateTransaction
70
+
71
+
72
+ returns base64 (unsigned) ──► you sign in HashPack / SDK / CLI ──► submit to Hedera
73
+ ```
74
+
75
+ Inspect anything before signing:
76
+
77
+ ```
78
+ hedera_decode_transaction { transactionBase64: "<bytes>" }
79
+ → { type: "TokenCreateTransaction", transactionId, nodeAccountIds, maxTransactionFee, ... }
80
+ ```
81
+
82
+ ## Tool catalog (51)
83
+
84
+ **Account (8):** create_account · transfer_hbar · update_account · delete_account · approve_hbar_allowance · get_account_info · get_account_balance · get_account_nfts
85
+
86
+ **Token / HTS (18):** create_fungible_token · create_nft_collection · mint_fungible · mint_nft · burn_token · transfer_token · transfer_nft · associate_token · dissociate_token · freeze_token_account · unfreeze_token_account · grant_kyc · revoke_kyc · pause_token · unpause_token · wipe_token · delete_token · get_token_info · get_nft_info
87
+
88
+ **Consensus / HCS (6):** create_topic · submit_message · update_topic · delete_topic · get_topic_info · get_topic_messages
89
+
90
+ **Smart contract / EVM (4):** deploy_contract · execute_contract · query_contract (eth_call) · get_contract_info
91
+
92
+ **File (4):** create_file · append_file · delete_file · get_file_info
93
+
94
+ **Schedule (4):** create_schedule · sign_schedule · delete_schedule · get_schedule_info
95
+
96
+ **Network / utility (6):** get_transaction · get_network_nodes · get_exchange_rate · get_network_supply · get_network_fees · decode_transaction
97
+
98
+ ## Development
99
+
100
+ ```bash
101
+ npm run lint # tsc --noEmit
102
+ npm run build # compile to dist/
103
+ node test-smoke.mjs # MCP stdio: live Mirror Node read + build-only write + decode
104
+ node demo.mjs # narrated "developer's first session" walkthrough (build-only)
105
+ node test-execute.mjs # LIVE testnet submit (needs a throwaway key in .env — see below)
106
+ ```
107
+
108
+ ### Live execution verification
109
+
110
+ `test-execute.mjs` proves the build-only output is real: the MCP server builds an
111
+ unsigned transaction, the harness signs it with a **throwaway testnet key from `.env`**
112
+ and submits it, then confirms the result independently via Mirror Node. The server
113
+ stays build-only the whole time — only the test harness ever touches a key.
114
+
115
+ ```
116
+ HEDERA_NETWORK=testnet
117
+ HEDERA_OPERATOR_ID=0.0.xxxxxx
118
+ HEDERA_OPERATOR_KEY=302e0201... # rotate/discard after verifying
119
+ ```
120
+
121
+ Get a free testnet account at [portal.hedera.com](https://portal.hedera.com).
122
+
123
+ Built on [`@hashgraph/sdk`](https://www.npmjs.com/package/@hashgraph/sdk) and [`@modelcontextprotocol/sdk`](https://www.npmjs.com/package/@modelcontextprotocol/sdk).
124
+
125
+ ## License
126
+
127
+ MIT © Matthew Karsten
@@ -0,0 +1,55 @@
1
+ /**
2
+ * HederaCtx — the keyless heart of the server.
3
+ *
4
+ * Design contract: this server NEVER holds, reads, or asks for a private key.
5
+ * - Read/query tools hit the public Mirror Node REST API (no auth).
6
+ * - Write tools BUILD a transaction, freeze it, and return the unsigned bytes
7
+ * (base64) plus a human summary. The caller signs & submits with their own
8
+ * wallet / SDK / CLI. Nothing is ever executed from here.
9
+ *
10
+ * The only optional input is HEDERA_OPERATOR_ID — an *account id* (not a key) —
11
+ * used as the default payer/treasury when building transactions.
12
+ */
13
+ import { AccountId, Client, Transaction } from "@hashgraph/sdk";
14
+ import { type NetworkConfig } from "./networks.js";
15
+ export declare function resolveTxType(tx: Transaction): string;
16
+ export interface BuildResult {
17
+ /** Short transaction-type label, e.g. "TokenCreateTransaction" */
18
+ type: string;
19
+ /** Frozen, unsigned transaction encoded as base64 */
20
+ base64: string;
21
+ /** Generated transaction id (payer@valid-start) */
22
+ transactionId: string;
23
+ }
24
+ export declare class HederaCtx {
25
+ readonly network: NetworkConfig;
26
+ readonly operatorId?: AccountId;
27
+ private _client?;
28
+ constructor();
29
+ /** Node account ids for this network as SDK AccountId objects. */
30
+ get nodeAccountIds(): AccountId[];
31
+ /**
32
+ * A network Client used only for offline operations (node list, fee schedules).
33
+ * No operator/key is set — it is never used to execute anything.
34
+ */
35
+ get client(): Client;
36
+ /** Resolve the payer account: explicit arg → env operator → error. */
37
+ payer(payerAccountId?: string): AccountId;
38
+ /**
39
+ * Freeze a transaction for offline signing (build-only) and serialize to base64.
40
+ * Sets a generated transaction id from the payer and the network's node accounts,
41
+ * so the resulting bytes are valid to sign and submit as-is.
42
+ */
43
+ build(tx: Transaction, payerAccountId?: string): BuildResult;
44
+ /** Render a BuildResult as the standard tool response. */
45
+ render(result: BuildResult, summary: string): string;
46
+ /** Build + render in one call. */
47
+ buildAndRender(tx: Transaction, summary: string, payerAccountId?: string): string;
48
+ /** GET a Mirror Node REST path (keyless). `path` should start with "/api/v1/...". */
49
+ mirror<T = any>(path: string): Promise<T>;
50
+ /** POST to a Mirror Node REST path (used for contracts/call eth_call reads). */
51
+ mirrorPost<T = any>(path: string, body: unknown): Promise<T>;
52
+ explorerTx(txId: string): string;
53
+ }
54
+ /** Pretty-print any JSON payload for tool output. */
55
+ export declare function json(value: unknown): string;
@@ -0,0 +1,162 @@
1
+ /**
2
+ * HederaCtx — the keyless heart of the server.
3
+ *
4
+ * Design contract: this server NEVER holds, reads, or asks for a private key.
5
+ * - Read/query tools hit the public Mirror Node REST API (no auth).
6
+ * - Write tools BUILD a transaction, freeze it, and return the unsigned bytes
7
+ * (base64) plus a human summary. The caller signs & submits with their own
8
+ * wallet / SDK / CLI. Nothing is ever executed from here.
9
+ *
10
+ * The only optional input is HEDERA_OPERATOR_ID — an *account id* (not a key) —
11
+ * used as the default payer/treasury when building transactions.
12
+ */
13
+ import { AccountAllowanceApproveTransaction, AccountCreateTransaction, AccountDeleteTransaction, AccountId, AccountUpdateTransaction, Client, ContractCreateTransaction, ContractExecuteTransaction, FileAppendTransaction, FileCreateTransaction, FileDeleteTransaction, ScheduleCreateTransaction, ScheduleDeleteTransaction, ScheduleSignTransaction, TokenAssociateTransaction, TokenBurnTransaction, TokenCreateTransaction, TokenDeleteTransaction, TokenDissociateTransaction, TokenFreezeTransaction, TokenGrantKycTransaction, TokenMintTransaction, TokenPauseTransaction, TokenRevokeKycTransaction, TokenUnfreezeTransaction, TokenUnpauseTransaction, TokenWipeTransaction, TopicCreateTransaction, TopicDeleteTransaction, TopicMessageSubmitTransaction, TopicUpdateTransaction, TransactionId, TransferTransaction, } from "@hashgraph/sdk";
14
+ import { resolveNetwork } from "./networks.js";
15
+ /**
16
+ * Resolve a human-readable transaction type. The @hashgraph/sdk bundle is
17
+ * minified, so `constructor.name` is mangled (e.g. "T") — we match by prototype
18
+ * via instanceof, which is unaffected by minification.
19
+ */
20
+ const TX_TYPES = [
21
+ [TransferTransaction, "TransferTransaction"],
22
+ [AccountCreateTransaction, "AccountCreateTransaction"],
23
+ [AccountUpdateTransaction, "AccountUpdateTransaction"],
24
+ [AccountDeleteTransaction, "AccountDeleteTransaction"],
25
+ [AccountAllowanceApproveTransaction, "AccountAllowanceApproveTransaction"],
26
+ [TokenCreateTransaction, "TokenCreateTransaction"],
27
+ [TokenMintTransaction, "TokenMintTransaction"],
28
+ [TokenBurnTransaction, "TokenBurnTransaction"],
29
+ [TokenAssociateTransaction, "TokenAssociateTransaction"],
30
+ [TokenDissociateTransaction, "TokenDissociateTransaction"],
31
+ [TokenFreezeTransaction, "TokenFreezeTransaction"],
32
+ [TokenUnfreezeTransaction, "TokenUnfreezeTransaction"],
33
+ [TokenGrantKycTransaction, "TokenGrantKycTransaction"],
34
+ [TokenRevokeKycTransaction, "TokenRevokeKycTransaction"],
35
+ [TokenPauseTransaction, "TokenPauseTransaction"],
36
+ [TokenUnpauseTransaction, "TokenUnpauseTransaction"],
37
+ [TokenWipeTransaction, "TokenWipeTransaction"],
38
+ [TokenDeleteTransaction, "TokenDeleteTransaction"],
39
+ [TopicCreateTransaction, "TopicCreateTransaction"],
40
+ [TopicMessageSubmitTransaction, "TopicMessageSubmitTransaction"],
41
+ [TopicUpdateTransaction, "TopicUpdateTransaction"],
42
+ [TopicDeleteTransaction, "TopicDeleteTransaction"],
43
+ [ContractCreateTransaction, "ContractCreateTransaction"],
44
+ [ContractExecuteTransaction, "ContractExecuteTransaction"],
45
+ [FileCreateTransaction, "FileCreateTransaction"],
46
+ [FileAppendTransaction, "FileAppendTransaction"],
47
+ [FileDeleteTransaction, "FileDeleteTransaction"],
48
+ [ScheduleCreateTransaction, "ScheduleCreateTransaction"],
49
+ [ScheduleSignTransaction, "ScheduleSignTransaction"],
50
+ [ScheduleDeleteTransaction, "ScheduleDeleteTransaction"],
51
+ ];
52
+ export function resolveTxType(tx) {
53
+ for (const [cls, name] of TX_TYPES) {
54
+ if (tx instanceof cls)
55
+ return name;
56
+ }
57
+ return "Transaction";
58
+ }
59
+ export class HederaCtx {
60
+ network;
61
+ operatorId;
62
+ _client;
63
+ constructor() {
64
+ this.network = resolveNetwork();
65
+ const opId = process.env.HEDERA_OPERATOR_ID?.trim();
66
+ if (opId && opId !== "0.0.xxxxxx") {
67
+ this.operatorId = AccountId.fromString(opId);
68
+ }
69
+ }
70
+ /** Node account ids for this network as SDK AccountId objects. */
71
+ get nodeAccountIds() {
72
+ return this.network.nodeAccountIds.map((id) => AccountId.fromString(id));
73
+ }
74
+ /**
75
+ * A network Client used only for offline operations (node list, fee schedules).
76
+ * No operator/key is set — it is never used to execute anything.
77
+ */
78
+ get client() {
79
+ if (!this._client) {
80
+ this._client = Client.forName(this.network.name);
81
+ }
82
+ return this._client;
83
+ }
84
+ /** Resolve the payer account: explicit arg → env operator → error. */
85
+ payer(payerAccountId) {
86
+ if (payerAccountId)
87
+ return AccountId.fromString(payerAccountId);
88
+ if (this.operatorId)
89
+ return this.operatorId;
90
+ throw new Error("No payer account. Pass `payerAccountId`, or set HEDERA_OPERATOR_ID in the environment.");
91
+ }
92
+ /**
93
+ * Freeze a transaction for offline signing (build-only) and serialize to base64.
94
+ * Sets a generated transaction id from the payer and the network's node accounts,
95
+ * so the resulting bytes are valid to sign and submit as-is.
96
+ */
97
+ build(tx, payerAccountId) {
98
+ const payer = this.payer(payerAccountId);
99
+ const txId = TransactionId.generate(payer);
100
+ tx.setTransactionId(txId).setNodeAccountIds(this.nodeAccountIds).freeze();
101
+ return {
102
+ type: resolveTxType(tx),
103
+ base64: Buffer.from(tx.toBytes()).toString("base64"),
104
+ transactionId: txId.toString(),
105
+ };
106
+ }
107
+ /** Render a BuildResult as the standard tool response. */
108
+ render(result, summary) {
109
+ return [
110
+ `✅ Built (unsigned) ${result.type} on ${this.network.name}`,
111
+ "",
112
+ summary,
113
+ "",
114
+ `Transaction ID: ${result.transactionId}`,
115
+ "",
116
+ "Sign & submit (this server never does):",
117
+ " • SDK: Transaction.fromBytes(Buffer.from(b64,'base64')).sign(key).execute(client)",
118
+ " • Wallet: import the bytes into HashPack / Blade, or use the `hedera` CLI",
119
+ "",
120
+ "Transaction (base64):",
121
+ result.base64,
122
+ ].join("\n");
123
+ }
124
+ /** Build + render in one call. */
125
+ buildAndRender(tx, summary, payerAccountId) {
126
+ return this.render(this.build(tx, payerAccountId), summary);
127
+ }
128
+ /** GET a Mirror Node REST path (keyless). `path` should start with "/api/v1/...". */
129
+ async mirror(path) {
130
+ const url = `${this.network.mirror}${path}`;
131
+ const res = await fetch(url, { headers: { accept: "application/json" } });
132
+ if (!res.ok) {
133
+ const body = await res.text().catch(() => "");
134
+ throw new Error(`Mirror Node ${res.status} for ${path}: ${body.slice(0, 300)}`);
135
+ }
136
+ return (await res.json());
137
+ }
138
+ /** POST to a Mirror Node REST path (used for contracts/call eth_call reads). */
139
+ async mirrorPost(path, body) {
140
+ const url = `${this.network.mirror}${path}`;
141
+ const res = await fetch(url, {
142
+ method: "POST",
143
+ headers: { "content-type": "application/json", accept: "application/json" },
144
+ body: JSON.stringify(body),
145
+ });
146
+ if (!res.ok) {
147
+ const text = await res.text().catch(() => "");
148
+ throw new Error(`Mirror Node ${res.status} for ${path}: ${text.slice(0, 300)}`);
149
+ }
150
+ return (await res.json());
151
+ }
152
+ explorerTx(txId) {
153
+ // HashScan expects transaction ids in the form 0.0.x-seconds-nanos
154
+ const normalized = txId.replace("@", "-").replace(/\.(\d+)$/, "-$1");
155
+ return `${this.network.explorer}/transaction/${normalized}`;
156
+ }
157
+ }
158
+ /** Pretty-print any JSON payload for tool output. */
159
+ export function json(value) {
160
+ return JSON.stringify(value, null, 2);
161
+ }
162
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hedera MCP Server
4
+ *
5
+ * Comprehensive Model Context Protocol coverage for Hedera (Hashgraph):
6
+ * Account, Token (HTS), Consensus (HCS), Smart Contract (EVM), File, Schedule,
7
+ * and Network services.
8
+ *
9
+ * Security posture (matches goat-network-mcp): BUILD-ONLY, never holds keys.
10
+ * - Reads/queries hit the public Mirror Node REST API (no auth).
11
+ * - Writes build + freeze + serialize an UNSIGNED transaction (base64). The
12
+ * caller signs and submits with their own wallet/SDK/CLI. Nothing executes here.
13
+ *
14
+ * Environment:
15
+ * HEDERA_NETWORK mainnet | testnet (default) | previewnet
16
+ * HEDERA_OPERATOR_ID optional default payer/treasury ACCOUNT ID (not a key)
17
+ * HEDERA_MIRROR_URL optional Mirror Node REST override
18
+ */
19
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Hedera MCP Server
4
+ *
5
+ * Comprehensive Model Context Protocol coverage for Hedera (Hashgraph):
6
+ * Account, Token (HTS), Consensus (HCS), Smart Contract (EVM), File, Schedule,
7
+ * and Network services.
8
+ *
9
+ * Security posture (matches goat-network-mcp): BUILD-ONLY, never holds keys.
10
+ * - Reads/queries hit the public Mirror Node REST API (no auth).
11
+ * - Writes build + freeze + serialize an UNSIGNED transaction (base64). The
12
+ * caller signs and submits with their own wallet/SDK/CLI. Nothing executes here.
13
+ *
14
+ * Environment:
15
+ * HEDERA_NETWORK mainnet | testnet (default) | previewnet
16
+ * HEDERA_OPERATOR_ID optional default payer/treasury ACCOUNT ID (not a key)
17
+ * HEDERA_MIRROR_URL optional Mirror Node REST override
18
+ */
19
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
20
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
21
+ import { HederaCtx } from "./context.js";
22
+ import { registerAccountTools } from "./tools/account.js";
23
+ import { registerTokenTools } from "./tools/token.js";
24
+ import { registerConsensusTools } from "./tools/consensus.js";
25
+ import { registerContractTools } from "./tools/contract.js";
26
+ import { registerFileTools } from "./tools/file.js";
27
+ import { registerScheduleTools } from "./tools/schedule.js";
28
+ import { registerNetworkTools } from "./tools/network.js";
29
+ const ctx = new HederaCtx();
30
+ const server = new McpServer({
31
+ name: "hedera-mcp",
32
+ version: "0.1.0",
33
+ });
34
+ let toolCount = 0;
35
+ const register = (name, description, shape, handler) => {
36
+ server.tool(name, description, shape, async (args) => {
37
+ try {
38
+ const text = await handler(args);
39
+ return { content: [{ type: "text", text }] };
40
+ }
41
+ catch (err) {
42
+ return {
43
+ content: [{ type: "text", text: `Error: ${err?.message ?? String(err)}` }],
44
+ isError: true,
45
+ };
46
+ }
47
+ });
48
+ toolCount++;
49
+ };
50
+ registerAccountTools(register, ctx);
51
+ registerTokenTools(register, ctx);
52
+ registerConsensusTools(register, ctx);
53
+ registerContractTools(register, ctx);
54
+ registerFileTools(register, ctx);
55
+ registerScheduleTools(register, ctx);
56
+ registerNetworkTools(register, ctx);
57
+ async function main() {
58
+ const transport = new StdioServerTransport();
59
+ await server.connect(transport);
60
+ console.error(`hedera-mcp running — ${toolCount} tools — ${ctx.network.name} ` +
61
+ `(mirror ${ctx.network.mirror})` +
62
+ (ctx.operatorId ? ` — default payer ${ctx.operatorId.toString()}` : " — build-only, no default payer"));
63
+ }
64
+ main().catch((err) => {
65
+ console.error("Fatal:", err);
66
+ process.exit(1);
67
+ });
68
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Hedera network configuration.
3
+ *
4
+ * Mirror Node REST base URLs are public and keyless — all read/query tools use them.
5
+ * nodeAccountIds are stable consensus-node accounts used when freezing a build-only
6
+ * transaction so the serialized bytes target real nodes.
7
+ */
8
+ export interface NetworkConfig {
9
+ /** Human label, e.g. "testnet" */
10
+ name: "mainnet" | "testnet" | "previewnet";
11
+ /** Mirror Node REST base URL (no trailing slash) */
12
+ mirror: string;
13
+ /** Consensus node account IDs used for build-only transaction freezing */
14
+ nodeAccountIds: string[];
15
+ /** HashScan explorer base for this network */
16
+ explorer: string;
17
+ }
18
+ export declare function resolveNetwork(): NetworkConfig;
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Hedera network configuration.
3
+ *
4
+ * Mirror Node REST base URLs are public and keyless — all read/query tools use them.
5
+ * nodeAccountIds are stable consensus-node accounts used when freezing a build-only
6
+ * transaction so the serialized bytes target real nodes.
7
+ */
8
+ const NETWORKS = {
9
+ mainnet: {
10
+ name: "mainnet",
11
+ mirror: "https://mainnet-public.mirrornode.hedera.com",
12
+ nodeAccountIds: ["0.0.3", "0.0.4", "0.0.5", "0.0.6", "0.0.7"],
13
+ explorer: "https://hashscan.io/mainnet",
14
+ },
15
+ testnet: {
16
+ name: "testnet",
17
+ mirror: "https://testnet.mirrornode.hedera.com",
18
+ nodeAccountIds: ["0.0.3", "0.0.4", "0.0.5", "0.0.6", "0.0.7", "0.0.8", "0.0.9"],
19
+ explorer: "https://hashscan.io/testnet",
20
+ },
21
+ previewnet: {
22
+ name: "previewnet",
23
+ mirror: "https://previewnet.mirrornode.hedera.com",
24
+ nodeAccountIds: ["0.0.3", "0.0.4", "0.0.5", "0.0.6"],
25
+ explorer: "https://hashscan.io/previewnet",
26
+ },
27
+ };
28
+ export function resolveNetwork() {
29
+ const requested = (process.env.HEDERA_NETWORK || "testnet").toLowerCase();
30
+ const net = NETWORKS[requested];
31
+ if (!net) {
32
+ throw new Error(`Unknown HEDERA_NETWORK="${requested}". Use one of: mainnet, testnet, previewnet.`);
33
+ }
34
+ if (process.env.HEDERA_MIRROR_URL) {
35
+ return { ...net, mirror: process.env.HEDERA_MIRROR_URL.replace(/\/+$/, "") };
36
+ }
37
+ return net;
38
+ }
39
+ //# sourceMappingURL=networks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"networks.js","sourceRoot":"","sources":["../src/networks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,QAAQ,GAAkC;IAC9C,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,8CAA8C;QACtD,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;QAC7D,QAAQ,EAAE,6BAA6B;KACxC;IACD,OAAO,EAAE;QACP,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,uCAAuC;QAC/C,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;QAC/E,QAAQ,EAAE,6BAA6B;KACxC;IACD,UAAU,EAAE;QACV,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,0CAA0C;QAClD,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC;QACpD,QAAQ,EAAE,gCAAgC;KAC3C;CACF,CAAC;AAEF,MAAM,UAAU,cAAc;IAC5B,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;IAC1E,MAAM,GAAG,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;IAChC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,2BAA2B,SAAS,8CAA8C,CACnF,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,CAAC;QAClC,OAAO,EAAE,GAAG,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;IAC/E,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Register } from "../types.js";
2
+ import { HederaCtx } from "../context.js";
3
+ export declare function registerAccountTools(register: Register, ctx: HederaCtx): void;
@@ -0,0 +1,79 @@
1
+ /** Account service: create, transfer, update, delete, allowances, and Mirror Node reads. */
2
+ import { z } from "zod";
3
+ import { AccountAllowanceApproveTransaction, AccountCreateTransaction, AccountDeleteTransaction, AccountId, AccountUpdateTransaction, Hbar, PublicKey, TransferTransaction, } from "@hashgraph/sdk";
4
+ import { json } from "../context.js";
5
+ export function registerAccountTools(register, ctx) {
6
+ register("hedera_create_account", "Build (unsigned) a new Hedera account with a given public key and optional initial HBAR balance.", {
7
+ publicKey: z.string().describe("ED25519 or ECDSA public key (DER or hex) controlling the new account"),
8
+ initialBalanceHbar: z.number().optional().describe("Initial balance in HBAR (default 0)"),
9
+ memo: z.string().optional().describe("Account memo"),
10
+ maxAutomaticTokenAssociations: z.number().int().optional().describe("Auto token-association slots"),
11
+ payerAccountId: z.string().optional().describe("Payer (defaults to HEDERA_OPERATOR_ID)"),
12
+ }, async (a) => {
13
+ const tx = new AccountCreateTransaction().setKey(PublicKey.fromString(a.publicKey));
14
+ if (a.initialBalanceHbar != null)
15
+ tx.setInitialBalance(new Hbar(a.initialBalanceHbar));
16
+ if (a.memo)
17
+ tx.setAccountMemo(a.memo);
18
+ if (a.maxAutomaticTokenAssociations != null)
19
+ tx.setMaxAutomaticTokenAssociations(a.maxAutomaticTokenAssociations);
20
+ return ctx.buildAndRender(tx, `Create account · key ${a.publicKey.slice(0, 16)}… · ${a.initialBalanceHbar ?? 0} ℏ`, a.payerAccountId);
21
+ });
22
+ register("hedera_transfer_hbar", "Build (unsigned) an HBAR transfer from one account to another.", {
23
+ fromAccountId: z.string().optional().describe("Sender (defaults to payer)"),
24
+ toAccountId: z.string().describe("Recipient account id, e.g. 0.0.1234"),
25
+ amountHbar: z.number().positive().describe("Amount in HBAR"),
26
+ memo: z.string().optional().describe("Transaction memo"),
27
+ payerAccountId: z.string().optional(),
28
+ }, async (a) => {
29
+ const from = AccountId.fromString(a.fromAccountId ?? ctx.payer(a.payerAccountId).toString());
30
+ const to = AccountId.fromString(a.toAccountId);
31
+ const tx = new TransferTransaction()
32
+ .addHbarTransfer(from, new Hbar(-a.amountHbar))
33
+ .addHbarTransfer(to, new Hbar(a.amountHbar));
34
+ if (a.memo)
35
+ tx.setTransactionMemo(a.memo);
36
+ return ctx.buildAndRender(tx, `Transfer ${a.amountHbar} ℏ · ${from} → ${to}`, a.payerAccountId);
37
+ });
38
+ register("hedera_update_account", "Build (unsigned) an account update (memo, auto-association slots).", {
39
+ accountId: z.string().describe("Account to update"),
40
+ memo: z.string().optional(),
41
+ maxAutomaticTokenAssociations: z.number().int().optional(),
42
+ payerAccountId: z.string().optional(),
43
+ }, async (a) => {
44
+ const tx = new AccountUpdateTransaction().setAccountId(AccountId.fromString(a.accountId));
45
+ if (a.memo != null)
46
+ tx.setAccountMemo(a.memo);
47
+ if (a.maxAutomaticTokenAssociations != null)
48
+ tx.setMaxAutomaticTokenAssociations(a.maxAutomaticTokenAssociations);
49
+ return ctx.buildAndRender(tx, `Update account ${a.accountId}`, a.payerAccountId);
50
+ });
51
+ register("hedera_delete_account", "Build (unsigned) an account deletion, transferring the remaining balance to another account.", {
52
+ accountId: z.string().describe("Account to delete"),
53
+ transferAccountId: z.string().describe("Account that receives the remaining balance"),
54
+ payerAccountId: z.string().optional(),
55
+ }, async (a) => {
56
+ const tx = new AccountDeleteTransaction()
57
+ .setAccountId(AccountId.fromString(a.accountId))
58
+ .setTransferAccountId(AccountId.fromString(a.transferAccountId));
59
+ return ctx.buildAndRender(tx, `Delete account ${a.accountId} → balance to ${a.transferAccountId}`, a.payerAccountId);
60
+ });
61
+ register("hedera_approve_hbar_allowance", "Build (unsigned) an HBAR allowance granting a spender the right to spend from an owner account.", {
62
+ ownerAccountId: z.string().optional().describe("Owner (defaults to payer)"),
63
+ spenderAccountId: z.string().describe("Spender granted the allowance"),
64
+ amountHbar: z.number().positive().describe("Allowance amount in HBAR"),
65
+ payerAccountId: z.string().optional(),
66
+ }, async (a) => {
67
+ const owner = AccountId.fromString(a.ownerAccountId ?? ctx.payer(a.payerAccountId).toString());
68
+ const tx = new AccountAllowanceApproveTransaction().approveHbarAllowance(owner, AccountId.fromString(a.spenderAccountId), new Hbar(a.amountHbar));
69
+ return ctx.buildAndRender(tx, `Approve ${a.amountHbar} ℏ allowance · ${owner} → ${a.spenderAccountId}`, a.payerAccountId);
70
+ });
71
+ // ---- Mirror Node reads (keyless) ----
72
+ register("hedera_get_account_info", "Read full account info (key, balance, memo, auto-renew, associations) from the Mirror Node.", { accountId: z.string().describe("Account id or EVM address") }, async (a) => json(await ctx.mirror(`/api/v1/accounts/${encodeURIComponent(a.accountId)}`)));
73
+ register("hedera_get_account_balance", "Read an account's HBAR and token balances from the Mirror Node.", { accountId: z.string().describe("Account id or EVM address") }, async (a) => json(await ctx.mirror(`/api/v1/accounts/${encodeURIComponent(a.accountId)}/tokens?limit=100`)));
74
+ register("hedera_get_account_nfts", "List NFTs owned by an account from the Mirror Node.", {
75
+ accountId: z.string().describe("Account id"),
76
+ limit: z.number().int().min(1).max(100).optional().describe("Max NFTs (default 25)"),
77
+ }, async (a) => json(await ctx.mirror(`/api/v1/accounts/${encodeURIComponent(a.accountId)}/nfts?limit=${a.limit ?? 25}`)));
78
+ }
79
+ //# sourceMappingURL=account.js.map