
YunoHost MCP
io.github.imattau由 GitHub 账号 imattau 发布v0.8.46更新于 Oct 24, 2026
Nostr-authenticated MCP server for secure YunoHost administration.
概览
基于 Nostr 认证的 MCP 服务器,用于管理 YunoHost:诊断、故障排查、_ynh 套件开发及可选的记忆功能。
- 可以做什么
- 通过受策略控制、可审计的服务器执行 YunoHost 管理与诊断操作
- 只读排查故障:解析 Nginx 日志、查询白名单日志、采集主机、服务、SSH 与网络快照、探测 HTTP 端点
- 开发与测试 _ynh 套件,发布目录条目并向 Armada 频道公告
- 使用可选的 Polypack 记忆工具存储、检索上下文并提交反馈
- 通过本地连接器把主流 MCP 客户端接入远程服务器,并用 Nostr 密钥为请求签名
- 为每个客户端生成密钥、签发短期委托,并用所有者签名应用批准高风险操作
- 适用场景
- 适合运行 YunoHost 并希望让 AI 客户端协助服务器管理、排查间歇性故障,或开发与发布 _ynh 套件的场景,并需要基于角色的权限与审计记录。
- 运行要求
- 需要一台 YunoHost 服务器,以及通过 uvx、uv tool 或 pip 安装的 yunohost-mcp-connect 套件(Python)。每个客户端需一个 Nostr 密钥文件,需 identity.toml 将公钥映射到角色;远程使用还需 HTTP 端点与 NIP-98 签名。可选设置包括 YUNOHOST_MCP_POLYPACK_URL、YUNOHOST_MCP_PUBLIC_BASE_URL 以及 Armada 密钥与邀请文件。
安装
在 SourceWeft 中
- 打开 控制台中的 YunoHost MCP,将其添加到工作区。
- 为需要使用其工具的对话启用该服务。
Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。
其他 MCP 客户端
参照 仓库 中的启动说明。
README
yunohost-mcp
Secure MCP server for YunoHost: Nostr-authenticated, policy-controlled, auditable administration, diagnostics, and _ynh package development for AI clients (Codex, Claude, OpenCode, ChatGPT-compatible MCP clients).
See PLAN.md for the full design and phased roadmap, and PHASE0_INVESTIGATION.md for how it maps onto YunoHost's actual Python API.
Running the server
By default fake_yunohost is off (real mode) — set YUNOHOST_MCP_FAKE_YUNOHOST=true to run against canned data on a machine without YunoHost installed. See identity.example.toml for identity.toml's shape (pubkey → role mapping; required before any HTTP request can do anything).
Optional local Polypack memory
The server can act as an authenticated façade for a separately installed
Polypack MCP service. Set YUNOHOST_MCP_POLYPACK_URL to that service's
loopback /mcp/ endpoint; the URL must resolve to 127.0.0.1, ::1, or
localhost, and Polypack remains the sole owner of its database. The YunoHost
MCP HTTP endpoint is still the only endpoint agents should expose publicly.
The initial integration exposes bounded memory_get, memory_list_contexts,
memory_recall, memory_context, memory_thread, memory_store, and
memory_feedback tools. Memory reads, writes, and feedback have separate
memory.read, memory.write, and memory.feedback scopes; writes are locked
and audited, while content is represented in the audit log only by length and
hash. Provenance is added by this server, and user metadata cannot forge its
reserved _yunohost_* fields. The integration is optional and core YunoHost
tools continue to work when Polypack is not installed or not configured.
Installing the client tools
The recommended client-side path is uvx, which creates an isolated
environment for the command without requiring users to manage a Python virtual
environment:
For a persistent command-line installation, use:
The package is also installable with python3 -m pip install yunohost-mcp-connect; that path is mainly useful for development or systems
where uv is not available.
Agent-assisted setup
The setup wizard is designed to be run by an AI agent on the user's local machine. It generates a fresh client identity, writes the selected MCP client configuration, and prints the one remaining security-sensitive step: granting the generated npub an appropriate role on the YunoHost server.
Supported clients are codex, claude-desktop, claude-code, gemini,
hermes, and opencode.
Setup is safe to rerun, refuses conflicting server definitions, backs up an
existing configuration before changing it, and never prints the private key.
Use --print-only when the agent should display configuration without writing
it. After granting the npub and restarting the client, diagnose the connection:
Connecting a client: yunohost-mcp-connect
Mainstream MCP clients (Claude Desktop, a plain Codex install, etc.) have no way to sign a NIP-98 Authorization header — that's specific to this server. yunohost-mcp-connect bridges the gap: a small local process that speaks plain MCP over stdio to your actual client, and forwards every request to the remote --transport http server, signed with your own Nostr key.
--key-file(or$YUNOHOST_MCP_CLIENT_KEY_FILE) points at a file holding a hex ornsec1...private key — preferred over--key/$YUNOHOST_MCP_CLIENT_KEY, which put the key in argv/environment where other processes on the same machine can read it.--generate-key PATHwrites a fresh private key toPATH(0600; refuses to overwrite an existing file), prints its npub, and exits without connecting anywhere — the way to get a--key-filein the first place. Use a distinctPATHper client; see "Give each client its own key file" below.--delegation-file(or$YUNOHOST_MCP_CLIENT_DELEGATION_FILE) presents a delegation event (PLAN.md Phase 11) alongside your own signature, for a disposable agent identity an owner granted a subset of their access to.- Point your MCP client's config at this command (not the server directly) —
tools/list,tools/call,resources/list, andresources/readare forwarded verbatim; authorization, policy, and audit still happen on the remote server.
Each connector starts its local MCP endpoint independently of the remote YunoHost handshake. If one configured YunoHost instance is offline, that connector stays alive, reports no discovered tools until the instance returns, and retries on later requests; other configured MCP servers can still start and remain usable.
Incident introspection
The server includes bounded, read-only diagnostics for intermittent outages:
- web_logs parses Nginx access/error logs, including HTTP and upstream status.
- journal_query reads allowlisted service, SSH, firewall, kernel, OOM, and systemd journals.
- system_snapshot, service_history, ssh_diagnose, and network_snapshot expose host, restart, access-control, and socket state.
- http_probe tests an HTTP(S) endpoint, while incident_snapshot collects the main evidence for a time window.
Log paths, output limits, command timeouts, and whether private HTTP targets are permitted are configurable with YUNOHOST_MCP_* settings. All of these tools are read-only and enforce bounded output.
Connecting Claude Desktop or Codex
Both point at yunohost-mcp-connect, not at the server directly — the bridge is what signs each request with your Nostr key. Use the full path to yunohost-mcp-connect in whatever environment you installed yunohost-mcp into (e.g. ~/.local/pipx/venvs/yunohost-mcp/bin/yunohost-mcp-connect, or a venv's bin/ directory — which yunohost-mcp-connect after activating it will tell you).
Give each client its own key file. YUNOHOST_MCP_CLIENT_KEY_FILE is the identity — whichever key signs a request determines its role and scopes on the server, nothing else. Point two different clients (or two different config files for the same client — a project-local .codex/config.toml shadows ~/.codex/config.toml) at the same key file and the second one silently authenticates as the first, with its exact permissions - no error, nothing to notice. Generate a fresh key per client rather than copying one that already works:
Each prints the new key's npub - grant it whatever role is appropriate for that specific client (see "Granting a disposable agent identity access" below, or identity.toml directly), not the role you already gave a different one. --generate-key refuses to overwrite a file that already exists.
Claude Desktop (claude_desktop_config.json — Settings → Developer → Edit Config):
Codex CLI (~/.codex/config.toml):
Run yunohost-mcp-connect --key-file <path> once per new key to see its npub (yunohost-mcp-connect: signing as npub1...), then grant that npub whatever role is actually appropriate for that client in identity.toml - not the role you already gave a different one.
For a delegated (disposable) identity instead of your own key, add YUNOHOST_MCP_CLIENT_DELEGATION_FILE pointing at the file yunohost-mcp-delegate produced (see below). Restart the client after editing its config — both read this file once, at startup.
Granting a disposable agent identity access: yunohost-mcp-delegate
An identity.toml entry grants access to one specific pubkey, permanently (until edited). A delegation (PLAN.md Phase 11) is the other way to grant access: an owner signs a short-lived, scoped grant to an agent's own disposable key, without ever adding that key to identity.toml or handing over any private key. yunohost-mcp-delegate is what an owner runs to create one:
--delegateis the agent's own pubkey (it must sign its own NIP-98 requests as always — a delegation never replaces that, it only adds standing).--remote-urlfetches the server's pubkey and this owner's own current scopes automatically — no need to type the server's pubkey by hand, and an over-broad--scope/--rolerequest is flagged (the server can never grant more than the delegator's own current scopes; seeauth/delegation.py). Pass--serverinstead if you'd rather supply the server's pubkey directly.--scope/--role(repeatable, combinable) choose what to grant;--ttl(e.g.24h,7d) how long — the server rejects anything over 30 days.- The output is a signed delegation event: a bearer credential once issued. Hand the file to the agent to use with
yunohost-mcp-connect --delegation-file agent-delegation.json, over a channel you trust (the same as you'd hand over an API key). - To take a delegation back before it expires, add its
id(printed after signing) torevoked_delegations.toml— this is independent of, and finer-grained than, removing the delegator's ownidentity.tomlentry (which revokes every delegation they've ever issued).
Approving high-risk operations: yunohost-mcp-approve
Some operations (system_upgrade, backup_restore, backup_delete, system_migrate, user_delete, permission changes, firewall changes) require owner co-signature on top of the requester's own confirmation (PLAN.md Phase 13, solo profile - see docs/owner-approval-plan.md in the packaging repo for the full design). The requester's call pauses with a confirmation_id; the configured owner reviews and approves it with yunohost-mcp-approve, signing through their own NIP-46 remote signer app (Amber, nsec.app, ...) - their private key never touches this server or the requesting agent's machine.
DNS publishing, catalogue publication, and package-test lifecycle operations also require owner co-signature. Package-test writes must first use package_test_prepare; the returned short-lived session binds the operation to one requester, candidate source, and app id. Treat package testing as privileged because candidate package scripts execute with YunoHost privileges.
For reverse-proxy deployments, set YUNOHOST_MCP_PUBLIC_BASE_URL to the exact public origin used in NIP-98 signatures (for example https://mcp.example.org). Requests with an unexpected Host header are rejected. Keep the local stdio transport restricted to trusted local clients: it intentionally grants the local process full administrator scope.
Optional NostrHost control-plane bridge
On a NostrHost derivative, the reference FastMCP server can submit registered
operations to the local signed control plane instead of executing them in the
MCP process. Enable it with YUNOHOST_MCP_NATIVE_CONTROL_PLANE_ENABLED=true,
set YUNOHOST_MCP_NATIVE_CONTROL_PLANE_RELAY, and provision a dedicated
64-character hex agent key at
YUNOHOST_MCP_NATIVE_CONTROL_PLANE_AGENT_KEY_PATH. The MCP server publishes
the signed request only; the control-plane daemon performs scope checks,
administrator approval, execution, and audit publication.
For bridged calls, the dedicated bridge key is the signed requester and
the authenticated MCP caller's Nostr public key is carried as the signed
actor tag on the request, execution, result, and state-snapshot records.
This makes agents and human users first-class audit identities while keeping
authorization anchored to the key that cryptographically submitted the
request.
One-time setup, on whatever device the owner keeps their signer app on:
Prints a nostrconnect:// URI to open in the signer app. This persists a reconnectable session locally so later approvals don't need to re-pair. If the signer app can instead export a bunker:// connection string itself (its own "add a connection" feature), yunohost-mcp-approve pair --owner-npub <owner-npub> --bunker-uri <uri> connects immediately using that instead - no link to open, nothing to wait on. Pairing requires the explicit owner key so a transport endpoint cannot be substituted for the configured owner.
To review and approve a specific pending operation:
This fetches the authoritative pending-operation record from the server (never trusts a locally-supplied plan), displays the exact tool, arguments, and operation_hash, and requires typing yes before submitting the signed approval. Once approved, the original requester can retry its call.
Automatic push approval. Once paired, this step usually isn't needed at all: the moment a require_owner_signature operation is requested, the server itself reuses the same paired session to open a live NIP-46 connection and ask your signer app to sign a small, human-readable approval event right then - a real push prompt on your signer app, no command to run. Approving there marks the ticket approved directly; declining, timing out (YUNOHOST_MCP_OWNER_PUSH_APPROVAL_TIMEOUT_SECONDS, default 90s), or no session being paired yet just leaves the ticket pending for a manual yunohost-mcp-approve approve as above. Disable entirely with YUNOHOST_MCP_OWNER_PUSH_APPROVAL_ENABLED=false.
Optional Armada announcements
The package-developer role includes communications.armada.write. With the
Armada integration enabled, armada_join explicitly accepts the configured
Concord invite for the bot by publishing a Guestbook Join. After a successful
catalog_publish, call catalog_announce with its JSON result to post to the
channel whose name matches the package repository (for example,
ditto_ynh). catalog_announcement_status checks durable delivery state.
Announcements are disabled by default and are best-effort. To enable them, provide a root-owned, mode-0600 bot key and invite URL file, then set:
Set YUNOHOST_MCP_ARMADA_AUTO_ANNOUNCE=true to have catalog_publish attempt
the announcement automatically after catalogue success. A failed or
unverified Armada operation never changes the catalogue result. The signing
identity must already have the required channel key; invite acceptance and
role assignment are separate operations.
Per-agent announcement keys. By default every announcement signs with
the shared bot key above. An identity.toml entry can instead set
armada_key_path to a dedicated, root-owned, mode-0600 key file so that
identity's own announcements and armada_join calls use its own Concord
identity instead of the shared bot:
That identity must call armada_join itself once its key file is in place -
having a distinct key implies nothing about community membership or channel
access. This is still a server-held, file-backed credential like the shared
bot key, never the identity's own NIP-98 signing key.
Announcing with the agent's own key, no key file at all. An MCP agent
connected through yunohost-mcp-connect (bridge.py) already holds its own
Nostr key locally to sign every NIP-98 request - it can announce and join
under that same key, with zero server-side credential provisioning, using
catalog_announce_draft/catalog_announce_submit and
armada_join_draft/armada_join_submit instead of the one-shot tools:
catalog_announce_draft(source, catalogue_publication)(orarmada_join_draft()) does all the routing and channel-key work that needs no secret, and returns an unsigned event plus a short-liveddraft_id.- The agent signs that exact event locally. The bridge answers this itself
via a local-only
sign_nostr_event(kind, tags, content, created_at)tool (never forwarded to the remote server, and restricted to Concord seal events) - the private key never leaves the bridge process. catalog_announce_submit(draft_id, signed_event)(orarmada_join_submit) verifies the signature matches exactly what was issued and the identity that requested it, then publishes.
The shared bot key / armada_key_path still cover catalog_publish's
YUNOHOST_MCP_ARMADA_AUTO_ANNOUNCE hook and any non-interactive/stdio
caller, since neither can do this two-step round trip.
Development
Creating a release tag
Maintainers can run the GitHub Actions Tag release workflow manually from
the branch or commit to release, providing a version without the v prefix
(for example, 0.1.1). It validates the version, refuses to overwrite an
existing tag, runs the full CI checks on Python 3.11 and 3.12, and only then
pushes an annotated v<version> tag.
来源:README.md,提交 8904f3c
工具
0版本历史
1- v0.8.46最新Sep 16, 2026
评分
已满足适用检查项的 50%
该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。
- 近 30 天内可连通25 分
请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。
- 已声明认证方式10 分
请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。
- 已列出工具15 分
请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。
- 描述必需15 分
- 图标10 分
- 文档15 分
- 许可证10 分