mcpField
H
HAI-MCP

HAI-MCP

Local
github.com/smlfgAI & Agents1Updated 1w ago

About HAI-MCP

HAI-MCP is an open-source, model-agnostic control plane for governing agent work through bounded missions and human oversight. It records contracts, authorizes time-limited sessions, checks activity against scope and supports owner-gated actions; it does not execute the work.

Key features

  1. 01Versioned mission contracts
  2. 02Time-bounded session leases
  3. 03Deterministic activity drift checks
  4. 04Owner-gated approvals
  5. 05Checkpoint and recovery tools

Use cases

  1. 01Scope an agent task with completion criteria
  2. 02Check proposed actions against a mission contract
  3. 03Require owner approval for sensitive changes
  4. 04Record evidence and recover mission context

MCP support

HAI-MCP exposes governance tools, resources and prompts through MCP, with stdio and streamable HTTP transports. MCP clients use it to authorize and record agent work; it does not run LLMs or execute tasks.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

mcp.json · Universal config
{
"mcpServers": {
"smlfg-hai": {
"command": "uvx",
"args": [
"hai-mcp"
],
"env": {
"HAI_HOME": "<HAI_HOME>",
"HAI_OWNER_HOME": "<HAI_OWNER_HOME>",
"HAI_TRANSPORT": "<HAI_TRANSPORT>",
"HAI_HTTP_HOST": "<HAI_HTTP_HOST>",
"HAI_HTTP_PORT": "<HAI_HTTP_PORT>",
"HAI_HTTP_TOKEN": "<HAI_HTTP_TOKEN>"
}
}
}
}
Run commanduvx hai-mcp
Environment variables to set
HAI_HOMEDirectory for the global HAI state (missions, leases, proofs). Default: ~/.hai
HAI_OWNER_HOMEDirectory for the owner out-of-band channel (one-time nonces). Deliberately outside HAI_HOME. Default: ~/.hai-owner
HAI_TRANSPORTTransport selection: 'stdio' (default) or 'streamable-http'.
HAI_HTTP_HOSTHost for streamable-http transport. Refused unless loopback or HAI_HTTP_TOKEN is set.
HAI_HTTP_PORTPort for streamable-http transport.
HAI_HTTP_TOKENSecretBearer token required to accept non-loopback streamable-http connections. Loopback binds without a token.

Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.

Packages
pypihai-mcp0.1.0

Tools

24

Saved tool list · updated 2w ago

ParameterTypeRequiredDescription
project_pathanyNo

Details

From the project README

HAI-MCP banner

HAI-MCP · Model-agnostic MCP control-plane for the Human Agent Interface (HAI) approach

License: MIT Python ≥ 3.12 MCP Issues


Why this repo exists

Agents are now driving shells, editors, browsers, and CI. Most of them work without a human in the loop long enough for the human to lose the thread. HAI — the Human Agent Interface — is an opinionated, evidence-based way to keep agentic work observable, bounded, owner-gated, and recoverable so a human can still own the work even when an agent is doing it.

HAI-MCP is the open-source, model-agnostic implementation of that approach. It is one of the pieces of Samuel Fleig's HAI stack — the part that any Model-Context-Protocol-speaking client can talk to, regardless of which LLM sits behind it.

Canonical site: https://www.human-agent-interface.com/ · About Samuel: https://www.human-agent-interface.com/samuel/


What "MCP control-plane" means here

MCP — the Model Context Protocol — is a standard JSON-RPC interface that lets a tool server expose tools, resources, and prompts to an LLM-backed client (Claude Code, Codex, Cursor, Grok, OpenCode, Hermes, …). The client discovers the server's tools and calls them during a conversation; the server stays stateless from the model's point of view.

A control-plane server is one that does not do the work itself — it governs how work is authorised, scoped, recorded, and handed back to the human. Concretely, an MCP control-plane:

ConcernWhat HAI-MCP exposes for it
Mission contracthai_open_mission, hai_get_contract, hai_recontract
Session leasinghai_authorize_session — time-bounded, contract-versioned
Activity classificationhai_check_activity / hai_drift_check — on-contract vs. off-contract
Focus & laneshai_set_focus, hai_status — at most 2 ACTIVE lanes
Owner gateone-time nonces out-of-band (HAI_OWNER_HOME or ntfy), or Touch ID on macOS, for accept / recontract / abandon
Evidence & closurehai_proof, hai_close_mission, hai_stop
Inbox & intakehai_intake, hai_distill, hai_park, hai_park_item
Recoveryhai_checkpoint, hai_recover

HAI-MCP is deliberately not an agent runtime. It never calls an LLM, never runs shell, never pushes to git, and never deletes files. It is the judge — agents call it to ask "may I?" and to record "I did".


