はじめに

Emacs内での大規模言語モデル(LLM)との連携は、ここ数年で劇的な進化を遂げてきました。

思い返せば2022年11月、初めて copilot.el によるAI autocompletion を体験したときの感動は鮮明に覚えています。

その後間もなくChatGPT が登場し、ChatGPT.el 等でEmacs内でのAIとの対話ができるようになりましたが、当時は機能も少なく、EmacsでLLMを使うメリットはあまり感じられませんでした。

ブレークスルーとなったのは、東京Emacs勉強会 サマーフェスティバル2024 のTomoya さんの発表で ellama を知ったことでした。 ellamaでは従来の対話形式だけでなく、様々な関数を通じてLLMを利用でき、Emacs が何倍も強力な開発環境へと変貌しました。

そして最近では gptelllm module として doom emacs に正式に組み込まれ、ツール連携やプロンプト/コンテクストエンジニアリング1が非常にスムーズになりました。

これとmcp.el と組み合わせることで、ある種 LLM in emacs のplateau を感じている今、タイミング的にちょうど良いかなと思い、この記事を書くことにしました。 gptel, mcp.el の設定方法や使う理由、補足としてmcp.el を用いる際のNixOS におけるエラー処理の方法などを紹介します。

  gantt
    title 私のEmacs 内LLM 遍歴
    todayMarker off
    dateFormat YYYY-MM
    axisFormat %Y-%m
    section 自動補完
        copilot.el :2022-11, 32M
    section 黎明期
        ChatGPT.el :2023-03, 17M
        org-ai :2023-12, 8M
    section 革命
        ellama/llm              :2024-08, 9M
    section 開拓期
        ai-org-chat :2024-11, 2M
        ob-llm :2025-01, 2M
        elisa :2025-03, 1M
        copilot-chat.el     :2025-03, 2M
    section 成熟期
        gptel+mcp.el              :2025-05, 2M
        claude-code.el              :2025-06, 1M

gptel とは

gptelは、Emacsのためのシンプルかつ強力な大規模言語モデル(LLM)クライアントです。 Emacs内のあらゆる場所から自由な形式でLLMと対話できる環境を提供します。 このデモを見ると使用イメージが分かりやすいです。

mcp.el とは

mcp.elは、AIと外部ツールの連携を標準化するオープンプロトコル「Model Context Protocol (MCP)」をEmacsに導入するパッケージです 。 これにより、 gptelのようなLLMクライアントが、Web検索、ファイルアクセス、GitHubリポジトリ操作といった様々な機能を備えたMCPサーバーと統一的に通信できるようになり、LLMの能力を大幅に拡張します。 mcp.elは、これらの外部ツール(サーバー)の起動や管理をEmacs内から一元的に行うハブとして機能します。

私が gptel & mcp.el を使う理由

gptel は doom emacs のmodule に組み込まれており、ほぼカスタマイズなしで、LLM modelやsystem prompt、 context, tool(MCP) の管理がスムーズに行えます。 また、対話形式でのセッションはPlain text (org/markdown)のバッファ上で行われるので、例えば「最初にローカルLLMやコストの小さいモデルで質問し、回答が不十分だったらモデルを切り替えて再度リクエストを送る」、のようなことが素早く簡単にできます。

LLMは過去の自身の回答内容に捉われたり、コンテクストが長くなるに連れて精度が落ちたりすること (AI Cliff)が知られていますが、 gptel ではLLM の過去の回答を削除/編集したうえで再度質問することもできるので、これを抑制することができる点も非常に気に入っています。

最近では多くの人がClaude-Code や Cursor といったAgent系のツールを使っていると思いますが、これらと違って常に主導権が自分にあり、LLMに思考を乗っ取られづらいという点も使い続ける理由の一つです。 (ただ、なるべく頭を使わずに早く成果物をとりあえず得たいときに、Claude-Code を使うこともあります。)

このように、 gptel & mcp.el はユーザーの主体性を保ちながら、LLMの力を最大限にもたらしてくれる、必要不可欠なツールとなっています。

私の gptel の設定

(use-package! gptel
  :config
  (require 'gptel-integrations)
  (setq gptel-model 'gpt-4.1
        gptel-default-mode 'org-mode
        gptel-use-curl t
        gptel-use-tools t
        gptel-confirm-tool-calls 'always
        gptel-include-tool-results 'auto
        gptel--system-message (concat gptel--system-message " Make sure to use Japanese language.")
        gptel-backend (gptel-make-gh-copilot "Copilot" :stream t))
  (gptel-make-xai "Grok" :key "your-api-key" :stream t)
  (gptel-make-deepseek "DeepSeek" :key "your-api-key" :stream t))

どの backend を使うか

gptel の README を見れば分かるように、gptel ではかなり多くの LLM の backend を使うことができます。

目的や使用量、予算によって選ぶべき backend は変わるのですが、 自分は Github Copilot Pro ($100.00 per year) に契約して、Github Models をメインの backend として使っており、今のところ満足しています。

Github Models backend を使っている理由

  1. AI 自動補完 のために pro plan を既に買っていたので追加コストがゼロだった
  2. 従量課金ではなく、定額制だから、コストを気にせず使える
  3. openai7種、Gemini 2種、Claude 3種の計12種類のモデルが使える2 (2025年6月現在)

モデルの使い分け

実際、毎回どのモデルを使うのかを考えるのは面倒なので、だいたい以下のように使い分けています。

  • 要約や翻訳、commit メッセージの生成などの簡単なタスク: GPT-4.1
  • コーディング: Claude Sonnet 4
  • 勉強・長いコンテクストが必要なタスク: Gemini 2.5 Pro
表 1: github copilot で使えるモデルの比較 by Claude (2025年6月時点)
モデル MMLU スコア インテリ指数 速度 (トークン/秒) レイテンシ (秒) コンテキスト長 (トークン) 倍率 最適な用途
無料
GPT-4.1 ⭐ 80.6% 53 155.6 0.42 1M 0 一般的なコーディング
長文コンテキスト分析
新デフォルト
GPT-4o ⚠️ 74.8% 41 - - 128k 0 マルチモーダルタスク
高速反復
高速・低コスト
Gemini 2.0 Flash 78.2% 46 230.5 0.24 1M 0.25x 高速プロトタイピング
コスト重視プロジェクト
o3-mini ⚠️ 79.1% 63 166.3 12.83 200k 0.33x 効率的推論
o4-mini 83.2% 70 149.7 40.10 128k 1x 合理的コストでの高度推論
高性能・バランス型
Claude 3.5 Sonnet 77.2% 44 - - 200k 1x コードワークフロー
チャート解釈
Claude 3.7 Sonnet 80.3% 48 79.0 1.24 200k 1x 柔軟な推論
バランス型パフォーマンス
Claude 3.7 Sonnet Thinking 80.3% 48 79.0 ~2.5 200k 1.25x プロセス可視化
段階的推論
Claude Sonnet 4 ⭐ 83.7% 53 49.1 1.33 200k 1x コーディング強化
命令理解向上
Gemini 2.5 Pro ⭐ 86.2% 70 146.4 35.45 1M 1x 高度推論
科学計算
o1 ⚠️ 84.1% 62 206.1 12.91 200k 1x 複雑な問題解決
o3 85.3% 70 142.0 16.39 130k 1x 高度推論
研究タスク
最上位・特化型
GPT-4.5 ⚠️ - 53 77.0 0.94 130k 50x クリエイティブライティング
事実知識
Claude Opus 4 ⭐ - - - - 200k 10x 自律的長時間タスク
複雑ワークフロー
  • ⚠️ 廃止予定のモデル
  • ⭐ オススメモデル

私の mcp.el の設定

(use-package! mcp
  :after gptel
  :custom
  (mcp-hub-servers
   `(("github" . (:command "docker"
                  :args ("run" "-i" "--rm"
                         "-e" "GITHUB_PERSONAL_ACCESS_TOKEN"
                         "ghcr.io/github/github-mcp-server")
                  :env (:GITHUB_PERSONAL_ACCESS_TOKEN ,(get-sops-secret-value "gh_pat_mcp"))))
     ("duckduckgo" . (:command "uvx" :args ("duckduckgo-mcp-server")))
     ("nixos" . (:command "uvx" :args ("mcp-nixos")))
     ("fetch" . (:command "uvx" :args ("mcp-server-fetch")))
     ("filesystem" . (:command "npx" :args ("-y" "@modelcontextprotocol/server-filesystem" ,(getenv "HOME"))))
     ("context7" . (:command "npx" :args ("-y" "@upstash/context7-mcp") :env (:DEFAULT_MINIMUM_TOKENS "6000")))))
  :config (require 'mcp-hub)
  :hook (after-init . mcp-hub-start-all-server))

(nixOS) uvx で起動するmcp server が Could not start dynamically linked executable というエラー

私の 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)」のようなものであり、この課題に対する一つの洗練された答えなのです。この経験は、単なるトラブルシューティングに留まらず、システム統合の本質を理解する上での貴重な学びとなります。


  1. コンテクストエンジニアリング: LLMに情報とツールを適切な形式、適切なタイミングで提供すること (参考記事)。 ↩︎

  2. Pro PlanではGPT-4.1/4oが無制限、その他モデルはモデル毎の倍率に応じて月300リクエストまで利用可能です(例: Claude Sonnet 3.7は1倍、GPT-4.5は50倍)。私はGPT-4.5 や Claude Opus 4 をほぼ使っていないからか、300回のプレミアムリクエストは思っていたよりも余裕がある印象です。 ↩︎