普段、メモには Bear、タスク管理には Things を使っています。どちらも Mac 上で MCP をつなげられるので、Claude Desktop で AI にメモを探してもらったり、タスクを整理してもらったりするのはとても快適です。ところが外出してスマホを使ったり、Web 版の Claude や ChatGPT を開いたりすると、これらのツールがすべて消えてしまいます。調べてみると、原因は MCP の「接続方式」にありました。この記事では、なぜそうなるのか、そして FastMCP を使ってローカルでしか使えない MCP をどこからでも使えるようにする方法を紹介します。

なぜ Web 版からはパソコンの中の MCP を呼べないのか?

まずはたとえ話から。MCP は、あなたのパソコンの中に住んでいる執事のようなもので、AI の代わりに Bear や Things からものを取ってくるのが仕事です。執事はあなたの家にしか住んでおらず、家の中にいる人しか彼を呼べません。

デスクトップ版の Claude もあなたのパソコンにインストールされているので、執事と同じ屋根の下に住んでいるようなものです。直接頼めばいいので、ちゃんと呼べます。

誤解しやすいのが Web 版とスマホです。画面は目の前にあり、ブラウザも自分のパソコンやスマホで開いているので、家の中にいるように見えます。でも実際には、ブラウザはただの窓にすぎません。窓から見えているのは画面で、本当に考えたり作業したりしているのはサービス提供元のデータセンターにあるコンピューターです。AI がツールを使うとき、執事を探しに行くのはデータセンター側のコンピューターであって、あなたのブラウザではありません。そしてあなたの家の執事は電話を持っていないので、データセンターから連絡がつかないのは当然です。

Web 版からパソコンの中の MCP を呼べない理由:Bear MCP の執事はあなたの家の Mac の中に住んでいて電話を持っておらず、ブラウザは画面を表示するだけなので、データセンターの AI は彼を見つけられない

2 種類の MCP の違い

MCP には実は 2 つの接続方式があります。

  • ローカル型(技術的には stdio と呼ばれます):執事はあなたの家に住んでいて、同じパソコン上のアプリしか呼べない
  • ネットワーク型(技術的には HTTP と呼ばれます):執事は電話を持っていて、その電話番号が URL。どこにあるサービスからでも電話をかけられる
ローカル型(stdio)ネットワーク型(HTTP)
どこに住んでいるかあなたのパソコンの中URL の向こう側
誰が呼べるか同じパソコン上のアプリURL にアクセスできるすべてのサービス
Web 版・スマホ不可可

2 種類の執事:ローカル型(stdio)の執事はパソコンの中だけで働き、外部と接続しないので Web 版やスマホからは呼べない。ネットワーク型(HTTP)の執事は URL の向こう側に住んでいて、データセンターの AI がネットワーク経由で呼び出せる

どちらを選ぶべきか?

MCP をどこからでも使いたいなら:迷わずネットワーク型。Web 版、スマホ、別のパソコンからでもそのまま使えます。

プライバシーを重視するなら:ローカル型。執事が電話を持っていないので、外部の人は連絡できません。そのパソコンに触れられる人だけが使えます。

アカウントを共有しているなら:ネットワーク型は不向き。ネットワーク型の MCP はアカウントにひも付くので、そのアカウントを共有している人なら誰でも使えてしまいます。しかも執事には誰が呼んでいるのか区別がつきません。この場合はローカル型とデスクトップ版(たとえば Claude Desktop)の組み合わせが向いています。設定はそれぞれのパソコンに保存されるので、お互いに影響しません。

まとめると、どこでも使うならネットワーク型、プライバシー重視ならローカル型、アカウント共有でもローカル型です。

なぜ「中継」が必要なのか

問題は、多くの MCP がローカル型しか用意していないことです。アプリの公式 MCP でも同じで、Bear 2.8 で登場した bearcli、Xcode 26.3 に内蔵された xcrun mcpbridge、1Password デスクトップ版に内蔵された MCP は、どれも stdio です。Obsidian には公式の MCP はありませんが、コミュニティ製のものもほとんどがデフォルトで stdio です。

ローカル型だけにしているのは、実はとても合理的です。これらのアプリのデータはもともとあなたのパソコンにあります。ローカル型ならネットワークを開く必要もパスワードを設定する必要もなく、呼べるのは自分のパソコンだけ。アプリ開発者にとって最もシンプルで安全な選択で、執事に電話を持たせるかどうかはユーザーに任せているわけです。

なので Web 版から使いたい場合は、自分で執事に電話を持たせる必要があります。その電話が、この記事でセットアップする FastMCP です。外からかかってきた電話を受けて執事に伝え、執事が作業を終えたら、また電話を通して返事をします。

中継の構成:データセンターにある Web 版の AI がネットワーク型(HTTP)で Mac 上の電話(FastMCP)に接続し、FastMCP がローカル型(stdio)で執事(Bear MCP)に取り次ぎ、執事が Bear を操作する

