見出し画像

MCP(Model Context Protocol)を活用したJグランツ補助金検索システムの実装例

デジタル庁プロダクトマネージャーユニットの土岐竜一です。事業者の手続システム総括班で、Jグランツを含む事業者向けシステムなどを担当しています。

この記事では、デジタル庁が運用する補助金電子申請システム「Jグランツ」のAPIを、Anthropic社が提唱するModel Context Protocol(MCP) によりラッピングし、LLMから利用可能なシステムのサンプル設計および実装について説明します。

具体的には、Pythonで簡単に実装できるFastMCPフレームワークを利用し、Jグランツの補助金検索や詳細の取得などの実用的な機能を備えたMCPサーバーを例として実装します。なお、本記事におけるコードはGitHubよりダウンロード可能です。

本実装例で実現できること

今回紹介するMCPサーバーを利用すると、LLM(Claudeなど)を通じて、以下のような自然言語によるJグランツの補助金検索や参照が可能になります。

最新状況把握(例)
質問例: 「最新のJグランツ上の補助金を教えて」
LLMの回答例:「現在募集中の補助金情報をお伝えします。締切りが迫っているものから順番に主な補助金をご紹介します。...」

複雑な条件での絞り込み(例)
質問例:「従業員50名の東京都の製造業で、金額1000万円以内、今月中に締切りの補助金はある?」
LLMの回答例:「製造業も含めて利用可能な9月末締切りの補助金がいくつかありますので、ご紹介します。...」

