Hazina MCP Integration Guide

Technology: hazina-mcp · Category: tooling · Last reviewed: 2026-08-23

Source: https://tech-stack.codeamanilabs.org/guide/hazina-mcp

Insight:

Hazina is codeAmani's own MCP server — a local stdio process over the encrypted secrets vault, not a hosted API. Its 14 tools are deliberately value-free: agents can wire, audit and inject secrets by reference, but no tool returns a plaintext value. The vault lives in WSL, so Windows clients reach it through a wsl.exe bridge.

Hazina MCP Integration Guide

Focus — running codeAmani's first-party Hazina MCP server from WSL and exposing it to Windows-side agents (Cursor's Grok bot, Claude Code desktop) without ever moving the vault.

Overview

Most MCP servers in this stack are vendor-hosted and remote — you point a URL at them and attach a bearer token. Hazina is the opposite: a local stdio server you own, launched as a child process, speaking JSON-RPC over stdin/stdout. There is no network listener and no endpoint to leak.

It fronts the Hazina encrypted secrets vault. The defining design decision is that no MCP tool returns a secret value. Agents get names, references, wiring graphs and readiness reports; the only path a real value takes is inject, which writes a gitignored env file on disk that the agent never reads back. That is what makes it safe to hand an autonomous agent.

Source of truth is Linux. The vault lives at ~/.codeamani/hazina inside WSL. The Windows copy under C:\Users\info\.codeamani\hazina is archive-only — do not create new bindings against it.

Official Documentation

Topic URL
Build an MCP server https://modelcontextprotocol.io/docs/develop/build-server
Connect local (stdio) servers https://modelcontextprotocol.io/docs/develop/connect-local-servers
TypeScript SDK https://github.com/modelcontextprotocol/typescript-sdk
MCP in Claude Code https://docs.claude.com/en/docs/claude-code/mcp
MCP in Cursor https://cursor.com/docs/context/mcp
WSL filesystem / interop https://learn.microsoft.com/en-us/windows/wsl/filesystems

Hazina's own repo is private (codeAmani-Labs/hazina-mcp — the MCP layer split out from the vault package); its docs ship in-tree at docs/INSTALL.md and docs/UBUNTU-GLOBAL.md.

How it is built

Hazina uses the standard MCP TypeScript SDK — McpServer + registerTool with Zod input schemas, connected over StdioServerTransport:

npm install @modelcontextprotocol/sdk zod
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const server = new McpServer({ name: 'hazina', version: VERSION });

server.registerTool(
  'status',
  { description: 'Whether the vault is initialized…', inputSchema: {} },
  async () => ({ content: [{ type: 'text', text: summary }] }),
);

await server.connect(new StdioServerTransport());

Two rules follow from stdio transport and are non-negotiable:

Defense in depth — the value-free guard. Every tool result passes through a guarded() wrapper before it leaves the process: it re-loads the catalog and asserts (assertNoValues) that no secret value appears as a substring of the serialized payload, throwing rather than returning if one does. So even a future buggy handler cannot leak a value across the agent boundary. To avoid false rejections on short non-secret literals (a PORT, a public URL fragment), the assertion only fires on catalog values at or above MIN_ASSERTED_SECRET_LEN = 16 characters. That constant must stay in sync between the vault package and the split-out codeAmani-Labs/hazina-mcp MCP layer — a length one side treats as "too short to be a secret" the other must treat identically.

Install (WSL)

cd ~/projects/hazina
npm install
npm run install:global      # -> ~/.local/bin/hazina  and  ~/.local/bin/hazina-mcp
hazina doctor               # readiness: vault, key, DPAPI path, counts (names only)

The hazina-mcp launcher is a bash wrapper that resolves its own symlinks, then:

Because the launcher supplies its own HAZINA_HOME, client configs do not need an env block — see the WSLENV note under Gotchas.

The 14 tools

All are value-free. Verified live against hazina 0.3.0.

Tool What it returns
status Vault initialized? entry + bound-project counts
doctor Readiness: HAZINA_HOME, vault/key presence, PowerShell DPAPI path
list_refs Every secret reference — path, type, tags, field names
list_projects Project names that have a binding
get_binding A project's env-to-ref mappings (literals shown as literals)
describe_project Each env var, its reference, and status (ok/missing/stale)
wiring_summary Fleet-wide graph of env-to-vault refs grouped by namespace
propose_binding Scans .env.example/.env.local, proposes a binding
bind Create/update a binding: ENV name to vault reference
unbind Remove one ENV name from a binding (does not delete the secret)
inject Resolve a binding, write the gitignored env file with real values
audit Cross-check catalog vs bindings: stale/unused entries
import_from_os_env Import from OS environment (Windows User/Machine/Process)
push Resolve a binding and push values to Vercel or Netlify

There is no reveal / get_value tool. By design.

inject and push are the only tools that move plaintext, and both write it outward (to a gitignored file, or to a host's env store) rather than returning it into the transcript.

Wiring it to clients

Where the client runs decides whether you need the bridge.

Client Runs on Config file Command
Grok Build (CLI) inside WSL ~/.grok/config.toml /home/barnabas/.local/bin/hazina-mcp
Claude Code (in WSL) inside WSL ~/.claude.json /home/barnabas/.local/bin/hazina-mcp
Cursor / Grok bot Windows ~/.cursor/mcp.json wsl.exe bridge
Claude Code desktop Windows ~/.claude.json wsl.exe bridge

Windows clients — the wsl.exe bridge

{
  "mcpServers": {
    "hazina": {
      "command": "wsl.exe",
      "args": ["-d", "Ubuntu", "--", "/home/barnabas/.local/bin/hazina-mcp"]
    }
  }
}

wsl.exe transparently proxies stdin/stdout, so the JSON-RPC stream survives the boundary untouched. The same block works in ~/.cursor/mcp.json and in ~/.claude.json.

WSL-native clients

# ~/.grok/config.toml
[mcp_servers.hazina]
command = "/home/barnabas/.local/bin/hazina-mcp"
claude mcp add --scope user hazina -- /home/barnabas/.local/bin/hazina-mcp

Verifying the bridge

Do not trust the config — speak the protocol to it:

printf '%s\n' \
 '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"1"}}}' \
 '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
 '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
 | wsl.exe -d Ubuntu -- /home/barnabas/.local/bin/hazina-mcp

Expect "serverInfo":{"name":"hazina","version":"0.3.0"} followed by 14 tools.

Gotchas

Hazina vs the vendor MCPs

Hazina Cloudflare / Vercel / xAI
Transport local stdio (child process) remote HTTP
Config key command + args url + Authorization header
Auth filesystem + DPAPI-wrapped key bearer API token / OAuth
Ownership first-party, private vendor-hosted
Failure mode process will not spawn 401 / network
Secrets exposure none — value-free tools token sits in the config

Cloudflare's are already wired in ~/.cursor/mcp.json (mcp.cloudflare.com/mcp, docs.mcp.cloudflare.com/mcp, bindings.mcp.cloudflare.com/mcp). Note the contrast: those configs carry ${CLOUDFLARE_API_TOKEN} in a header — exactly the kind of sprawl Hazina exists to eliminate. See cloudflare/, vercel/ and xai/ for the vendor-side guides.

codeAmani notes

Official docs: