Skip to main content

Hathor Forge MCP

Hathor Forge is a local blockchain development environment for Hathor Network.

It helps developers run a complete local Hathor stack with minimal setup, including a fullnode, miner, wallet-headless service, block explorer, API explorer, and MCP server.

The MCP server allows AI assistants to control the local environment programmatically. This means you can ask an LLM to start the local network, create wallets, fund them, send transactions, inspect blocks, check service status, and test local development flows.

tip

If you would like to learn more about Hathor Forge features and capabilities, check out the Hathor Forge documentation.

What this integration is for

Use Hathor Forge MCP when you want your LLM to help with local development tasks such as:

warning

Hathor Forge is intended for local development only. Do not expose the MCP server publicly, and do not use Forge development wallets, seeds, or funds on mainnet or testnet.

  • Starting and stopping a local Hathor network.
  • Checking fullnode, miner, and wallet service status.
  • Creating local development wallets.
  • Funding wallets from the local faucet.
  • Sending local HTR transactions.
  • Inspecting local blocks and transactions.
  • Testing wallet-headless flows locally.
  • Preparing local examples before moving to testnet or production infrastructure.
  • Debugging local setup issues.
  • Resetting local development data.

Unlike the hathor-wallet-headless and hathor-blueprint articles, this page is not about installing a code skill. Hathor Forge uses MCP tools to let the assistant interact with a running local environment.

Preparing Hathor Forge

Before connecting an LLM to Hathor Forge, make sure your local environment is ready.

Use the official Forge documentation as the source of truth for installation, features, and supported workflows:

note

Hathor Forge and Hathor Skills solve different problems. Skills improve the LLM's reasoning about Hathor-specific development tasks. Forge MCP gives the LLM tools to operate a local Hathor environment.

Setting up MCP

Hathor Forge exposes an MCP server that AI assistants can connect to.

The default MCP endpoint is:

http://127.0.0.1:9876/mcp

Setup with Claude Code

Start Hathor Forge in one terminal:

nix run github:HathorNetwork/hathor-forge -- --start

Then register the MCP server in another terminal:

claude mcp add --transport http hathor-forge http://127.0.0.1:9876/mcp

After registration, Claude Code can call the Hathor Forge MCP tools.

Setup with .mcp.json

You can also add the MCP server to your project-level .mcp.json file:

{
"mcpServers": {
"hathor-forge": {
"type": "http",
"url": "http://127.0.0.1:9876/mcp"
}
}
}

This is useful when you want the MCP configuration to live with a specific project.

Setup with Claude Desktop

In the Hathor Forge desktop app:

  1. Open Settings.
  2. Go to MCP Integration.
  3. Select Copy Config.
  4. Paste the generated configuration into Claude Desktop's MCP configuration file.

Verifying MCP availability

After Hathor Forge is running, verify the MCP server health endpoint:

curl http://127.0.0.1:9876/health

Then ask Claude Code a small test question:

Check the status of my local Hathor Forge environment.

A useful response should use Forge MCP tools to inspect the local node, miner, wallet service, and overall status.

You can also ask:

Start the local Hathor environment and tell me which services are running.

The assistant should use the available MCP tools instead of only giving manual instructions.

Main capabilities

Hathor Forge exposes tools grouped by development area.

CategoryExample tools
Nodestart_node, stop_node, get_node_status
Minerstart_miner, stop_miner, get_miner_status
Wallet Servicestart_wallet_service, stop_wallet_service, get_wallet_service_status
Walletsgenerate_seed, create_wallet, get_wallet_status, get_wallet_balance, get_wallet_addresses, send_from_wallet, close_wallet
Faucetget_faucet_balance, send_from_faucet, fund_wallet
Blockchainget_blocks, get_transaction
Quick Actionsquick_start, quick_stop, get_full_status, reset_data

When working with Hathor Forge MCP, follow this process:

  1. Start Hathor Forge locally.
  2. Connect your AI assistant to the MCP server.
  3. Ask the assistant to check the full local environment status.
  4. Ask for a plan before making changes.
  5. Use Forge MCP tools for local-only actions such as wallet creation, funding, and local transactions.
  6. Inspect results with the local explorer or MCP blockchain tools.
  7. Reset local data only when you are sure you no longer need the current state.
  8. Move to testnet or production workflows only after separating Forge-specific assumptions from real network assumptions.

Example prompt:

I am using Hathor Forge MCP for local development.