申請書類のダウンロード(例
質問例:「DX推進補助金の募集要項と申請書を要約して」
LLMの回答例:「DX推進に関連する補助金の詳細情報を取得し、また添付されている内容を要約します...」

対象補助金に募集要項や申請様式などがファイル添付されている場合には、LLMで処理しやすいように、それらのファイルをテキスト(Markdown形式)に変換しLLMに返します。これによりすぐに添付ファイルの情報を含めた詳細内容の把握が可能になります。

また、今回はStreamable HTTPを利用したリモートMCP サーバーとして実装を行っているため、RailwayやRenderといったクラウドサービスにデプロイすれば、例えばClaude Desktopから「コネクタ」として直接接続できます。これは、複数のユーザーで同一のMCP サーバーを共有したり、モバイルからなどデバイスを越えて補助金検索をしたりする場合に有用です。

※免責事項

本記事で紹介する実装は、技術検証を目的としたサンプルコードです。以下の点にご留意ください。
・本コードはデジタル庁が公式に提供・保守するものではありません。
・Jグランツサービスの検索性や動作の安定性を保証するものではありません。
・実際の利用にあたっては、JグランツAPIの利用規約に準じてご利用ください。

Jグランツとは

Jグランツシステムの概要

Jグランツ(補助金電子申請システム)は、国および地方自治体が提供する補助金・助成金の情報を一元的に管理し、事業者が電子申請を行えるプラットフォームです。2020年のサービス開始以降、毎年約1,000種類の補助金が掲載され、累計で百万件を超える申請が処理されています。

システムの特徴としては、単なる申請受付システムにとどまらず 、補助金の公募情報の検索から申請書類の作成、審査プロセスの管理、交付決定後の実績報告まで、補助金ライフサイクル全体をデジタル化している点が挙げられます。

また、 「デジタル社会の実現に向けた重点計画 (令和7年6月13日閣議決定)」において、「事業者向け補助金については、2025 年度以降、全ての補助金の電子申請への対応を原則とする方針のもと、J グランツにおいて、代理申請機能を追加したところ、その利用拡大を進める 」と書かれています。そのとおり、Jグランツは代理申請機能を追加し、また登録口座のチェック機能などの拡充も予定されており、より活用を促進すべきプラットフォームとして注目されています。

Jグランツ公開APIの仕様

Jグランツは外部システムとの連携を促進するため、REST APIを公開しています (2025年現在、ベータ機能として公開されています)。

現在のところ、一般に公開されているAPIとしては以下の大きく2つになります。それぞれ、補助金の一覧を取得するAPIと詳細を取得するAPIです。これらは、追加の契約などはいらず 、API利用規約に準ずる形で利用することが可能です。実際の利用規約に関しては、「API利用規約」をご覧ください。

APIエンドポイントと、APIメソッドは次のとおりです。

APIエンドポイントhttps://api.jgrants-portal.go.jp/exp/v1/public

APIメソッド

APIメソッドの「メソッド」「エンドポイント」「機能」「必須パラメータ」「オプションパラメータ」が表になっている。①メソッド:GET、エンドポイント:/subsidies、機能:補助金一覧取得、必須パラメータ:・keyword(検索キーワード、2〜255文字※)・sort(created_date/acceptance_start_datetime/acceptance_end_datetime)・order(ASC/DESC)・acceptance(0:全て/1:受付中のみ)、オプションパラメータ:・use_purpose(利用目的、最大255文字)・industry(業種、最大255文字)・target_number_of_employees(従業員数制約)・target_area_search(補助対象地域)②メソッド:GET、エンドポイント:/subsidies/id/{id}、機能:補助金詳細取得、必須パラメータ:・id(補助金ID、18文字以下、URLパスに含める)、オプションパラメータ:なし

パラメータの注意点

  • /subsidiesエンドポイントは、keyword、sort、order、acceptanceの4つがすべて必須パラメータです。

  • ※keywordは最低2文字、最大255文字で、スペースのみの入力や空白文字は使用できません。本実装例では"事業"をデフォルトキーワードとして使用しています。

  • sortで指定できるのは、作成日・受付開始日時・受付終了日時の3種類。

  • acceptanceで受付中の補助金のみに絞り込むことが可能(1を指定)。

また、それぞれのレスポンス例は次のとおりです。

レスポンス例 1( /subsidies -補助金一覧取得) :

{
  "result": [
    {
      "id": "XXXXXXXXXXXXXXXXXXX",
      "title": "XXX補助金2025",
      "subsidy_max_limit": 4500000,
      "acceptance_start_datetime": "2025-03-01T00:00:00Z",
      "acceptance_end_datetime": "2025-12-28T17:00:00Z",
      "target_area_search": "全国",
      "target_industry": "全業種",
      "target_number_of_employees": "中小企業・小規模事業者",
      "use_purpose": "業務効率化・売上アップ",
      "detail": "中小企業・小規模事業者等が自社の課題やニーズに合ったITツールを導入する経費の一部を補助..."
    },
    {
      "id": "a0W5h00000UdK8xEAX",
      "title": "XXX助成金",
      "subsidy_max_limit": 10000000,
      "acceptance_end_datetime": "2025-03-31T23:59:59Z",
      "target_area_search": "全国",
      "target_industry": "製造業",
      "detail": "生産性向上のための設備投資を支援..."
    }
  ],
  "total_count": 1248,
  "page": 1,
  "limit": 20
}

レスポンス例 2( /subsidies/id/{id} -補助金詳細取得) :

{
  "result": {
    "id": "a0WJ200000CDR9HMAX",
    "title": "XXX補助金2025(通常枠)",
    "detail": "中小企業・小規模事業者等が自社の課題やニーズに合ったITツール(ソフトウェア、サービス等)を導入する経費の一部を補助することで、業務効率化・売上アップをサポートします。",
    "subsidy_max_limit": 4500000,
    "subsidy_rate": "1/2以内",
    "acceptance_start_datetime": "2025-03-01T00:00:00Z",
    "acceptance_end_datetime": "2025-12-28T17:00:00Z",
    "target_area_search": "全国",
    "target_industry": "全業種",
    "target_number_of_employees": "中小企業・小規模事業者",
    "inquiry_url": "https://.....go.jp/",
    "update_datetime": "2025-01-05T10:30:00Z",
    "application_guidelines": [
      {
        "name": "公募要領_通常枠_第1次.pdf",
        "data": "(BASE64文字列)"
      }
    ],
    "outline_of_grant": [
      {
        "name": "補助金概要説明資料.pdf",
        "data": "(BASE64文字列)"
      }
    ],
    "application_form": [
      {
        "name": "様式.zip",
        "data": "(BASE64文字列)"
      }
    ]
  }
}

補助金の詳細情報を取得すると、添付ファイルは {name: "ファイル名", data: "BASE64エンコードされたファイルデータ"} という構造で返されます。上記の例では簡略化していますが、実際のBASE64文字列は数MB〜数十MBに及ぶことがあるため注意が必要です。

Model Context Protocol (MCP) とは

MCPの概要と特徴

Model Context Protocol(MCP)は、2024年11月にAnthropic社が公開した、LLMと外部システムを接続するための標準化プロトコルです。従来、LLMが外部APIやデータベースにアクセスするには個別のカスタム実装が必要でしたが、MCPによりこれらの接続を統一的な方法で実現できるようになります。Tools実行・データ取得・サービス連携の標準インタフェースを提供し、LLMと外部システムの連携を標準化します。

MCPは、外部のResources(データベースや文書など)を「参照可能な資源」として、外部サービスを「呼び出し可能なTools」として統一的に扱える仕組みを提供します。これにより、LLMが最新情報の取得や業務システムとの連携を標準的な方法で実現できます。

MCPのアーキテクチャ

MCPのアーキテクチャは、MCPホスト(アプリ本体) 、MCPクライアント(ホスト内の通信コンポーネント) 、MCPサーバー(機能提供側)の3要素からなります。

MCPのアーキテクチャ概要と題した図。一番上の四角に「MCPホスト(アプリ本体)」があり、その四角の中に「AIアプリ(LLM)」→「MCPクライアント」と書かれている。「MCPクライアント」から矢印が2つに分かれ、「stdio(ローカル)」と「Streamable HTTP(リモート)」に結びついている。「stdio(ローカル)」と「Streamable HTTP(リモート)」は、上から二番目の四角で「トランスポート」としても括られている。「stdio(ローカル)」と「Streamable HTTP(リモート)」それぞれからの矢印が、上から三番目の四角の「MCPサーバー(機能提供側)」で結ばれる。「MCPサーバー(機能提供側)」の中に「Tools(ツール)/Resources(リソース)/Prompts(プロンプト)/Logging(ロギング)」と書かれている。
図1:MCPのアーキテクチャ概要
  • MCPホスト(Host): MCPクライアントを実行するアプリケーション環境(Claude Desktop、VS Codeなど)。ユーザーインターフェースと接続管理を担当

  • MCPクライアント(Client): ホスト内で動作し、MCPサーバーと通信するコンポーネント。ツール呼び出しとスキーマ整合を実行

  • MCPサーバー(Server): 実際の機能を提供する実装部分。ツールの実装とリソース管理を担当

これら3つのコンポーネントは、MCPプロトコルを介して連携し、LLMと外部システムをシームレスに統合します。

MCPの4つの基本要素

MCPは以下の4つの基本要素を提供し、LLMと外部システムの間で情報をやり取りするための「共通言語」として機能します。

  • Tools(ツール): LLMが実行可能な関数を定義。外部API呼び出し、ファイル処理、データ操作など多様な機能を提供。docstringがLLMへの説明として使用され、型定義により安全に実行。

  • Resources(リソース): LLMがアクセス可能なデータやファイルを管理。URI形式で統一的にアクセスでき、権限管理やキャッシング機能を備える。

  • Prompts(プロンプト): 再利用可能なPromptsテンプレート。LLMの振る舞いを一貫させ、ベストプラクティスを共有する基盤。

  • Logging(ロギング): デバッグや運用監視のためのログ出力。開発から本番環境まで、目的に応じたログレベルで運用可能。

MCP ホスト/クライアント/サーバーの関係

ユーザーの自然言語入力はホスト内のLLMが解釈し、ホスト内のMCPクライアントが必要なTools呼び出しをサーバーへ送ります。サーバーは外部APIやファイルI/Oなどの実処理を行い、結果をクライアント経由でLLMに返し、UIへ表示されます。

本実装ではサーバーをHTTP(FastMCPのStreamable HTTP)で公開し、先に述べたように Railwayや Renderといったクラウドサービスにデプロイすれば、MCPホスト(Claude Desktopなど)から「コネクタ」として直接接続できます。また、MCP サーバーをローカル環境でも起動でき、その場合は、ホストからは FastMCP CLI のプロキシ( uvx fastmcp run http://localhost:8000/mcp )で橋渡し接続します(図2)。

JグランツMCPサーバーのシステム構成と題した図。「利用者」から出ている矢印は、「自然言語」の文字を経て、「MCPホスト(LLM)」「Claude Desktop」に結びつく。「Claude Desktop」から出ている矢印は、「標準出入力(stdio)」を経て、「MCPクライアント(FastMCP proxy)」に結びつく。「MCPクライアント(FastMCP proxy)から出ている矢印は「HTTP」を経て、「サービス層」「MCPサーバー(FastMCP)Streamable HTTP」に結びつく。「MCPサーバー(FastMCP)Streamable HTTP」から2つの矢印が出ていて、左側の矢印は「HTTPS」を経て「JグランツAPI(外部API)」、右側の矢印は「保存」を経て「ローカルファイル(添付ファイルダウンロード)」につながる。
図2:JグランツMCPサーバーのシステム構成

ホストからの自然言語による問い合わせを受け取ると、それを適切なAPI呼び出しに変換し、Jグランツ APIから情報を取得します。

MCPサーバーの設計

MCP サーバーのTools粒度はユーザーの意図を単位とする

MCP サーバーを実装する上ではTools設計がキーとなります。既存Webサービスで提供されているAPIを、粒度そのままにラッピングして説明書きを加えて単純に公開することもあります (もちろんよく練られているWebサービスのAPIを毀損するわけではありません)。しかし、結果を取得するまで時間がかかったり、トークン量やコンテキスト量の超過が発生したり、期待する結果が返ってこなかったり、ハルシネーションが頻発するなど、そもそもやりたかったことが途中までしかできないことが発生します。

例えば、

  • Toolsを細かくしすぎる: LLMによるTools選択を難しくし、冗長な呼び出しにつながるリスクがある。LLMがMCP サーバーのどのToolsを呼べばよいか分からなくなってしまう。

  • Toolsを粗くしすぎる: LLMによる誤用を高める可能性がある。実際にはできないのにLLMが積極的にそのMCP サーバーのToolsを呼び出してしまう。

ということが指摘されています。現在推奨されている設計方針としては、 「ユーザーの意図(Intent) 」を単位として中粒度で設計することが有効とされています。

学術的にも、LLMを用いたToolsチェーン設計においては、特に「複雑なタスクを複数のステップに分解したLLMチェーン」に関する研究が進んでいます。例えば、Grunde-McLaughlinらによる調査では、クラウドソーシング(人による分業)とLLMチェーンの類似性が示され、設計者は目的(Objectives)->戦略(Strategies)->戦術(Tactics)という三層構造を意識してチェーンを設計するべきとされており、この中粒度設計の考え方に合致します【Grunde-McLaughlin et al., 2023】 。人に渡せる単位でのTools設計です。さらに、Wuらによる2024年のEMNLP発表研究「ToolPlanner」では、LLMが異なる粒度の指示(multi-granularity instructions)に対応できるTools強化学習モデルを提案しています。この研究では高レベルの計画(solution path planning)と具体的なタスクの実行を統合する設計が有効であるとされ、まさにIntentベース設計と整合します【Wu et al., 2024】 。

そのため、目的としての「事業で使える補助金を申請したい」という全体計画から、ユーザーが行うであろう具体的なプロセスを分解して定義し、MCPサーバーが具備すべきToolsを考えることが有用です。

実際に補助金申請プロセスと、あるべきMCPTools定義とJグランツとをマッピングした例は以下のとおりです。例えば「1.きっかけ・情報収集」と「2.検索・選定」は同じJグランツAPIを呼び出しますが、MCPToolsとしては分けて用意します。

なお、Jグランツは現在公開APIとして補助金検索と詳細情報取得APIの2つのみの公開であり、申請準備および申請のAPIは対象外となります。また、通知をする機能もありませんが、一方で検索および詳細情報取得はそのままAPIとして使えます。

補助金申請プロセスに応じたMCPToolsとJグランツAPI(理想)

補助金申請プロセスに応じたMCPツールとJグランツAPI(理想)が「プロセス」「事業者の行動」「MCPツール定義例」「JグランツAPI」の項目で表になっている。プロセス①きっかけ・情報収集、事業者の行動:補助金の存在を知る(支援者、ニュース、SNS、公式サイトなど)、MCPツール定義例:get_subsidy_overview( )、JグランツAPI:/subsidies、プロセス②検索・選定、事業者の行動:条件で検索・候補を絞り込み、気になる案件を保存、MCPツール定義例:search_subsidies( )、JグランツAPI:/subsidies、プロセス③詳細確認、事業者の行動:詳細要件や添付資料を確認、MCPツール定義例:get_subsidy_detail(subsidyId)/get_file_content(subsidyId)、JグランツAPI:/subsidies/id/{id}、プロセス④準備、事業者の行動:書類作成・必要情報の確認・社内確認、MCPツール定義例:checklist( )/requiredDocs( )(チェックリスト生成や必要書類提示の支援)、JグランツAPI:記述なし、プロセス⑤申請、事業者の行動:オンライン申請フォーム入力・書類添付・提出、MCPツール定義例:startApplication(subsidyId)/uploadDocument(file)/submitApplication( )、JグランツAPI:記述なし、⑥申請後管理、事業者の行動:進捗確認・不備対応・審査結果確認、MCPツール定義例:checkApplicationStatus(appId)/respondToReviewRequest(appId,response)、JグランツAPI:記述なし

実装したMCPToolsの機能拡張(今回の実装)

実装したTools一覧は以下のとおりです。
システム的な面を考慮して、pingという機能的に必要なMCPToolsを実装している点と、あとは添付ファイルは処理負荷分散やコンテキスト消費を抑制するために、別で取得するように分けています。

「MCPツール名」「JグランツAPI」「拡張・追加機能」「設計思想」が表になっている。MCPツール名:get_subsidy_overview、JグランツAPI:なし(独自実装)、拡張・追加機能:締切期間別の自動分類・金額規模別の集計・緊急案件の抽出・CSV形式での出力、設計思想:APIに存在しない機能のうち、LLMが補助金の全体像を把握するために必要最小限の統計機能のみ、MCPツール名:search_subsidies、JグランツAPI:GET/subsidies、拡張・追加機能:ソート機能(締切日・開始日・作成日)・複雑な条件の組み合わせ・受付中フィルタリング・デフォルトキーワード「事業」、設計思想:基本的なAPI機能を忠実にラップしつつ、LLMが自然言語から検索条件を構築しやすいインターフェイスを提供、MCPツール名:get_subsidy_detail、JグランツAPI:GET/subsidies/id/{id}、拡張・追加機能:BASE64ファイルの自動デコード・ローカルファイル保存・MCP経由のアクセス情報・受付状態の自動判定、設計思想:トークン消費の問題を解決する最小限の処理に特化し、大容量データを効率的に扱えるよう工夫、MCPツール名:get_file_content、JグランツAPI:なし(独自実装)、拡張・追加機能:MarkItDown変換(PDF/Word/Excel等)・BASE64/Markdown形式の選択・多形式ファイル対応、設計思想:保存されたファイルをLLMが理解しやすい形式で提供、MCPツール名:ping、JグランツAPI:なし(MCP標準)、拡張・追加機能:接続確認・サーバー応答チェック、設計思想:MCP仕様で要求される標準機能のみを実装

補助金の詳細情報には、募集要項や申請書などのPDF、Word、ExcelファイルがBASE64エンコードされた形式で含まれています。これらの大容量データをそのままClaude Desktopに渡すと、会話のトークンリミットを急速に消費してしまうという課題がありました。

この問題を解決するため、本実装では2つを採用しました。

1. ファイルのローカル保存: BASE64データをサーバー側でデコードし、ローカルファイルとして保存した後、 file:// URLを返す方式により、トークン消費を大幅に削減。

2. Markdown変換機能: Microsoft製のMarkItDownライブラリを使用して、PDF、Word、Excel、PowerPoint、ZIPなど多様な形式のファイルをMarkdown形式に変換。これにより、LLMが文書内容を直接理解し、質問に答えることが可能に。

特にMarkdown変換機能は、単純なテキスト抽出ではなく、文書の構造(見出し、リスト、表など)を保持したまま変換するため、LLMが文書の階層構造を理解しながら情報を処理できます。

LLM(MCPホスト)にうまく使ってもらうためのPromptsやResourcesを用意する

実際に利用者とLLMとのやりとりを経た上で、LLMにどうToolsを選択してもらうのか、はToolsの定義でもある程度指示を出すことができますが、本実装では、MCPのPromptsResourcesにおいてもそのガイドを提供することにしました。Promptsを動的なガイダンス・使い方ガイドとして使い、Resourcesを静的なガイドラインを提供することに使うイメージです。

実装例:Prompts

画像

実装例:Resources

画像

Python実装の詳細

本セクションでは、FastMCPフレームワークを用いたJグランツMCPサーバーの実装について、コード構造からファイル処理まで解説します。

実装アーキテクチャ

ファイル構成

jgrants-mcp-server/
├── jgrants_mcp_server/
│   └── core.py              # メインコード(約430行)
├── requirements.txt          # 依存ライブラリ
└── tests/
    └── test_core.py         # テストコード

依存ライブラリ

本実装では、以下の最小限のライブラリのみを使用しています:

画像

設計方針

  • 単一ファイル構成: メインロジックを core.py に集約し、可読性と保守性を両立。

  • 非同期処理: すべてのToolsを非同期関数として実装し、パフォーマンスを最適化。

  • シンプルなAPI: FastMCPの @mcp.tool() デコレータで簡潔にToolsを定義。エラーハンドリング: API呼び出しやファイル処理の失敗を適切にLLMへ返却。

実装したMCPTools

以下は、本サーバーで提供する6つのToolsの詳細です。

画像

主要ヘルパー関数

共通処理を以下のヘルパー関数に切り出すことで、各Toolsを10〜40行のコンパクトな実装に抑えています。

API通信関連

  • _http_client(): `httpx.AsyncClient` のシングルトンインスタンスを返す

  • _get_json(url, params=None, retries=3): JグランツAPIへのGETリクエストを実行し、JSON結果を返却。リトライ機能付き

データ整形関連

  • _parse_int(value) : 文字列や数値を安全に整数変換。_deadline_status(end_datetime) : 締切日時から受付状態( 「受付中」 「終了」 「期限間近」 )を判定。

  • _compact_detail(result, subsidy_id) : API詳細レスポンスをLLMに適した形式に整形。

ファイル処理関連

  • _sanitize_name(filename) : ファイル名から危険な文字を除去(パストラバーサル対策)。

  • _save_files(subsidy_id, file_categories) : BASE64添付ファイルをデコードして FILES_DIR/<補助金ID>/ 配下に保存。

  • _render_markdown(file_path) : 保存済みファイルをMarkdown形式に変換(PDF/Word/Excelなどに対応)。

  • _prepare_file_payload(file_path) →_load_file_payload(file_path) →_get_file_content_internal(subsidy_id, filename, format) :ファイル返却のフォールバック処理(Markdown → BASE64の順で試行)。

添付ファイル処理の詳細フロー

JグランツAPIから返される添付ファイルは、BASE64エンコードされた大容量データとなるため、以下の4段階で処理します。

「LLM」「MCPツール」「JグランツAPI」「ファイルシステム」の4つの軸が描かれいて、それぞれでの処理ステップが矢印を使って表示されている。

処理ステップ詳細:

1. 詳細情報取得: get_subsidy_detail が /subsidies/id/{id} エンドポイントを呼び出し、application_guidelines (公募要領) 、 outline_of_grant (概要資料) 、 application_form(申請様式)などの配列を取得。

2. ファイル保存:_save_files() がBASE64データをデコードし、 FILES_DIR/<補助金ID>/ ディレクトリ配下に保存。ファイル名は_sanitize_name() で危険な文字を除去。

3. ファイル参照: get_file_content で保存済みファイルを参照すると、拡張子に応じて以下の優先順位で変換を試行:

  • PDF: pdfplumber でテキスト抽出 → Markdown整形。

  • Word/Excel/PowerPoint/ZIP: markitdown ライブラリでMarkdown変換。

  • その他: テキストファイルとして読み込み。

  • すべて失敗: BASE64形式で返却。

4. トークン最適化: file:// URLを返すことでLLMのトークン消費を抑制し、必要な場合のみMarkdown変換結果を提供。

実装コード例

Tools実装例:補助金詳細取得

MCPToolsの実装において最も重要なのがdocstringです。FastMCPでは、関数のdocstringがそのままLLMへの説明文として使用されます。LLMはこのdocstringを読んでToolsの機能を理解し、適切な場面で呼び出すかを判断します。

以下はget_subsidy_detail Toolsの実装例です:

@mcp.tool()
async def get_subsidy_detail(subsidy_id: str) -> Dict[str, Any]:
    """
    指定された補助金の詳細情報を取得し、添付ファイルをローカルに保存します。

    このツールは以下の情報を返します:
    - 補助金の詳細情報(タイトル、補助上限額、補助率、受付期間など)
    - 添付ファイルのfile:// URL(公募要領、概要資料、申請様式など)
    - ファイル保存先ディレクトリのパス

    Args:
        subsidy_id: 補助金ID(18文字以下の文字列)

    Returns:
        補助金の詳細情報(添付ファイルのfile:// URLを含む)

    注意:
        - 添付ファイルは自動的にローカルに保存されます
        - ファイルの内容を確認するには get_file_content ツールを使用してください
    """
    if not subsidy_id or not isinstance(subsidy_id, str):
        return {"error": "subsidy_id は文字列で指定してください"}

    # JグランツAPI呼び出し
    url = f"{API_BASE_URL}/subsidies/id/{subsidy_id}"
    data = await _get_json(url)
    if "error" in data:
        return data

    # レスポンス整形
    result = data.get("result", data)
    if isinstance(result, list):
        result = result[0] if result else {}
    if not isinstance(result, dict):
        return {"error": "不明なレスポンス形式"}

    # 詳細情報の整形と添付ファイル保存
    detail = _compact_detail(result, subsidy_id)
    detail["files"] = _save_files(detail["id"], {
        "application_guidelines": result.get("application_guidelines", []),
        "outline_of_grant": result.get("outline_of_grant", []),
        "application_form": result.get("application_form", []),
    })
    detail["save_directory"] = str(FILES_DIR / detail["id"])

    return detail

docstringのポイント:

  • 概要: Toolsが何をするかを明確に記述(1行目)。

  • 詳細説明: 返される情報の具体的な内容を箇条書きで列挙。

  • 引数の説明: Argsセクションで各引数の型と制約を記載。

  • 戻り値の説明: Returnsセクションで返却される内容を説明。

  • 注意事項: 注意 セクションで使用上の重要な情報を記載(他のToolsとの連携など)。

このように充実したdocstringを書くことで、LLMがToolsを適切に理解し、ユーザーの意図に沿った形で呼び出せるようになります。

Prompts実装例

Promptsは、LLMに対して定型的なガイダンスや指示を提供するための機能です。Toolsの使い方、ベストプラクティス、注意事項などをPromptsとして定義することで、LLM がより効果的にMCPサーバーを活用できるようになります。

Promptsは、ユーザーがMCPサーバーの使い方を理解していない場合でも、LLMが適切な手順を提案できるようにする「動的なガイド」として機能します。

@mcp.prompt()
async def subsidy_search_guide():
    """補助金検索のベストプラクティスを提供するプロンプト"""
    return """# Jグランツ補助金検索ガイド

## 効果的な検索のポイント

1. **キーワードの選び方**
   - 2文字以上必須(デフォルト: "事業")
   - 業種や目的を含めると精度向上

2. **絞り込み条件の活用**
   - 対象地域、業種、従業員数、受付状態を組み合わせる
   - 締切日順、金額順でソート可能

## 推奨検索パターン
- **広く探してから絞り込む**: まずキーワード検索 → 統計で全体把握 → 条件絞り込み
- **目的明確型**: 最初から条件を指定して候補を限定
"""

@mcp.prompt()
async def api_usage_agreement():
    """API利用規約と免責事項の確認プロンプト"""
    return """# Jグランツ API 利用にあたっての同意事項

## 免責事項
**本実装はあくまでサンプル実装であり、Jグランツサービスの検索性向上を保証するものではありません。**
最新情報は必ず公式サイトでご確認ください。

## 利用規約
- 出典表示: 「Jグランツポータル(https://www.jgrants-portal.go.jp)」を明記
- 適切な利用: 過度なAPI呼び出しは避ける
- 個人情報: 取得した情報の適切な管理
"""

Promptsの設計ポイント:

  • 具体的な手順: 「まずキーワード検索 → 統計で全体把握 → 条件絞り込み」のように、具体的なステップを示す。

  • ベストプラクティス: 効果的な使い方をパターンとして提示。

  • 注意事項: 免責事項や利用規約など、重要な情報を明記。

  • Markdown形式: 見出しや箇条書きを活用して、LLMが構造を理解しやすくする。

Resources実装例

Resourcesは、LLMがアクセス可能な静的または動的なデータを提供するための機能です。ガイドライン、設定情報、参照ドキュメントなどを、URI形式でアクセス可能なResourcesとして定義します。

Resourcesは、Promptsが「動的なガイド」であるのに対し、 「静的なリファレンス」として機能します。LLMは必要に応じてこれらのResourcesを参照し、正確な情報に基づいた応答を生成できます。

@mcp.resource("jgrants://guidelines")
async def usage_guidelines():
    """MCPサーバー利用ガイドラインを提供するリソース"""
    return """# Jグランツ MCP サーバー利用ガイドライン

## 基本的な使い方

1. **検索から始める**: `search_subsidies` で候補を探す
2. **詳細を確認**: `get_subsidy_detail` で詳細情報と添付ファイルを取得
3. **統計で全体像を把握**: `get_subsidy_statistics` で締切日・金額規模を確認

## API制限と注意事項

- **レート制限**: 1分間に60リクエストまで(推奨値)
- **タイムアウト**: 30秒で自動切断
- **ファイルサイズ**: 大容量PDFは変換に時間がかかる場合あり

## トラブルシューティング

- 検索結果0件 → キーワードを変更("事業"等の汎用的なワードを試す)
- 添付ファイル変換失敗 → BASE64形式で再取得
- タイムアウト → 検索条件を絞り込む
"""

Resourcesの設計ポイント

  • URI形式: jgrants://guidelines のように、独自のスキームを使った分かりやすいURIを定義。

  • 包括的な情報: 基本的な使い方、制限事項、トラブルシューティングなど、必要な情報を網羅。

  • 具体的な数値: レート制限やタイムアウトなど、具体的な数値を記載してLLMの判断材料とする。

  • トラブルシューティング: よくある問題とその解決策を提示することで、LLMがエラー発生時に適切な対処を提案できる。

実行方法

前提環境

  • Python 3.11 以上( asyncio と httpx の最新機能を利用)

  • macOS / Linux / WSL を想定。Windows でも動作しますが、パス表記を適宜読み替えてください。

  • Jグランツ公開APIへのネットワーク到達性

セットアップ

1. リポジトリを取得

git clone https://github.com/digital-go-jp/jgrants-mcp-server.git
cd jgrants-mcp-server

2. 依存ライブラリをインストール(仮想環境推奨)

 python3 -m venv .venv
 source .venv/bin/activate
 pip install -r requirements.txt

環境変数とカスタマイズ

実行前に、必要に応じて以下の環境変数を設定できます:

画像

設定例:

export JGRANTS_FILES_DIR=/tmp/jgrants_files

利用例

HTTPサーバーとして起動

python -m jgrants_mcp_server.core --mode http --host 127.0.0.1 --port 8000

起動すると FastMCP の Streamable HTTP が立ち上がり、Claude Desktop などから直接接続できます。ファイルは FILES_DIR/<補助金ID>/ 以下に保存されます。

Claude Desktop設定

MCPサーバーをClaude Desktopから利用するには、以下の設定を行います。

1. MCPサーバーを起動

python -m jgrants_mcp_server.core --port 8000

2. Claude Desktopの設定ファイルを編集

設定ファイルの場所:

  • Mac: `~/Library/Application Support/Claude/claude_desktop_config.json`

  • Windows: `%APPDATA%\Claude\claude_desktop_config.json`

以下の設定を追加:

{
  "mcpServers": {
    "jgrants": {
      "command": "uvx",
      "args": [
        "fastmcp",
        "run",
        "http://localhost:8000/mcp"
      ]
    }
  }
}

3. Claude Desktopを再起動

設定を反映させるため、Claude Desktopを再起動します。

この設定の仕組み

1. uvx がFastMCPを自動的にインストール・実行
2. FastMCP CLIがHTTPプロキシとして動作
3. Claude DesktopからのJSON-RPCリクエストをHTTPサーバーに転送
4. Tools、Resources、Promptsのすべての機能が利用可能

トラブルシューティング

uvx がインストールされていない場合:

pip install uv

または、 fastmcp を直接使用:

{
  "mcpServers": {
    "jgrants": {
      "command": "fastmcp",
      "args": ["run", "http://localhost:8000/mcp"]
    }
  }
}

動作確認のヒント

  • search_subsidies に「DX」 「スタートアップ」などのキーワードを渡して件数が返るかチェック。

  • get_subsidy_detail → get_file_content の順に呼び、Markdown変換されたPDF要約を確認。

  • get_subsidy_statistics を output_format="csv" で呼ぶと、ブログでも掲載しやすい集計表が得られます。

  • テストを走らせる場合は pip install pytest 後、 python -m pytest tests/test_core.py などを実行してください。

おわりに

本記事では、Model Context Protocol(MCP)を活用したJグランツ補助金検索システムの実装例を紹介しました。

本実装では、MCPのベストプラクティスに従い、ユーザーの意図(Intent)を単位とした中粒度のTools設計を採用しました。補助金申請プロセスという実際のユースケースに沿ってToolsを定義することで、LLMが適切にToolsを選択・実行できる設計としています。

また、JグランツAPIから返される大容量のBASE64添付ファイルをMarkdown形式に変換することで、LLMのトークン消費を最適化し、実用的な会話を実現しました。さらに、PromptsやResourcesといったMCPの機能を活用し、LLMが効果的にToolsを使用できるガイダンスを提供しています。Streamable HTTP対応により、クラウドサービスへのデプロイも容易で、リモートから複数のユーザーが同じMCPサーバーを共有することも可能です。

現在、MCPは急速に進化している技術領域です。MCP仕様自体が頻繁に更新されており、ホスト(LLM)側のサポート状況もばらつきがあります。特にTools機能は広くサポートされている一方で、Resourcesなどの機能はまだ発展途上の段階にあります。

また、エコシステムとしても、MCPサーバーの発見可能性を高めるMCPレジストリの整備、MCPサーバーの品質を評価するレピュテーションの仕組み、複数のMCPサーバーを同時利用する際の優先順位制御、そして認証・認可とユーザー同意の仕組みなど、実用化に向けた課題が数多く残されています。これらの課題に対しては、実証実験や仕様提言、学術研究が盛んに行われており、今後の発展が見込まれています。

行政処理システムにおいて、APIを提供するサービスは増加していますが、仕様書の理解が必要な複雑なAPIも少なくありません。MCPは、LLMを介してこれらのAPIを自然言語で利用可能にする橋渡し役として機能します。専門知識を持たないユーザーでも、対話を通じて行政サービスにアクセスできる環境が実現します。本実装が、ユーザー視点・LLM視点でのAPI設計の見直しや、行政サービスのアクセシビリティ向上のきっかけとなることが期待されます。

本記事で紹介したコードはGitHubで公開しています。本実装例が、より多くの人々にとってアクセシブルな行政サービスの実現に向けた一助となれば幸いです。

参考

◆デジタル庁Techブログの記事一覧は以下のリンクをご覧ください。

◆関連するデジタル庁の採用情報は以下のリンクをご覧ください。

ピックアップされています

デジタル庁Techブログ

  • 42本

ブックマーク

  • 7本
買うたび 抽選 ※条件・上限あり \note クリエイター感謝祭ポイントバックキャンペーン/最大全額もどってくる! 12.1 月〜1.14 水 まで
MCP(Model Context Protocol)を活用したJグランツ補助金検索システムの実装例|デジタル庁
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1