Caddy MCP Server について
Caddy MCP Serverは、MCPクライアントからCaddyの管理APIに接続し、Webサーバーを管理します。設定、ルート、リバースプロキシ、TLS、PKI、メトリクスを扱い、並行変更や破壊的変更を保護します。
主な機能
- 01Caddy管理APIのエンドポイントを網羅
- 02設定とルートの管理
- 03リバースプロキシとメトリクスの確認
- 04TLSとPKIの管理
- 05ETagによる同時書き込みの保護
- 06ツール注釈と変更スナップショット
活用シーン
- 01Caddyのルートを重複なく更新
- 02設定済みルートとアップストリームの確認
- 03TLS、PKI、サーバーメトリクスの確認
- 04設定変更からの安全な復元
MCP 対応
Caddy管理APIをラップした18個のツールと4個のリソースをMCPクライアントに公開します。ツールは読み取り専用、破壊的操作、冪等性のヒントを宣言し、設定変更ではETagとスナップショットを利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
18掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| path | string | いいえ | 設定パス(例:'apps/http/servers/srv0') |
詳細
@yawlabs/caddy-mcp
ワンクリックでローカルの Yaw MCP 設定に追加され、すべての Yaw Terminal セッションで利用できるようになります。または、以下の手順で手動インストールできます。
Claude Code、Cursor、およびあらゆる MCP クライアントから Caddy ウェブサーバーを管理できます。 Caddy の管理 API リファレンスにあるすべてのエンドポイントを網羅する 18 個のツールと 4 個のリソースを提供します。対象は設定、ルート、リバースプロキシ、TLS、PKI、メトリクス、スナップショットです。
Yaw Labs が開発・保守しています。
この実装を選ぶ理由
ほかの Caddy MCP サーバーは管理 API の半分しかラップしておらず、エラーを黙って無視します。この実装は違います。
- 管理 API を完全に網羅 — Caddy の管理 API リファレンスにあるすべてのエンドポイントを網羅しています。
/load、/config/*、/id/*、/stop、/adapt、/pki/ca/*、/reverse_proxy/upstreams、/metricsに対応しています。404 を返すだけの仮のツールはありません。Caddy の Go ランタイムデバッグエンドポイント(/debug/pprof/*、/debug/vars)は意図的にラップしていません。リークの傾向を調べるには、同じ管理レジストリから取得されるfilter: "go_goroutines"または"go_memstats"を指定してcaddy_metricsを使ってください。スタックダンプ、CPU プロファイル、トレースを取得するには、管理エンドポイントに直接 curl してください(Caddy のプロファイリングに関するドキュメント)。 - 並行書き込みも安全 — ETag(
If-Match)を使用するため、変更によってほかのユーザーの変更が黙って上書きされることはありません。HTTP 412 Precondition Failedは、分かりやすいメッセージで通知されます。 - デフォルトで安全な変更操作 —
caddy_config_setは、append(POST)ではなく、べき等なoverwrite(PATCH)をデフォルトで使用します。2 回呼び出してもルートが重複しません。設定ルートへの書き込みは設定全体(管理エンドポイントを含む)を置き換えるため、confirm=trueがなければ拒否され、caddy_loadと同様に事前にスナップショットが作成されます。 - 堅牢な解析 — ルートが null、ハンドラーが文字列、マッチャーが配列以外の場合でも、
caddy_list_routesが不正な設定でクラッシュすることはありません。回帰テスト済みです。 - エラーに認証情報を漏らさない —
CADDY_ADMIN_URLのパスまたはクエリにトークンが含まれている場合、接続失敗メッセージにはオリジンのみが表示されます。 - フォールバックエラーの通知 — TLS の書き込みで PATCH が失敗し、PUT によるフォールバックも失敗した場合は、実際に何が起きたか分かるように両方のエラーボディを返します。
- ツールアノテーション — すべてのツールで
readOnlyHint、destructiveHint、idempotentHintが宣言されているため、MCP クライアントは安全な操作について確認を省略できます。 - 即時起動 — MCP SDK と Zod の 2 つのランタイム依存関係を含む単一のバンドルとして提供されます。
node_modulesのインストールに 5 分もかかりません。 - 入力の堅牢化 — アダプター名、
@id値、サーバー名、CA ID はすべて、長さの上限付きで正規表現による検証を行います。CRLF ヘッダーインジェクションと ReDoS を防止します。
クイックスタート
1. Caddy 管理 API を有効にする
Caddy では、デフォルトで管理 API が localhost:2019 で有効になっています。Caddy を Docker 内またはリモートホスト上で実行している場合は、CADDY_ADMIN_URL を介して公開してください。
2. プロジェクトのルートに .mcp.json を作成する
macOS / Linux / WSL:
{
"mcpServers": {
"caddy": {
"command": "npx",
"args": ["-y", "@yawlabs/caddy-mcp@latest"]
}
}
}
Windows:
{
"mcpServers": {
"caddy": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@yawlabs/caddy-mcp@latest"]
}
}
}
Windows で追加の手順が必要なのはなぜですか? Node 20 以降、
child_process.spawnは.cmdファイル(Windows ではnpxが該当します)を直接実行できません。cmd /cでラップするのが標準的な回避策です。このファイルにはシークレットが含まれていないため、コミットしても安全です。
3. 再起動して承認する
Claude Code(または MCP クライアント)を再起動し、プロンプトが表示されたら Caddy MCP サーバーを承認してください。
これで完了です。AI アシスタントに次のように尋ねてみましょう。
「api.local を localhost:3000 にプロキシしてください」
「srv0 に設定されているルートを教えてください」
「Prometheus のメトリクスを表示してください」
設定
| 環境変数 | デフォルト | 説明 |
|---|---|---|
CADDY_ADMIN_URL | http://localhost:2019 | Caddy 管理 API の URL です。Docker 内では http://caddy:2019 に設定するか、TLS 終端リバースプロキシの背後にある管理エンドポイントの場合は https URL に設定してください。Caddy がループバックアドレス以外に適用する Host/Origin のルールについては、「トラブルシューティング」を参照してください。Caddy 標準のリモート管理リスナー(admin.remote、デフォルトは :2021)はサポートされていません。TLS クライアント証明書が必要ですが、caddy-mcp は提示しないためです。unix ソケットも指定できます。unix:///var/run/caddy-admin.sock または Caddy 独自の表記である unix//var/run/caddy-admin.sock のいずれかを使用してください。詳しくは以下を参照してください。 |
CADDY_API_TOKEN | (なし) | 任意の Bearer トークンです。すべてのリクエストで Authorization: Bearer <token> として送信されます。Caddy の管理 API 自体にはトークン認証がなく、このヘッダーは無視されます。管理エンドポイントの前に認証プロキシがある場合にのみ必要なため、caddy-mcp が Caddy に直接接続する場合は設定しないでください。このヘッダーが管理リスナーに届いた場合、Caddy 2.0 から 2.11.2 では INFO レベルの admin.api の「received request」ログ行に平文で記録されます。例外は /metrics で、ここは 2.2.1 以降 DEBUG レベルで記録されています。これを REDACTED として記録する Caddy 2.11.3 以降を実行するか、認証後にプロキシでヘッダーを削除してください(Caddy:header_up -Authorization、nginx:proxy_set_header Authorization "";)。 |
CADDY_MCP_SNAPSHOT_DIR | (なし) | caddy_revert スナップショットを永続化するディレクトリです。未設定の場合、スナップショットはメモリ内にのみ保存され、このサーバーの再起動時に失われます。スナップショットは Caddy の設定全体を含み、シークレットが含まれる可能性があるため、デフォルト値は設定せず、明示的に指定する方式になっています。 |
CADDY_MAX_RETRIES | 2 | 一時的な障害に対する再試行回数です。ネットワークエラー、および 502/503/504(これらを送信するのは Caddy の前にあるプロキシのみ)が対象です。Caddy 自身が返す 500 は確定的な拒否であるため再試行せず、4xx と 412 も再試行しません。リプレイによって結果が変わる可能性があるリクエストも再試行しません。これには /config/* と /id/* への POST(追記、または既存キーの置き換えを行うため、再試行するとルートが重複する可能性があります)、および .../routes/0 のような配列インデックスに対する PUT または DELETE(リプレイすると 2 つ目のルートが挿入されたり、そのインデックスに移動したルートが削除されたりする可能性があります)が含まれます。また、裸の /id/<id> への PUT も含まれます。Caddy はこれを、識別された要素の配列インデックスに解決するためです。これらはパスの表記にかかわらず対象になります。末尾のスラッシュがある場合や、Caddy がメソッドを選択する前に削除する末尾の /... セグメントがある場合も同様です。そのため、.../routes/0/... と PUT /id/<id>/... も対象になります。タイムアウトした設定変更は再試行されません(CADDY_LOAD_TIMEOUT を参照)。接続が拒否された場合は何も送信されていないため、すべてのメソッドで再試行されます。/load、/adapt、/stop への POST は引き続き再試行されます。上限は 5 です。上限を超える値を指定すると、制限が分かるように stderr に一度だけ通知が出力されます。0 を指定すると無効になります。 |
CADDY_TIMEOUT | 10000 | 設定を変更しない管理 API リクエストのタイムアウト(ミリ秒)です。GET、/adapt、/stop、PKI、アップストリーム、メトリクスが対象です。設定変更には CADDY_LOAD_TIMEOUT が使われます。数値以外、<= 0、または 1ms 未満の小数値が指定された場合はデフォルト値に戻ります。 |
CADDY_LOAD_TIMEOUT | 55000 | 設定を変更するすべてのリクエストのタイムアウト(ミリ秒)です。POST /load と、/config/* および /id/* 以下へのすべての POST/PUT/PATCH/DELETE が対象です。いずれも Caddy 内で同期的に全体を再読み込みします。変更によってリスナーが閉じられる場合、Caddy は再読み込み中に apps.http.shutdown_delay の時間だけ待機します。また、変更が別の再読み込みの完了待ちになることもあるため、正当に長時間かかる場合があります。このタイムアウトでは再試行されません。クライアントが処理を諦めた後も Caddy は変更を適用し続けるため、エラーには結果が不明であり、再試行する前に設定を読み直すよう示されます(その場合、caddy_load と caddy_revert はスナップショットを保持します)。MCP クライアントのリクエストタイムアウト(MCP SDK ではデフォルト 60 秒)より短くしてください。そうしないと、クライアントが処理を諦めた後にエラーが届き、表示されません。デフォルト値はその 5 秒前に設定されています。数値以外、<= 0、または 1ms 未満の小数値が指定された場合はデフォルト値に戻ります。 |
| Unix ソケット管理エンドポイント: |
Caddy が推奨するセキュリティ強化策は、管理 API をループバックポートから Unix ソケットに移し、ファイルシステムのアクセス権限でアクセスを制御することです。
{
admin unix//var/run/caddy-admin.sock
}
CADDY_ADMIN_URL を同じパス(unix:///var/run/caddy-admin.sock)に設定すると、リクエストは TCP ではなくソケット経由で送信されます。caddy-mcp を実行するプロセスには、ソケットファイルの読み取り/書き込み権限が必要です。認証プロキシが実際にそのソケットをリッスンしている場合を除き、ここでは CADDY_API_TOKEN を未設定のままにしてください。Unix パス経由では、caddy-mcp は通常 Caddy 自身のソケットと通信しており、トークンは機能しません。また、Caddy 2.11.3 より前のバージョンではトークンが平文でログに記録されます。
ランタイム(oam または Node):
caddy-mcp コマンドは、使用可能な oam が見つかった場合はそちらを優先し、見つからない場合は Node で実行します。0.18.0 より古い oam では実行しません。
| 環境変数 | デフォルト | 説明 |
|---|---|---|
CADDY_MCP_RUNTIME | auto | auto:0.18.0 以降の最新の oam を使用し、なければ Node を使用します。oam:oam を使用し、使用できない場合はエラーで終了します。node:常に Node を使用します。oam でのみ問題が発生する場合の回避策です。 |
CADDY_MCP_SANDBOX | (未設定) | 1 に設定すると、oam の --permission サンドボックス内でサーバーを実行します。ネットワークアクセスは CADDY_ADMIN_URL のホストとポートに制限され、ファイルシステムへのアクセスは CADDY_MCP_SNAPSHOT_DIR に制限されます。子プロセスは実行できません。oam が必要です。auto の場合、oam がインストールされていないマシンではサンドボックスなしで実行されるため、サンドボックスを必須にするには CADDY_MCP_RUNTIME=oam と組み合わせてください。Unix ソケットの CADDY_ADMIN_URL は、まだサンドボックスからアクセスできません。 |
OAM_BIN | (未設定) | 使用する oam バイナリのパスです。設定されていない場合、ランチャーは OAM_INSTALL_DIR、インストール先(~/.oam/bin、Windows の場合は %LOCALAPPDATA%\oam\bin)、および PATH を確認し、最新のものを選択します。 |
古い oam は oam self-update で更新できます。デフォルトで oam 上でサーバーを実行する Yaw MCP では、yaw-mcp set <namespace> runtime=node を実行すると、このサーバーを Node に切り替えられます。
その他の MCP クライアント:
| クライアント | 設定ファイル |
|---|---|
| Claude Code | .mcp.json(プロジェクトルート)または ~/.claude.json(グローバル) |
| Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json(macOS) |
| Cursor | ~/.cursor/mcp.json |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| VS Code | .vscode/mcp.json |
上記と同じ JSON ブロックを、これらのいずれかで使用してください。
ツール
設定管理(6)
- caddy_config_get — 任意の JSON パス(または設定全体)の設定を読み取ります。
- caddy_config_set — 指定したパスの設定を書き込みます。モード:
overwrite(PATCH。デフォルト。冪等です。キーが存在している必要があり、パス配下のサブツリー全体を置き換えます)、append(POST。配列に追加しますが、既存の非配列キーは置き換えます。存在しない親キーは作成できません)、insert(PUT。配列の位置を指定して挿入するか、不足している親キーも含めてキーを厳密に作成します。キーがすでに存在する場合は 409 で失敗します。設定のないインスタンスでもサーバーやアプリを作成するにはこの方法を使います)。/...で終わるパス(例:apps/http/servers/srv0/routes/...)でappendを実行し、値が配列の場合は、1 回のリクエストですべての要素を追加します。すべて追加するか、まったく追加しないかのどちらかで、リロードは 1 回です。/...を付けずに配列値を指定すると、配列全体が 1 つの要素として追加されるため、routesやlistenなどの型付き配列では Caddy が設定の読み込みを拒否します。設定のルート(''、'/'、'config'、'/config/'、スラッシュのみの形式、またはそのいずれかの末尾に単独の...セグメントを付けたもの)を指すパスは、設定全体を対象とし、confirm=trueが必要です。その場所でoverwriteとappendを実行すると、caddy_loadと同様に、adminブロックを含めてvalueで設定全体を置き換えます。ただし、valueにadminブロックが含まれていない場合、Caddy は新しい設定のadmin.listenで指定されたアドレス、指定がない場合はデフォルトアドレスに管理エンドポイントを再バインドし、admin.disabledが設定されている場合はアドレスにバインドしません。その後、別の場所を指すCADDY_ADMIN_URLは機能しなくなります。ルートへの書き込みでは、可能な場合、以前の設定が自動的にスナップショットされるため、caddy_revertで復元できます。他のパスはスナップショットされません。ルートでのinsertは、先にルートのcaddy_config_deleteを実行した場合にのみ成功し、それ以外は 409 になります。逆に、ルートの削除後にoverwriteを実行すると、append、insert、またはcaddy_loadで設定が再作成されるまで 404 が返されます。 - caddy_config_delete — 指定したパスの設定を削除します。
confirm=trueが必要です(親パスを削除すると、すべての子孫も削除されます)。設定のルート(''、'/'、'config'、'/config/'、スラッシュのみの形式、またはそのいずれかの末尾に単独の...セグメントを付けたもの)を指すパスは、設定全体を対象とします。すべてのアプリとサーバー、およびadminブロックがアンロードされ、その後 Caddy は管理エンドポイントをデフォルトアドレス(localhost:2019、または Caddy の環境変数$CADDY_ADMIN)に再バインドします。CADDY_ADMIN_URLが別の場所を指している場合、その後 Caddy には caddy-mcp からもcaddy_revertからもアクセスできなくなります。ルートを削除すると、可能な場合、以前の設定が自動的にスナップショットされるため、Caddy にまだアクセスできる間にcaddy_revertで復元できます。他のパスはスナップショットされません。設定をアンロードするのではなく置き換える場合は、caddy_loadを使用してください。 - caddy_config_by_id —
@idタグを使って設定を取得、設定、削除します。深い階層のパスをたどるよりも簡単です。deleteアクションにはconfirm=trueが必要です。すべてのsetとdeleteでは、最初に Caddy にidの解決先を問い合わせ、設定ツリー内に解決されない場合は拒否します。設定ルートに解決される場合(通常は設定自体の最上位の@idが文字列または数値の場合)、設定全体を指します。その場合、サブパスを指定せずに(または単独の...を指定して)setとdeleteを実行すると、ルートでのcaddy_config_set/caddy_config_deleteと同様に、設定全体を置き換えるかアンロードします。どちらもconfirm=trueが必要で、以前の設定が先にスナップショットされ、管理エンドポイントの移動先が報告されます。その内部のサブパスは通常の書き込みとして扱われます。 - caddy_load — 設定全体をアトミックに置き換えます。すべての設定変更と同様に、
CADDY_LOAD_TIMEOUT(デフォルトは 55 秒)で実行されます。以前の設定が自動的にスナップショットされ、タイムアウトして結果が不明な場合もそのスナップショットは保持されます。Caddyfile アダプターの警告を一覧表示し、Caddy が HTTP 200 を返した場合でも、読み込みに失敗したことをエラーとして報告します。これは、警告付きで変換された Caddyfile に対して Caddy 2.11.4 が HTTP 200 を返す場合があるためです(caddyserver/caddy#7246)。formatはjson(デフォルト)またはcaddyfileです。標準の Caddy で登録されているアダプターはcaddyfileのみです。そのため、カスタムビルドに含まれる他のアダプターを使う場合は、まずcaddy_adaptで変換してから JSON を読み込んでください(下記のアトミックデプロイの例を参照)。 - caddy_revert — ロールバック用の設定スナップショットを管理します。アクション:
list、save、apply(確認が必要)。メモリ上に直近 10 件を保持します。caddy_loadの実行前、および設定ルートを対象とするcaddy_config_delete、caddy_config_set、caddy_config_by_idの実行前に、自動でスナップショットされます。applyがタイムアウトして結果が不明な場合、ロールバック前の設定がスナップショット [0] として保持され、それより古いスナップショットはすべて 1 つずつ後ろに移動します。エラーには、対象のスナップショットが現在どこにあるかが示されます。
ルート操作(4)
- caddy_reverse_proxy — 1 回の呼び出しでリバースプロキシを追加します:
from='api.local' to=['localhost:3000']。冪等な書き込みには省略可能なidを渡します。呼び出しを繰り返すと、ルートが重複するのではなく、その場で置き換えられます。 - caddy_add_route — マッチ条件とハンドラーを完全に制御してルートを追加します(任意の Caddy ハンドラー)。
- caddy_remove_route —
@id(推奨)またはインデックスでルートを削除します。confirm=trueが必要です。 - caddy_list_routes — 人が読みやすいルートの概要を表示します。堅牢な設計で、予期しない設定でもクラッシュしません。
TLS と設定の変換(2)
- caddy_tls — TLS 設定を確認または設定します。アクション:
status、set_email(ACME メールアドレス)、set_acme_ca(ACME CA URL)、set_acme_profile(ACME プロファイル、Caddy 2.10 以降 — 実験的なアップストリーム機能です。ACME プロファイル仕様はまだドラフトであり、Caddy はこのフィールドが変更される可能性があるとしています。Caddy は読み込み時に任意のプロファイル名を受け入れるため、CA が公開していない名前を指定した場合、発行時にのみ失敗し、Caddy 自身のログに記録されます)、および読み取り専用のech_status(apps/tls/encrypted_client_helloの Encrypted ClientHello 設定、Caddy 2.10 以降)。設定アクションは、まず PATCH を試みます。apps/tlsが設定されていない場合は最小限の設定を PUT し、存在しない親要素も作成するため、設定がまったくないインスタンスでも機能します。既存の設定では、発行者のパスにディープマージしてから結果を PATCH で書き戻すため、兄弟要素(カスタム証明書、on_demand、追加のポリシーなど)が保持されます。既存の構造が想定外の場合は、構造に応じたエラーを返して拒否し、既存設定を上書きすることはありません。 - caddy_adapt — 登録済みの任意のアダプター形式の設定を、適用せずに Caddy JSON へ変換します。
caddyfile(組み込み、デフォルト)に加え、Caddy バイナリにコンパイルされているアダプターモジュール(例:nginx(caddy-nginx-adapter)、yaml(caddy-yaml))を使用できます。既存の設定をプレビューしたり移行したりするのに便利です。Caddy 2.11.4 以前では、Caddyfile のorderグローバルオプションがプレビューだけにとどまらない点に注意してください。このオプションは、その Caddy プロセスのディレクティブ順序を変更するため、同じプロセス内で後から実行する Caddyfile の adapt や読み込みにも影響します。また、order行が失敗しても、指定したディレクティブは削除されます(caddyserver/caddy#7995。アップストリームでは修正済みですが、2.11.4 時点では未リリースです)。
サーバー操作(6)
- caddy_status — 接続確認と設定の概要(サーバー数、ルート、TLS モード)。TLS ラベルは、待ち受けポートから推測するのではなく、保存された設定に対して Caddy 独自の自動 HTTPS ルールを再現するため、
enabled、enabled (no listener gets TLS: all are on the HTTP port)、auto (HTTPS)、auto (HTTPS: host matchers on a non-HTTP port)、mixed (TLS on non-HTTP listeners only)、off (HTTP only)、off (no host matchers)、off (automatic HTTPS disabled)またはoff (empty tls_connection_policies)と表示されます。条件付きのenabled表示の 2 種類は、Caddy がサーバー単位ではなくソケット単位で TLS を判断すること(app.go:535)に由来します。HTTP ポートのリスナーでは接続ポリシーが無視されるため、そのポートだけにバインドするサーバーは TLS 用に設定されていても、TLS を一切提供しません。 - caddy_list_servers — 名前、アドレス、ルート数、TLS の状態とともに、すべての HTTP サーバーを一覧表示します。
caddy_statusと同じラベルを使いますが、このツールが読み取るのはapps/http/serversのみであり、既定のhttp_port80/https_port443 を前提とします。カスタムポートを使うインスタンスでは、正しいラベルを取得できるのはcaddy_statusです。 - caddy_upstreams — Caddy の
/reverse_proxy/upstreams配列をそのまま返す、リバースプロキシバックエンドの健全性情報です。Caddy 2.11.2 以降では、これは設定済みのアップストリーム一覧ではありません。動的アップストリームは、動的ソースが最後に返してから約 1 時間、一覧に残るため、アドレスがそれを参照していた設定より長く残ることがあります。また、解決済みアドレスがエントリのダイヤル文字列と異なる場合、リクエスト処理中のバックエンドが 2 回表示されることがあります。追加のエントリは常にfails 0を表示し、num_requestsを繰り返します。エントリ間でnum_requestsを合計しないでください。 - caddy_metrics — Prometheus メトリクス(リクエスト数、所要時間、接続、TLS ハンドシェイク)。任意の
filter(メトリクス名に対する部分一致。該当するメトリクスの# HELP/# TYPE行も保持)とmax_lines(既定値 500)を指定すると、負荷の高いサーバーでも応答を簡潔に保てます。 - caddy_pki — CA 情報と証明書チェーン(既定の CA:
local)。 - caddy_stop — グレースフルシャットダウン。誤操作を防ぐため、
confirm=trueが必要です。
リソース
参照可能な読み取り専用データです。MCP クライアントはツール呼び出しなしで直接取得できます。
caddy://config— 現在の Caddy JSON 設定全体。caddy://servers— 設定済みのすべての HTTP サーバーの概要。caddy://upstreams— リバースプロキシのアップストリーム健全性情報をそのまま表示します。caddy_upstreamsと同じ 2.11.2 以降の注意事項があります。動的アップストリームが残ることや、処理中のエントリが重複することがあるため、num_requestsを合計しないでください。caddy://metrics— Prometheus メトリクス(テキストのエクスポジション形式)。クライアントのコンテキスト量を抑えるため、先頭 500 行までに制限されています。フィルターを適用した出力や、より多くの出力を取得するには、filter/max_linesを指定してcaddy_metricsツールを使用してください。
例
リバースプロキシを追加する
> "Proxy api.example.com to my app on port 3000"
→ caddy_reverse_proxy({ from: "api.example.com", to: ["localhost:3000"] })
冪等なリバースプロキシ(自動化から安全に再実行可能)
> "Make sure api.example.com points at localhost:3000, with a stable id"
→ caddy_reverse_proxy({ from: "api.example.com", to: ["localhost:3000"], id: "api-prod" })
# First call creates the route under @id="api-prod".
# Subsequent calls with the same id REPLACE in place — no duplicate routes.
# Refuses with a clear error if "api-prod" is already in use by a non-route
# config object (TLS issuer, server, etc.) — @ids are config-global in Caddy.
Prometheus メトリクスをフィルタリングする
> "Just the HTTP request metrics, please"
→ caddy_metrics({ filter: "http_requests" })
# Keeps sample lines whose metric name contains "http_requests",
# plus their `# HELP` / `# TYPE` lines. Drops the rest.
適用前に Caddyfile をプレビューする
> "Convert this Caddyfile to JSON so I can review it:
example.com {
reverse_proxy localhost:8080
}"
→ caddy_adapt({ config: "..." })
遅いルートを診断する
> "Fetch Prometheus metrics and tell me which route is slowest"
→ caddy_metrics()
@id でルートを安全に更新する
> "Update the route with @id 'api-v2' to point to the new backend"
→ caddy_config_by_id({ id: "api-v2", action: "set", value: {...} })
# Uses ETags — you'll get HTTP 412 if someone else changed it first
アトミックデプロイ
> "Replace the whole config with this Caddyfile"
→ caddy_adapt({ config: "..." }) # validate first
→ caddy_load({ config: adaptedJson }) # apply atomically
トラブルシューティング
「Caddy 管理 API に接続できません」
- Caddy が実行中であることを確認してください。
caddy runまたはsystemctl status caddyを実行します。 - 管理エンドポイントを確認してください。デフォルトは
http://localhost:2019です。Caddy が Docker 内にある場合は、コンテナーのホスト名を使用します。 - MCP 設定の
envでCADDY_ADMIN_URLを設定し、一致させてください。 - SSH トンネル経由の場合は、両端で同じポートを割り当て(
ssh -L 2019:localhost:2019 <host>)、CADDY_ADMIN_URLはデフォルトのままにしてください。Caddy はHostヘッダーを自身のリッスンアドレスと照合するため、異なるローカルポートを使うトンネルでは403 host not allowed: localhost:<port>が返されます。 - リバースプロキシの背後にある場合は、プロキシの
host:portをリモート側 Caddy のadmin.originsに追加してください。Caddy はHostとOriginの両方を確認し、admin.originsを設定するとデフォルトのlocalhost/127.0.0.1/::1のエントリーが置き換えられるため、ローカルツールからも引き続きアクセスする必要がある場合はlocalhost:2019も指定してください。ループバック以外のアドレスやワイルドカードを使ったadmin.listen(たとえば上記の Docker のhttp://caddy:2019)でも、任意のHostが許可されるわけではないため、同様にadmin.originsを設定する必要があります。 CADDY_ADMIN_URLを Caddy のネイティブなリモート管理リスナー(admin.remote、デフォルトは:2021)に向けると、HTTP 通信が始まる前に失敗します。このリスナーは TLS クライアント証明書を必要としますが、caddy-mcp は証明書を提示しないためです。Caddy が実行中で接続を受け付けている場合でも、このメッセージが表示されます。
「HTTP 412 Precondition Failed」
- 読み取りと書き込みの間に、誰か(または何か)が設定を変更しました。
- キャッシュされた ETag が無効になっています。設定を再読み込みして、もう一度試してください。
リクエストで「HTTP 401」または「HTTP 403」が返される
- Caddy 独自のチェックは、読み取りを含むすべての管理リクエストで実行され、常に JSON の
{"error":...}ボディを返します。これが返された場合は、Caddy が返したものです。admin.listen/admin.originsの許可リスト(host not allowed: ...、client is not allowed to access from origin ...、required Origin header is missing or invalid。上記のトンネルとプロキシの箇条書きを参照)、またはadmin.remoteの場合は、その mTLS の認証情報と権限チェックが原因です。 - ボディのない 401/403 は、Caddy の前段にあるもの(プロキシ、ゲートウェイ、SSO レイヤー)から返されています。
CADDY_API_TOKENが適用されるのはその場合だけなので、トークンがない、または間違っていることが原因の一つであり、プロキシのその他のアクセスルールも原因になります。 - Caddy の管理 API には独自のベアラートークン認証がないため、Caddy のエラーボディを伴う 401/403 は、
CADDY_API_TOKENを設定しても解消されません。
caddy_adapt から、または format: "caddyfile" を指定した caddy_load から返される 「directive 'X' is not an ordered HTTP handler」
- 原因は2つありますが、Caddy のエラーからは区別できません。
- ディレクティブに登録済みの順序がありません。通常はプラグインのディレクティブです。
orderグローバルオプションを追加するか、routeブロックで囲んでください。 - Caddy 2.11.4 以前では、同じ Caddy プロセス内で
orderを使用した先行の、または並行して実行された Caddyfile の適用処理が、そのプロセス全体のディレクティブ順序から該当のディレクティブを削除している場合があります。Caddy を再起動するとデフォルトの順序に戻ります(caddyserver/caddy#7995、未リリース)。
- ディレクティブに登録済みの順序がありません。通常はプラグインのディレクティブです。
- 2つ目の原因により、1分前には適用できた Caddyfile が、編集していないのに失敗し始めることがあります。Caddy 独自のアドバイス(「
orderグローバルオプションを使って試す」)は、1つ目の原因を解決し、2つ目の問題を覆い隠します。
SIGUSR1/systemctl reload caddy を実行すると、Caddyfile の再読み込みが停止する
- 想定された動作であり、ここでのバグが原因ではありません。Caddy 2.11.1 以降では、
SIGUSR1によるディスク上のファイルからのリロードは、設定が管理 API 経由で一度も変更されていない場合に限られます。caddy-mcp(またはその他の API クライアント)から最初の書き込みが行われると、Caddy は実行中の設定を API が所有するものと見なし、SIGUSR1は何もしなくなります。 - インスタンスごとに設定の所有者を一つ選びます。Caddyfile を信頼できる唯一の情報源とする場合は、caddy-mcp の読み取り専用ツール(
caddy_status、caddy_list_routes、caddy_adapt)を使い、ファイルからリロードします。caddy-mcp が設定を管理する場合は、SIGUSR1ではなくcaddy_loadで変更を適用します。 - Caddy 2.11.4 以前については、補足事項があります。
caddy_adaptは設定に関しては読み取り専用ですが、アダプターに関してはそうではありません。Caddyfile のorderグローバルオプションは、そのプロセスのディレクティブ順序を変更します。また、失敗したorder行は、後続のプロセス内での変換を壊すことがあります。これにはSIGUSR1によるリロードとcaddy run --watchが該当します。一方、パッケージ版のsystemctl reload caddyが実行するcaddy reloadは、CLI プロセス内で変換を行うため影響を受けません。
Windows:MCP サーバーが起動しない
- クイックスタートのセクションにある
cmd /c npx ...のパターンを使ってください。Node 20 以降では.cmdファイルを直接起動できません。
要件
-
Node.js 20+
-
Caddy 2.11.3 以降で、管理 API が有効になっていること(デフォルト:
localhost:2019)。 最新の 2.11.x を推奨します。Caddy 2.11.4 で検証済みです。この下限には、管理 API 側に関する理由が 2 つあります。- Caddy 2.11.2 以前では、すべての管理 API リクエストのヘッダーが INFO レベルでログに記録されます。そのため、
CADDY_API_TOKENのAuthorizationヘッダーが管理リスナーに届くと、トークンが平文で Caddy のログに書き込まれます (caddyserver/caddy#7578)。 - Caddy 2.11.1 以前では、重複する
@idが黙って受け入れられます。競合するcaddy_reverse_proxyの作成、またはルート ID に対するmode: "insert"を指定したcaddy_config_by_idの設定により、同じ@idを共有する要素が 2 つ残り、/id/から解決されるのはそのうちの一方だけです。
古い 2.x もほぼ動作しますが、どちらも Caddy の
ETagの送信方法に起因する例外が 2 つあります。Caddy 2.8.0 以降では、ETagはレスポンスヘッダーとして送信されます。Caddy 2.5.2 から 2.7.x では HTTP トレーラーとして送信されますが、このクライアントでは読み取れません。それ以前のバージョンでは送信されません。そのため、2.8.0 より前では次のようになります。If-Match(ETag)による同時実行制御は無効です。送り返すためにキャッシュされる ETag が存在しないためです。- すべての
caddy_config_by_idのsetとdeleteは拒否されます。このツールは、@idを通じて書き込む前に、Caddy がその@idをどこに解決するかを知るために ETag を読み取ります。ETag を読み取れない場合は、安全側に倒して処理を中止します。
@idの書き込み処理は、リリースごとにライブ統合テストスイートで検証されるPATCHのセマンティクスに依存します。 - Caddy 2.11.2 以前では、すべての管理 API リクエストのヘッダーが INFO レベルでログに記録されます。そのため、
コントリビューション
git clone https://github.com/YawLabs/caddy-mcp.git
cd caddy-mcp
npm install
npm run lint # Biome check
npm run lint:fix # Auto-fix
npm run build # tsup bundle
npm test # Vitest (782 unit tests, +39 POSIX-only unix-socket and launcher tests; +39 live-Caddy integration tests gated by CADDY_MCP_INTEGRATION=1)
npm run typecheck # tsc --noEmit
リリースプロセスを含む完全なワークフローについては、CONTRIBUTING.md を参照してください。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。