Before creating any wallets or transactions, check the local environment status and tell me:
1. Whether the node is running.
2. Whether the miner is running.
3. Whether the wallet service is running.
4. Whether the faucet has funds.
5. What I should do next for a safe local test.

Asking better questions

Avoid asking the LLM vague questions that do not make it clear whether you want local development, testnet, or production behavior.

Ambiguous prompt

Create a wallet and send HTR.

Comprehensive prompt

I am using Hathor Forge MCP in a local development environment.

Create a local wallet named demo, fund it with 50 local HTR from the faucet, check the balance, then send 5 local HTR to another local wallet.

Use only the local Hathor Forge environment.
Do not use mainnet or testnet.
Summarize each step and the final balances.

The comprehensive prompt makes it clear that the assistant should use local Forge tools and local development funds only.

Development example

This use case shows how a developer can use Hathor Forge MCP with an LLM to test a local wallet transaction flow.

Use case description

A developer wants to test a simple local payment flow before building a production or testnet integration.

The local workflow should:

  • Start the Hathor Forge environment.
  • Create two local wallets.
  • Fund the first wallet from the local faucet.
  • Send local HTR from the first wallet to the second wallet.
  • Check both balances.
  • Inspect the transaction locally.

Starter Code for a Local Wallet Flow

The following starter code shows how a developer can structure a small local TypeScript project for testing a wallet transaction flow against the local services exposed by Hathor Forge.

This code is intended for local development only. It should not be used against testnet or mainnet without reviewing service URLs, wallet persistence, funding strategy, endpoint schemas, and security assumptions.

warning

The exact Headless Wallet endpoint paths, request bodies, response fields, and wallet headers must be verified in the official Headless Wallet API reference before using this code outside a local Forge experiment.

Example project structure:

forge-local-wallet-flow/
├─ package.json
├─ .env.example
└─ src/
├─ config.ts
├─ forgeHealth.ts
├─ headlessWalletClient.ts
├─ amount.ts
└─ run-local-wallet-flow.ts

Package file

package.json
{
"name": "forge-local-wallet-flow",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "tsx src/run-local-wallet-flow.ts"
},
"dependencies": {
"dotenv": "^16.4.7"
},
"devDependencies": {
"@types/node": "^22.10.2",
"tsx": "^4.19.2",
"typescript": "^5.7.2"
}
}

Install dependencies:

npm install

Run the local flow:

npm run dev

Local environment variables

.env.example
# Hathor Forge MCP health endpoint.
# This is used only to confirm that Forge is running locally.
FORGE_HEALTH_URL=http://127.0.0.1:9876/health

# Local wallet-headless service exposed by Hathor Forge.
# Confirm this port in your Forge setup.
HEADLESS_WALLET_URL=http://127.0.0.1:8001

# Local-only safety flag.
HATHOR_NETWORK=localnet

# Local wallet identifiers used by this script.
# The exact wallet creation/opening flow must be verified against the API reference.
SENDER_WALLET_ID=sender
RECEIVER_WALLET_ID=receiver

Copy it before running the script:

cp .env.example .env

Configuration helper

src/config.ts
import 'dotenv/config';

export type LocalForgeConfig = {
forgeHealthUrl: string;
headlessWalletUrl: string;
network: 'localnet';
senderWalletId: string;
receiverWalletId: string;
};

function requireEnv(name: string): string {
const value = process.env[name];

if (!value) {
throw new Error(`Missing required environment variable: ${name}`);
}

return value;
}

export function getLocalForgeConfig(): LocalForgeConfig {
const network = requireEnv('HATHOR_NETWORK');

if (network !== 'localnet') {
throw new Error(
`This script is local-only. Expected HATHOR_NETWORK=localnet, received: ${network}`
);
}

return {
forgeHealthUrl: requireEnv('FORGE_HEALTH_URL'),
headlessWalletUrl: requireEnv('HEADLESS_WALLET_URL').replace(/\/$/, ''),
network,
senderWalletId: requireEnv('SENDER_WALLET_ID'),
receiverWalletId: requireEnv('RECEIVER_WALLET_ID'),
};
}

Forge health check

src/forgeHealth.ts
export async function assertForgeIsRunning(healthUrl: string): Promise<void> {
const response = await fetch(healthUrl);

if (!response.ok) {
throw new Error(
`Hathor Forge health check failed with status ${response.status}`
);
}

const body = await response.text();

console.log('Forge health check:', body || 'OK');
}

