本文へ移動
cccskills
無料GitHub で公開

mcp-server

Copilot Studio から利用する自前 MCP Server を Azure Functions 上に構築する。JSON-RPC 2.0 の最小実装、受信 Entra ID JWT 検証 / 送信 Managed Identity のキーレス認証、Private Endpoint 下でのデータ投入、Entra アプリ登録のスコープ公開と事前承認、デプロイの実測検証までを非対話スクリプトで完結させる。

インストール方法を見る

含まれるファイル(27)

  • SKILL.md22.4 KB
  • references/.env.example2.7 KB
  • references/auth-model.md6.5 KB
  • references/copilot-studio-dlp.md6.9 KB
  • references/copilot-studio-registration.md10.4 KB
  • references/file-backed-tools.md7.6 KB
  • references/indexed-file-db-access.md6.0 KB
  • references/private-data-seeding.md7.4 KB
  • references/protocol.md6.3 KB
  • references/sql-tools-pattern.md8.4 KB
  • references/troubleshooting.md31.3 KB
  • scripts/add_connector_redirect_uri.py3.0 KB
  • scripts/cleanup_admin_endpoints.py3.4 KB
  • scripts/configure_connector_oauth.py12.6 KB
  • scripts/configure_entra_api.py4.8 KB
  • scripts/configure_function_storage.py3.3 KB
  • scripts/deploy_mcp_function.py10.1 KB
  • scripts/diagnose_connector_token.py8.1 KB
  • scripts/diagnose_copilot_dlp.py3.0 KB
  • scripts/generate_copilot_studio_guide.py11.9 KB
  • scripts/query_host_logs.py2.3 KB
  • scripts/seed_mcp_data.py2.7 KB
  • scripts/test_cleanup_admin_endpoints.py2.3 KB
  • scripts/test_generate_copilot_studio_guide.py4.8 KB
  • scripts/test_update_connector_oauth.py2.9 KB
  • scripts/update_connector_oauth.py4.7 KB
  • scripts/verify_mcp_server.py5.4 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

MCP Server 開発スキル

Copilot Studio のエージェントから 社内の業務データ(DB・ファイル共有・業務 API) を参照させるための 自前 MCP Server を Azure Functions 上に構築する。

役割分離: VNet / Private Endpoint / Managed Identity といった Azure 基盤の構成は azure-infra スキル に委譲する。本スキルは MCP プロトコル層・Entra 認可・データ投入・ Copilot Studio 登録 を担当する。

設計原則

原則内容
データ層は非公開、コンピュート層は公開SQL / Storage は Private Endpoint のみ。Function App の HTTP エンドポイントは公開する(Copilot Studio は SaaS からアウトバウンド接続するため、非公開にすると到達できない)
キーレス受信 = Entra ID Bearer JWT 検証、送信 = Managed Identity。関数キー・接続文字列・共有キーを使わない
プロトコルは最小実装initialize / tools/list / tools/call / ping のみ。SSE ストリーム・セッション管理は実装しないが、Streamable HTTP の規約には従う(Copilot Studio は Streamable のみ対応)
成否はルート実測で判定デプロイの終了コードや ARM のメタデータを信用せず、HTTP プローブで実際のルートを確認する
非対話で完走Azure 操作も auth_helper 経由(az login を手順に含めない)。→ 認証リファレンス

サブリファレンス

リファレンス内容
MCP プロトコル最小実装JSON-RPC 2.0 の実装と Streamable HTTP の必須要件、ツール定義の書き方
認証モデル受信 JWT 検証 / 送信 Managed Identity の実装
Private 環境でのデータ投入Private Endpoint 下でシードするための管理エンドポイントパターン
ファイルを読ませるツールの設計サイドカーテキストレイヤー・パストラバーサル対策・出力上限・プロンプトインジェクション防御
SQL バックエンドのツール設計パラメータ化クエリ・集計軸のホワイトリスト・トークン寿命と接続プール・読み取り専用権限
File / DB の認可とページ画像本人認可、索引 ID、改訂・ページ照合、投入時画像キャッシュ、欠損404と実測ゲート
Copilot Studio への登録オンボーディングウィザード、コピペ用 MD 生成、OAuth 接続。OpenAPI 方式もここ
Copilot Studio の DLP 診断MCP ツールが DLP でブロックされた場合の読み取り診断と最小変更
admin スキル実装着手前の環境チェックと DLP 事前チェック、カスタムコネクタの DLP 分類変更
.env サンプル本スキルのパラメータ
異常系・トラブルシュート実際に踏んだ失敗と恒久対策

