別記事 gpt.el & mcp.el で整う emacs llm環境 -> mcp.el の設定例 にあるようにmcp.el で使ういくつかの mcp server の起動で uvx を使用しているのですが、nixOS で最初に起動したときにエラーが出てしまいました。 解決方法と原因を Gemini に調べさせたので、メモしておきます。

症状とエラーメッセージ

*Mcp-Hub* buffer で mcp-hub-view-log を確認すると、以下のエラーが出ていました:

[stderr]  Could not start dynamically linked executable: /home/bk/.cache/uv/archive-v0/unI5q9QapqXHm9fPXna4G/bin/python
[stderr]  NixOS cannot run dynamically linked executables intended for generic
[stderr]  linux environments out of the box. For more information, see:
[stderr]  https://nix.dev/permalink/stub-ld
[jsonrpc] D[14:56:49.461] Connection state change: `exited abnormally with code 127

解決策:nix-ld を有効にする

nix conifguration で、以下を足したら直りました。

programs.nix-ld.enable = true;

根本原因: ファイルシステムの思想的対立

このエラーの根本原因を理解するには、一般的なLinuxディストリビューションとNixOSとの間にある、ファイルシステムに関する哲学的な違いを理解する必要があります。

FHSの世界

ほとんどのLinuxディストリビューションは、Filesystem Hierarchy Standard (FHS) に準拠しています。 これは /bin に実行ファイル、 /usr/lib に共有ライブラリといった、ファイルシステムの標準的なディレクトリ構造を定めたものです 。 外部でコンパイルされたバイナリは、共有ライブラリ( .so ファイル)や、バイナリを実行するために不可欠な動的リンカ(例: ld-linux-x86-64.so.2 )が、これらの標準的な場所に存在することを前提としています。

NixOSの世界

NixOSは意図的にFHSを採用しません。 すべてのパッケージとその依存関係は、 /nix/store 内の、ハッシュ値を含む一意で隔離されたパスにインストールされます。 各バイナリはビルド時にパッチが当てられ、依存するライブラリをこの特定の /nix/store パスから探すように変更されます。 この仕組みこそが、NixOSの純粋性、再現性、そして信頼性の源泉です 。

衝突の瞬間

今回のエラーは、この二つの世界の思想が衝突する瞬間に発生します。 ユーザーのケースでは、uvxが実行しようとしているMCPサーバー(内部的にはPythonで書かれている)は、FHSの世界でコンパイルされたバイナリです。 Linuxカーネルがこのバイナリを実行しようとすると、まずELFヘッダにハードコードされた動的リンカ(例: /lib64/ld-linux-x86-64.so.2 )を探しに行きます。 しかし、標準的なNixOSシステムにはそのパスに動的リンカは存在しないため、カーネルは実行を開始できず、 Could not start dynamically linked executable というエラーを吐き出して即座に失敗するのです 。

nix-ld を有効にするとうまくいく理由

nix-ldを有効にすると、FHSが期待する標準的な動的リンカのパス(例: /lib64/ld-linux-x86-64.so.2 )に、nix-ldが提供する特別なプログラムが配置されます 。 カーネルがFHS準拠の非Nixバイナリを実行しようとすると、今度はこのnix-ldのシムプログラムの起動に成功します。 起動したシムプログラムは、 NIX_LD_LIBRARY_PATH という特別な環境変数を読み取ります。 この環境変数には、 programs.nix-ld.libraries で指定されたライブラリが格納されている /nix/store 内のパスが設定されています。 この情報を使って、シムプログラムはNixOSの真の動的リンカを /nix/store から探し出し、必要なライブラリのパス情報を引き渡して実行します。 結果として、本来NixOS上では実行できなかったFHSバイナリが、あたかも標準的なLinux環境にいるかのように、自身の依存ライブラリを見つけて正常に起動できるようになるのです 。

より広い文脈:代替策とトレードオフ

nix-ldは強力な解決策ですが、唯一のものではありません。この問題を解決する別のアプローチとしてbuildFHSEnv(や、それをラップしたsteam-runなど)が存在します 。 buildFHSEnvは、システム全体にFHS互換のシムを導入するのではなく、特定のアプリケーションのためだけに、一時的でサンドボックス化されたFHS環境を構築します。 この二つの選択は、NixOSコミュニティで頻繁に議論される、古典的なエンジニアリング上のトレードオフを象徴しています 。

  • nix-ld: 実用主義(Pragmatism)。システム全体の互換性を高め、非Nixバイナリを「ただ動かす」ことを容易にします。その代償として、NixOSの純粋性をわずかに損なう可能性があります。
  • buildFHSEnv: 純粋主義(Purity)。アプリケーションごとに厳格な隔離を保ち、NixOSの思想を忠実に守ります。しかし、アプリケーションごとに明示的な設定が必要であり、手間がかかる場合があります。

教訓

この問題解決のプロセスは、単なるバグ修正以上の教訓を含んでいます。 それは、依存関係の管理と再現可能な環境の確保という、現代のソフトウェア開発におけるより大きな挑戦の縮図です。 クリーンで宣言的なシステム(NixOS)と、外部の混沌とし、命令的で、プリコンパイルされたソフトウェアエコシステムとの境界で発生する摩擦(インピーダンスミスマッチ)を、どのようにして管理するか。 nix-ld のようなツールは、異なるソフトウェア哲学の間を繋ぐ「Foreign Function Interface (FFI)」のようなものであり、この課題に対する一つの洗練された答えなのです。この経験は、単なるトラブルシューティングに留まらず、システム統合の本質を理解する上での貴重な学びとなります。