HTR amount helper

src/amount.ts
const HTR_DECIMALS = 2;
const HTR_FACTOR = 10 ** HTR_DECIMALS;

export function htrToIntegerAmount(amount: number): number {
if (!Number.isFinite(amount)) {
throw new Error('Amount must be a valid number');
}

if (amount <= 0) {
throw new Error('Amount must be greater than zero');
}

const integerAmount = Math.round(amount * HTR_FACTOR);

if (integerAmount <= 0) {
throw new Error('Amount is too small');
}

if (integerAmount / HTR_FACTOR !== amount) {
throw new Error('Amount has too many decimal places');
}

return integerAmount;
}

Local Headless Wallet client

src/headlessWalletClient.ts
export type WalletBalance = {
available: unknown;
locked?: unknown;
raw: unknown;
};

export type WalletAddressResult = {
address: string;
raw: unknown;
};

export type SendTransactionResult = {
txId: string;
raw: unknown;
};

export type HeadlessWalletClientOptions = {
baseUrl: string;
};

export class LocalHeadlessWalletClient {
private readonly baseUrl: string;

constructor(options: HeadlessWalletClientOptions) {
this.baseUrl = options.baseUrl.replace(/\/$/, '');
}

private walletHeaders(walletId: string): HeadersInit {
return {
'content-type': 'application/json',

// Confirm the exact wallet identifier header in the
// official Headless Wallet API reference.
'x-wallet-id': walletId,
};
}

async getWalletStatus(walletId: string): Promise<unknown> {
// TODO: Confirm the exact endpoint in the API reference.
const response = await fetch(`${this.baseUrl}/wallet/status`, {
method: 'GET',
headers: this.walletHeaders(walletId),
});

if (!response.ok) {
throw await this.toError(response, 'Failed to get wallet status');
}

return response.json();
}

async createOrOpenWallet(walletId: string): Promise<void> {
// TODO: Confirm the correct local wallet creation/opening flow.
// Depending on your setup, wallets may need to be created, started,
// unlocked, or opened using different endpoints.
console.log(`Prepare local wallet: ${walletId}`);

try {
await this.getWalletStatus(walletId);
console.log(`Wallet ${walletId} is reachable`);
} catch {
console.log(
`Wallet ${walletId} is not reachable yet. Verify the wallet creation/opening endpoint in the API reference.`
);
}
}

async getCurrentAddress(walletId: string): Promise<WalletAddressResult> {
// TODO: Confirm the exact address endpoint and response shape.
const response = await fetch(`${this.baseUrl}/wallet/address`, {
method: 'GET',
headers: this.walletHeaders(walletId),
});

if (!response.ok) {
throw await this.toError(response, 'Failed to get wallet address');
}

const data = await response.json();

return {
address: data.address ?? data.base58 ?? data.result?.address,
raw: data,
};
}

async getBalance(walletId: string): Promise<WalletBalance> {
// TODO: Confirm the exact balance endpoint and response shape.
const response = await fetch(`${this.baseUrl}/wallet/balance`, {
method: 'GET',
headers: this.walletHeaders(walletId),
});

if (!response.ok) {
throw await this.toError(response, 'Failed to get wallet balance');
}

const data = await response.json();

return {
available: data.available ?? data.balance?.available ?? data,
locked: data.locked ?? data.balance?.locked,
raw: data,
};
}

async sendHtr(params: {
fromWalletId: string;
destinationAddress: string;
amount: number;
}): Promise<SendTransactionResult> {
// TODO: Confirm the exact transaction endpoint, request body,
// and response shape in the Headless Wallet API reference.
const response = await fetch(`${this.baseUrl}/wallet/simple-send-tx`, {
method: 'POST',
headers: this.walletHeaders(params.fromWalletId),
body: JSON.stringify({
outputs: [
{
address: params.destinationAddress,
value: params.amount,
},
],
}),
});

if (!response.ok) {
throw await this.toError(response, 'Failed to send local HTR');
}

const data = await response.json();

return {
txId: data.tx_id ?? data.hash ?? data.txId,
raw: data,
};
}

private async toError(response: Response, fallbackMessage: string): Promise<Error> {
let details: unknown;

try {
details = await response.json();
} catch {
details = await response.text();
}

return new Error(
`${fallbackMessage}. Status: ${response.status}. Details: ${JSON.stringify(details)}`
);
}
}