ワークフロー(正常系)

Step 1: ツール定義を先に確定する

MCP は「エージェントがツール名と入力スキーマだけを見て呼ぶ」ため、実装より先にツール定義を決める。

  1. 接続するデータソース(Azure SQL / Azure Files / 業務 API)を列挙する。
  2. データソースごとに 1 つの MCP Server を立てる(責務分割・障害分離のため)。
  3. ツールは 「一覧」「検索」「取得」の 3 系統 を基本形にする。エージェントは一覧で語彙を得てから検索するため、 list_* が無いと的外れな検索語で空振りする。
  4. 各ツールの name / description / inputSchema を確定する。→ protocol.md
  5. 一覧・検索・取得のすべてで、認証済み利用者が参照できる範囲を決める。MI のデータアクセス権を本人権限と扱わない。設計確定後に admin の環境・DLP/ACP チェックを実行し、NG があれば停止する。索引取得は 認可契約 に従う。
例: 部品DB MCP   -> list_categories / search_parts / get_part_inquiries / search_inquiries
例: 文書共有 MCP -> list_categories / list_documents / get_document / search_documents

Step 2: Entra アプリ登録でスコープを公開し、クライアントを事前承認する

MCP Server を 保護対象 API として登録する。ここを飛ばすと、後でトークン取得が AADSTS650057 で失敗する。

python .github/skills/mcp-server/scripts/configure_entra_api.py

このスクリプトは以下を行う。

  1. identifierUris に api://{app-id} を設定する。
  2. OAuth2 権限スコープ(既定 MCP.Access)を公開する。
  3. パブリッククライアント(Azure CLI / Azure PowerShell)を 事前承認し、同意画面なしでトークンを取得できるようにする。

重要: スコープ公開と事前承認を 1 回の PATCH にまとめてはいけない。 新規スコープ ID が未登録扱いになり InvalidValue ... delegatedPermissionIds で失敗する。 スクリプトは 2 段階に分割して送信している。

Step 3: Azure 基盤を構築する

azure-infra スキル の手順で以下を構築する。本スキル固有の要件のみ以下に示す。

リソース本スキル固有の要件
Function AppFlex Consumption + VNet 統合 + システム割り当て MI。HTTP は公開のまま
データストアPrivate Endpoint のみ(publicNetworkAccess=Disabled・共有キー禁止)
RBACFunction App の MI にデータ層へのデータプレーンロールを付与
Functions 用ストレージ共有キー禁止のため AzureWebJobsStorage は使わず、AzureWebJobsStorage__accountName の ID ベース接続にする。MI に Storage Blob Data Owner が必要
ファイル共有共有の作成はマネジメントプレーンで行う(データプレーンのロールでは共有を作成できない)

Function App の作成直後は AzureWebJobsStorage に共有キーの接続文字列が入る。共有キー禁止のストレージでは この状態でホストが起動できず、デプロイは成功するのに全ルートが 404 になる。作成直後に必ず切り替える。

python .github/skills/mcp-server/scripts/configure_function_storage.py --app <function-app-name> --account <storage-account>

Step 4: MCP Server を実装する

Azure Functions(Node.js 20 / TypeScript / v4 プログラミングモデル)で実装する。

