# human-mcp
<div align="center">
<img src="docs/assets/human-mcp-logo.svg" width="96" height="96" alt="human-mcp logo" />
<h3>Ask a real human from an MCP tool call.</h3>
<p>
A human-in-the-loop MCP server for moments where agents need judgment, visual review, account-bound action, or a short escalation path.
</p>
<p>
<a href="README.md">English</a>
·
<a href="README.zh-CN.md">简体中文</a>
·
<a href="#why-people-care">Why it matters</a>
·
<a href="#online-panel">Online panel</a>
·
<a href="#deploy-with-an-agent">Deploy</a>
·
<a href="#security-model">Security</a>
·
<a href="#technical-details">Technical details</a>
</p>
</div>
<p align="center">
<a href="https://github.com/LIghtJUNction/human-mcp/actions/workflows/release.yml"><img alt="Release workflow" src="https://github.com/LIghtJUNction/human-mcp/actions/workflows/release.yml/badge.svg" /></a>
<a href="https://github.com/LIghtJUNction/human-mcp/releases"><img alt="GitHub release" src="https://img.shields.io/github/v/release/LIghtJUNction/human-mcp?display_name=tag&sort=semver" /></a>
<a href="Cargo.toml"><img alt="MIT license" src="https://img.shields.io/badge/license-MIT-green.svg" /></a>
<a href="Cargo.toml"><img alt="Rust 2024" src="https://img.shields.io/badge/Rust-2024-f46623?logo=rust&logoColor=white" /></a>
<a href="https://modelcontextprotocol.io/"><img alt="MCP" src="https://img.shields.io/badge/MCP-human--in--the--loop-6f42c1" /></a>
<a href="Cargo.toml"><img alt="Axum backend" src="https://img.shields.io/badge/backend-Axum-005f73" /></a>
<a href="human-mcp-webui/package.json"><img alt="React 19 frontend" src="https://img.shields.io/badge/frontend-React%2019-61dafb?logo=react&logoColor=111111" /></a>
<a href="human-mcp-webui/package.json"><img alt="Bun runtime" src="https://img.shields.io/badge/runtime-Bun-000000?logo=bun&logoColor=white" /></a>
<a href="#deploy-with-an-agent"><img alt="AUR packages" src="https://img.shields.io/badge/packages-AUR-1793d1?logo=archlinux&logoColor=white" /></a>
<a href="#security-model"><img alt="Passkeys and OAuth" src="https://img.shields.io/badge/auth-Passkeys%20%2B%20GitHub%20OAuth-2ea44f" /></a>
</p>
`human-mcp` lets an agent ask a logged-in person for help without leaving the MCP loop. The agent calls a tool, the server creates a task, the human answers in the web UI, and the agent receives the result.
Use it when a workflow needs a person for one small but important step: choosing between options, reading an image, checking a website, retrieving an account-bound code, approving a risky action, or escalating an ambiguous decision.
For Simplified Chinese documentation, see [README.zh-CN.md](README.zh-CN.md).
## Repository Map
| Area | Path | Purpose |
| --- | --- | --- |
| Server | `src/` | Rust MCP server, REST APIs, auth, task lifecycle, and deployment logic. |
| Web UI | `human-mcp-webui/` | React task workbench for humans who receive and answer requests. |
| SDK | `crates/human-mcp-sdk/` | Shared types for plugin manifests and integration code. |
| Examples | `examples/` | Minimal client and integration examples. |
| Deployment | `docs/` | Agent deployment prompt, systemd/nginx notes, packaging, and security details. |
## Online Panel
| Purpose | URL |
| --- | --- |
| Human workbench | <https://human.lmm.best/> |
| MCP endpoint | <https://human.lmm.best/mcp> |
Use the site root for the browser panel. Use the no-trailing-slash endpoint for MCP JSON-RPC: `/mcp`.
## Login And Registration
Use **GitHub OAuth** to register and log in to the public panel at <https://human.lmm.best/>. More login methods can be added later.
Normal users do not need a password. There is no ordinary user password to remember, store, or leak. After logging in, users can add a passkey and use passwordless sign-in on supported devices.
Email/password login is only for the administrator account. The admin password is a strong private secret and should not be published in README, issues, screenshots, examples, or user-facing setup guides.
## Why People Care
| When the agent hits this | `human-mcp` gives it this |
| --- | --- |
| Needs judgment, not more tokens | A typed human task with title, prompt, choices, image, steps, and timeout |
| Needs a real account holder | A logged-in human workbench with identity, presence, and answer history |
| Cannot wait inside one request | Async task creation plus later polling with `read_human_replies` |
| Needs the right human | Profiles, tags, friends, online status, and reputation-aware discovery |
| Needs new collaboration patterns | Community plugin manifests for request templates, route strategies, scoring rules, and third-party channels |
| Needs operational deployment | Rust server, React UI, systemd, nginx, AUR packages, and release workflow |
## How It Feels
```mermaid
flowchart LR
A[Agent] -->|calls MCP tool| B["POST /mcp"]
B --> C[Task envelope]
C --> D[Human workbench]
D -->|answer| E[Result or reply mailbox]
E --> A
C -. timeout .-> F[Expired request]
F --> G[Trash and structured MCP error]
```
The important design choice: the agent does not directly control a person. It creates a bounded task envelope with a type, owner, prompt, timeout, and lifecycle.
## Most Interesting Parts
| Piece | Why it is useful |
| --- | --- |
| High-value shortcuts | `approve`, `judge`, and `feedback` cover the common agent escalations without making callers pick a task kind. |
| Blocking and async asks | Use `ask_human` when the agent should wait; use `ask_human_*_async` when the agent should keep moving. |
| Typed tasks | Text, choice, yes/no judgment, image review, and step-by-step tasks get clearer UI than a single free-form prompt. |
| Human directory | Agents can discover online humans by profile, tag, friend graph, and reputation, subject to server visibility rules. |
| Community plugins | Load request templates, route strategies, scoring rules, and external channel declarations from plugin manifests. |
| Agent-bound identity | Each human has an agent secret, so MCP requests are tied back to a specific human account instead of a global anonymous token. |
| Practical server packaging | The repo includes nginx routing, systemd units, Arch/AUR packaging, release artifacts, and admin-triggered updates. |
## Deploy With An Agent
Copy this command, run it anywhere with internet access, then send the fetched prompt to the agent that will deploy `human-mcp` on your server:
```bash
curl -fsSL https://raw.githubusercontent.com/LIghtJUNction/human-mcp/main/docs/AGENT_DEPLOY_PROMPT.md
```
The prompt tells the agent to inspect the server, install the package, configure the site root and `/mcp`, verify the MCP endpoint, and keep admin secrets out of public output.
<details>
<summary><strong>Manual Server Deployment Guide</strong></summary>
This is the short human-run path for an Arch Linux server. See [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) for the longer deployment note.
1. Install the package:
```bash
paru -S human-mcp-git
# or, after a GitHub Release exists:
paru -S human-mcp-bin
```
2. Initialize the private admin login:
```bash
sudo human-mcp init-admin --email <admin-email>
sudoedit /etc/human-mcp.env
```
3. Set the public URL and packaged web directory:
```bash
HUMAN_PUBLIC_BASE_URL=https://your-domain.example
HUMAN_WEB_DIST=/usr/share/human-mcp/web
```
4. Enable GitHub OAuth for normal users by setting the GitHub client id and secret in `/etc/human-mcp.env`:
```bash
HUMAN_GITHUB_CLIENT_ID=<github-oauth-client-id>
HUMAN_GITHUB_CLIENT_SECRET=<github-oauth-client-secret>
```
5. Start the service:
```bash
sudo systemctl enable --now human-mcp.service
curl -fsS http://127.0.0.1:8787/healthz
```
6. Configure nginx so:
- `location = /mcp` proxies to backend `/mcp` for MCP JSON-RPC.
- `location /` proxies to the web UI, API, WebSocket, and static assets.
7. Verify:
```bash
curl -fsS https://your-domain.example/api/auth/config
curl -i https://your-domain.example/
```
The panel should load at `https://your-domain.example/`. Normal users should register with GitHub OAuth, then optionally add a passkey.
</details>
## Security Model
`human-mcp` is designed to make the trust boundary explicit: agents may request help, but humans, admins, and server policy decide what is visible and who may act.
| Boundary | Mechanism |
| --- | --- |
| Agent access | MCP calls require a per-human agent secret through `x-human-agent-secret` or `Authorization: Bearer ...`. |
| Human access | Normal users log in with GitHub OAuth and can add passkeys for passwordless sign-in. |
| Admin access | Admin APIs call `require_admin`; email/password login is reserved for the administrator and should stay private. |
| Directory privacy | Agent directory visibility defaults to `self_only`; optional modes expose friends, public users, or users above a reputation threshold. |
| Reserved identity | `#admin` is reserved. Users and agents cannot assign it through profiles or task text. |
| Task containment | Requests have typed payloads, required title/prompt validation, normalized choices/tags, and server-clamped timeouts. |
| Runtime containment | The packaged service runs as the `human-mcp` user with `ProtectSystem=strict`, `ProtectHome=true`, and write access limited to `/var/lib/human-mcp`. |
| Self-update containment | The web UI can only trigger a configured update command. Packaged sudoers limits this to starting `human-mcp-self-update.service`. |
| Secret hygiene | Ordinary users have no password to leak. Session tokens are stored in memory as SHA-256 hashes keyed by `HUMAN_SESSION_SECRET`; OAuth client secrets are not returned by public config APIs. |
Human answers are still input. Treat them like any other external result: validate before using them for destructive actions, run the service behind HTTPS, and protect `/etc/human-mcp.env`.
## Technical Details
The rest is folded so the README stays readable. Open only what you need.
<details>
<summary><strong>What It Provides</strong></summary>
- MCP JSON-RPC endpoint at `/mcp`.
- Human workbench web UI served at `/`.
- Rust backend with REST APIs and WebSocket updates.
- Bun/Vite/React frontend in the `human-mcp-webui` git submodule.
- Blocking and async human request tools for text, choice, yes/no judgment, image review, and step-by-step tasks.
- Per-human agent access secrets, public profiles, tags, friends, reputation, reports, and online presence.
- Community plugin manifests loaded from `HUMAN_PLUGIN_DIR`, with SDK types published as `human-mcp-sdk`.
- AUR packages for Arch Linux:
- `human-mcp-git`: builds from GitHub source.
- `human-mcp-bin`: installs a GitHub Release tarball.
- Admin-only password login, GitHub OAuth registration for normal users, and passkey sign-in support.
- Live presence count and persisted active periods in the users JSON file.
- Request envelope lifecycle: pending, answered, expired, trash, plus persisted late replies for async tools.
</details>
<details>
<summary><strong>Important Paths</strong></summary>
| Purpose | Path |
| --- | --- |
| MCP endpoint | `/mcp` |
| Web UI | `/` |
| Local backend bind | `127.0.0.1:8787` by default |
| Packaged web dist | `/usr/share/human-mcp/web` |
| Service env file | `/etc/human-mcp.env` |
| User/activity store | `/var/lib/human-mcp/users.json` |
| SQLite store | `/var/lib/human-mcp/human-mcp.sqlite3` |
| systemd unit | `human-mcp.service` |
| self-update unit | `human-mcp-self-update.service` |
`GET /mcp` is intentionally not the UI; it returns a method warning. Open the UI at `/`.
</details>
<details>
<summary><strong>Local Development</strong></summary>
```bash
cp env.example .env
cargo run
```
Build the frontend inside the submodule:
```bash
cd human-mcp-webui
bun install
bun run build
```
Then restart the backend. For local dev, `HUMAN_WEB_DIST=./human-mcp-webui/dist` is fine.
Useful checks:
```bash
cargo test
cargo check
cd human-mcp-webui && bun run build
curl -fsS http://127.0.0.1:8787/healthz
```
</details>
<details>
<summary><strong>MCP Tools</strong></summary>
Implemented MCP methods:
- `initialize`
- `notifications/initialized`
- `tools/list`
- `tools/call`
Current tools include:
| Tool | Purpose |
| --- | --- |
| `approve` | Ask for human approval or denial before a proposed action and wait for the answer. |
| `judge` | Ask for a human yes/no judgment and wait for the answer. |
| `feedback` | Ask for short free-form human feedback and wait for the answer. |
| `ask_human` | Create a human request and wait for the answer. |
| `ask_human_async` | Create a human request and return a `request_id` immediately. |
| `ask_human_text_async` | Create a non-blocking text-answer request. |
| `ask_human_choice_async` | Create a non-blocking choice request. |
| `ask_human_judgment_async` | Create a non-blocking yes/no judgment request. |
| `read_human_replies` | Read completed replies for the user attached to this agent secret. |
| `list_human_nodes` | List configured downstream human-mcp nodes without exposing secrets. |
| `search_human_network` | Search visible human profiles across downstream human-mcp nodes. |
| `ask_human_network_async` | Route an async human request to a downstream human-mcp node and collect the answer through `read_human_replies`. |
| `read_human_network_ledger` | Read the local hash-chained federation ledger for cross-node audit receipts. |
| `create_human_task` | Create a visible AI task for the human account attached to this agent secret. |
| `list_human_tasks` | List AI-created tasks for the attached human account. |
| `leave_human_memo` | Leave an offline memo on a visible human's memo board. |
| `list_agent_inbox` | List pending human-to-agent messages, including friend requests and ask-me prompts. |
| `request_human_friend` | Send a friend request from this connected agent to a visible human. |
| `accept_human_friend` | Accept a human's pending friend request to this connected agent. |
| `list_online_humans` | List online human operators and public profiles visible to this agent. |
| `search_human_profiles` | Search visible human profiles by text or `#tag`. |
| `list_human_tags` | List visible `#tag` usage counts. |
| `rate_human` | Rate a human from 0 to 10; feedback is weighted by the rater's own reputation. |
| `report_human` | Report a human to the administrator mailbox and apply a zero-score weighted feedback signal from this actor. |
| `list_human_plugins` | List loaded community plugins and their request templates, route strategies, scoring rules, and channels. |
| `create_human_request_from_template` | Create an async human request from a plugin request template. |
`approve`, `judge`, and `feedback` are blocking convenience wrappers over `ask_human`. Use the `ask_human_*_async` tools and `read_human_replies` when the agent should continue work while the human answers.
### human-mcp Network
A `human-mcp` instance can act as a root or branch node and forward requests to downstream instances. The root loads child nodes from `HUMAN_FEDERATION_FILE`; each edge uses its own downstream agent secret. Remote answers are copied back into the root node's local reply mailbox, so callers still poll the root with `read_human_replies`.
TOML example:
```toml
[[nodes]]
node_id = "branch-cn"
endpoint = "https://branch.example/mcp"
agent_secret = "child-node-agent-secret"
description = "CN operators"
tags = ["#ops", "#cn"]
trust_level = "trusted"
max_hops = 3
```
Network tools:
- `list_human_nodes`: inspect configured nodes; `agent_secret` is hidden.
- `search_human_network`: send profile searches to downstream nodes.
- `ask_human_network_async`: create a cross-node async request and read the returned local `request_id` with `read_human_replies`.
- `read_human_network_ledger`: inspect recent local federation ledger entries and the current chain head.
The network borrows the useful part of blockchain design: a local append-only
hash chain. Each cross-node request creation, expiry, failure, and collected
reply appends a ledger entry whose hash includes the previous entry hash. This
creates tamper-evident routing receipts without adding proof-of-work, tokens, or
global consensus.
Reputation is a weighted trust score, not a raw average. GitHub OAuth seeds an initial prior from public account signals such as account age, public repositories, sampled stars, follower count, source-repo ratio, and recent activity. Each rating is weighted by the rater's current reputation, repeated ratings from the same actor update the prior rating, and reports create an audit entry plus a zero-score feedback signal. Profile and leaderboard responses include a public `reputation_breakdown` with seed source, seed weight, feedback weight, total weight, and confidence so agents can rank humans without guessing how much evidence backs the score.
### `ask_human`
`ask_human` accepts simple human tasks:
```json
{
"kind": "choice|judgment|text|image_review|steps",
"title": "Short task title",
"prompt": "What the human should do",
"choices": ["A", "B"],
"image_url": "https://...",
"image_base64": "iVBORw0KGgo...",
"image_mime_type": "image/png",
"steps": ["Open the site", "Read the SMS code"],
"timeout_seconds": 60,
"background": false
}
```
Image review tasks may use either `image_url` or `image_base64`. `image_base64` may be raw base64 bytes or a full `data:image/...;base64,...` URL. When raw base64 is used, `image_mime_type` defaults to `image/png`.
`timeout_seconds` is agent-configurable. If omitted, the backend uses 60 seconds. Values are clamped by the server before the envelope is created. The blocking tool waits for the answer. The async tools return a `request_id` immediately; poll `read_human_replies` to collect completed replies.
The backend creates an envelope:
```json
{
"id": "...",
"title": "...",
"prompt": "...",
"kind": "text",
"created_at": 1000,
"timeout_seconds": 60,
"expires_at": 1060
}
```
If the human does not answer in time, the request is removed from pending, added to trash, and the MCP caller receives a structured error:
```json
{
"code": -32001,
"message": "Human request timed out after 60 seconds",
"data": {
"request_id": "...",
"title": "...",
"timeout_seconds": 60,
"expired_at": 1060,
"suggestion": "Try again with a longer timeout or simplify the request."
}
}
```
Example payloads are in `examples/`; `examples/README.md` maps each file to the
current MCP tool schema.
Tags are normalized to lowercase `#tag` values. `#admin` is a reserved tag: clients and agents cannot assign it through profile updates or task text, and the backend only derives it for the configured admin identity.
### Community Plugins
Plugins are declarative JSON or TOML manifests loaded at startup from
`HUMAN_PLUGIN_DIR`. A manifest can contribute request templates, route
strategies, scoring rules, and third-party channel declarations. The server
exposes loaded plugins through `list_human_plugins`, and agents can create an
async request from a template with `create_human_request_from_template`.
Template ids use `plugin-id/template-id`. Template text supports simple
`{{variable}}` substitution from the tool call's `variables` object. Plugin
authors can use the published `human-mcp-sdk` crate to build and validate
manifests before distribution.
Example manifest: [examples/community-release-plugin.json](examples/community-release-plugin.json).
</details>
<details>
<summary><strong>HTTP and WebSocket API</strong></summary>
Authenticated UI APIs:
- `GET /api/me`
- `GET /api/me/profile`
- `POST /api/me/profile`
- `GET /api/passkeys`
- `POST /api/passkeys/register/start`
- `POST /api/passkeys/register/finish`
- `POST /api/passkeys/{id}/delete`
- `GET /api/agent/access`
- `POST /api/agent/secret`
- `GET /api/requests`
- `POST /api/requests/{id}/answer`
- `GET /api/sent`
- `GET /api/tasks`
- `POST /api/tasks/{id}/status`
- `GET /api/trash`
- `POST /api/trash/clear`
- `GET /api/users/online`
- `GET /api/users/search?q=...`
- `POST /api/humans/rate`
- `POST /api/humans/report`
- `GET /api/leaderboard`
- `GET /api/tags`
- `GET /api/friends`
- `POST /api/friends`
- `POST /api/friends/{email}/accept`
- `POST /api/friends/{email}/remove`
- `GET /api/ws`
Admin APIs:
- `GET /api/admin/users`
- `POST /api/admin/users`
- `POST /api/admin/users/{email}`
- `POST /api/admin/users/{email}/kick`
- `GET /api/admin/reports`
- `GET /api/admin/settings`
- `POST /api/admin/settings`
- `GET /api/admin/update`
- `POST /api/admin/update`
- `GET /api/admin/webhooks`
- `POST /api/admin/webhooks`
WebSocket events:
```json
{ "type": "request_created", "request": {} }
{ "type": "request_answered", "id": "...", "answer": {} }
{ "type": "request_expired", "id": "...", "expired_request": {} }
{ "type": "trash_cleaned", "removed_count": 1 }
{ "type": "presence_changed", "online_count": 1 }
```
</details>
<details>
<summary><strong>Configuration</strong></summary>
`env.example` documents all supported variables. Important production values:
```bash
HUMAN_BIND=127.0.0.1:8787
HUMAN_PUBLIC_BASE_URL=https://your-domain.example
HUMAN_WEB_DIST=/usr/share/human-mcp/web
HUMAN_USERS_FILE=/var/lib/human-mcp/users.json
HUMAN_DB_FILE=/var/lib/human-mcp/human-mcp.sqlite3
HUMAN_ADMIN_EMAIL=<admin-email>
HUMAN_ADMIN_PASSWORD=<generated-admin-password>
HUMAN_SESSION_SECRET=<generated-session-secret>
HUMAN_TRASH_RETENTION_SECONDS=604800
HUMAN_CLEANUP_INTERVAL_SECONDS=60
HUMAN_SELF_UPDATE_COMMAND=/usr/bin/sudo -n /usr/bin/systemctl start human-mcp-self-update.service
HUMAN_SELF_UPDATE_TIMEOUT_SECONDS=30
HUMAN_PLUGIN_DIR=/etc/human-mcp/plugins
HUMAN_NODE_ID=root
HUMAN_FEDERATION_FILE=/etc/human-mcp/federation.toml
```
Production note: after AUR install, make sure `/etc/human-mcp.env` uses the packaged web directory:
```bash
HUMAN_WEB_DIST=/usr/share/human-mcp/web
```
If this is left as `./human-mcp-webui/dist`, `https://your-domain.example/` will return 404 because the service runs from `/var/lib/human-mcp`.
</details>
<details>
<summary><strong>Arch Deployment</strong></summary>
Install with an AUR helper as a normal user, not root:
```bash
paru -S human-mcp-git
# or, after a GitHub Release exists:
paru -S human-mcp-bin
```
On servers where the AUR user is `arch`, use a login shell:
```bash
sudo -iu arch paru -S human-mcp-git
```
Avoid `sudo -u arch paru ...`; it can inherit root's working directory/git environment and fail with errors like `fatal: error reading '/root/.git'`.
Initialize or reset the admin account:
```bash
sudo human-mcp init-admin --email <admin-email>
sudoedit /etc/human-mcp.env
sudo systemctl enable --now human-mcp.service
```
The `init-admin` command writes `/etc/human-mcp.env`, generates a new session secret, and prints the generated admin password. Save that password in your password manager; do not commit it.
Packaged installs include admin-triggered self-update support. The web UI calls `POST /api/admin/update`; the service then starts `human-mcp-self-update.service` through a sudoers rule limited to that exact systemctl command. The oneshot unit runs the configured AUR helper as the normal AUR user, upgrades `human-mcp-bin` or `human-mcp-git`, reloads systemd, and restarts `human-mcp.service`.
Override updater defaults in `/etc/human-mcp-update.env` when needed:
```bash
HUMAN_UPDATE_AUR_USER=arch
HUMAN_UPDATE_HELPER=paru
HUMAN_UPDATE_PACKAGE=human-mcp-bin
```
Because the updater runs from systemd without a TTY, the AUR user must be able to run its package installation step non-interactively, for example with `sudo -n true` succeeding for that user.
After editing `/etc/human-mcp.env`:
```bash
sudo systemctl restart human-mcp.service
```
</details>
<details>
<summary><strong>Nginx Reverse Proxy</strong></summary>
Include `packaging/nginx/human-mcp.conf` in the HTTPS server block for your domain.
Required behavior:
- `location = /mcp` proxies to backend `/mcp` for JSON-RPC.
- `location /` proxies to backend `/` for the web UI, API, WebSocket, and static assets.
- `/mcp/` should redirect to `/`.
Example verification:
```bash
sudo nginx -t
sudo systemctl reload nginx
curl -i https://your-domain.example/
curl -fsS https://your-domain.example/api/auth/config
```
A working `/` response should be `HTTP 200` with the web UI HTML.
</details>
<details>
<summary><strong>Verification Checklist</strong></summary>
After install or upgrade:
```bash
pacman -Q human-mcp-git human-mcp-bin 2>/dev/null || true
human-mcp --version
systemctl is-active human-mcp.service
curl -fsS http://127.0.0.1:8787/healthz
curl -fsS http://127.0.0.1:8787/mcp \
-H 'content-type: application/json' \
--data @examples/mcp-tools-list.json
curl -i https://your-domain.example/
```
Expected:
- service is `active`
- health returns `{"ok":true}`
- `tools/list` includes `ask_human`
- `/` returns the web UI HTML, not 404
</details>
<details>
<summary><strong>Release Packaging</strong></summary>
Build a binary release tarball:
```bash
scripts/package-release.sh
# or explicitly:
scripts/package-release.sh <version>
```
With no argument, the script reads the version from `Cargo.toml`. If an explicit
version does not match `Cargo.toml`, packaging fails instead of producing a
misnamed tarball.
Or publish through GitHub Actions:
```bash
git tag v<version>
git push origin v<version>
```
The `Release` workflow can also be run manually from GitHub Actions. Its `version` input is optional and defaults to `auto`, which uses the version in `Cargo.toml`. The GitHub Release tag is always `v<version>`. It builds the Rust binary and web UI, uploads the tarball plus `.sha256` as workflow artifacts, and creates or updates that GitHub Release.
The tarball is written to `dist-release/` and contains:
- `human-mcp`
- `web/`
- `packaging/systemd/human-mcp.service`
- `packaging/systemd/human-mcp-self-update.service`
- `packaging/scripts/human-mcp-self-update`
- `packaging/sudoers/human-mcp-self-update`
- `packaging/sysusers/human-mcp.conf`
- `packaging/tmpfiles/human-mcp.conf`
- `env.example`
For `human-mcp-bin`, upload the tarball to GitHub Release `v<version>`, then update `aur/human-mcp-bin/PKGBUILD` and `.SRCINFO` with the new version and sha256.
</details>
<details>
<summary><strong>Troubleshooting</strong></summary>
### `https://domain/` returns 404
Check backend root first:
```bash
curl -i http://127.0.0.1:8787/
```
If it is also 404, inspect the running service environment:
```bash
pid=$(systemctl show -p MainPID --value human-mcp.service)
sudo tr '\0' '\n' < /proc/$pid/environ | grep HUMAN_WEB_DIST
```
Fix `/etc/human-mcp.env`:
```bash
HUMAN_WEB_DIST=/usr/share/human-mcp/web
```
Then restart:
```bash
sudo systemctl restart human-mcp.service
```
### AUR build says it is reading `/root/.git`
Run `paru` through a login shell for the normal AUR user:
```bash
sudo -iu arch bash -lc 'unset GIT_DIR GIT_WORK_TREE; cd ~; paru -S human-mcp-git'
```
### Admin login still shows `<admin-email>`
The admin account was not initialized. Run:
```bash
sudo human-mcp init-admin --email <admin-email>
sudo systemctl restart human-mcp.service
```
</details>