Local wallet flow script

src/run-local-wallet-flow.ts
import { htrToIntegerAmount } from './amount';
import { getLocalForgeConfig } from './config';
import { assertForgeIsRunning } from './forgeHealth';
import { LocalHeadlessWalletClient } from './headlessWalletClient';

async function main() {
const config = getLocalForgeConfig();

console.log('Starting local Hathor Forge wallet flow...');
console.log('Network:', config.network);

await assertForgeIsRunning(config.forgeHealthUrl);

const walletClient = new LocalHeadlessWalletClient({
baseUrl: config.headlessWalletUrl,
});

console.log('\nPreparing local wallets...');
await walletClient.createOrOpenWallet(config.senderWalletId);
await walletClient.createOrOpenWallet(config.receiverWalletId);

console.log('\nGetting receiver address...');
const receiverAddress = await walletClient.getCurrentAddress(
config.receiverWalletId
);

console.log('Receiver address:', receiverAddress.address);

console.log('\nChecking balances before transaction...');
const senderBalanceBefore = await walletClient.getBalance(config.senderWalletId);
const receiverBalanceBefore = await walletClient.getBalance(
config.receiverWalletId
);

console.log('Sender balance before:', senderBalanceBefore.available);
console.log('Receiver balance before:', receiverBalanceBefore.available);

const amount = htrToIntegerAmount(5);

console.log('\nSending local HTR...');
const tx = await walletClient.sendHtr({
fromWalletId: config.senderWalletId,
destinationAddress: receiverAddress.address,
amount,
});

console.log('Local transaction sent:', tx.txId);

console.log('\nChecking balances after transaction...');
const senderBalanceAfter = await walletClient.getBalance(config.senderWalletId);
const receiverBalanceAfter = await walletClient.getBalance(
config.receiverWalletId
);

console.log('Sender balance after:', senderBalanceAfter.available);
console.log('Receiver balance after:', receiverBalanceAfter.available);

console.log('\nLocal flow completed.');
console.log({
network: config.network,
senderWalletId: config.senderWalletId,
receiverWalletId: config.receiverWalletId,
receiverAddress: receiverAddress.address,
sentAmount: amount,
txId: tx.txId,
});
}

main().catch((error) => {
console.error('\nLocal wallet flow failed.');

if (error instanceof Error) {
console.error(error.message);
} else {
console.error(error);
}

process.exit(1);
});

What the assistant should do before running this code

Before running this starter code, ask the assistant to use Hathor Forge MCP to prepare the local environment:

Using Hathor Forge MCP, prepare my local environment for the TypeScript wallet flow.

Please:
1. Check the full local environment status.
2. Start the node, miner, and wallet service if needed.
3. Create or prepare a local sender wallet.
4. Create or prepare a local receiver wallet.
5. Fund the sender wallet with local HTR from the faucet.
6. Confirm both wallets are local-only.
7. Return the wallet identifiers I should use in my .env file.

After the assistant prepares the local environment, update .env with the local wallet identifiers and run:

npm run dev

Expected local output

Starting local Hathor Forge wallet flow...
Network: localnet
Forge health check: OK

Preparing local wallets...
Prepare local wallet: sender
Prepare local wallet: receiver

Getting receiver address...
Receiver address: <local-address>

Checking balances before transaction...
Sender balance before: <sender-balance>
Receiver balance before: <receiver-balance>

Sending local HTR...
Local transaction sent: <local-transaction-id>

Checking balances after transaction...
Sender balance after: <updated-sender-balance>
Receiver balance after: <updated-receiver-balance>

Local flow completed.

The exact values depend on your local Hathor Forge state.

LLM-defined Local Plan

Start by asking the LLM for a plan, not immediate actions.

I want to test a local wallet transaction with Hathor Forge MCP.

Before using any tools, give me a plan that includes:
- which local services must be running
- which wallets need to be created
- how the faucet will be used
- how the transaction will be sent
- how balances will be checked
- how the transaction can be inspected
- what should stay local-only

A good LLM answer should explain that Forge is a local development environment and should not be confused with testnet or mainnet.

Example of expected output:

  • Start the local node, miner, and wallet service.
  • Create a sender wallet and a receiver wallet.
  • Fund the sender wallet from the local faucet.
  • Confirm the sender balance.
  • Send local HTR to the receiver wallet.
  • Confirm both balances.
  • Inspect the transaction using Forge tools or the local explorer.
  • Keep all seeds, funds, and assumptions local.