Features

  • One state engine, 23 tools — three surfaces (legacy control plane, mission lifecycle, daily-loop wrappers) sharing one hardened core.
  • Strict fail-closed boundary — inputs are typed and rejected, not coerced. A String "2" is refused for an Integer field; the server stays reachable instead of silently mangling types.
  • Versioned mission contracts — every mission has a contract with a monotonic version. Recontracting produces a visible field-level diff and revokes every existing lease.
  • Time-bounded session leases — hai_authorize_session binds a lease to a mission id, a contract version, a duration, a role, a contribution, and a claimed criterion set.
  • Deterministic drift check — hai_check_activity classifies planned or observed activity against the contract without ever calling an LLM.
  • Two-principal owner gate:
    • Default (nonce): the server delivers a one-time code to the owner channel (HAI_OWNER_HOME / file, or ntfy). The client never sees the code. The code is bound to the exact change, single-use, expiring; only the hash is stored in HAI_HOME.
    • touchid (macOS): the server process shows a Touch ID prompt for that exact change. There is no code. The agent's follow-up call applies it; the client cannot approve itself.
    • ack_legacy: the old self-asserted owner_ack flag — an honor system, surfaced as such by hai_health.
  • Mount table — hai_bind_project joins a logical project_id to a device-local directory behind owner_ack + reason.
  • Model-agnostic — same binary, same tools, same contract. Switch LLMs without rewriting governance.
  • Two transports — stdio (default) and streamable-http with optional bearer-token binding (loopback only by default).
  • Checkpoint & recover — hai_checkpoint snapshots context; hai_recover returns the smallest recovery next action.
  • 203 tests green — the engine is covered; the slice remains open for the learning-budget and owner-instrument follow-ups.

Install & run

Requires Python ≥ 3.12 and uv.

git clone https://github.com/smlfg/hai-mcp.git
cd hai-mcp
uv sync --all-extras
uv run hai-mcp          # stdio transport, default

Streamable-HTTP transport:

HAI_TRANSPORT=streamable-http \
HAI_HTTP_HOST=127.0.0.1 \
HAI_HTTP_PORT=8765 \
HAI_HTTP_TOKEN="$(openssl rand -hex 32)" \
uv run hai-mcp

HTTP binding to non-loopback hosts is refused unless HAI_HTTP_TOKEN is set. See docs/OWNER_GATE.md and the --help output.


Sample usage — wiring the server into a client

The server is transport-agnostic; every MCP client gets the same 23 tools. Drop the snippet into the client's MCP config and restart.

Claude Code / Claude Desktop
{
  "mcpServers": {
    "hai": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/absolute/path/to/hai-mcp",
        "hai-mcp"
      ],
      "env": {
        "HAI_HOME": "/home/you/.hai",
        "HAI_OWNER_HOME": "/home/you/.hai-owner"
      }
    }
  }
}
Cursor
{
  "mcpServers": {
    "hai": {
      "command": "uv",
      "args": [
        "run",
        "--directory",
        "/absolute/path/to/hai-mcp",
        "hai-mcp"
      ],
      "env": {
        "HAI_HOME": "/home/you/.hai",
        "HAI_OWNER_HOME": "/home/you/.hai-owner"
      }
    }
  }
}
Codex / Hermes / any MCP stdio client

Same shape — point at the uv run --directory … hai-mcp command and pass the two env vars. More snippets live in docs/client-snippets/.


Sample usage — driving the protocol

A typical agent loop calls HAI-MCP before it acts and after it acts.

1. Open a bounded mission
hai_mission_start(
  problem   = "Refactor the evaluator harness to be deterministic.",
  artifact  = "Pull request titled 'evaluator: deterministic harness'.",
  done_criteria = [
    {"id": "C1", "description": "Two A/B cases produce identical verdicts on three reruns."},
    {"id": "C2", "description": "Harness runs offline; no live network calls."},
  ],
  owner             = "samuel",
  time_limit_hours  = 6,
  non_goals         = ["Do not touch the MCP server.", "Do not change contract shapes."],
  constraints       = {"python": ">=3.12", "branch": "slice/eval-determinism"},
)
2. Authorise a session lease
hai_authorize_session(
  mission_id         = "<from open>",
  contract_version   = 1,
  agent_identity     = "codex-cli",
  role               = "implementer",
  contribution       = "Deterministic A/B harness",
  expected_result    = "Green pytest with frozen inputs.",
  duration_minutes   = 90,
  criterion_ids      = ["C1", "C2"],
  device_id          = "mbp-mirgraatin",
  harness_id         = "codex-cli/0.45",
)
3. Check an activity before running it
hai_check_activity(
  session_id     = "<from lease>",
  activity_step  = "Replace random.seed with a seeded fixture in tests/test_eval_ab.py",
  criterion_id   = "C1",
  affected_paths = ["tests/test_eval_ab.py", "tests/fixtures/ab/case1.json"],
)
# → {"verdict": "on_contract", ...}
4. Close with evidence
hai_proof(
  mission_id        = "<from open>",
  contract_version  = 1,
  outcome_summary   = "A/B cases produce identical verdicts on three reruns; harness offline.",
  evidence          = {
    "C1": {"command": "pytest tests/test_eval_ab.py -q", "exit_code": 0,
           "reruns": [0, 0, 0]},
    "C2": {"command": "pytest tests/test_eval_ab.py -q --offline", "exit_code": 0},
  },
)
5. Owner-gated promotion

