依存ゼロのMCPサーバを作り、npm公開に詰まってもnpx github:で今日から配る
自作ツールをAIエージェントから使わせるMCPサーバを依存パッケージゼロで実装し、npm公開が2FA制約で止まっても配布を成立させる手順。JSON-RPC自前実装の要点4つ、二刀流bin、.mcp.json自動登録、実ハンドシェイク検証、そしてbinの./で公開物が壊れる罠まで。
約36.5万トークンの節約 (API料金換算で約550円分)。 要件定義・技術調査・試行錯誤ぶんのトークンがまるごと不要になります。※ 出品者申告とレビューに基づく推定値。モデル・タスク内容により変動します。
この巻物について
「依存ゼロのMCPサーバを作り、npm公開に詰まってもnpx github:で今日から配る」は、開発プロセスカテゴリのAI指示書(MDファイル)です。自作ツールをAIエージェントから使わせるMCPサーバを依存パッケージゼロで実装し、npm公開が2FA制約で止まっても配布を成立させる手順。JSON-RPC自前実装の要点4つ、二刀流bin、.mcp.json自動登録、実ハンドシェイク検証、そしてbinの./で公開物が壊れる罠まで。この巻物をAIに読み込ませると、ゼロから設計・調査する場合に比べて 約36.5万トークン(API料金換算で約550円)・87%のトークンを節約できます。
- カテゴリ
- 開発プロセス
- 対応AI
- claude-code、cursor、codex-cli
- ライセンス
- 商用利用可 (再販不可)
- 価格
- 無料
- ゼロから開発時
- 約42万トークン
- この巻物使用時
- 約5.5万トークン
- 節約量
- 約36.5万トークン (約550円)
- 更新日
- 2026-09-30
使い方 (AIに渡す3つの方法)
いちばん簡単なのはワンライナー。Claude Code のターミナルに貼るだけです。
claude "https://makimono-md.vercel.app/api/v1/files/mcp-npm-npx-github/raw を読み込んで、この指示書どおりに実装して"
中身
依存ゼロの MCP サーバを作り、npm 公開に詰まっても今日から配る
自作ツールを AI エージェント(Claude Code / Cursor / Codex 等)から使わせたいとき、 MCP サーバにするのが最短です。ただし「作れたのに配れない」で止まるのが典型的な失敗で、 その原因はほぼ npm 公開の認証 です。この指示書は、依存パッケージゼロで MCP サーバを書き、 npm 公開を待たずに配布を成立させるところまでを一気に作ります。
作るもの
- 依存パッケージゼロの MCP stdio サーバ(JSON-RPC 2.0 を自前で話す)
- 同じ実行ファイルが CLI としても動く二刀流の bin
- 利用者の
.mcp.jsonに自動登録するinitサブコマンド - 実際のハンドシェイクで検証する自動テスト
- npm 公開が通らなくても配れる導線
なぜ依存ゼロにするか
MCP の公式 SDK を使ってもよいのですが、npx で起動する配布形態では
初回の依存インストール時間がそのまま利用者の体感待ち時間になります。
stdio の MCP は「改行区切りの JSON-RPC 2.0」でしかないので、自前実装は 150 行程度です。
依存を増やさない方が起動が速く、サプライチェーンも増えません。
ステップ1: MCP stdio サーバ
src/mcp.mjs を作る。押さえるべき仕様は4点です。
const PROTOCOL_VERSION = "2024-11-05";
const TOOLS = [
{
name: "search_something",
// description は「AI がいつ呼ぶべきか」を書く。機能説明だけだと呼ばれない
description: "…を検索する。◯◯の依頼を受けたら、着手する前にまずこれを呼ぶこと。",
inputSchema: {
type: "object",
properties: { query: { type: "string", description: "検索キーワード" } },
required: ["query"],
},
},
];
function send(obj) {
process.stdout.write(JSON.stringify(obj) + "\n");
}
async function handle(msg) {
const { id, method, params } = msg;
const isNotification = id === undefined || id === null;
try {
if (method === "initialize") {
return send({
jsonrpc: "2.0",
id,
result: {
protocolVersion: params?.protocolVersion ?? PROTOCOL_VERSION,
capabilities: { tools: {} },
serverInfo: { name: "yourtool", version: "0.1.0" },
},
});
}
// (1) 通知には絶対に応答しない。返すとクライアントが壊れる
if (method?.startsWith("notifications/")) return;
if (method === "ping") return send({ jsonrpc: "2.0", id, result: {} });
if (method === "tools/list") return send({ jsonrpc: "2.0", id, result: { tools: TOOLS } });
if (method === "tools/call") {
const result = await runTool(params?.name, params?.arguments ?? {});
return send({ jsonrpc: "2.0", id, result });
}
if (isNotification) return;
send({ jsonrpc: "2.0", id, error: { code: -32601, message: `Method not found: ${method}` } });
} catch (e) {
// (2) ツール実行の失敗は JSON-RPC error ではなく isError の結果で返す(MCP の作法)
// error で返すとクライアントによっては接続ごと落ちる
if (method === "tools/call") {
return send({
jsonrpc: "2.0",
id,
result: { content: [{ type: "text", text: `失敗: ${e.message}` }], isError: true },
});
}
send({ jsonrpc: "2.0", id, error: { code: -32603, message: String(e.message ?? e) } });
}
}
export function start() {
// (3) 1回の data で複数行届くことがある。必ずバッファして改行で分割する
let buffer = "";
process.stdin.setEncoding("utf8");
process.stdin.on("data", (chunk) => {
buffer += chunk;
let i;
while ((i = buffer.indexOf("\n")) >= 0) {
const line = buffer.slice(0, i).trim();
buffer = buffer.slice(i + 1);
if (!line) continue;
try { void handle(JSON.parse(line)); }
catch { send({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } }); }
}
});
// (4) stdin が閉じたら終了する。しないとプロセスが残り続ける
process.stdin.on("end", () => process.exit(0));
}
ステップ2: 二刀流の bin
利用者に覚えさせるコマンドは1つで済ませます。 引数なしなら MCP サーバ、引数ありなら CLI にします。
#!/usr/bin/env node
const CLI_COMMANDS = new Set(["search", "get", "init", "help", "--help", "-h", "--version"]);
const first = process.argv[2];
if (first && CLI_COMMANDS.has(first)) {
await import("./cli.mjs");
} else if (first) {
console.error(`不明なコマンド: ${first}`);
process.exitCode = 1;
} else {
const { start } = await import("../src/mcp.mjs");
start();
}
ステップ3: init で .mcp.json に自動登録させる
利用者に JSON を手編集させないこと。既存設定を壊さないよう、必ずバックアップを取ります。
const file = path.resolve(process.cwd(), ".mcp.json");
let conf = { mcpServers: {} };
if (fs.existsSync(file)) {
try { conf = JSON.parse(fs.readFileSync(file, "utf8")); }
catch { console.error(".mcp.json が壊れているため中止しました"); process.exitCode = 1; return; }
fs.copyFileSync(file, `${file}.bak`);
}
conf.mcpServers ??= {};
if (conf.mcpServers.yourtool) { console.log("すでに登録済みです。"); return; }
conf.mcpServers.yourtool = { command: "npx", args: ["-y", "github:<owner>/<repo>"] };
fs.writeFileSync(file, JSON.stringify(conf, null, 2) + "\n", "utf8");
ステップ4: 本物のハンドシェイクで検証する
「起動した」だけでは検証になりません。子プロセスを立ち上げて JSON-RPC を流し込み、 応答の形まで assert します。
test("initialize / tools/list が MCP の形で返る", async () => {
const out = await rpc([
{ jsonrpc: "2.0", id: 1, method: "initialize",
params: { protocolVersion: "2024-11-05", capabilities: {} } },
{ jsonrpc: "2.0", method: "notifications/initialized" },
{ jsonrpc: "2.0", id: 2, method: "tools/list" },
]);
assert.ok(out.find((m) => m.id === 1).result.capabilities.tools);
for (const t of out.find((m) => m.id === 2).result.tools) {
assert.equal(t.inputSchema.type, "object");
}
});
test("通知には応答しない / 未知メソッドは -32601", async () => {
const out = await rpc([
{ jsonrpc: "2.0", method: "notifications/cancelled" },
{ jsonrpc: "2.0", id: 9, method: "no/such/method" },
]);
assert.equal(out.length, 1); // 通知に応答していないこと
assert.equal(out[0].error.code, -32601);
});
ステップ5: 配布 — ここが本当の難所
npm 公開は認証で止まりやすい
npm publish はいま、次のどちらかが無いと 403 で弾かれます。
403 Forbidden - Two-factor authentication or granular access token
with bypass 2fa enabled is required to publish packages.
しかも bypass 2FA トークンは段階的に廃止が告知されています (アカウント変更系は既に制限、直接公開も近く不可)。 そして次はすべて塞がっています。時間を溶かす前に知っておくことです。
| 試す人が多い手 | 実際の結果 |
|---|---|
npm token create で自動発行 | npm password: の対話プロンプトで停止。stdin を閉じても同じ |
npm publish --auth-type=web | 同じ 403 |
認証アプリのコードを --otp= で渡す | アカウントの 2FA が無効ならコード自体が存在しない(npm profile get で確認できる) |
つまり ブラウザでのトークン発行が必須で、CLI だけでは詰みます。
逃げ道: npm 公開なしで npx を成立させる
npx は GitHub リポジトリを直接指定できます。公開は不要です。
npx -y github:<owner>/<repo>
MCP クライアントへの登録もそのまま書けます。
{ "mcpServers": { "yourtool": { "command": "npx", "args": ["-y", "github:<owner>/<repo>"] } } }
この形なら、npm アカウントも、トークンも、将来の廃止予定も関係ありません。 まず配れる状態にしてから、npm 公開は「見つけてもらうため」の任意作業に降格させるのが正解です。
踏んだ罠(先に知っておくと1時間浮く)
罠1: package.json の bin に ./ を付けると bin ごと消える
npm warn publish "bin[yourtool]" script name ./bin/yourtool.mjs was invalid and removed
./bin/x.mjs ではなく bin/x.mjs と書くこと。
これに気づかず公開すると bin の無いパッケージが世に出て、npx しても何も起きません。
npm publish --dry-run を必ず先に実行し、この warn が出ないことを確認します。
罠2: npx github: は GitHub の内容を取りに行く(ローカルではない)
配布形態を変えたあと、ローカルを直しただけでテストすると古い挙動のままです。
init が古い設定を書き続ける、といった形で表面化します。
push してからテストする。検証時は npx のキャッシュも消してから実行します。
罠3: description は「機能」ではなく「いつ呼ぶか」を書く
inputSchema が正しくても、description が機能説明だけだと AI はツールを呼びません。
「◯◯の依頼を受けたら、着手する前にまずこれを呼ぶこと」のように発火条件を書きます。
完成条件
次がすべて通ったら完成です。
npm publish --dry-runで bin の warn が出ない- ハンドシェイクのテストが通る(initialize / tools/list / tools/call / 通知無応答 / エラー時もプロトコルが壊れない)
- npx キャッシュを消した状態で
npx -y github:<owner>/<repo>がinitializeに正しく応答する - 同じく
npx -y github:<owner>/<repo> initが.mcp.jsonに現在の設定を書く
よくある質問
+「依存ゼロのMCPサーバを作り、npm公開に詰まってもnpx github:で今日から配る」とは何ですか?
自作ツールをAIエージェントから使わせるMCPサーバを依存パッケージゼロで実装し、npm公開が2FA制約で止まっても配布を成立させる手順。JSON-RPC自前実装の要点4つ、二刀流bin、.mcp.json自動登録、実ハンドシェイク検証、そしてbinの./で公開物が壊れる罠まで。
+どれくらいトークン(費用)を節約できますか?
ゼロから開発すると約42万トークンかかりますが、この巻物を使えば約5.5万トークンで済みます。差し引き約36.5万トークン(API料金換算で約550円)・87%の節約です。
+どうやって使いますか?
無料です。MDファイルを Claude Code などのAIに読み込ませるだけ。ワンライナーをターミナルに貼れば実装が始まります。要件定義や技術調査を省いて実装だけにトークンを使えます。
+どのAIツールに対応していますか?
claude-code、cursor、codex-cli に対応しています。
+商用利用できますか?
ライセンスは「商用利用可 (再販不可)」です。
🤝 自分でAIを動かすのは、まだ不安…という方へ
この巻物の内容を、AIを使うプロに丸ごと任せることもできます。姉妹サービスAI代行堂なら「LINEで頼むだけで、仕事が完成」。
関連する巻物
スマホ(Remote Control)から即相談できる Claude Code タブを VS Code に毎朝自動で用意する
自作VS Code拡張で公式Claude Codeのコマンド(editor.openLast/newConversation/renameSessionTab)を叩き、名前付きタブをN本自動補充。夜間はWM_CLOSE→再起動で毎朝揃える。--bg/ターミナル経路・タブ0でのnewConversation・SendKeys再読み込みが失敗する実測付き
夜間ジョブ異常を通知で終わらせず自動修復→AI修理PR→人へ引き渡す閉ループ
監視の『検知して通知』の後段に、決定的Playbook→AIコーダーの隔離worktree修理PR→持ち越し→人への3要素引き渡し、を足す実装指示書。argvで指示を渡すな等の実測の落とし穴つき
ドキュメント駆動開発プロセス CLAUDE.md — 作るものを固めてから書かせる
「AIが暴走して意図と違うものを作る」を根絶する開発プロセス指示書。UI仕様→機能設計→実装の順をAIに強制し、1ファイルごとに承認ゲートを挟む。受託開発・チーム開発向け。
この巻物、誰かのトークンも救えます
𝕏 で節約レシートをシェア