TECH PLAY

MCP

イベント

該当するコンテンツが見つかりませんでした

マガジン

該当するコンテンツが見つかりませんでした

技術ブログ

こんにちは、株式会社タイミーで MLOps エンジニアをしている KY です。普段は ML プラットフォームの構築・運用を担当しています。 私たちのチームでは、機械学習エンジニアやデータサイエンティストが開発に集中できるよう、VS Code のリモート開発(Remote SSH および Dev Container)を活用した開発環境を提供しています。本記事では、その中でも 共通 Dev Container Feature によるガードレール にフォーカスし、各チームが自分たちで開発環境を立ち上げられることを前提にしながら、 セキュア・バイ・デフォルト をどう実現しているかをご紹介します。 なぜ Dev Container Feature にガードレールを寄せるのか この記事を書こうと思ったきっかけは、もともと機械学習エンジニアやデータサイエンティスト向けだった開発環境を、データアナリストをはじめとする別職種のメンバーにも広げ始めたことでした。ユーザー層が広がるにつれ、「どこまでを各自の設定に任せ、どこからを仕組みで縛るか」をあらためて考え直す必要が出てきた、というのが出発点です。あわせて、組織として求められるセキュリティレベルも年々高まってきています。 ML プラットフォーム特有の事情として、ユーザーの専門領域が幅広い、という点があります。機械学習エンジニアやデータサイエンティストはモデリングやデータ分析を主戦場としており、依存パッケージの脆弱性管理やコンテナの権限設計といった領域は、本来の業務の中心ではないことが多いです。だからこそ、これらをユーザー個々の習熟度に委ねるのではなく、プラットフォーム側で初期値を配る方針を取りました。 各チームがセルフサービスで開発環境を立ち上げられ、特別な設定をしなくても初期状態でセキュリティのベースラインが担保される 状態を目指しています。推奨パスに乗るだけで安全に進められる、いわゆる「ゴールデンパス」の発想であり、 セキュア・バイ・デフォルト を仕組みで成立させるアプローチです。 この方針を devcontainer.json レベルで素直に表現できる仕組みが Dev Container Feature でした。Feature を1行足すだけで宣言的にガードレールが適用されるため、「各チームが自律的に環境を立ち上げつつ、危険な操作だけは仕組みで塞ぐ」という設計とよく噛み合っています。 共通 Dev Container Feature によるガードレール 私たちの開発環境では、共通化した Dev Container Feature(以下、共通 Feature)を配っています。まず、ベースイメージと Feature の役割は明確に分けています。 Docker Hardened Images(以下、DHI)をベースにした開発用イメージでは、各種開発ツール(Python / uv / gcloud / Claude Code など)をインストールしておきます 。 共通 Feature では、それらツールの設定ファイル配置とガードレール適用のみを担います 。 この前提のもと、各チームの devcontainer.json は以下のようにシンプルで、ベースイメージを指定し、共通 Feature を追加するだけで、後述するガードレールがまとめて適用されます。 { " image ": " asia-northeast1-docker.pkg.dev/<PROJECT>/<CUSTOM_DHI_PATH>:<TAG> ", " features ": { " asia-northeast1-docker.pkg.dev/<PROJECT>/<CUSTOM_FEATURE_PATH>:<TAG> ": {} } } こうしてレイヤーを分けておくと、ツールの入れ物とポリシーの適用が混ざらずに整理されるため、 よりセキュアに締めやすい という体感があります。たとえばポリシー側だけを Renovate で継続的に更新していけるので、イメージの差し替えと独立してセキュリティ設定の追従・レビューを回せます。なお、ベースイメージ側で押さえるべきリスク(OS パッケージの脆弱性など)と、Feature 側で押さえるべきリスク(ツールの権限・設定)をどう切り分けるかといった論点もあります。ただし本記事のスコープ外のため、詳細は割愛します。 この Feature がプロビジョニング時に各種設定ファイルを配置し、ガードレールを自動で効かせます。実際には複数のツール設定を同じ方式で配布していますが、本記事では代表例として AI エージェントの制御を取り上げます。 Claude Code などの AI エージェントの制御 昨今、 Claude Code のような AI コーディングエージェントが普及していますが、無制限の権限を与えると破壊的変更や意図しないデータ送信のリスクがあります。共通 Feature は /etc/claude-code/managed-settings.json を自動生成し、システムレベルで制御を行います。 { " strictKnownMarketplaces ": [ { " source ": " github ", " repo ": " <ORGANIZATION>/<REPOSITORY> " } ] , " allowedMcpServers ": [ { " name ": " <APPROVED_MCP_NAME> ", " command ": " ... " } ] , " permissions ": { " deny ": [ " Bash(sudo:*) ", " Bash(gcloud:*) ", " Read(~/.config/**) " ] } } ※ 実際の設定から一部を抜粋しています。 プラグインマーケットプレイスと MCP サーバーは、社内で承認されたもののみに制限しています(ホワイトリスト形式)。また、 sudo や gcloud などの権限昇格・クラウド操作、 ~/.config/ 配下の機密情報へのアクセスといった危険な操作は、Deny リストでブロックしています。ユーザー側の settings.json では上書きできない managed settings として配置しているため、「うっかり緩めてしまう」ことを構造的に防げます。 Feature に寄せることの嬉しさ これらを共通 Feature として提供していることで、以下のようなメリットが得られています。 各チームの devcontainer.json は Feature を1行足すだけでよく、 セキュリティ設定の知識なしにベースラインを満たせる 。 Feature のバージョンを上げるだけで、 全社的にガードレールを一括更新できる (Renovate で自動 PR される)。 設定の出所が Feature に集約されているため、 監査やレビューの対象が明確 になる。 実際に運用してみると、Renovate の PR を1本マージするだけで全チームの Claude Code 設定が同時に更新されるのは、想像していた以上に運用が軽くなったと感じています。 補足:周辺で効かせている多層防御 共通 Feature だけで全てを押さえようとせず、周辺の仕組みと組み合わせて多層防御を成立させています。ベースイメージには DHI を採用してコンテナ起動時点でのベースラインを引き上げ、ホストとなる Remote SSH 用 VM 側にも同等のポリシーを展開し、依存関係は Dependabot / Renovate で継続的に追従させる、という具合です。 おわりに 今回は、MLOps チームが 共通 Dev Container Feature を使って、ML 開発環境のガードレールをどのように設計・運用しているかをご紹介しました。 振り返ってみると、 ツールは DHI イメージ、設定は共通 Feature、更新は Renovate と責務を分けておくと、それぞれに対するレビューや更新のサイクルを独立して回しやすいのが大きな利点でした。ガードレール自体を作ることよりも、 ガードレールを錆びさせない構造 に落とすことが、各チームの自律性を損なわずにベースラインを引き上げていくうえでの要だったように思います。 参考文献 Claude Code - System settings : /etc/claude-code/managed-settings.json に関する公式ドキュメント Dev Containers - Features : Dev Container Feature の仕様 こうした「セキュア・バイ・デフォルトな ML 開発環境」を、より多くのチームと一緒に磨き込んでいきたいと考えています。 We're Hiring! タイミーでは、ML プラットフォームの構築・運用やセキュアな開発環境の整備に一緒に取り組んでいただけるエンジニアを募集しています! 少しでも興味を持っていただけましたら、ぜひ以下のリンクから詳細をご覧ください。 MLOpsエンジニア シニアMLOpsエンジニア 募集ポジション一覧
はじめに こんにちは。開発本部 開発1部 デリッシュリサーチチームの江﨑です。 デリッシュリサーチは、デリッシュキッチンに蓄積された検索ログやレシピへの反応をもとに食トレンドを分析できるサービスです。 本記事では、社内用にデリッシュリサーチのデータを Claude から自然言語で問い合わせられるようにする MCP サーバーを自作した話を紹介します。FastMCP と Databricks Apps で実装した構成、運用上のノウハウ、そしてリリース後に社内で広がった活用事例をまとめます。 はじめに 背景:なぜ自前の MCP サーバーを作ったか システム全体像 使用技術 MCP サーバーの実装 ツール一覧 ツールの基本パターン シノニムの代表語正規化 Databricks Apps での運用ノウハウ app.yaml で起動コマンドを定義 Resource 宣言の上限 20 個 ツール呼び出し履歴を Unity Catalog に蓄積 実際の呼び出しの流れ 試してみた事例 ダッシュボードでは出せない切り口に対応 MCP × Web 検索を組み合わせたトレンド分析 商材タイアップ提案の素材集め まとめ 参考リンク 背景:なぜ自前の MCP サーバーを作ったか デリッシュリサーチには各種分析機能があり、検索トレンド・レビュー・お気に入りレシピなど、マーケティングに使えるデータが一通り揃っています。ただ、実際に業務で使おうとすると、いくつかの壁がありました。 分析の手間 :デリッシュリサーチを開いて、目当ての機能を探して、フィルタを設定して、結果から示唆を得る、という手順が必要です。気になったことをちょっと確認する用途には、やや手数が多くなります。 分析の仕方に一定のスキルが必要 :どの切り口で見るか、どのフィルタを組むか、数字をどう読み解くかは訓練が要る作業で、誰でもすぐに使いこなせるとはいきません。 画面を横断した分析がしづらい :それぞれの機能はタブごとに分かれており、「検索データ × 気温 × 都道府県」のような掛け合わせの問いには答えづらい構造でした。 実際のデリッシュリサーチの画面は次のようになっています。 デリッシュリサーチの画面 デリッシュリサーチは社外のクライアント企業に提供しているサービスですが、社内のメンバーも利用しており、同じ壁にぶつかっていました。一方で、ちょうど社内には Claude が広く配布され始めており、 「Claude で何ができるか」の具体例を作って社内全体での活用を推進したい という思いもありました。デリッシュリサーチのデータを Claude のチャットから自然言語で聞ける MCP を作れば、上の 3 つの壁を越えつつ、社内向けの Claude 活用事例にもなります。 加えて、Databricks には Managed MCP サーバーという仕組みがあります。これは Unity Catalog の汎用ツール(Vector Search、Genie Space、Databricks SQL、Unity Catalog Functions)を MCP として AI クライアントに提供するものです。ただし、シノニム正規化や複数テーブル結合を伴うドメイン特有の集計を Managed MCP に組み込むのは難しく、求めている精度のデータを提供するには物足りませんでした。 そこで、リサーチデータの集計操作そのものをツールとして公開する 自前の MCP サーバー を作ることにしました。 システム全体像 構成は以下のとおりです。 システム全体像 チームの admin が Custom Connector に MCP サーバーを一度登録すれば、利用者は Claude.ai や Claude Desktop から Databricks の SSO でログインするだけで接続できます。MCP サーバー本体は Databricks Apps 上で稼働しており、Databricks SDK を経由して Unity Catalog のテーブルにアクセスします。 Databricks Apps は、Databricks ワークスペース上で Web アプリケーションをホストできる機能です。Unity Catalog と同じワークスペース上で動かせるため、アプリに自動で割り当てられるサービスプリンシパルからそのまま Unity Catalog のテーブルにアクセスできます。 認証は Databricks ワークスペースの OAuth で行います。利用者が Claude から MCP に接続すると、最初に Databricks のログイン画面に飛ばされてログインします。以降の MCP リクエストには発行されたアクセストークンが付与されます。Databricks Apps の手前にあるリバースプロキシがそれを検証したうえで、認証済みのエンドユーザー情報を x-forwarded-email などのヘッダーに載せてアプリに転送してくれます。MCP サーバーのコード側ではこのヘッダーを読むだけで「誰が呼び出しているか」が分かります。 使用技術 本 MCP サーバーで使用している主な技術は以下のとおりです。 項目 技術 言語 Python 3.11 以上 MCP フレームワーク FastMCP 2.x Web フレームワーク FastAPI + uvicorn ホスティング Databricks Apps データ層 Unity Catalog(Delta テーブル) 観測 OpenTelemetry パッケージ管理 uv FastMCP は Python で MCP サーバーを書くためのフレームワークです。MCP の HTTP ベースの通信方式(Streamable HTTP)に対応しており、Databricks Apps 上で動かせます。 MCP サーバーの実装 ツール一覧 現在、MCP サーバーには次のようなツールが登録されています。 キーワードの検索数を期間・粒度を指定して取得 検索ワードランキング 組み合わせ検索ランキング 主ワードに対する副ワードの傾向分析 都道府県別の検索ワードランキング 都道府県別の組み合わせ検索ランキング お気に入りに追加されたレシピのランキング レシピ単位のレビューと平均評価 気温と検索数の相関 食材の物価データ 食材の物価の前年同月比ランキング ツールの基本パターン FastMCP では、Python の関数に @mcp_server.tool デコレータを付けるだけでツールとして登録できます。本 MCP では、関数の docstring・引数のバリデーション・SQL 実行・整形して返却、という流れを全ツールで揃えています。 def register (mcp_server): @ mcp_server.tool # FastMCP にツールとして登録 def get_search_trends ( search_word: str = "" , start_date: str = "" , end_date: str = "" , granularity: str = "monthly" , ) -> dict : """指定ワードの検索数推移を期間・粒度を指定して取得する。 Args: search_word: 検索ワード(例: "キャベツ")。シノニムは自動で代表語に正規化される。 start_date: 開始日(YYYY-MM-DD、省略時は前年同月の月初) end_date: 終了日(YYYY-MM-DD、省略時は前日) granularity: 粒度(daily / weekly / monthly / quarterly / yearly) """ # 引数のバリデーション search_word = search_word.strip() if not search_word: return { "error" : "search_word is required" } # 表記ゆれを代表語に正規化(後述のシノニム正規化) main_word = resolve_to_main(search_word) # SQL を実行し、結果を整形して返却 try : rows = _fetch_basic_trends(main_word, start_date, end_date, granularity) return { "search_word" : main_word, "data_points" : len (rows), "data" : rows} except Exception : # エラーは Unity Catalog の観測テーブルに記録される logger.exception( "get_search_trends failed" , extra={ "tool" : "get_search_trends" }) return { "error" : "Internal error" } ツールの docstring は AI クライアントがそのままツールの説明として参照します。AI 側がどのツールをどんな引数で呼ぶかは、この docstring の質に強く依存します。 Args: の各引数に「何を渡してよいか」「省略時の挙動」を必ず明記する運用にしています。 シノニムの代表語正規化 集計テーブルの search_word は、ETL の段階で表記ゆれや言い換えが代表語に寄せられた状態で保存されています。たとえば「キャベツ」「きゃべつ」のような表記の違いは代表語「キャベツ」に集約されています。MCP のツール側でも、入力されたワードを resolve_to_main() で代表語に変換してから集計テーブルを参照するようにしました。これにより、ユーザーがどの表記で問い合わせても同じ結果を返せます。 Databricks Apps での運用ノウハウ app.yaml で起動コマンドを定義 Databricks Apps では、リポジトリのルートに app.yaml を置いたうえで、Workspace 上の管理画面から GitHub リポジトリを連携してデプロイしています。ソースを更新した後は Workspace 側で再デプロイを実行するだけで反映されます。 command : [ "uv" , "run" , "opentelemetry-instrument" , "custom-mcp-server" ] env : - name : WAREHOUSE_ID value : "<warehouse-id>" opentelemetry-instrument を経由して起動することで、アプリのログ・トレース・メトリクスが自動で Unity Catalog 上の観測テーブルに流れます。 Resource 宣言の上限 20 個 Databricks Apps では、参照したいテーブルや SQL Warehouse を UI上で宣言できます。宣言したリソースはデプロイ時にアプリのサービスプリンシパルへ自動で GRANT され、削除時には自動で REVOKE されます。 運用していて詰まったのが、 1 アプリあたりに宣言できる resource の数は 20 個まで という制約です。これは 2026 年 5 月時点で公式ドキュメントには明記されておらず、実際に 21 個目を追加しようとしてエラーで気付きました。今回の MCP では参照するテーブルが 20 個を超えており、すぐに上限に到達してしまいました。 そのため、UIからではなく Unity Catalog 側で 手動 GRANT を運用する方式 に切り替えました。 GRANT USE CATALOG ON CATALOG external_marketing_research TO `<sp-uuid>`; GRANT USE SCHEMA ON SCHEMA external_marketing_research.search TO `<sp-uuid>`; GRANT SELECT ON TABLE external_marketing_research.search.search_count TO `<sp-uuid>`; ツール呼び出し履歴を Unity Catalog に蓄積 社内向けに公開している以上、誰がどのツールをどの引数で呼んだかを追えるようにしておきたい要件がありました。 FastMCP には Middleware クラスがあり、ツール呼び出しの前後にフックを差し込めます。これを使い、呼び出し履歴を Unity Catalog のテーブルに INSERT する仕組みを入れました。MCP が参照している他の集計テーブルと同じカタログに置くことで一元化できます。 class HistoryMiddleware (Middleware): async def on_call_tool (self, context, call_next): tool_name = context.message.name user = get_request_user() # x-forwarded-email から取得 start = time.perf_counter() is_error = False try : return await call_next(context) except Exception : is_error = True raise # 例外は握りつぶさず外側に伝播させる finally : # 成功/失敗どちらの場合も履歴を書く duration_ms = (time.perf_counter() - start) * 1000 self._schedule_write( tool_name=tool_name, user_email=user[ "email" ] if user else None , arguments_json=_serialize_arguments(context.message.arguments), duration_ms=duration_ms, is_error=is_error, ) Databricks Apps では、リクエストヘッダーの x-forwarded-email にエンドユーザーのメールアドレスが入ります。これを contextvars で受け取り、INSERT 時に user_email として記録しています。 このテーブルを使うと、誰が何を呼んだかを追える監査記録としてだけでなく、次のような切り口で利用状況を集計できます。 ツール別の呼び出し頻度 :どのツールが実際によく使われているかを把握し、機能改善の優先度を判断する ツール別のエラー率と所要時間 :例外発生率と平均レスポンス時間からツールの健全性を確認する ユーザー別の利用状況 :誰がどれくらい使っているかを見て、活用事例のヒアリング相手を決める 実際の呼び出しの流れ たとえば「リサーチ MCP を使用して、キャベツのトレンドを分析してください」と Claude に投げかけると、必要なツールを Claude が自分で判断して順番に呼び出し、結果を分析・可視化して回答してくれます。 MCPの呼び出し例 この例では、次の流れで動いています。 まず利用可能なツールを把握する 過去 2 年分の検索トレンドと組み合わせワードのツールを呼び出す 続けて物価データのツールも呼び出して相関を確認する 取得したデータをもとに、要約(前年同期比、価格との相関係数、ピーク月など)とグラフを生成する 利用者は自然言語で問いを投げるだけで、その背後で複数のツールが呼ばれ、検索データ・物価データ・組み合わせワードを横断したアウトプットが返ってきます。 試してみた事例 社内リリース後、エンジニアからビジネス職まで、さまざまなメンバーに触ってもらいました。まだ実業務での運用に組み込んでいるわけではなく、各自で試しながら可能性を探っている段階ですが、いくつか興味深い使い方が出てきたので紹介します。 ダッシュボードでは出せない切り口に対応 「平日と比較して休日に検索頻度が増加する料理を教えてください」のように、デリッシュリサーチの管理画面上のプリセットでは答えられない切り口の問いにも対応できます。AI 側で日次データを取得するツールを呼び出し、平日/休日の比率を計算する手順を自分で組み立てて回答します。 MCP × Web 検索を組み合わせたトレンド分析 「リサーチ MCP の検索データ」と「Web 検索」を併用して、特定の食材・調理法のブームを背景情報込みで分析するような使い方も試されています。たとえば、せいろブームの背景に Web 上のどんな話題があり、検索数とどう連動しているかをまとめる、といった分析です。 商材タイアップ提案の素材集め 「ビール商材向けにおつまみレシピのタイアップ提案を考えて」のような依頼でも、MCP からレビュー数の多いレシピや時期別の検索傾向を取得し、提案スライドまで作るところまで行われました。 数値や因果関係の最終確認は必要ですし、プロンプトや精度にもまだ改善の余地があります。とはいえ、提案のドラフトを素早く試作する用途として手応えを感じています。 まとめ 今回は社内向けのデリッシュリサーチ MCP サーバーを自作した話を紹介しました。 リリース後、エンジニアからビジネス職までいろいろなメンバーに触ってもらっています。デリッシュリサーチ単体では難しい横断的な分析や、分析からスライド作成までを一気通貫でやれる点に可能性を感じています。SNS など外部のデータソースも組み合わせて、活用の幅を伸ばしていきたいです。 最後まで読んでいただきありがとうございました! 参考リンク Model Context Protocol FastMCP Databricks Apps Databricks マネージド MCP サーバーを使用する Unity Catalog 権限リファレンス
はじめに サーバーワークスの池田です。 今週(5/17〜5/23)の Claude Code は v2.1.144 から v2.1.150 まで6バージョンがリリースされました(v2.1.146 は公式 CHANGELOG に記載のない欠番です)。大型の新機能というより、バグ修正と既存機能の安定化が主役の1週間でした。 そのなかでも、日々の運用に効く変更が3点あります。いずれも派手さはないものの、毎日触る部分の挙動が変わるため影響範囲は広いです。 /usage の項目別内訳(v2.1.149): 利用上限を何が消費しているかを skills・subagents・plugins・MCP サーバー…

動画

該当するコンテンツが見つかりませんでした

書籍