For hai_accept_next_step, hai_recontract, or abandoning a mission, the first call without owner_code asks the owner out of band.

  • file / ntfy: a one-time code is delivered to HAI_OWNER_HOME or an ntfy topic. Relaying it back as owner_code=<code> completes the action. The client never sees the code; only its hash is stored in HAI_HOME.
  • touchid (macOS): set HAI_OWNER_CHANNEL=touchid on the server. The server shows a Touch ID prompt and returns status: owner_approved. Call the same tool again with the same arguments (no code) to apply that exact change. Optional: HAI_OWNER_TOUCHID_TIMEOUT (default 60), HAI_OWNER_TOUCHID_HELPER (a compiled binary), and HAI_OWNER_TOUCHID_FALLBACK=file only when Touch ID cannot run.

The approval is bound to the exact change and is single-use. On a Mac, uv run python scripts/manual_touchid.py prompt and … gate exercise the real sensor; CI mocks the helper. Detail: docs/OWNER_GATE.md.


State layout

  • Global: $HAI_HOME — default ~/.hai
  • Owner channel: $HAI_OWNER_HOME — default ~/.hai-owner (deliberately outside HAI_HOME so the agent cannot read it)
  • Per-project: <project_path>/Projek-Managment/ (legacy) or device mount + relative prefixes when a project_id is bound
  • Mount table: HAI_HOME/core/projects.json

All writes are resolved and confined to these roots.


Project layout

hai-mcp/
├── docs/
│   ├── TOOL_CONTRACT.md      # normative tool contract (gates, errors, schemas)
│   ├── OWNER_GATE.md         # nonce + ack_legacy owner-gate spec
│   ├── BUILD_HANDOFF.md
│   ├── client-snippets/      # ready-to-paste mcp.json snippets
│   ├── eval/                 # A/B harness contract
│   ├── plans/                # dated design slices
│   └── visuals/              # mission-lifecycle banner assets
├── scripts/                  # stdio smoke + impact-eval runner
├── src/hai_mcp/              # the server
└── tests/                    # 203 tests

Limitations

HAI-MCP is intentionally narrow. It does not:

  • Call any LLM. The server is dumb on purpose — governance is a separate concern from generation.
  • Execute code, run shells, push git, or delete files. It refuses tools like "commit & push", "run pytest", "rm -rf". Agents are expected to do those things and report back via hai_check_activity / hai_proof.
  • Merge with hai-intake packages. The intake pipeline is a separate stack; coexistence is fine, fusion is not.
  • Provide a UI. There is no dashboard. The control plane speaks MCP and writes JSON; visualisation is the client's job.
  • Multi-mission concurrency. Exactly one active mission globally. Open a new one only after the previous is closed (completed or abandoned).
  • Cross-device writes. Each device sees only its own mounts. The mount table is per-device; the contract is global.
  • Forward compatibility for major MCP bumps. The server pins mcp>=1.9.0,<2; a v2 of MCP will require a separate migration slice.
  • No revocation list / no kill-switch API. Lease invalidation happens via recontract, mission close, or hai_stop; there is no out-of-band "revoke everything right now" tool.
  • No automatic recovery from a corrupted HAI_HOME. If the global state directory is corrupted, the server fails closed — by design, but recovery is manual (see hai_recover).

See docs/TOOL_CONTRACT.md for the full gate matrix and docs/OWNER_GATE.md for the owner-gate contract.


Tests

uv run pytest                       # full suite
uv run python scripts/stdio_smoke.py  # stdio round-trip smoke

The repo carries 203 green tests as of the Touch ID owner-channel slice. CI status lives on the GitHub Actions page of the repository.


Contributing

The control plane is small on purpose — additions go through a contract slice:

  1. Read docs/TOOL_CONTRACT.md.
  2. Open an issue describing the tool / gate / state change.
  3. Land it behind a fail-closed slice with tests + plan in docs/plans/.

Pull requests that change gates, schemas, or the mount table without a matching plan will be asked to follow the same path.


License

MIT — see LICENSE. Copyright © 2026 Samuel Fleig.


Acknowledgements

HAI-MCP is one piece of Samuel Fleig's HAI stack. It stands on:

  • the Model Context Protocol specification,
  • the mcp Python SDK (mcp>=1.9.0,<2),
  • and the legacy ~/.config/hai-agent-mcp Hermes bridge that this server replaces for control-plane work. Coexistence is supported; the bridge is not required.

Canonical HAI site: https://www.human-agent-interface.com/ · About Samuel Fleig: https://www.human-agent-interface.com/samuel/

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.