TrueNAS SCALE について
TrueNAS SCALEは、TrueNAS SCALEのストレージ、共有、アプリ、システム状態を調査・管理するMCPサーバーです。HTTPとstdioに対応し、ユーザーごとのAPIキーを使い、読み取り操作をデフォルトで提供します。
主な機能
- 01ストレージとシステム状態の確認
- 02共有とアプリの管理
- 03ユーザー別APIキーによる認証
- 04読み取りツールをデフォルトで有効化
- 05書き込み操作の任意有効化
活用シーン
- 01TrueNASのストレージ状態の確認
- 02共有とアプリの確認・管理
- 03リモートMCPクライアントからNASへ接続
MCP 対応
Streamable HTTPまたはstdioで、TrueNAS操作ツールをクライアントに公開します。HTTPでは各呼び出し元が個人のAPIキーを提示し、書き込みツールはデフォルトで無効です。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
docker run -i --rm -e TRUENAS_MCP_TARGET -e TRUENAS_MCP_ALLOW_PLAINTEXT -e TRUENAS_MCP_TARGET_INSECURE -e TRUENAS_MCP_ENABLE_WRITES ghcr.io/cedricziel/truenas-mcp:0.4.2TRUENAS_MCP_TARGETTrueNAS host to manage, optionally `host:port`. Requires TrueNAS SCALE 25.04 or later.TRUENAS_MCP_ALLOW_PLAINTEXTServe MCP without TLS. Set here because the listener is published on loopback only; drop it and supply TRUENAS_MCP_TLS_CERT/KEY if the port is reachable from elsewhere.TRUENAS_MCP_TARGET_INSECUREAccept the TrueNAS certificate unverified while keeping the connection encrypted. TrueNAS ships a self-signed certificate for `CN=localhost`, so no address you can reach it by will validate.TRUENAS_MCP_ENABLE_WRITESExpose the mutating tools. Read-only by default; unrecoverable operations stay unreachable either way.ローカルサーバーにはマシン上の実行環境(Node.js 18 以上など)が必要です。設定ファイルの場所はクライアントごとに異なります。
ghcr.io/cedricziel/truenas-mcp:0.4.2Streamable HTTPツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
truenas-mcp
TrueNAS SCALE 用の MCP サーバーです。読み取りを優先し、TrueNAS アプリとしてデプロイでき、各ユーザー自身の API キーで認証します。
ステータス:動作しますが、まだ新しいプロジェクトです。 設計に含まれるすべての機能を実装し、稼働中の TrueNAS 26 環境で検証済みです。機能の不足ではなく、まだ荒削りな部分があることを想定してください。
なぜこれを作ったのか
iX は公式の truenas/truenas-mcp を公開しています。ニーズに合うなら、そちらをお使いください。このプロジェクトは、公式版にない次の 3 つの機能を提供します。
- stdio にしか対応していないため、NAS 上のコンテナとしてデプロイし、外部からアクセスすることができません。
- サーバー全体で 1 つの API キーを保持するため、認証方法にかかわらず、すべての呼び出し元が同じアクセス権を得ます。
- アプリの対応範囲がカタログに沿ったものです(インストール、アンインストール、閲覧)。すでに実行中のアプリの新しいイメージを取得し、再デプロイする方法はありません。
設計
設計の核となる考え方は 3 つです。
認証情報が認可そのものです。 呼び出し元は自身の TrueNAS API キーを渡します。このサーバーにはキーを保存しません。セッションでアクセスできる範囲は、そのユーザーのキーで許可された範囲に限られます。キーは TrueNAS UI から失効でき、漏えいする共有シークレットもありません。認証と認可が食い違う 2 つのシステムである状態をなくします。stdio 経由で提供する場合は、キーを含めるリクエストがないため、代わりに環境変数からキーを受け取ります。ただし、クライアントはユーザーごとにプロセスを 1 つ起動するので、この場合もキーはそのユーザー自身のものです。この設計で排除するのは、複数の呼び出し元に対して 1 つのキーを使い回すことであり、設定そのものではありません。
読み取りツールと書き込みツールでは形を分けます。 読み取りは、引数の大半を共有しており、ミドルウェアの 815 個のメソッドをそれぞれツールにすることもできないため、関心領域ごとに op 列挙型を使うツールへまとめています。書き込みは個別のツールにします。MCP のアノテーションはツールごとに設定されるため、安全な操作と破壊的な操作を 1 つの op パラメーターの背後にまとめると、どちらも同じ同意ゲートを通ることになります。list_pools の確認にうんざりしたユーザーが、そのプールをエクスポートすることもできるツールを許可リストに追加してしまう可能性があります。
デフォルトでは読み取り専用です。 変更を加えるツールは、明示的に有効にした場合にのみ表示されます。これとは別に、復旧不可能な操作を拒否リストで定めており、どのような設定でも実行できません。また、この拒否リストはメソッド名だけでなく、引数値にも適用されます。アプリの削除は復旧できますが、ボリュームと一緒に削除すると復旧できません。どちらも同じメソッドを使います。
これらの考え方はいずれも、抽象的な議論ではなく稼働中の環境で検証しました。そして、その検証で得られた結果を受けて、いくつかの考え方は見直されました。
要件
- TrueNAS SCALE 25.04 以降。TrueNAS 26 では REST API が削除されているため、このサーバーはバージョン管理された JSON-RPC 2.0 WebSocket API のみを使用します。
- ユーザーごとの TrueNAS API キー。認証情報 → API キーから作成してください。
TrueNAS アプリとしてデプロイする
deploy/truenas-custom-app.yaml をコピーし、TRUENAS_MCP_TARGET を調整して、アプリ → 探索 → YAML を使用してインストールに貼り付けます。
ホストソケットはマウントせず、特権アクセスも要求しません。同じマシン上で動作している場合も、サーバーはネットワーク経由でミドルウェアに接続します。これにより、すべての接続にユーザー ID が付与され、root 相当のソケットアクセスを避けられます。
別の場所で実行する
サーバーを管理対象のマシン上で実行する必要はありません。むしろ、そうしない方がよい理由があります。TrueNAS アプリとしてインストールすると、マシンに問題があるとき、つまり何が起きているのかを最も確認したいときに、サーバーを利用できなくなります。
docker run -p 8080:8080 \
-e TRUENAS_MCP_TARGET=nas.local \
-e TRUENAS_MCP_TLS_CERT=/tls/cert.pem \
-e TRUENAS_MCP_TLS_KEY=/tls/key.pem \
ghcr.io/cedricziel/truenas-mcp:main
バイナリの実行
各GitHub リリース
には、Linux、macOS、Windows 向けの amd64 および arm64 用バイナリと、
checksums.txt が添付されています。設定は環境変数のみです。設定ファイルはなく、
フラグは --stdio と --healthcheck だけです。
デフォルトでは、バイナリは HTTP サーバーとして動作します。実行してもクライアントが 自動的に検出するわけではありません。ポートで待ち受け、クライアントが URL で接続します。 クライアント自身がサーバーを起動する場合は、以下の stdio 経由での提供を参照してください。
TRUENAS_MCP_TARGET=nas.local \
TRUENAS_MCP_LISTEN=127.0.0.1:8080 \
TRUENAS_MCP_TARGET_INSECURE=true \
TRUENAS_MCP_ALLOW_PLAINTEXT=true \
./truenas-mcp
クライアントの接続先を http://localhost:8080/mcp に設定し、
クライアントの接続と同様に、TrueNAS API キーを
Authorization: Bearer ヘッダーで送信してください。
2 つの TLS 設定についてで説明している理由から、
通常は TRUENAS_MCP_TARGET_INSECURE が必要です。TrueNAS は
CN=localhost の自己署名証明書を使用しており、ほかのアドレスに対しては検証に
通りません。TRUENAS_MCP_ALLOW_PLAINTEXT をここで使用できるのは、
TRUENAS_MCP_LISTEN がリスナーをループバックにバインドするためです。
これは同じマシンからのみ到達可能であり、そのセクションで平文通信を許容する
条件として説明されているものです。デフォルトのバインドアドレスは :8080 で、
すべてのインターフェースを対象とします。そのため、この設定を外したまま平文通信を
使用すると、API キーがネットワーク上を流れることになります。
stdio 経由での提供
一部のクライアントはサーバーをサブプロセスとして起動し、URL に接続するのではなく、
標準入力と標準出力を介して通信します。--stdio を指定すると、同じツールを
その方法で提供します。
claude mcp add --scope user truenas \
--env TRUENAS_MCP_TARGET=nas.local \
--env TRUENAS_MCP_TARGET_INSECURE=true \
--env TRUENAS_MCP_API_KEY=$YOUR_TRUENAS_API_KEY \
-- /path/to/truenas-mcp --stdio
ここではヘッダーを送信するリクエストがないため、キーは
TRUENAS_MCP_API_KEY から取得されます。これは HTTP トランスポートで回避される
共有シークレットとは異なります。クライアントはユーザーごとにプロセスを 1 つ起動するため、
渡されるキーはそのユーザー自身のものであり、プロセスがアクセスできるのはそのキーで
許可されている範囲だけです。同じ変数は HTTP モードでは拒否されます。1 つのプロセスが
多数の呼び出し元に対応し、設定されたキーが全員で共有されるためです。
リスナーに関する設定は適用されません。TRUENAS_MCP_LISTEN、2 つの TLS 設定、
TRUENAS_MCP_ALLOW_PLAINTEXT は、リスナーが存在しない場合にセキュリティを弱める
ものではないため、エラーではなく警告を出して無視されます。
--stdio と同時に --healthcheck を指定すると、起動されていないリスナーを
検査することになるため拒否されます。
リスナーではなく接続先に関する設定は引き続き適用されます。
これには TRUENAS_MCP_TARGET_INSECURE と TRUENAS_MCP_ENABLE_WRITES が含まれます。
設定
設定はすべて環境変数で行います。設定ファイルや永続ボリュームは不要です。設定が無効な場合、機能を制限して起動するのではなく、起動を拒否します。
| 変数 | デフォルト | 意味 |
|---|---|---|
TRUENAS_MCP_TARGET | 必須 | TrueNAS ホスト。任意で host:port を指定できます |
TRUENAS_MCP_LISTEN | :8080 | バインドアドレス |
TRUENAS_MCP_TLS_CERT / TRUENAS_MCP_TLS_KEY | — | MCP を TLS 経由で提供します |
TRUENAS_MCP_ALLOW_PLAINTEXT | false | TLS なしで提供します(下記を参照) |
TRUENAS_MCP_TARGET_INSECURE | false | 接続先の証明書を検証せずに受け入れます |
TRUENAS_MCP_TARGET_ALLOW_PLAINTEXT | false | TLS なしで接続先に接続します |
TRUENAS_MCP_ENABLE_WRITES | false | 変更を伴うツールを公開します |
TRUENAS_MCP_API_KEY | — | --stdio 用の認証情報です。指定しないと拒否されます |
TRUENAS_MCP_OAUTH_ISSUER | — | OAuth を有効にします。サーバー自身の外部から到達可能なベース URL |
TRUENAS_MCP_OAUTH_ENCRYPTION_KEY | 生成されます | 64 桁の 16 進文字列(32 バイト)。下記を参照 |
TRUENAS_MCP_OAUTH_ACCESS_TOKEN_TTL | 1h | 発行された OAuth アクセストークンの有効期間 |
TRUENAS_MCP_OAUTH_REFRESH_TOKEN_TTL | 720h (30 days) | リフレッシュトークンの有効期間。0 にすると無効になります |
HTTP トランスポートでは認証情報を設定できません。 呼び出し元がリクエストごとに認証情報を指定します。--stdio を指定せずに TRUENAS_MCP_API_KEY を設定すると、暗黙のフォールバックではなく起動エラーになります。stdio では認証情報を含めるリクエストがなく、プロセスは単一ユーザーにサービスを提供するため、そのユーザーのキーを渡す方法としてこの変数を使います。stdio 経由での提供を参照してください。
2 つの TLS 設定について
トランスポートのスキームと証明書の検証は、意図的に分けられています。
TrueNAS に付属する自己署名証明書は CN=localhost 用に発行されており、SAN は DNS:localhost のみです。そのため、接続可能なアドレスでは検証に成功しません。解決策は TRUENAS_MCP_TARGET_INSECURE=true にすることです。これにより、接続は暗号化されたまま、認証だけが行われなくなります。証明書の問題を理由に平文通信に切り替えると、TrueNAS に API キーがそのまま見えてしまうため、キーを失効させる必要があります。
TRUENAS_MCP_ALLOW_PLAINTEXT は、呼び出し元が通過する境界に関する設定であり、そこでは呼び出し元の API キーが送信されます。サーバーの前段でリバースプロキシが TLS を終端する場合は適切ですが、平文リスナーに直接接続できる場合は不適切です。
クライアントの接続
claude mcp add --scope user --transport http truenas \
https://your-host/mcp \
--header "Authorization: Bearer $YOUR_TRUENAS_API_KEY"
Authorization ヘッダーを設定できないクライアントは、キーを X-TrueNAS-API-Key として送信することもできます。どちらも指定されていないリクエストは 401 で拒否されます。
サーバーを起動して接続するのではなく、サーバーを起動するクライアントには、stdio 経由での提供をお勧めします。
OAuth クライアントの接続(Claude.ai など)
Claude.ai のようなホスト型 MCP クライアントが TrueNAS API キーを直接保持することはありません。 OAuth 2.1(ディスカバリー、Dynamic Client Registration(RFC 7591)、PKCE を使用した認可コードフロー)のみを使用します。発行者 URL を設定すると有効になります。
docker run -p 8080:8080 \
-e TRUENAS_MCP_TARGET=nas.local \
-e TRUENAS_MCP_TLS_CERT=/tls/cert.pem \
-e TRUENAS_MCP_TLS_KEY=/tls/key.pem \
-e TRUENAS_MCP_OAUTH_ISSUER=https://your-host \
-e TRUENAS_MCP_OAUTH_ENCRYPTION_KEY=$(openssl rand -hex 32) \
ghcr.io/cedricziel/truenas-mcp:main
TRUENAS_MCP_OAUTH_ISSUER には、クライアント側からサーバーにアクセスできる正確なベース URL(末尾のスラッシュなし)を指定する必要があります。TRUENAS_MCP_OAUTH_ENCRYPTION_KEY は、このプロセスが発行するすべてのクライアント登録、認可コード、トークンを保護します。未設定でも動作しますが、再起動のたびに新しいキーが生成され、未使用のものはすべて無効になります。短時間の試用を超えて使う場合は、明示的に設定してください。TrueNAS の認証情報も、クライアント/トークンのデータベースも、どこにも保存されません。OAuth で発行されるものはすべて自己完結型で、この単一のキーで検証されます。その理由については、openspec/changes/oauth-dcr-authorization/design.md を参照してください。
上記の raw API キーと同様に、クライアントの接続先を https://your-host/mcp に設定します。認可サーバー、登録先、リソース所有者への送信先などは、/.well-known/oauth-protected-resource から自動的に検出されます。初回接続時にはブラウザーで同意画面が開き、TrueNAS のユーザー名(任意。自分にのみ表示)と API キーを求められます。これらを送信して対象が受け入れるまで、クライアントには何も許可されません。
TRUENAS_MCP_ALLOW_PLAINTEXT は、raw API キーの接続方式と同様に機能します。これは、エッジで TLS を終端するリバースプロキシからこのプロセスへ平文で転送するための設定であり、暗号化せずに同意画面をインターネットに公開するためのものではありません。
上記の raw API キーの接続方式は OAuth と併用でき、これまでどおり動作します。OAuth を有効にしても、最初の方式に置き換わるのではなく、接続方法がもう 1 つ追加されるだけです。
現在の状況
対応済み:
- Streamable HTTP トランスポート、セッションごとの認証情報、認証情報がない場合の
401 - Dynamic Client Registration を備えた OAuth 2.1。OAuth のみを使用するクライアント(Claude.ai など)が対象です。詳しくは OAuth クライアントの接続を参照してください
- サーバーに接続するのではなく、サーバーを起動するクライアント向けの、プロセスごとに単一の認証情報を使う Stdio トランスポート
- JSON-RPC ミドルウェアクライアント:1 つの接続上での並行呼び出し、到達不能/未認証/未認可/レート制限を区別する構造化エラー、中断されたリクエストを「適用された可能性あり」として報告
- 接続が切れた場合のセッション再接続、および 25.04 より古いリリースに対する実行の拒否
- コンテナーイメージ、CI、GHCR への公開、TrueNAS アプリのデプロイ
未実装: リソースの サブスクリプション によるジョブの進捗通知。ポーリングで同じ情報を取得でき、設計上も信頼できる方法として扱われています。サブスクリプションは常にポーリングを補完する機能であり、MCP クライアントでのサポートも限定的です。
ツール
| ツール | 操作 |
|---|---|
storage | list_pools、show_pool、list_datasets、show_dataset、list_snapshots |
system | info、alerts、list_services、update_status、version、audit_log |
sharing | list_smb、show_smb、smb_acl、list_nfs、show_nfs、list_web |
virtualization | list_vms、show_vm、vm_devices、list_containers、show_container、container_devices |
backup | list_cloud_syncs、show_cloud_sync、cloud_credentials、list_replications、show_replication、list_rsync_tasks、list_snapshot_tasks |
filesystem | list_directory、stat、space、acl、read |
apps | list、show、config、containers、outdated_images、upgrade_summary、rollback_versions、used_ports |
catalog | list、categories、show |
jobs | list、show |
search_methods | 名前でミドルウェアメソッドを検索します |
describe_method | メソッドの引数を要約します |
call_method | メソッドを直接呼び出します |
inventory | ボックス全体の概要を1回の呼び出しで取得します。MCP アプリとして表示されます |
server_info | — |
system_info | — |
各ツールでは、title、readOnlyHint、destructiveHint、idempotentHint、openWorldHint の MCP アノテーション一式をすべて宣言しています。仕様では destructiveHint と openWorldHint の既定値が true であるため、フィールドが未設定でも「不明」を意味するのではなく、「最悪のケースを想定する」ことを意味します。そのため、読み取りツールが破壊的と扱われると、安全な操作でも確認プロンプトが表示され、重要なプロンプトまでクリックして進めることを利用者に覚えさせてしまいます。
読み取りツールが使用するすべてのメソッドについて、対象側の RBAC メタデータを確認し、READONLY_ADMIN で実行できることを検証しています。つまり、「このツールは変更を加えられない」という点は、単に主張されているのではなく、確認済みです。
例外は filesystem read だけです。これはファイルのテキストを返しますが、64 KiB で切り詰められ、バイナリファイルは拒否します。何も変更しませんが、ミドルウェアの filesystem.get には FULL_ADMIN が必要なため、読み取り専用キーでは「許可されていません」と明確に表示されます。ファイルは core.download 経由でストリーミングされるため、call_method は filesystem.get と、ダウンロードまたはアップロード用のパイプを必要とするその他すべてのメソッドを拒否します。
apps の outdated_images、upgrade_summary、rollback_versions 操作があることで、呼び出し側は書き込み階層が実行する前に、操作すべきかどうかを判断できます。これらがない状態で変更を行えるようにすると、モデルは推測を強いられます。3つすべてがアプリの name を受け取り、ミドルウェアにはこれに相当するフリート全体を対象とした操作はありません。
catalog は「インストールできるものは何か」に答え、apps は「インストールされているものは何か」に答えます。1つのツールに2つの操作を設けるのではなく、意図的に2つのツールに分けています。適切な名前のツールから選ぶほうが、複数の操作を詰め込んだツールから選ぶより、モデルの性能が高くなるためです。catalog list は、デフォルトでは識別情報とバージョンのフィールドのみを表示します。基盤となるメソッドは約400件のエントリを返し、それぞれに完全なHTMLのREADME、設定スキーマ、バージョン履歴が含まれます。そのため、表示項目を絞らずに一覧を取得すると、apps list 自体に表示項目の絞り込みが設けられた理由となった問題をはるかに上回る規模で、呼び出し側のコンテキストを使い果たします。catalog categories から取得できるカテゴリを指定して絞り込めます。full=true を指定すると、引き続きすべてが返されます。catalog show は、名前を指定すると1件のエントリの完全なレコードを返すため、別途 catalog.get_app_details を呼び出す必要はありません。
書き込みツール
デフォルトでは無効です。TRUENAS_MCP_ENABLE_WRITES=true を設定すると公開されます。
| ツール | 効果 | 注釈 |
|---|---|---|
app_pull_images | 最新のイメージを取得して再デプロイ | 破壊的 |
app_redeploy | イメージを取得せずに再デプロイ | 破壊的 |
app_stop | 実行中のアプリを停止 | 破壊的、冪等 |
app_upgrade | 新しいバージョンにアップグレード | 破壊的 |
app_rollback | 問題のあるアップグレードや取得をロールバック | 破壊的 |
app_start | 停止中のアプリを起動 | 冪等 |
create_snapshot | データセットのスナップショットを作成 | 追加 |
create_smb_share | SMB 経由でパスを共有 | 追加 |
update_smb_share | SMB 共有を変更 | 破壊的 |
delete_smb_share | SMB 経由の共有を停止 | 破壊的 |
create_nfs_export | NFS 経由でパスをエクスポート | 追加 |
update_nfs_export | NFS エクスポートを変更 | 破壊的 |
delete_nfs_export | NFS 経由のエクスポートを停止 | 破壊的 |
set_smb_share_acl | 共有に接続できるユーザーを設定 | 破壊的 |
set_path_acl | パスのファイルシステム権限を設定 | 破壊的 |
共有と権限の設定が主な目的です。 これは TrueNAS の運用で最も難しい部分であり、最も破壊的な影響が少ない部分でもあります。共有の設定ミスはサポートへの問い合わせにつながるだけで、データの損失にはなりません。これをアシスタントに任せることこそ、このサーバーの目的です。
本当の危険が潜んでいるのはメソッドではなく、引数 です。filesystem.setacl は recursive、traverse、stripacl を受け付けます。recursive と stripacl を組み合わせると、データセット全体を走査してすべての ACL を破棄します。その結果、テラバイト単位のデータへのアクセスがロックされ、以前の権限がわからなければ元に戻せません。この 3 つは常に拒否されるため、特定のパスの ACL 設定は引き続き利用できますが、範囲に制限のない形式は利用できません。これが、拒否リストでメソッド名ではなく引数の値を制限する理由です。
ツールはそれぞれ独立しているため、同意の判断も個別に行われます。これらを 1 つの op の下にまとめると、app_stop が app_start と同じ制限を受けることになります。他のツールを提供する場合は、app_rollback も必ず提供されます。これは復旧手段であり、ツールを公開しても問題ないと判断できる理由です。
変更処理はブロックしません。すぐに job_id を返します。jobs(op="show", job_id=…) でそのジョブを追跡してください。
どのような設定でも拒否される操作: プールのエクスポート、データセットの削除、ディスクの消去、ブートデバイスの切り離し、スナップショットの破棄、および remove_ixvolumes を指定した app.delete です。後者の危険性はメソッドではなく引数にあります。これらは設定で切り替えられません。Web インターフェースを使用してください。
アプリのログについて: TrueNAS はコンテナの出力を JSON-RPC メソッドではなく、app.container_log_follow イベントソースを通じて公開します。apps(op="logs", name=...) は、ライブ追跡ではなく、タイムスタンプ付きの件数制限されたログ末尾を返します。アプリに複数のコンテナがある場合は、まず apps(op="containers", name=...) を呼び出し、返された ID の 1 つを container として渡してください。
ディスカバリーの代替手段
ミドルウェアには74個の名前空間に815個のメソッドがあります。その大半は専用ツールを用意するほどではないため、リリースごとにコードを変更しなくても、search_methods / describe_method / call_method で残りをカバーできます。
到達可能かどうかは、メソッド名から推測するのではなく、対象の独自のRBACメタデータによって決まります。READONLY_ADMIN が付与されているメソッドは読み取り可能で、変更を伴うメソッドには書き込み権限が必要です。これはミドルウェア自身が示す正確な判定であり、ここを変更しなくてもAPIのバージョンに追従します。**APIの94%**に到達でき、読み取り可能なものは411個、変更を伴うものは359個です。
対象外の6%は意図的なものです。
core.bulkは任意のメソッドを実行します。これを到達可能にすると、拒否リスト、書き込み権限、そしてここにあるほかのすべてのゲートを回避できてしまいます。auth.*はサーバーが管理すべきものです。呼び出し元がこれを操作すると、セッション終了後も有効で、APIキーのUIにも表示されないトークンを発行できてしまいます。これはオペレーターが発行していない認証情報です。- ロールを一切宣言していないメソッド。 この対象では、これらは無害な読み取りではなく、セッションやプロトコルの制御処理です。そのため、「権限チェックなし」はリスクなしではなく、リスク不明として扱います。
describe_method はスキーマをそのまま出力せず、要約します。稼働中の対象で測定したところ、sharing.smb.create のスキーマは約31,000文字、directoryservices.update は約53,000文字でした。また、モデルは小さく密なスキーマより、大きく疎なスキーマのほうが正確に扱えないため、忠実に出力しようとするとコストが増える一方で、性能は低下します。本当に必要な場合は full=true を渡してください。
リソース
| URI | 内容 |
|---|---|
truenas://alerts | 現在のアラート |
truenas://system/health | バージョン、ホスト名、稼働時間、ハードウェア |
truenas://pools | 容量と健全性を含むプール |
truenas://apps | インストール済みアプリとその状態 |
truenas://job/{id} | 長時間実行される操作の進行状況 |
truenas://docs/query-filters | call_method のフィルター構文 |
truenas://docs/dataset-properties | ZFS フィールドの意味と継承 |
リソースとツールの違いはコストではなく、_制御の主体_です。ツールはモデルが制御し、リソースは人が指定します。人がリソースを指定する場合は、往復通信もツールの予算も不要なため効果があります。一方、モデルがリソースを探さなければならない場合は、汎用のリスト/読み取りツール経由でアクセスすることになり、避けるはずだった往復通信が再び発生するため、効率が低下します。
そのため、ここでは参照可能なエンティティや資料をリソースとし、計算やパラメーター化を伴うものはツールにします。ドキュメントリソースは、この設計の中でも特に効果的です。フィルター構文やZFSの意味論を、すべてのツールの説明で繰り返すのではなく、一度だけ説明できます。ツールの説明に記載すると、リクエストごとにトークンを消費することになります。ツールの説明でそれらを繰り返さないことをテストで検証しています。
MCP Apps
MCP App は、ホストがテキストの代わりにインタラクティブなビューとして結果を表示できるツールです。ツールには ui:// リソースを指定する _meta.ui.resourceUri が含まれます。このリソースは text/html;profile=mcp-app として配信される自己完結型の HTML ドキュメントで、ホストはこれをサンドボックス化された iframe に読み込み、postMessage を介して通信します。この拡張機能をサポートしていないホストはメタデータを無視し、通常の構造化された結果を受け取るため、アプリによって通常のクライアントに負担が生じることはありません。
| アプリ | ツール | リソース | 表示内容 |
|---|---|---|---|
| Inventory | inventory | ui://truenas/inventory | 容量、データセット、アプリ、VM、コンテナ、共有、アラートを含むプール。フィルター、更新 |
すべてのアプリはインラインです。外部スクリプト、スタイルシート、画像、接続はありません。CSP を宣言しないアプリにホストが適用するデフォルトポリシーでは、これらすべてが禁止されています。また、ドメインを宣言すると、ホストの実行場所から CDN にアクセスできることへの依存と引き換えに、サンドボックスを失うことになります。これらのいずれかを参照するアプリは、テストで拒否されます。
inventory は各セクションを個別に取得し、それぞれの結果を個別に報告します。プールは読み取れるがアプリは読み取れない API キーの場合でも、プールは取得されます。キーがアクセスできない最初のセクションで呼び出し全体が失敗するのではなく、拒否されたことが errors.apps の下に記録されます。どのセクションも読み取れなかった場合に限り、呼び出しは失敗します。
レジストリは internal/apps にあります。アプリの追加には、そこへのエントリーと、エントリーで指定するツールが必要です。Go テストでは、すべてのエントリーが拡張機能の規約に従っていることを確認し、make test-apps では実際のブラウザー上で、偽のホストを使って各ビューを実行します。
MCP Tasks
すべての変更を伴うツールはミドルウェアのジョブを開始し、その ID を返します。Tasks 拡張機能(io.modelcontextprotocol/tasks。プロトコル 2026-07-28 時点で安定版)は、まさにこの用途のためのプロトコル独自の形式であるため、ジョブは別のライフサイクルではなくタスクとして公開されます。
各リクエストとともに送信する機能でこの拡張機能を宣言したクライアントには、書き込みツールの通常の結果の代わりに、タスク ID を含む CreateTaskResult が返されます。クライアントは tasks/get をポーリングします。これはジョブの状態と進捗を報告し、ジョブが終了状態になると、同期的に実行した場合にツールが生成する結果を返します。completed にはジョブの戻り値が含まれ、failed にはそのエラーが含まれ、中止されたジョブは cancelled として扱われます。tasks/cancel は、対象のジョブを中止するよう要求します。この拡張機能を宣言していないクライアントには、従来どおりジョブ開始の結果が返され、どちらの場合も jobs でジョブを追跡できます。
タスク ID はサーバーごとに生成され、サーバーは認証情報ごとに構築されるため、タスクにアクセスできるのは、そのタスクを開始した認証情報を使った場合に限られます。対応付けはメモリ上に保持されるため、再起動後はタスク ID が不明になり、tasks/get はその旨を返します。読み取り専用サーバーではジョブを開始しないため、拡張機能は書き込み層が有効な場合にのみ通知されます。
リリース
リリースはrelease-pleaseを通じてのみ行います。ほかの方法はありません。main のConventional Commitの履歴を読み取り、次のバージョンと変更履歴を記載したリリースPRを常にオープンにします。そのPRをマージすることでリリースが作成されます。
push to main ──▶ ci.yml test, lint, publish :main and :sha-<commit>
└─▶ release.yml maintain the release PR
│
merge PR ─────────┴─▶ tag vX.Y.Z, GitHub release,
publish :X.Y.Z :X.Y :latest
ci.yml は意図的にタグに反応しないため、リリースなしでバージョンタグが作成されることはありません。公開前に、リリースジョブはタグ付けされたコミットに対してテストを再実行します。タグのコミットはCIが最後にチェックしたものとは異なり、リリースの信頼性は、それを許可するテストの信頼性に左右されるためです。
各リリースには、コンテナイメージに加えて、Linux、macOS、Windows用のバイナリとchecksums.txtも添付されます。
トークン。 contents: writeとpull-requests: writeの権限を持つPATをRELEASE_PLEASE_TOKENリポジトリシークレットとして設定してください。設定しない場合、ワークフローはGITHUB_TOKENにフォールバックします。これは機能しますが、後続のワークフローを起動できないため、リリースタグによって公開ジョブが開始されません。
開発
make test # unit tests
make test-apps # browser tests for the MCP Apps; needs Node 22
make lint # go vet + golangci-lint
make build
make image
統合テストには稼働中のTrueNASが必要で、make testからは除外されています。
TRUENAS_TEST_URL=wss://nas.local/api/current \
TRUENAS_TEST_API_KEY=... \
TRUENAS_TEST_INSECURE=true \
go test -tags=integration ./...
このサーバーに期待される動作は、コードから推測するのではなく、ケイパビリティ仕様として文書化されています。各シナリオは、今後テストケースとして実装されるものです。
ライセンス
MITです。LICENSEを参照してください。
ここで使用しているミドルウェアクライアントは、GPL-3.0のtruenas/truenas-mcpを改変したものではなく、一から作成されています。これにより、このプロジェクトではライセンスの選択肢が開かれています。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。