• トップ
  • ブログ一覧
  • Google公式MCPが出た日、僕らはまだ自社版MCPを実装していた
  • Google公式MCPが出た日、僕らはまだ自社版MCPを実装していた

    こやまん

    こんにちは、GWはいかがお過ごしでしょうか? "こやまん" です。
    今回は個人ではなく、グループとしての記事となります。

    Google公式MCPが出た日、僕らはまだ自社版MCPを実装していた

    実は、作っている途中でGoogleが公式のCalendar MCPツールをリリースしました。タイミングが絶妙すぎて、メンバー全員でちょっと笑いました。

    ライトコードには、プロジェクトを横断してメンバーが集まり、社内の困りごとを技術で解決してみようというグループワークの取り組みがあります。今回はその一環として、「Google CalendarをClaudeから操作するMCPサーバー」を作っていました。社員同士のスケジュール調整をLLMに任せたい、という素朴な動機から始まったテーマです。

    Cloud Runへのデプロイ、サービスアカウントのドメイン全体の委任(DWD)、Claude Desktopからの動作確認まで一通り終わり、あとは社内に展開するだけ、という段階で公式版がリリースされました。

    タイミングは残念でしたが、それでも最後まで作り切って良かったと思っています。

    理由は2つあります。作ってみて初めて見えたものがあったこと、そして「もうMCPサーバーは自分で書かなくていい」という空気の中にも、確実に残る領域があると気づけたことです。両方とも、手を動かしたから言える話だと思っています。

    学習目的のグループワークとして始まったテーマでしたが、結果的に「自分たちでMCPサーバーを書く意味とは何か」を考える機会になりました。今回はその過程で見えたことを書いていきます。

    MCPサーバーは下火、らしい

    ここ最近、MCPサーバーを自前で作る話題は明らかに減ってきています。体感ベースですが、SNSや勉強会で「MCPサーバー作りました」系の発信は2025年前半をピークに落ち着いた印象があります。

    理由はいくつか思い当たります。

    ひとつは、主要SaaSの公式対応が進んだことです。Slack、GitHub、Notion、そして今回のGoogle Calendarのように、よく使われる連携先は公式または準公式のMCPツールが揃ってきました。「とりあえずSaaS APIをラップしたMCPを書く」という最初の山場は、もう公式が引き受けてくれる時代になりつつあります。

    もうひとつは、LLMクライアント側の進化です。Claude DesktopもClaude Codeも、MCP以外の経路で外部連携できる道が広がっています。ネイティブ統合、ブラウザ拡張、CLI直叩き。MCPは「LLMに外部ツールを使わせる唯一の道」ではなくなりました。

    そして地味に効いているのが、初期MCP設計が引きずる課題です。当初のMCPはローカル実行のstdioトランスポートが中心で、リモート配布・認証・監査といったエンタープライズ要件は後付けで進化してきました。Streamable HTTPでだいぶ改善されましたが、本番運用するならOAuth、IPフィルタ、ログ収集を自分で組む必要が今もあります。

    これらが重なって、「MCPサーバー自作」のコスパは確実に下がっています。今回作ったものも、まさにGoogle公式版に置き換わる類のものでした。

    ——ですが、最後まで動かしたからこそ持ち帰れたものがありました。順に書いていきます。

    作ったもの

    社内で複数人の予定を合わせるとき、こんなやり取りが発生しがちです。

    「今週ちょっとMTGしたいんですけど、空いてる日ありますか?」
    「水曜の午後なら空いてますよ」
    「あ、でももう一人も入れたくて……Aさんはどうですか?」

    Googleカレンダーで空き時間を確認しつつ、Slackで都合を聞き、回答を待ち、またカレンダーと照らし合わせる。この作業、慣れてはいるけど地味にストレスです。

    LLMがカレンダーを直接見てくれれば、「田中さんと佐藤さんの来週の共通空き時間を教えて」の一言で終わる話なのでは?というわけで作ってみました。

    実装したツールは2つです。

    search_users名前やメアドのキーワードでGoogle Workspaceのユーザーを検索します。
    get_free_slotsメアドのリストと時間範囲を渡すと、共通の空き時間スロットを返します。

    ユーザー: 田中さんと佐藤さんの来週の空き時間を教えて

    Claude: (search_users("田中") を実行)
    (search_users("佐藤") を実行)
    田中さん tanaka@example.com、佐藤さん sato@example.com ですね。
    (get_free_slots([tanaka@..., sato@...], 来週) を実行)

    来週の共通空き時間:
    - 月曜 14:00〜16:00
    - 水曜 10:00〜12:00
    - 金曜 15:00〜17:00

    中身はFastMCPで書いて、Cloud RunにStreamable HTTPで立てました。認証はサービスアカウントのDomain-Wide Delegation(DWD)。クライアント認証は「VPN固定IP + APIキー」のアプリ層方式です。Free/Busy APIで予定の中身は読みません。

    ここまでは「ふつうの実装」です。ふつうの実装にこそ、後から振り返ると意味のある選択が混じっていました

    公式ツールには載らない、3つの設計判断

    作っている時は気づきませんでしたが、公式版のリリースノートと並べてみると、自分たちの実装には汎用ツールでは選ばれないであろう設計判断が3つ含まれていました。

    判断1: Free/Busyだけ使う

    Google Calendar APIには予定の詳細を取得するエンドポイントもあります。タイトル、参加者、説明文、すべて取れます。しかし今回はFree/Busy APIだけを使いました。

    スケジュール調整に予定の中身は要りません。「いつ埋まっているか」だけで十分です。社員のカレンダー内容をLLMに読ませない、という意思決定がコードとして表現されています。

    公式ツールはおそらく「機能を増やす方向」に進みます。ユーザーのユースケースの幅を広げるのが正解だからです。一方、社内向けに作るツールは「何を読まないか」を決められます。これは小さいですが本質的な違いだと思います。

    判断2: VPN IP + APIキーのアプリ層認証

    Cloud Runの標準認証はIAMベースですが、Claude DesktopからIDトークンを毎回取りに行くのは現実的ではありません。そこでCloud Run自体は`allUsers`で公開しつつ、アプリ層のミドルウェアで二重チェックする構成にしました。

    • 社内VPNの固定IPからのアクセスのみ通す(CIDRマッチ)
    • `X-API-Key`ヘッダーがSecret Manager由来の値と一致するもののみ通す
    1class AuthMiddleware(BaseHTTPMiddleware):
    2    async def dispatch(self, request, call_next):
    3        forwarded_for = request.headers.get("X-Forwarded-For", "")
    4        client_ip = forwarded_for.split(",")[-1].strip()
    5        if not _is_allowed_ip(client_ip, self.allowed_networks):
    6            return Response("Forbidden", status_code=403)
    7
    8        api_key = request.headers.get("X-API-Key", "")
    9        if api_key != self.mcp_api_key:
    10            return Response("Unauthorized", status_code=401)
    11
    12        return await call_next(request)

    これは「自社のネットワーク境界」を前提にした設計です。SaaS型の汎用MCPはこの設計を取れません。誰でも繋げる必要があるからです。社内向けだからこそ、ネットワーク境界そのものをセキュリティ層として活用できる、という発想です。

    判断3: DWDで全社員を一括カバーする

    社員一人ひとりがOAuthで認証する代わりに、サービスアカウントのDWDで「ドメイン内のユーザーに成り代わってAPIを叩く」設定を採用しました。

    DWDは強い権限です。SA鍵が漏れれば全社員のカレンダーにアクセスできてしまいます。それでもこれを選んだのは、社内向けのツールとしてユーザー側の認証を不要にしたかったからです。鍵管理さえ厳格にやれば、ユーザー体験は劇的にシンプルになります。

    公式ツールはユーザー個別のOAuthが基本になるはずです。それが汎用解として正しいからです。「全社で1つの認証境界に揃える」という判断は、自社の運用ポリシーを知っている人間にしか下せないものだと思います。

    ハマったポイント、再分類

    実装中に詰まった点を書きます。ただし単なる失敗談としてではなく、「これはクライアント側の進化で消える課題か、それとも残る課題か」という観点で分類してみたいと思います。

    Domain-Wide Delegationの設定 → 残る課題

    Google Cloud側でSAを作るだけでなく、Workspace管理者側に「このSAのClient IDで、このスコープを許可してほしい」と依頼する必要があります。社内の誰に何を頼むか、という話で、技術的というより組織的な作業です。

    これはMCPがどれだけ進化しても消えません。組織の権限境界を越える作業は、人間の調整が必ず発生します。むしろこの種の手間がある領域は、自前で構築する判断と相性がよいとも言えます。

    Cloud RunでのSA鍵の渡し方 → 消える課題

    ローカルではJSONファイルパスで渡していましたが、Cloud Runにファイルはありません。最終的にSecret Managerに保存して環境変数経由で注入する形に落ち着きました。

    1# auth.py(抜粋)
    2key_json = os.environ.get("GOOGLE_SERVICE_ACCOUNT_KEY_JSON")
    3if key_json:
    4    info = json.loads(key_json)
    5    return service_account.Credentials.from_service_account_info(
    6        info, scopes=scopes,
    7    ).with_subject(admin_email)
    8# それ以外はファイルパスから読み込み

    これはクライアントとMCPフレームワーク側が成熟すれば消える類の課題です。FastMCPを含む各種フレームワークがクラウド前提のSecret注入をテンプレ化していけば、こんな分岐は書かなくてよくなります。デプロイ時の認証情報受け渡しは、標準化が進む途中の領域だと感じています。

    IAM認証を諦めた件 → 消える(消えてほしい)課題

    Cloud Run標準のIAM認証ではなくアプリ層認証に逃げたのは、Claude Desktopから毎回IDトークンを取りに行く仕組みを組むのが重かったからです。

    これはMCPクライアント側がOAuth/IAM連携の標準サポートを進めてくれれば消えます。実際、リモートMCPでの認証ハンドリングは標準化議論が活発になっている領域です。今のうちに自前で組んでおいた経験は、標準化された時に「何が抽象化されたか」が分かる解像度になります

    残り続ける領域 = 自前MCPの存在意義

    ここまで書いてきて、「自前MCPサーバーを作るべき領域」がだいぶ絞れてきた気がします。

    作らなくていい領域:

    • 主要SaaSの汎用的な操作(カレンダー、メール、チャット、Issue管理など)
    • 個人ユーザーの認証で完結するもの
    • 公式ツールが既にある、または近い将来出そうなもの

    今でも作る価値がある領域:

    • 社内固有のロジック(営業時間、最小単位、独自ルール)が必要なもの
    • データ最小化やプライバシー観点で「何を読まないか」を決めたいもの
    • ネットワーク境界や組織の認証境界に紐付いた制御をしたいもの
    • 社内SIEMへのログ送信など、監査要件を組み込みたいもの
    • 社内システム(基幹DB、独自API、レガシーツール)との接続

    要するに、「汎用化されるとむしろ困る部分」が自前MCPの守備範囲として残ります。公式ツールが充実するほど、この差分が逆にくっきり見える構図だと思います。

    まとめ: 作るべきMCPと、待つべきMCP

    タイミング悪く公式ツールに先を越された今回の経験で、自分たちの中の判断基準が変わりました。

    新しくMCPサーバーを書こうとする時、まず問うべきはこの2つだと思います。

    1. これは、近いうちに公式または準公式が出そうな領域か? 出そうなら、待った方がいいです。出ない/出ても自社要件に合わないことが見えているなら、作る価値があります。
    2. この実装に、自社固有の判断が含まれるか? 「営業時間」「読まないデータ」「ネットワーク境界」「認証ポリシー」のような、汎用ツールでは選べない判断が含まれるなら、自前で作る合理性があります。逆にこれが含まれないなら、公式ツールを待つかラップする方が早いです。

    今回のCalendar MCPは、振り返ると「1の判断は外したが、2の意味では正解だった」テーマでした。Google公式版が出ても、Free/Busyだけ使う設計、VPN境界に閉じた認証、DWDによる全社カバー、これらは置き換わりません。

    そして何より、学習を目的としたグループワークだったからこそ、最後まで作り切ったことに価値がありました。途中でやめていたら、「公式が出たから無駄になった」で終わっていたと思います。動くものを作って、運用設計まで考えて、公式版のリリースを見て、それでも残る価値を見つけ出す。この一連の経験そのものが、次にMCPを書くべきかどうかを判断する解像度になりました。

    MCPサーバーが下火と言われる時代に、それでも自分の手で書く意味があるとすれば、それは「公式ツールでは表現できない自社の判断を、コードという形で残すこと」なのだと思います。Google公式版が出た瞬間に置き換えられるMCPは、そもそも自前で書くべきではなかった。逆に、公式版が出ても置き換えられない部分を持っているMCPは、書く価値がある。

    その線引きの感覚は、たぶん作ってみないと身につきません。グループワークで一通り走り切ったからこそ、たどり着けた感覚だったと思います。

    参考

    ライトコードでは、エンジニアを積極採用中!

    ライトコードでは、エンジニアを積極採用しています!カジュアル面談等もございますので、くわしくは採用情報をご確認ください。

    採用情報へ

    おすすめ記事

    エンジニア大募集中!

    ライトコードでは、エンジニアを積極採用中です。

    特に、WEBエンジニアとモバイルエンジニアは是非ご応募お待ちしております!

    また、フリーランスエンジニア様も大募集中です。

    background