あ、なんか自分で作ったほうが早くね?
課金はしたくない。でもその機能は使いたい。
そんな考えから始まった開発沼。
(ちなみに筆者は音楽の人なので例えがだいたい音楽系の例えになるので許して...シテ...)
とりあえず「Github Copilotを使っておけ」と師匠から助言を貰ったので、
AIエージェントでコーディングをしていて「わー楽しい(白目)(エナドリ5本目)」
とかやっていたら、ふと思いました。
MCPを触っていると、モデルより先に人間の方が詰まる瞬間があるな?
そう、設定ファイルです。
で、そのMCPの設定ファイル。
便利なんですが、壊れ方が地味です。
- JSONの形は合っているように見える
-
commandも書いた -
argsもそれっぽい - でもMCPサーバーは起動しない
- ログを見る
- 祈る
- もう一回ログを見る
みたいなやつです。
JSONは悪くない。
だいたい悪いのは人間と、昨日の自分と、雑にコピペした args です。
ということで、MCP設定ファイル用のlinterとして mcp-config-lint を作りました。
と、その前にLinterってなんぞや?MCPってなに?
って方のために超雑かつラフに説明します。
俺が当時まんま思ってた事と口調で書くので、
多少(?)砕けた口調ですが許してクレメンス。
MCP ってなんだよ
MCP(Model Context Protocol[だった気がする])は、AIと外部ツールをつなぐ
「共通規格の接続口」
わかりやすく言うと、USB-C ポートがよく例に出されますな。
昔のスマホって充電ケーブルがメーカーごとにバラバラで
「このケーブルここには刺さらへんやん! タコが! 」ってなってたよね。
それがUSB-Cに統一されてどこでも使えるようになった。MCPがまさにそれ。
AI(Claude とか GPT とか)は元々テキストを返すだけの存在なんだけど、MCP を使うと GitHub・データベース・ブラウザ・Figma みたいな外部ツールに「標準化された同じ方法」で繋がれるようになる。
MCPがなかった頃は、ツールごとに「繋ぐためのコード」を
毎回ゼロから書かないといけなくて、めちゃくちゃ面倒だった 。
ほんで具体的にどう使うん?
例えばAIに「このリポジトリのコードを読んで修正して」って頼んだとき
AIが「GitHubにアクセスしなきゃ」と判断
MCP経由でGitHubサーバーに接続
コードを取得 → 修正 → プッシュまで全自動
これを CursorやClineみたいなAIエディタが普通にやってくれる。
MCPサーバーさえあれば、AIの「できること」が無限に拡張できるって感じ。
じゃあ逆にLinterってなんや
Linterは、コードの「文法・マナー違反を自動で指摘してくれる先生」みたいなもん。
音楽で例えるなら、作った曲をDAWに流し込んだら「ここのノートが音痴です」
「ここリズムずれてます」
って自動で指摘してくれる機能みたいなもんやね。
うーん...わかりずらいか..? 音楽に生きて音楽で死ぬ人なので他の例えが浮かばない( ´・ω・)
まぁとりあえず、プログラミングにも
「動くけど汚い・危険なコード」ってのが山ほどある。
スパゲッティコードとか呼ばれてたりするらしい。
美味しそうだよね。バグとかミートボールコードっていうんかな
知りませんが(゜-゜)
まぁ例えばさ、使ってない変数を大量に放置してるとか
インデントがバラバラ
危険なパターンで書いてある
これを人間が全部チェックするのは地獄の2丁目なんで、
Linter が自動で「ここおかしいぞ!」って赤線引いてくれる。
ESLint・Biome・textlintとかが有名どころですね。
| 一言で言うと | 音楽で例えると | |
|---|---|---|
| MCP | AI と外部ツールを繋ぐ USB-C | DAW のプラグイン規格(VST とか) |
| Linter | コードの自動チェッカー | 音程・リズムの自動採点機能 |
| MCP × Linter | AI が自分でコード品質を直す仕組み | AI が作曲して自動採点まで全部やる感じ |
↑ちなみにこれ作るのめっちゃ時間かかった(いらない説明)
要するに
MCP = AI の手足を増やす規格、Linter = コードの品質管理ツールで、
これを組み合わせると「AI が書いて、チェックして、直す」が
全部自動化できる最強ワークフローが作れる。
って感じです!
本題入りまーす
作ったもの
mcp-config-lint は、MCPの設定ファイルを静的にチェックするためのCLIツールです。
バカざっくり言うと、
MCPクライアントを起動してから設定ミスに気づくのではなく、起動前に怒ってほしいな~みたいな。
というためのツールです。
設定ファイルって、小さいうちは「まあ手で見ればいいか」となりがち。
でもMCPのconfigには command、args、env が入る。
つまり、ただのJSONに見えて、実質「ローカルで何を起動するか」の定義です。
小さい顔をしたインフラですワ。かわいいふりして普通に強ぇ。
使い方
基本はこんな感じです。
npx mcp-config-lint
ファイルパスやglobパターンを直接渡すこともできます。
npx mcp-config-lint ./mcp.json
プロジェクトに入れて使うなら、dev dependencyにしてもよいです。
npm install -D mcp-config-lint
npx mcp-config-lint
CIに入れる場合は、たとえばこんな感じ。
name: lint-mcp-config
on:
pull_request:
push:
branches: [main]
jobs:
mcp-config-lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v6
with:
node-version: "20"
- run: npm ci
- run: npx mcp-config-lint --json --fail-on medium
MCP設定はローカルに置くことも多いんですが、
チームで共有するテンプレートや、dotfiles、開発環境のセットアップ手順に含めるなら、
CIでチェックできるだけでかなり気が楽になります。
「動かしてから気づく」より「PRで落ちる」方がまだ人間に優しいです。
PRで赤くなるのもツラミが強いですが、深夜2時にグロッキーになった状態で
MCPログを読むよりは概ね健康的です。
何をチェックするのか
mcp-config-lint が見ているのは、MCP設定ファイルの
「スキーマとしての正しさ」よりも
「そのまま公開すると危ないかもしれないパターン」です。
たとえば以下のようなものを検出します。
- JSON / JSONC として壊れている設定
-
envに直書きされた token / secret / password っぽい値 - 高エントロピーで secret っぽい環境変数値
-
curl | shやeval系の危険なシェル実行 -
sudo、chmod 777、rm -rf /などの権限昇格・破壊的操作っぽいコマンド -
npx/dlx/uvxでパッケージバージョンが固定されていない実行 -
~/.ssh、.aws/credentials、.kube/configなどの機密ファイル参照 - ホームディレクトリ配下を広く参照する設定
-
curl/wgetなどのネットワーク取得コマンド
たとえば、ザックリですが、こういう設定があったとします。
{
"mcpServers": {
"github": {
"env": {
"GITHUB_TOKEN": "ghp_1234567890abcdefghijklmnopqrstuvwxyz"
}
}
}
}
見た目はそれっぽいですが、
tokenらしきものが直書きされています。
(これ開発を学んでる初期の頃にしょっちゅうやらかしてました)
こういう設定に対して、linter側で
path/to/mcp.json
HIGH hardcoded-env-secret line 6
Environment key GITHUB_TOKEN contains a literal secret value.
remediation: Replace the literal with a safe placeholder or environment variable reference.
pointer: $.mcpServers.github.env.GITHUB_TOKEN
snippet: [REDACTED length=37]
Findings: 1. Scanned 1 file(s).
起動前に気づける上に、出力のsnippet部分はちゃんと値が伏せられます。
ログに生のtokenが残らないのも地味に大事なや~つです。
目指したこと
作るときに意識したのは、主にこのあたりです。
1. MCP初心者にもわかるエラーにする
linterでありがちなのが、怒ってはくれるけど何を直せばいいかわからないパターンです。
Invalid config だけ出されても、こちらとしては「でしょうね」という顔になります。
なので、なるべく
- どのサーバー定義で
- どのキーが
- なぜダメで
- どう直せばよさそうか
が伝わるようにしたいと思っています。
エラー文はUIです。
CLIでもUIです。
人間が読む以上、そこにはUXが発生します。
2. 実行しない
mcp-config-lint は、基本的に設定ファイルを静的にチェックするツールです。
つまり、設定に書かれている command を勝手に実行しない方針です。
これはほんまに大事です。
MCP設定にはローカルコマンドや環境変数が入るので、linterが勝手に実行し始めると、
それはもうlinterというより「好奇心の強い何かしらの化け物」です。
静的に見てわかるミスは静的に潰す。
実行が必要な検証とは分ける。
この線引きはかなり意識しています。
3. CIに入れやすくする
個人的に、こういうツールはCIに入って初めて価値が跳ねると思っとります。
ローカルで気が向いたときに叩くツールも便利ですが、
設定ファイルは「うっかり壊れる」ものです。
うっかりを防ぐには、人間の注意力ではなく機械に寄せた方がいい。
人間の注意力は有限です。
しかも金曜夕方に急激に劣化します。
なんなら月曜日は終日で火曜日も終日で木曜はシャットダウン状態です。
水曜日ぐらいですよ。注意力がちょっとマシな日。
なので、mcp-config-lint はCIで使いやすいように、
問題があれば非ゼロ終了するCLIとして扱えるようにしています。
逆に、やらないこと
mcp-config-lint は、MCPサーバーの安全性を完全に保証するツールではないです。
ってかそんなツールあるならむしろ(ヽ゚д゚)クレ
たとえばですよ
- そのMCPサーバー自体が安全か
- 実行時にどんな通信をするか
- tool callの中身が妥当か
- 権限設計が適切か
までは、このツールだけでは判断しません。
そこまでやると、もはやconfig lintではなくセキュリティ監査ツールです。
それはそれでほんまに欲しいですが(2回目)、まずは足元のJSONからです。
「玄関の鍵を閉める前に、家の構造計算を始めない」くらいの粒度感です。
なぜ作ったのか
MCPまわりは、今後もっと設定が増えると思っとります。
使うツールが増える。
接続するサービスが増える。
チームで共有したい設定も増える。
ローカルだけで完結していたconfigが、だんだん「管理すべきもの」になっていく。
そうなると、設定ファイルにも最低限の品質チェックが欲しくなります。
コードにはESLintやPrettierを入れるのに、MCP configは目視だけ、というのも少し心細い。
しかもMCP configは、壊れるとAIエージェント側の挙動に影響します。
ほんまにやめてほしい(切実)
エージェントが賢いかどうか以前に、入口のJSONで転んでいたら悲しい。
F1マシンに乗ってコンビニの縁石で擦るみたいな話です。
今後やりたいこと
今後は、もう少しルールを増やしていきたいです。
たとえば、
- クライアントごとの設定ファイル検出
- よくあるMCPサーバー設定のプリセットチェック
- secret検出ルールの強化
- ルールの有効/無効切り替え
- JSON Schemaとしての再利用
- GitHub Actions向けのCI例をさらに充実させる
- エラー表示の改善
あたりを考えています。
特に、secretまわりはちゃんとやりたいです。
MCP configにtokenを雑に置くと、便利さと引き換えに将来の自分が微妙な顔をしますから...
微妙というか闇落ちします。
将来の自分は他人です。
しかもだいたい厳しめのレビューをしてきます。
2年後になって「なんやねんこの設計。どこぞのバカが書いたんや」と言い、
冷静に「僕です」と言って消滅します。
おわりに
mcp-config-lintは、派手でもなければ万能ツールでもありません。
AIエージェントを賢くするわけでもないし、
MCPサーバーを自動生成するわけでもありません。
ただ、設定ミスで溶ける時間を少しでも減らせたらな~と思って作ったツールです。
でも、こういう地味なところを潰していくのが、
開発体験には効くと思っています。
設定ファイルは、動いているときは空気です。
壊れた瞬間だけ、急に主役ヅラしてきます。
その主役交代をなるべく防ぎたい。
というわけで、MCP設定ファイルで「なんで動かないんだっけ」を
何度かやったことがある人は、ぜひ mcp-config-lint を試してみてください。
Issue、PR、フィードバック歓迎です。
スターも歓迎です。OSS作者にとってスターは、合法的な葉っぱみたいなもんです。
でもあんまり厳しい事言われると現実見ちゃっておぢさん泣いちゃうから許してください。
おわり
ませんでした。
記事を書いてて最後に気がついたんですがリポジトリのURL貼ってませんでした。
ヨロシクオネガイシマス