もちろん、デスクトップ版しか使わないなら中継は不要で、ローカル型をそのまま使えば大丈夫です。

実践:FastMCP で bearcli を中継する

中継専用のツールもありますが、最終的に FastMCP を選びました。理由はシンプルで、セキュリティです。ツールを 1 つ増やすたびに、誰かに手を加えられうる場所が 1 つ増えます(セキュリティ用語でいう「攻撃対象領域(アタックサーフェス)」)。FastMCP はもともと多くの MCP が使っている開発ライブラリなので、内蔵の proxy 機能で中継すれば、新しいツールをもう 1 つ信頼する必要がありません。Python を数行書くだけで済みます。

環境の準備

Bear 2.8 以降、bearcli はアプリ本体に同梱されています。パスは次のとおりです。

/Applications/Bear.app/Contents/MacOS/bearcli

まずはターミナルで実行して、MCP サーバーが起動するか確認しておきましょう(入力待ちで止まるので、Ctrl+C で終了すれば OK です)。

/Applications/Bear.app/Contents/MacOS/bearcli mcp-server

次に uv で小さなプロジェクトを作り、FastMCP をインストールします。

uv init bear-http
cd bear-http
uv add "fastmcp>=3,<4"

uv は uv.lock を生成して、実際にインストールしたバージョンを固定します。あとで別のマシンで環境を作り直しても、同じバージョンになります。

中継プログラム

proxy.py を作成します。

from fastmcp.server import create_proxy

config = {
    "mcpServers": {
        "bear": {
            "command": "/Applications/Bear.app/Contents/MacOS/bearcli",
            "args": ["mcp-server"],
        }
    }
}

proxy = create_proxy(config, name="bear-http")

if __name__ == "__main__":
    proxy.run(transport="http", host="127.0.0.1", port=8000)

それぞれ説明します。

  • config の形式は Claude Desktop の claude_desktop_config.json と同じです。command は起動するプログラム、args はその引数で、FastMCP に「執事は誰で、どうやって起こすのか」を教えているわけです
  • create_proxy() は MCP サーバーを作成します。このサーバー自体はツールを 1 つも持っておらず、リクエストを受け取ると bearcli を起動してリクエストを転送し、結果を返します
  • proxy.run(transport="http", ...) は電話の電源を入れて、ネットワーク型でサービスを提供します。URL は http://127.0.0.1:8000/mcp になります

起動します。

uv run proxy.py

FastMCP 2.x を使っている場合は関数名が異なるので、from fastmcp import FastMCP として FastMCP.as_proxy(config, name="bear-http") を使ってください。それ以外の書き方はほぼ同じですが、インストールしたバージョンのドキュメントを確認してください。

テスト

別のターミナルを開き、FastMCP 自身のクライアントで小さなスクリプト check.py を書いて、ツールが見えるか確認します。

import asyncio
from fastmcp import Client

async def main():
    async with Client("http://127.0.0.1:8000/mcp") as client:
        tools = await client.list_tools()
        for tool in tools:
            print(tool.name)

asyncio.run(main())
uv run check.py

Bear のツール名(メモの一覧、検索、読み取りなど)が表示されれば、中継は成功です。

いくつかの細かいポイント

  • まずは自分のパソコンからだけ接続できるようにする:プログラム中の 127.0.0.1 は「このパソコン自身」という意味です。つまり電話はこのパソコンからの着信しか受けず、外からはかけられないので、テストにはぴったりです。ネット上の例では 0.0.0.0 と書かれていることが多いですが、これは同じネットワーク(たとえば同じ Wi-Fi)にいる人なら誰でもかけられるという意味なので、テスト段階ではやめておきましょう
  • ほかの MCP にも使う:Things やほかのローカル型 MCP も同じやり方で、command と args を差し替えるだけです。mcpServers に複数を並べて、同じ URL でまとめて提供することもできます

まとめと注意点

中継は MCP をどこからでも使えるようにするためのものですが、すべての場面で中継すべきとは限りません。どこでも使いたいならネットワーク型、プライバシー重視やアカウント共有ならローカル型。両者は、執事に電話を持たせるだけでつながります。

最後に注意点を 2 つ。この記事では詳しく扱いませんが、本当に外出先で使う前には必ず対応してください。

  1. Mac を起動したまま、スリープさせず、ネットに接続しておく:電話も執事もあなたの Mac の中にいます。Mac が眠ってしまうと、電話に出る人がいなくなります
  2. URL は公開する必要があり、必ず認証をかける:Web 版の AI はサービス提供元のデータセンターから電話をかけてきます。上で紹介した「このパソコンからの着信だけ受ける」設定や、自宅の Wi-Fi からしかアクセスできない URL には、データセンターからはつながりません。なので最終的には公開 URL が必要になります。ただし電話番号を公開したら必ずパスワードをかけてください。そうしないと、自分のメモを世界中に読み書きされる状態になってしまいます

認証と公開 URL のデプロイ方法については、また機会があれば別の記事で書きます。