Claudeに自分専用の機能を持たせたいなら、いちばん素直な道がMCPサーバーの自作です。手元のファイルを整理させる、社内データベースを検索させる、自前のAPIを叩かせる。こうした「本来AIにはできないこと」を後付けする仕組みは、2024年11月にAnthropicがMCPを公開して以降、公式SDKや対応クライアントが整ってきました。最小構成ならPythonで数十行、本記事で作るローカルメモのサーバーでも1ファイルに収まります。
つまずく場所はだいたい決まっています。SDKの書き方、ホストへの登録、そして動かないときにどこを見るか。この3点さえ押さえれば、初めてでも自作ツールをClaudeから呼び出せる状態まで一直線です。本記事では、整数を2倍にするだけの最小サーバーから始め、ローカルのメモを検索・追加できる実用サーバーまでを、実際に動かしながら作ります。
- MCPは、AIアプリと外部ツール・データソースを繋ぐためにAnthropicが公開したオープン標準
- 公式Python SDKのFastMCPを使えば、関数にデコレータを付けるだけでツールを公開できる
- 最小サーバーを動かし、Claude DesktopやIDEの設定ファイルに登録するまでが土台
- 本記事のコードは安定版の mcp 1.28.0/プロトコル2025-11-25 で実際に動かして確認している(2.0系プレリリースは対象外)
なお、SDKのバージョンや設定ファイルの仕様、対応クライアントは更新が速い領域です。本記事のコードと手順は2026年6月時点の公式情報をもとにした最小例なので、手を動かすときは各公式ドキュメントで最新仕様を確認してください。以降の章ではこの注意を繰り返しません。
MCPとは何か、なぜ自前ツールを自作するのか
MCP(Model Context Protocol)は、AIアプリケーションを外部のシステムに繋ぐためにAnthropicが公開したオープン標準です。公式ドキュメントでは、その位置づけがこう説明されています。
MCP (Model Context Protocol) is an open-source standard for connecting AI applications to external systems.(MCPは、AIアプリケーションを外部システムに接続するためのオープンソース標準である)
Think of MCP like a USB-C port for AI applications.(MCPは、AIアプリにとってのUSB-Cポートのようなものだと考えるとよい)
出典: modelcontextprotocol.io 公式ドキュメント『What is the Model Context Protocol (MCP)?』
身近なPC機器で例えると、いちばん近いのはUSB-Cです。対応した機器ならどれでも同じ口に挿せるように、MCPに対応したホストとサーバーも同じ作法で繋がります。AIがファイルやデータベース、検索エンジンといった外部システムを扱うための「共通の差し込み口」を決めた規格、と捉えるとイメージしやすいでしょう。
AIに能力を後付けする手段はMCPだけではありません。Claude向けに作業手順そのものをパッケージ化するAgentSkillという仕組みもあります(html-ppt-skillとは:AIエージェントにHTMLスライド生成能力を差し込むAgentSkillの設計と実利用感)。両者は競合ではなく役割が違うだけで、MCPは「外部のプログラムやデータに繋ぐ配管」、AgentSkillは「やり方そのものを教える指示書」に近い、と整理しておくと混乱しません。
MCPが解決する「ツールごとの個別実装」問題
MCPが登場する前は、AIに外部機能を足すたびに、そのAIサービス固有のやり方で実装する必要がありました。あるクライアント向けにはこの書き方、別のクライアント向けには別の書き方。同じ「天気を取得する機能」でも、繋ぎ先ごとに作り直す手間が発生していたわけです。
MCPはここを共通化します。プロトコルに沿ってサーバーを1つ作っておけば、対応ホスト(Claude Desktop、対応IDE、その他のクライアント)から同じように呼び出せる。一度書けば複数のクライアントで使い回せるのが、自作のコストを大きく下げているポイントです。公式SDKは複数の言語向けに用意されており、なかでもPythonとTypeScript(Node.js)は例やドキュメントが揃っています。最初の1台はこのどちらかが無難で、本記事ではPythonを使います。
自作が向くケースと、既存サーバーで足りるケースの線引き
公式・コミュニティ製の既成MCPサーバーは数多く公開されています。ファイルシステム操作、Git操作、特定SaaSとの連携など、よくある用途はすでに誰かが作っていることも珍しくありません。やりたいことが定番の範囲なら、まず既存サーバーを探すほうが早道です。
自作が要るのは、自社の業務システムや社内APIに繋ぎたい、ローカルにある独自フォーマットのファイルを処理させたい、複数のツールを束ねた専用ワークフローを組みたいといった「自分の環境にしかない事情」が絡む場面。こうなると既成品では届きません。
全体像と前提環境|ホスト・クライアント・サーバーの関係
実装に入る前に、それぞれの役割の関係を頭に入れておくと迷いません。MCPには、ホスト・クライアント・サーバーという3つの役割があります。
ホストは、Claude DesktopやIDEといった「AIを動かしている本体アプリ」。そのホストの中にクライアントが組み込まれ、MCPの通信を担当します。自作するのがサーバーで、ツールやデータを公開する側です。やり取りは「ホスト内のクライアント」と「自作サーバー」の間で行われ、AIはクライアント経由でサーバーの機能を呼び出す、という流れになります。
この通信には、標準入出力(stdio)を使う方式と、Streamable HTTPを使う方式の、大きく2つがあります(2025-11-25仕様の標準トランスポートはこの2つで、旧来のHTTP+SSEは置き換えられました)。どちらを選ぶかで、サーバーの作り方と配置場所が変わってきます。
tools / resources / prompts という3つの提供単位
MCPサーバーがAIに公開できるものは、一般的に3種類に分かれます。最初に区別しておくと、何をどう実装すればいいかが見えてきます。
toolsはAIが実行できる「関数」です。「データベースに問い合わせる」のように、何か処理を実行して結果を返すもので、自作で最もよく使います。resourcesはAIが読み取れる「データ」を指し、設定ファイルやドキュメント、レコードなど参照させたい情報を渡す口です。promptsは定型の指示テンプレートで、よく使う依頼の型をあらかじめ用意しておく仕組み。まず触るべきはtoolsで、関数を1つ公開できればMCPサーバーの基本はほぼ掴めます。本記事も最小構成ではtoolsから始めます。
ローカル常駐(stdio)とリモート(HTTP)の使い分け
トランスポート(通信方式)の選択は、用途で決まります。
| 比較軸 | stdio方式 | Streamable HTTP方式 |
|---|---|---|
| 主な用途 | 手元のローカル利用 | リモート公開・複数人共有 |
| サーバーの常駐 | ホストが必要時に起動 | 起動しっぱなしにする |
| 配布のしやすさ | 設定ファイルにコマンドを書くだけ | ホスティング先の準備が要る |
| 初期セットアップの手間 | 少ない | 多い |
| 向いている段階 | 開発・個人利用・試作 | チーム配布・本番運用 |
stdioは、標準入力と標準出力を通じてホストとサーバーがやり取りする方式です。Claude Desktopやコマンドライン系のクライアントがローカルのサーバーと話すときの定番で、公式ドキュメントでもローカル開発やCLIツール、試作の段階ではstdioが基本とされています。ホストが必要なタイミングでサーバーを起動してくれるので、こちらで常駐させておく必要がありません。HTTP方式は、サーバーをネットワーク越しに公開したいとき(複数ユーザーで1台を共有する、社内ネットワークに置いて誰でも繋げるようにする)に使いますが、常駐運用やホスティング先の準備が必要になるぶん手間は増えます。最初の1台は、まずstdioで作るのが素直です。なお、HTTPで共有・公開する場合は、常駐させるだけでなく認証・認可、HTTPS、到達範囲の制限、公開するツールの権限設計が必要です。認証なしで誰でも到達できる場所に置くのは避けてください。
前提として用意するものは多くありません。PythonまたはNode.jsのランタイム、パッケージをインストールする手段、そしてMCP対応ホスト(Claude Desktopや対応IDE)。これだけです。本記事のようにSQLite検索や外部API呼び出しだけを行うサーバーの範囲なら、ローカルでLLM本体を動かすわけではないのでGPUは不要です(サーバー側でローカルLLMや画像・音声処理、大規模な埋め込み生成などを行う場合は、その処理に応じたCPU/GPU/メモリが要ります)。依存関係を汚さないよう、プロジェクトごとに仮想環境を用意しておくことをおすすめします。
まず最小構成で動かす|Python製MCPサーバーの実装
公式Python SDKに含まれるFastMCP(プロトコルの細かい処理を肩代わりしてくれる高レベルなAPI)を使い、ツールを1つだけ持つ最小のサーバーを動かします。まずは「数値を2倍にして返す」程度の単純なツールで構いません。動く成功体験を1回作ることが、何より先決です。なお本記事で使うのは、公式MCP Python SDK(mcp パッケージ)に含まれる mcp.server.fastmcp.FastMCP です。名前のよく似た別パッケージ fastmcp(from fastmcp import FastMCP)も存在しますが、インストール名もimportも異なるので混同しないでください。
SDKをインストールします(Python 3.10以上が必要です)。本記事と同じ挙動を再現するため、版を固定して導入します(最新版を試す場合は pip install "mcp[cli]" でも入りますが、v2以降はAPIが変わる可能性があります)。
pip install "mcp[cli]==1.28.0"
次が、ツールを1つ持つ最小のMCPサーバーです。
from mcp.server.fastmcp import FastMCP
# サーバーに名前を付けて初期化する
mcp = FastMCP("my-first-server")
@mcp.tool()
def double(number: int) -> int:
"""渡された整数を2倍にして返す"""
return number * 2
if __name__ == "__main__":
# 引数なしの run() は標準入出力(stdio)で起動する
mcp.run()
これを server.py として保存すれば、もう動くサーバーです。
tool定義とスキーマ(入力引数の型付け)
このコードで注目したいのが @mcp.tool() の1行です。@ で始まる目印はデコレータと呼ばれ、「この関数をMCPのツールとして公開する」という指示になります。関数の前に置くだけで、FastMCPがその関数をAIから呼べるツールとして登録してくれます。
AIに「この関数はどんな引数を取り、何を返すのか」を正しく伝える役目を果たすのが、引数の型ヒントとdocstring(関数の先頭に書く説明文)です。先ほどの例では number: int という型ヒントが「整数を1つ受け取る」ことを示し、docstringがツールの用途を伝えています。FastMCPはこの型ヒントとdocstringを自動で読み取り、ツールの仕様(スキーマ)を組み立てます。
つまり、ツールの精度を上げる近道は、型ヒントとdocstringを丁寧に書くこと。AIはこの情報をもとに「いつ、どんな値でこのツールを呼ぶか」を判断します。説明が雑だと、呼ぶべき場面で呼ばれなかったり、おかしな引数を渡されたりする。逆に説明が明確なら、AIは的確にツールを使い分けてくれます。
サーバー単体での動作確認(インスペクタ)
書いたサーバーが正しく動くかは、ホストに登録する前に単体で確認しておくと安心です。SDKには動作確認用のインスペクタ(サーバーのツールを一覧表示し、手動で呼び出して挙動を見られる検証ツール)が付属しています(uv を使う環境では、以下の mcp コマンドの先頭に uv run を付けます)。
mcp dev server.py
このコマンドでインスペクタが立ち上がり、登録したツールの一覧や、引数を入れて呼んだときの戻り値を画面上で確認できます。先ほどの double ツールに 21 を渡して 42 が返ってくれば、サーバー側は問題なく動いている証拠です。なお、このインスペクタはNode.js製のため、mcp dev の利用には Node.js/npx が必要です。入れたくない場合は、Claude Desktopなど別のMCPホストや自作クライアントで疎通を確認してください。
print() の出力先)がプロトコル専用の通信路として使われています。デバッグのつもりで print() を入れると、その文字列が通信に混ざり、サーバーが正しく認識されなくなることがあります。途中経過を出したいときは、標準エラー出力やログファイルへ書き出してください。標準出力には、プロトコルが扱うデータ以外を流さないのが鉄則です。
実用的なツールに広げる|ローカルのメモを検索・追加する
2倍を返すだけでは実感が湧きません。もう一歩進めて、ローカルのSQLiteに保存したメモを、AIに検索・追加させるサーバーを作ります。これくらいの粒度になると、自作の効きどころが見えてきます。次のコードは、検索ツールと追加ツールに加え、最近のメモを返すresourceと、要約を促すpromptまでを1ファイルにまとめたものです。サンプルデータを初回だけ自前で投入するので、そのまま動かして試せます。
"""最小構成の汎用 MCP サーバ: ローカルメモ(SQLite バックエンド)。
tools(検索 / 追加)、resource(最近のメモ)、prompt(要約雛形)を公開する。
初回起動時にサンプル DB を自前で作るので、そのまま再現できる。
"""
from __future__ import annotations
import sqlite3
import sys
from contextlib import closing
from pathlib import Path
from mcp.server.fastmcp import FastMCP
DB_PATH = Path(__file__).with_name("notes.db")
def _db() -> sqlite3.Connection:
conn = sqlite3.connect(DB_PATH)
conn.row_factory = sqlite3.Row
return conn
def _init_db() -> None:
with closing(_db()) as conn, conn:
conn.execute(
"CREATE TABLE IF NOT EXISTS notes ("
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
" title TEXT NOT NULL, body TEXT NOT NULL, tags TEXT DEFAULT '',"
" created_at TEXT DEFAULT (datetime('now')))"
)
empty = conn.execute("SELECT COUNT(*) FROM notes").fetchone()[0] == 0
if empty: # 再現用のサンプルを最初の1回だけ投入
conn.executemany(
"INSERT INTO notes (title, body, tags) VALUES (?, ?, ?)",
[
("買い物リスト", "牛乳、卵、パン", "生活"),
("MCPメモ", "FastMCP は型ヒントとdocstringからスキーマを生成する", "開発"),
("読書", "達人プログラマーを再読する", "学習"),
],
)
# STDIO の落とし穴: stdout は JSON-RPC が流れる経路なので print() してはいけない
# (protocol が壊れる)。ログは必ず stderr へ。
def _log(msg: str) -> None:
print(msg, file=sys.stderr)
mcp = FastMCP("notes")
@mcp.tool()
def search_notes(query: str) -> str:
"""ローカルのメモをキーワードで部分一致検索する。
Args:
query: 検索キーワード(タイトル・本文・タグを対象)
"""
like = f"%{query}%"
with closing(_db()) as conn: # パラメータ化クエリ(SQL インジェクション対策)
rows = conn.execute(
"SELECT id, title, body, tags FROM notes"
" WHERE title LIKE ? OR body LIKE ? OR tags LIKE ? ORDER BY id",
(like, like, like),
).fetchall()
if not rows:
return f"「{query}」に一致するメモはありません。"
return "\n".join(f"#{r['id']} [{r['tags']}] {r['title']}: {r['body']}" for r in rows)
@mcp.tool()
def add_note(title: str, body: str, tags: str = "") -> str:
"""新しいメモを追加する。
Args:
title: メモのタイトル
body: 本文
tags: 任意のタグ(カンマ区切り)
"""
with closing(_db()) as conn, conn:
cur = conn.execute(
"INSERT INTO notes (title, body, tags) VALUES (?, ?, ?)",
(title, body, tags),
)
return f"メモ #{cur.lastrowid} を追加しました:{title}"
@mcp.resource("notes://recent")
def recent_notes() -> str:
"""最近のメモ5件を返すリソース。"""
with closing(_db()) as conn:
rows = conn.execute(
"SELECT title, body FROM notes ORDER BY id DESC LIMIT 5"
).fetchall()
return "\n".join(f"- {r['title']}: {r['body']}" for r in rows)
@mcp.prompt()
def summarize_notes(topic: str) -> str:
"""指定トピックのメモを要約させるプロンプト雛形。"""
return f"メモから「{topic}」に関するものを探し、要点を3つにまとめてください。"
def main() -> None:
_init_db()
_log("notes MCP server starting (stdio)")
mcp.run(transport="stdio")
if __name__ == "__main__":
main()
押さえどころは2つ。ツールがデータベースに触れる箇所では、文字列を直接組み立てず、必ずプレースホルダ(?)でパラメータを渡しています。AIが渡してくる引数をそのままSQLに連結すると、インジェクションの入口になりかねないためです。もう1つは、stdioサーバーなのでログを標準エラー出力(sys.stderr)へ流している点。標準出力を汚さないための実装です。
このサーバーを確認用の小さなクライアントから繋ぎ、initialize(接続)→ ツール一覧の取得 → ツール呼び出し、の順で叩くと、公開したツール・リソース・プロンプトが実際に応答します。手元で stdio 経由で実行したときの結果が次の出力です。これは確認用クライアントによる実測例で、サーバー単体やインスペクタの標準出力そのものではありません(クライアント側が受け取った応答を並べたものです)。確認環境はWindows 11/Python 3.11.9(64bit)/mcp 1.28.0で、2026年6月時点のものです。
SERVER: notes / protocol 2025-11-25
TOOLS: ['search_notes', 'add_note']
RESOURCES: ['notes://recent']
PROMPTS: ['summarize_notes']
search_notes('MCP') -> #2 [開発] MCPメモ: FastMCP は型ヒントとdocstringからスキーマを生成する
add_note(...) -> メモ #4 を追加しました:会議
search_notes('会議') -> #4 [仕事] 会議: 明日10時から
注目したいのは1行目で、ネゴシエートされたプロトコルが 2025-11-25 になっています。これは執筆時点の安定版仕様で、起動時にクライアントとサーバーがバージョンを擦り合わせていることを示します。add_note で追加したメモ(#4)が、直後の search_notes("会議") で引けていることからも、ツールが実際に状態を変えながら動いているのが分かります。最小の double から始めても、骨組みは同じまま、tool・resource・promptを足していけばここまで広げられます。
add_note のような書き込み(副作用)を伴うツールは、読み取りツールよりリスクが高めです。ホスト側の確認UIに頼り切らず、サーバー側でも読み取り専用モードや許可リスト、確認済みの操作だけを実行する設計を検討してください。MCPサーバーは便利な機能をAIに渡す仕組みであると同時に、任意のデータアクセスやコード実行の経路にもなり得ます。読み取り範囲・書き込み権限・外部への公開範囲は、必要最小限に絞るのが基本です。
エージェント開発全般でのデータ漏えいと対策は AIエージェント開発の情報漏洩リスクと防止策、ツールに与える権限の絞り込みは AIエージェントに権限を与える前の設計ガイド でも詳しく扱っています。
Claude・IDEから呼べるように登録する
サーバーが単体で動いたら、ホストに登録して実際にAIから呼べるようにします。Claude Desktopには、完成品を配布・管理する方法と、開発中に手早く繋ぐ方法があります。配布・一般利用には、サーバーと依存をまとめた拡張 Desktop Extensions(.mcpb)をワンクリックで入れる方法が用意されています(Settings → Extensions)。自分で書いたサーバーを開発中に登録するなら、設定ファイル claude_desktop_config.json への追記や、後述の mcp install が手軽です。設定ファイルの場所は、Windowsなら %AppData%\Claude\claude_desktop_config.json、macOSなら ~/Library/Application Support/Claude/claude_desktop_config.json。ファイルが無ければ新規作成します。
{
"mcpServers": {
"notes": {
"command": "C:\\path\\to\\python.exe",
"args": ["C:\\path\\to\\notes_server.py"]
}
}
}
mcpServers の下に、サーバー名・起動コマンド・引数を書きます。保存してClaude Desktopを再起動すると、ツールが認識されます。なお公式SDKには登録を補助する mcp install server.py というコマンドもあり、手で設定ファイルを編集する代わりに使えます。
command や args のファイルパスは、相対パスでなく絶対パスで書くのが安全。ホストはシェルとは別の作業ディレクトリでサーバーを起動するため、相対パスだとファイルを見失います。Windowsではパス区切りのバックスラッシュを \\ と二重にするか、/(スラッシュ)を使ってください。uv や仮想環境のPythonを使う場合は、その実行ファイルの絶対パスを command に指定します(場所は、cmdなら where python、PowerShellなら Get-Command python で確認できます)。設定を変えたら、反映には再起動が要ります。なお、ここに書いた command はホストがログインユーザーの権限でそのまま実行します。信頼できる自作コードや公式パッケージだけを登録し、出所の不明な command / args は貼り付けないでください。
ここまでのJSON例はClaude Desktop(チャットアプリ)用です。Claude CodeやIDE連携で使う場合は登録先が別で、スタンドアロンのClaude Code CLIは claude_desktop_config.json を読みません。Claude Codeでは claude mcp add コマンドで登録するのが基本で、stdioであることを --transport stdio で明示し、-- 以降に起動コマンドを書きます(パスにスペースが入る場合は引用符で囲みます)。
claude mcp add --transport stdio notes -- python "C:\path\to\notes_server.py"
登録先はスコープで分かれます。既定のlocal(そのプロジェクト専用、~/.claude.json に保存)、リポジトリに含めてチーム共有するproject(.mcp.json、--scope project)、全プロジェクト共通のuser(--scope user)。本章ではClaude DesktopとClaude Codeを例にしています。VS CodeやCursorなどのIDEは、各製品の公式MCP設定に従ってください。
Claude Code自体を安全に動かす設定(Hook・サンドボックス)は Claude Codeを安全に自律実行する方法 に、各コーディングツールの選び方は AIコーディングツール比較 にまとめています。
登録できると、ホスト側にツールの一覧が表示され、会話の中で必要に応じてツールが呼ばれるようになります。なお、MCPサーバーを「自作する」のではなく「既存のものを使う」だけなら、ノーコードで繋ぐ入口もあります(ClaudeとZapier MCP連携 完全ガイド:ノーコード自動化からAPI実装まで)。作る側と使う側で入り口が違うので、目的に応じて選んでください。
現行仕様と、今後の変化
本記事で確認した動作は、安定版の仕様2025-11-25に基づきます。MCPは更新が速く、次期仕様(2026-07-28)がリリース候補として進行中で、プロトコルのステートレス化や拡張機能の枠組み(Extensions)、長時間処理を扱うTasks(2025-11-25で実験的に導入され、次期では拡張として再設計)といった話題が並んでいます。とはいえ、「FastMCPでツールを定義し、ローカルではstdioでホストに繋ぐ」という考え方自体は引き続き使われる見込みです。ただし2026-07-28のリリース候補には破壊的変更が含まれるため、実際に動かすときは公開時点のSDKとホストの対応状況を確認してください。まず最小構成で勘所を掴んでおけば、仕様が進んでも追従しやすいはずです。
まとめ
MCPサーバー自作の流れは、最小構成で一度動かし、実用的なツールに広げ、ホストに登録する、という一本道です。いきなり多機能を目指す必要はありません。ツール1つだけのサーバーで「呼べた」状態を作れば、ローカルデータの検索やファイル操作、API連携への拡張がぐっと見通しやすくなります。最初の一歩は、手元で最小サーバーを起動し、インスペクタで疎通を確認するところから。そこさえ越えれば、あとは自分の環境に必要なツールを足していくだけです。
よくある質問
Q. プログラミング初心者でも自作できますか?
PythonかNode.jsの基本構文が書ける程度なら着手できます。公式SDKがサーバーの土台を用意してくれるため、ゼロから通信処理を書く必要はありません。まずは引数を受け取って値を返すだけのツールから始めると、つまずきにくいです。
Q. 無料で始められますか?
SDKもPythonランタイムも無償で揃うため、ローカルで動かす範囲なら追加費用なしで試せます。ただしClaudeなどホスト側のプランや、ツールから呼ぶ外部APIの料金に加え、サーバーをリモート公開する場合のホスティング費用や認証基盤などは別途かかる場合があります。
Q. Claude以外のツールからも呼べますか?
MCPは特定製品専用ではなく、Claude Desktop/Claude Code、VS Code、Cursorなどの対応クライアントで利用できます。ChatGPTでもMCPベースのApps/Developer mode/API連携が提供されていますが、こちらは主にリモートMCP(SSEやStreamable HTTPで接続)を前提としており、本記事で扱うローカルstdioサーバーとは登録方法も利用条件も異なります。「一度書けば複数のクライアントで使い回せる」のはMCPの強みですが、ローカルのstdioサーバーをどのクライアントにも同じ手順でそのまま挿せるわけではありません。対応状況は更新が速いため、使いたいクライアントの公式情報を確認してください。
参考資料
- What is the Model Context Protocol (MCP)? — Model Context Protocol 公式ドキュメント
- Build an MCP server — Model Context Protocol 公式ドキュメント
- Specification (2025-11-25) — Model Context Protocol
- modelcontextprotocol/python-sdk — 公式Python SDK(FastMCP)