<server-name>/
├── local.settings.json        # ★ 必須(Step 5 参照)
├── host.json
├── package.json
├── src/
│   ├── functions/
│   │   ├── mcp.ts             # route: mcp        認可 + JSON-RPC ディスパッチ
│   │   └── adminSeed.ts       # route: seed-*     一時的なデータ投入用(Step 8 で削除)
│   ├── lib/
│   │   ├── auth.ts            # 受信 JWT 検証
│   │   └── <datasource>.ts    # 送信 Managed Identity アクセス
│   └── tools/
│       └── <domain>Tools.ts   # ツール定義 + ハンドラ
  • ハンドラは authLevel: 'anonymous' にし、認可はコード側の JWT 検証で行う(関数キーを使わない)。
  • src/index.ts は各関数モジュールを import するだけにする。存在しないモジュールを 1 行でも import すると worker が 起動できず、全ルートが 404 になる(関数を削除・退避したら import も必ず消す)。
  • Copilot Studio から使うなら Streamable HTTP の必須要件を満たす(通知には 202 + 本文なし、 protocolVersion は 2025-03-26 以降をネゴシエート、GET / DELETE に 405)。これを外すと curl では成功するのにコネクタ接続だけが失敗する。
  • 実装の詳細は protocol.md と auth-model.md を参照。
  • ストレージ上の文書を読ませるツールを作るなら、パス検証・出力上限・戻り値の注意書きを必ず入れる。 → file-backed-tools.md
  • SQL を読むツールを作るなら、全クエリのパラメータ化と読み取り専用権限を前提にする。 → sql-tools-pattern.md
  • MCP Server は Copilot Studio のツールとして登録し、Code App のデータソースへ直接追加しない。 Code App に表示するページ画像は、認可された投入処理で描画・検証して Dataverse の索引へ保存する。 エージェント応答へ Base64 画像を載せず、会話経路と画面表示経路を分離する。

Step 5: デプロイする

python .github/skills/mcp-server/scripts/deploy_mcp_function.py --project <path> --app <function-app-name>

このスクリプトは デプロイ前チェック → ビルド → publish → ルート実測検証 を通しで行う。手作業で func を叩かない。

事前チェックの内容(いずれも実際に失敗した事象への恒久対策):

チェック理由
local.settings.json の存在と FUNCTIONS_WORKER_RUNTIME無いと Worker runtime cannot be 'None' で publish が失敗する。このファイルは .gitignore 対象のため clone 直後は存在しない
func コマンドの実行可否npm グローバルインストールで zip が未展開のまま残ることがある。失敗時は自動で展開して復旧する
ビルド出力(dist/)の存在空パッケージのままデプロイされ、ルートが 404 になるのを防ぐ
ビルド前の dist/ 削除tsc は dist/ をクリーンしない。削除した関数の .js が残り、ルートが復活する
src/index.ts の相対 import が全て実在すること解決できない import が 1 行でもあると worker が起動できず、残すはずのルートまで含めて全滅する
AzureWebJobsStorage が ID ベース接続であること共有キー禁止のストレージに接続文字列で繋ごうとするとホストが起動しない(Step 3)
publish 後のルート実測func publish は成功しても終了コード 1 と "appears to be unhealthy" を返すことがある。終了コードで判定しない

ルートが 404 のままなら、ホストの起動ログで原因を特定する(0 functions loaded なら worker の起動失敗)。

python .github/skills/mcp-server/scripts/query_host_logs.py --component <app-insights-name>

Step 6: データを投入する

データ層が Private Endpoint 内にあるため、ローカル PC からは接続できない。 VNet 統合された Function App 内の一時的な管理エンドポイント経由で投入する。

python .github/skills/mcp-server/scripts/seed_mcp_data.py
  • 管理エンドポイントは 共有シークレット(ADMIN_SEED_SECRET) で保護し、アプリ設定に置く。
  • DB のスキーマ作成・MI へのロール付与は Entra 管理者権限が要るため、実行者のアクセストークンを渡して実行する。
  • 詳細は private-data-seeding.md。
  • 継続的な文書取り込みは一時シードと分け、SharePoint / 業務ストレージの作成イベントから Agent flow を起動する。 Function は PDF 正本と検索用サイドカーを書き、図番・改訂・ページを照合した画像キャッシュを Dataverse の 検証済み索引へ保存する。既存の人手注記サイドカーは上書きしない。

Step 7: エンドツーエンドで検証する

python .github/skills/mcp-server/scripts/verify_mcp_server.py

api://{app-id}/.default のトークンを取得し、Streamable HTTP 準拠の検査に続けて tools/list でツール一覧、tools/call で実データが返ることを確認する。 ツール一覧が返るだけでは不十分で、必ず 1 つ以上のツールを実行して中身を見る。

Step 8: 管理エンドポイントを削除して Copilot Studio に登録する

  1. 投入用の管理エンドポイントを削除して再デプロイする(攻撃面を残さない)。

python .github/skills/mcp-server/scripts/cleanup_admin_endpoints.py --project <path> --app <function-app-name> --route seed-upload --route seed-sql


このスクリプトは関数ファイルの削除に加えて **`src/index.ts` から該当 `import` を除去**し、
`dist/` をクリーンしてから再デプロイする。どちらか一方でも漏れると、残すべき `mcp` を含む全ルートが落ちる。
`--route` は実際の削除対象すべてを列挙する必須引数。上記2ルートは例であり、関数登録の `route` と照合する。独自名の管理関数は自動検出されないため、削除計画に明示してから実行する。

2. アプリ設定から `ADMIN_SEED_SECRET` を削除する。
3. 残すルートが 401、削除したルートが 404 であることを HTTP で実測する。
4. Copilot Studio の MCP オンボーディングウィザードで、エージェントにツールとして追加する。
→ [copilot-studio-registration.md](references/copilot-studio-registration.md)

```powershell
python .github/skills/mcp-server/scripts/configure_connector_oauth.py --audience $env:MCP_API_AUDIENCE --secret-out .secrets/connector-oauth.json
python .github/skills/mcp-server/scripts/generate_copilot_studio_guide.py `
  --server-name example-files-mcp `
  --server-description "文書を検索して内容を取得します。" `
  --server-url "https://<function-app>.azurewebsites.net/api/mcp" `
  --display-name "文書 MCP 接続" `
 --environment-id $env:POWER_PLATFORM_ENVIRONMENT_ID `
  --output "<server-dir>/copilot-studio-connection.md"
  • Server name は 1~64 文字の英字・数字・ハイフン・ドットのみ。日本語や空白は Power Platform の内部コネクタ名作成で 400 になるため、生成スクリプトが事前に拒否する。

  • 生成する Scopes は <API scope> offline_access とする。offline_access がないとリフレッシュトークンが 発行されず、アクセストークン失効後に接続が Missing refresh token で無効になる。生成スクリプトが必ず付与する。

  • Copilot Studioで利用する場合は、エージェント固有の https://copilotstudio.microsoft.com/c2/tenants/<tenant-id>/environments/<environment-id>/bots/<bot-schema>/channels/pva-studio/conversations/<conversation-id>/user-connections を直接提示する。Power Apps / Power Automateのみで利用する場合は、コネクタ固有の https://make.preview.powerapps.com/environments/<environment-id>/connections/available/<connector-id> だけを提示し、Copilot Studio URLは出さない。 接続作成、サインイン、同意、Studioでの接続選択は利用者本人が行い、エージェントは事後検証を担当する。

  • 接続作成後は pac connection list --environment <environment-id> で各接続のIDを取得し、 https://make.preview.powerapps.com/environments/<environment-id>/connections/<connector-id>/<connection-id>/details 形式のリンクを接続ごとに利用者へ提示する。接続の作成や再認証は代行しない。

  • OAuthポップアップはPower Appsへ戻るまで閉じない。認可中断で残った Error 接続は再利用せず、 個別詳細ページから削除して利用者本人が新しい接続を作成する。

  • 生成 MD は Client secret を含む。MCP Server ごとに分け、先に .gitignore へ追加する。

  • pac connector download の apiProperties.json は clientSecretを含まない。そのまま pac connector updateへ渡すと有効なsecretが失われるため、既存コネクタの更新には必ず次を使う。

    python .github/skills/mcp-server/scripts/update_connector_oauth.py `
      --environment $env:POWER_PLATFORM_ENVIRONMENT_ID `
      --connector-id <connector-id> `
      --secret-file .secrets/connector-oauth.json
    
  • 認証は OAuth 2.0、構成は Manual を選ぶ。接続画面では任意の表示名も生成 MD から貼り付ける。

  • コネクタ作成後に表示された callback URL、または AADSTS50011 に表示された URI は、次で Entra に追加する。

    python .github/skills/mcp-server/scripts/add_connector_redirect_uri.py `
      --audience $env:MCP_API_AUDIENCE `
      --redirect-uri "https://global.consent.azure-apim.net/redirect/<connector-id>"
    
  • This tool is blocked by your data loss prevention policy と表示された場合は、公開やポリシー変更を 繰り返さず、Copilot Studio の DLP 診断 に従って適用ポリシーと コネクタ分類を読み取り確認する。認証は standard スキルの auth_helper.py に統一し、 PowerShell の対話サインインやブラウザ認証を追加しない。

  • DLP を解消したのに Edit 画面で Couldn't load MCP tools ... HTTP 401 が出る場合は、 DLP やアプリ登録を疑う前に必ず次のスクリプトで原因を分類する。

    python .github/skills/mcp-server/scripts/diagnose_connector_token.py --apps $env:MCP_FUNCTION_APPS
    

    繰り返す jwt expired と診断された場合は設定不備ではなく、Copilot Studio 側が保持する アクセストークンが失効したまま更新されていないだけ。Copilot Studio(または Power Apps > Connections)で対象コネクタの接続を選び、**再認証(reconnect)**すれば解消する。 詳細は troubleshooting.md を参照。

OpenAPI をコード管理する必要がある場合だけ、カスタムコネクタのインポート方式を使う。

複数の MCP Server を 1 エージェントに束ねる場合は、コネクタの description とエージェントの指示文の **両方に「どの質問でどのサーバーを使うか」**を明記しないと選択を誤る。 エージェント本体の構築は copilot-studio-v2 スキル に委譲する。

  1. (任意)M365 Copilot(Cowork)からも使う場合は、同じ MCP Server を Cowork プラグインの agentConnectors.remoteMcpServer としても登録する。Server の実装は増えない (API アプリを 1 つに集約しておけば登録が 2 系統になるだけ)。 → cowork/references/custom-mcp-connector.md

検証チェックリスト

  • ツール定義に list_* 系があり、エージェントが語彙を獲得できる
  • Entra アプリ登録でスコープを公開し、クライアントを事前承認した(Step 2)
  • Function App の HTTP は公開、データ層は Private Endpoint のみ
  • 関数キー・接続文字列・共有キーを一切使っていない
  • local.settings.json が存在し FUNCTIONS_WORKER_RUNTIME が設定されている
  • AzureWebJobsStorage__accountName による ID ベース接続になっている(接続文字列が残っていない)
  • src/index.ts の相対 import が全て実在するモジュールを指している
  • デプロイ成否を 終了コードではなくルートの HTTP 実測で判定した
  • tools/call で実データが返ることを確認した
  • Streamable HTTP 準拠(通知に 202 / バージョンネゴシエーション / GET に 405)を検証した
  • 管理エンドポイントを削除し、ADMIN_SEED_SECRET をアプリ設定から消した
  • 削除後に「残すルート = 401 / 削除したルート = 404」を HTTP で実測した
  • スクリプトが auth_helper 経由で非対話に完走する(az login を要求しない)
  • Copilot Studio 接続の Scopes に <API scope> offline_access が含まれ、再接続後に自動更新できる
  • 利用者へ対象環境の Power Apps 接続一覧と Copilot Studio エージェント一覧のURLを提示した
  • 作成済みの各接続について Power Apps の個別詳細URLを利用者へ提示した
  • Copilot Studio の Edit 画面で 401 が出たら、DLP/設定変更の前に diagnose_connector_token.py で 「未接続・トークン失効・その他」を切り分けた

参考リンク

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

admin

無料日本語概要

Power Platform のテナント / 環境ガバナンスを確認・設定する管理スキル。開発着手前の環境チェック(既定環境ではないか・マネージド環境・Dataverse / Code Apps / MCP の有効化・セキュリティ ロール・管理 API アクセス)と DLP 事前チェックを非対話スクリプトで実行し、必要ならマネージド環境設定・カスタムコネクタの DLP 分類・ACP(Advanced connector policies)の許可コネクタを dry-run 付きで変更する。Microsoft 第一者サービスだけを許可する ACP 推奨プロファイルの適用と、クラシック DLP から ACP への移行も支援する。クラシック DLP と ACP は既定の混成モードで併用され、より制限の厳しい方が適用されるため両方を確認する。オプションとして、既定環境 / 個人開発者環境 / 市民開発者環境 / AI CoE セントラル / AI CoE 内製開発の 5 グループからなるテナント全体の環境戦略を、読み取り専用スキャン → 移行プラン(admin-migration-plan.md)→ レビュー → 適用の順で策定・実行する。設定は環境グループのルールで行うのを原則とし、グループ ルールに無い項目(既定環境ルーティング・Dataverse for Teams 禁止・Dataverse 検索・グループへの割り当て・Copilot クレジット配分)だけをテナント設定・環境個別設定・Dataverse の組織設定で補う。IP 制限・テナント分離・監査ログ・ライセンス配分などの管理設定は references にまとめる。

geekfujiwara/CodeAppsDevelopmentStandard722026年10月9日 更新

agent-flows

無料日本語概要

Copilot Studio 新 UI の Agent flows / Workflows を構築・公開・検証する。Dataverse レコード作成/更新トリガーから既存の発行済み Copilot Studio v2 を Agent ノードで呼ぶ標準経路、Code Apps との非同期要求/結果連携、および手動 Start + inline Agent の API ライフサイクル検証を扱う。

geekfujiwara/CodeAppsDevelopmentStandard722026年10月9日 更新

agm-qa-authoring

無料日本語概要

株主総会の想定問答を、IR 抜粋(決算短信・説明資料・招集通知など)を根拠に下書きし、利用者の確認後に Dataverse の想定問答テーブルへ「下書き」として登録するスキル。 Use when ユーザーが「配当について想定問答を作って」「この論点の想定問答を 3 件追加して」「招集通知から想定問答を作って」「想定問答を登録して」と依頼したとき。 Dataverse MCP コネクタ(describe / read_query / search_data / create_record / update_record)を使用する。削除・テーブル変更のツールは使わない。

geekfujiwara/CodeAppsDevelopmentStandard722026年10月9日 更新

agm-qa-review

無料日本語概要

株主総会の想定問答を点検し、根拠の IR 抜粋に無い数値・存在しない根拠 ID・回答者や注意事項の抜け・趣旨の重複・下書きのまま残っているものを一覧にするスキル(書き込みはしない)。 Use when ユーザーが「想定問答を点検して」「根拠の無い数値が無いか確認して」「下書きの想定問答を一覧にして」と依頼したとき。 Dataverse MCP コネクタ(describe / read_query / search_data)を使用する。書き込み・削除のツールは使わない。

geekfujiwara/CodeAppsDevelopmentStandard722026年10月9日 更新

agm-rehearsal-script

無料日本語概要

株主総会の質疑応答のリハーサル台本(議長・株主・回答役員の読み上げ原稿)を、承認済みの想定問答から作り、Dataverse のリハーサル台本テーブルへ登録するスキル。 Use when ユーザーが「リハーサルの台本を作って」「QA-001〜QA-010 で読み上げ原稿を作って」「番号を言わない株主も入れた台本を作って」と依頼したとき。 Dataverse MCP コネクタ(describe / read_query / search_data / create_record / update_record)を使用する。削除・テーブル変更のツールは使わない。

geekfujiwara/CodeAppsDevelopmentStandard722026年10月9日 更新

ai-builder

無料日本語概要

AI Builder の AI プロンプト(GPT Dynamic Prompt)を Dataverse API で作成し、Copilot Studio エージェントにツール(アクション)として追加する。Power Automate フローとの統合パターンも含む。

geekfujiwara/CodeAppsDevelopmentStandard722026年10月9日 更新

geekfujiwara のスキルをすべて見る

このスキルの問題を報告する