Running the Local Workflow

After the plan is clear, ask the assistant to execute it:

Using Hathor Forge MCP, run the local wallet transaction workflow.

Steps:
1. Check the full local environment status.
2. Start any required services that are not running.
3. Create a wallet named sender.
4. Create a wallet named receiver.
5. Fund sender with 50 local HTR.
6. Send 5 local HTR from sender to receiver.
7. Check both balances.
8. Return a summary of the transaction.

The assistant should use Forge MCP tools to perform the workflow.

Reviewing Results

After the workflow runs, ask for a review:

Review the local transaction workflow results.

Check whether:
- the node was running
- the miner was running
- the wallet service was running
- sender was funded before sending
- receiver received the expected amount
- all actions stayed inside Hathor Forge local development
- no mainnet or testnet assumptions were used

If the workflow failed, ask the assistant to debug the local environment before trying again.

Debugging local setup

If MCP tools fail or the assistant cannot connect to Forge, ask:

I am using Hathor Forge MCP and the assistant cannot use the tools.

Help me debug the setup.

Check:
- whether Hathor Forge is running
- whether the MCP endpoint is reachable
- whether the MCP server URL is correct
- whether Claude Code is configured with the MCP server
- whether the local ports are already in use
- whether I should restart Forge or re-register the MCP server

For manual verification, check:

curl http://127.0.0.1:9876/health

Prompt patterns for common tasks

Check local environment status

Using Hathor Forge MCP, check my full local environment status.

Tell me:
- whether the node is running
- whether the miner is running
- whether the wallet service is running
- whether the faucet has funds
- what action I should take next

Start a local development stack

Using Hathor Forge MCP, start the local Hathor development stack.

After starting it:
- confirm the node status
- confirm the miner status
- confirm the wallet service status
- tell me whether the environment is ready for local wallet tests

Create and fund a wallet

Using Hathor Forge MCP, create a local wallet named demo and fund it with 100 local HTR from the faucet.

After funding:
- check the wallet balance
- show the wallet address
- confirm that this wallet is for local development only

Send a local transaction

Using Hathor Forge MCP, send 5 local HTR from wallet sender to wallet receiver.

Before sending:
- confirm both wallets exist
- confirm sender has enough balance
- confirm this is a local Forge transaction

After sending:
- return the transaction identifier
- check both balances

Test wallet-headless locally

I want to test a wallet-headless integration against Hathor Forge.

Help me:
- confirm the local wallet-headless service is running
- identify the local wallet-headless URL
- create or fund a local wallet if needed
- explain which parts of this test are Forge-specific
- explain what I must change before moving to testnet

Use this together with Headless Wallet Skill when you are building application code that talks to Headless Wallet.

Test a blueprint locally

I want to test a nano contract blueprint using Hathor Forge.

Help me plan:
- how to prepare the local environment
- how to create or fund the required wallets
- how to publish or use the blueprint locally
- how to execute the contract flow
- how to inspect the resulting transactions
- what I must verify before using this outside local development

Use this together with Blueprint Skill when you are designing or reviewing blueprint source code.

LLM guardrails

When using Hathor Forge MCP, the LLM should follow these rules:

  • Do not describe Hathor Forge as a Claude Code skill.
  • Do not use Forge assumptions for mainnet or testnet workflows.
  • Do not expose the local MCP server publicly.
  • Do not treat Forge development wallets, seeds, or funds as real network assets.
  • Do not move from localnet to testnet or production without explicitly changing the setup.
  • Do not reset local data without making clear that existing local state will be removed.
  • Do not ask the user to share seeds, private keys, or sensitive credentials.
  • Do not assume MCP tools are available before verifying the connection.
  • Explain which actions are local-only.
  • Explain which steps must be repeated differently for testnet or production.

Practical checklist

Before using Hathor Forge MCP with an LLM, verify:

  • Hathor Forge is running locally.
  • The MCP endpoint is reachable at http://127.0.0.1:9876/mcp.
  • Your AI assistant is configured to use the Hathor Forge MCP server.
  • The local node is running.
  • The miner is running when you need new local funds or confirmations.
  • The wallet service is running before wallet operations.
  • The faucet has funds before funding wallets.
  • All wallets and transactions are local development artifacts.
  • The local MCP server is not exposed publicly.
  • You understand which assumptions must change before moving to testnet or production.

Next steps

After reviewing this workflow: