対話型 UI ウィジェットを宣言型エージェントに追加するには、 モデル コンテキスト プロトコル (MCP) サーバー ベースのアクション をエージェントに追加し、エージェントで使用される MCP ツールを拡張して UI を含めることができます。 Microsoft 365 Copilotでは、次のメソッドを使用して作成された UI ウィジェットがサポートされています。
- MCP アプリ - MCP サーバーが対話型ユーザー インターフェイスをホストに配信できるようにする MCP の拡張機能。
- OpenAI Apps SDK - 追加の ChatGPT 機能を備えた MCP Apps 標準に基づいて ChatGPT アプリを構築するためのツール。
たとえば、MCP サーバー プラグインについては、GitHub でのMicrosoft 365 Copilotに関する MCP ベースの対話型 UI サンプルに関するページを参照してください。
MCP Apps または OpenAI Apps SDK の機能がサポートされる詳細については、「 サポートされている機能」を参照してください。
前提条件
- 「Copilot 機能拡張オプションの要件」で指定されている要件
- UI ウィジェットを提供するリモート MCP サーバー、または UI ウィジェットを実装するように変更できる MCP サーバー
- MCP インスペクターなどの MCP サーバー応答を表示するツール
- Visual Studio Code
- Microsoft 365 Agents Toolkit (バージョン 6.6.1 以降)
MCP サーバーの要件
- 認証 - OAuth 2.1 と Microsoft Entra シングル サインオン (SSO) がサポートされています。 開発目的で匿名認証がサポートされています。 認証の詳細については、「 エージェントで API プラグインの認証を構成する」を参照してください。
-
許可される URL - MCP サーバーと ID プロバイダーの両方で、次の URL を許可する必要があります。
- CORS のウィジェット ホスト URL - Copilot は、MCP サーバー固有のホストの下にウィジェット UI をレンダリングします。
{hashed-mcp-domain}.widget-renderer.usercontent.microsoft.com。ここで、{hashed-mcp-domain}は MCP サーバーのドメインの SHA-256 ハッシュです。 ウィジェット ホスト URL ジェネレーターを使用して、MCP サーバー URL に基づいてホスト URL を生成できます。 - OAuth 2.1 リダイレクト URI:
-
https://teams.microsoft.com/api/platform/v1.0/oAuthRedirectCopilot 用 -
https://vscode.dev/redirectエージェント ツールキットを使用してツールをフェッチする Visual Studio Code の場合
-
- MICROSOFT ENTRA SSO リダイレクト URI:
-
https://teams.microsoft.com/api/platform/v1.0/oAuthConsentRedirectCopilot 用 - Visual Studio Code では現在、ツールをフェッチするための SSO はサポートされていません
-
- CORS のウィジェット ホスト URL - Copilot は、MCP サーバー固有のホストの下にウィジェット UI をレンダリングします。
- UI ウィジェット - UI ウィジェットは、MCP アプリまたは OpenAI Apps SDK の要件に従って実装する必要があります。
ベスト プラクティス
ユーザー エクスペリエンスの設計
UX 設計のベスト プラクティスの詳細については、「 宣言型エージェントでの対話型 UI ウィジェットのユーザー エクスペリエンス ガイドライン」を参照してください。
API の可用性を確認する
すべての window.openai.* API が、すべてのプラットフォームまたはホストで使用できるわけではありません。 サポートされていない API は undefined。 API の可用性を常にチェックし、API が使用できない場合はフォールバックを提供します。
例
この単純なパターンは、API を呼び出す前にチェックすることでランタイム エラーを回避します。
if (window.openai.callTool) {
const result = await window.openai.callTool({ name: 'myTool', params: {} });
} else {
// Handle unsupported case — show fallback UI, skip the feature, etc.
}
この例では、全画面表示モードに入るボタンは、ホストが requestDisplayMode API をサポートしている場合にのみレンダリングされます。
function FullScreenButton() {
// Don't render the button if the host doesn't support it
if (!window.openai.requestDisplayMode) {
return null;
}
return (
<button onClick={() => window.openai.requestDisplayMode({ mode: 'fullscreen' })}>
Enter Fullscreen
</button>
);
}
または、ウィジェットが起動時に使用するすべての API の可用性をチェックし、それに応じて機能を有効または無効にすることができます。
interface PlatformCapabilities {
canCallTools: boolean;
canChangeDisplayMode: boolean;
canSendMessages: boolean;
}
function detectCapabilities(): PlatformCapabilities {
return {
canCallTools: !!window.openai.callTool,
canChangeDisplayMode: !!window.openai.requestDisplayMode,
canSendMessages: !!window.openai.sendMessage,
};
}
// Use at widget startup
const capabilities = detectCapabilities();
if (!capabilities.canCallTools) {
// Show a reduced-functionality experience
}
宣言型エージェントを作成する
Visual Studio Code を開き、左側のアクティビティ バーで [Microsoft 365 エージェント ツールキット ] アイコンを選択します。
[エージェント ツールキット] 作業ウィンドウで [ 新しいエージェント/アプリの作成 ] を選択します。
[ 宣言型エージェント] を選択します。
[ アクションの追加] を選択し、[ MCP サーバーで開始] を選択します。 メッセージが表示されたら、[ リモート MCP サーバー] を選択します。
MCP サーバーの URL を入力します。
エージェント プロジェクトの場所を選択します。
エージェントの名前を入力します。
これらの手順を完了すると、Agent Toolkit によってエージェントに必要なファイルが生成され、エージェント プロジェクトが読み込まれた新しい Visual Studio Code ウィンドウが開きます。
エージェントを更新してサイドロードする
.vscode/mcp.json ファイルを開きます。 ファイル エディターで [ スタート] ボタンを選択します。
ファイル エディターで [ ATK: Fetch action from MCP ] ボタンを選択し、[ ai-plugin.json] を選択します。
使用するエージェントのツールを選択し、[ OK] を選択します。 UI ウィジェットを持つ少なくとも 1 つのツールを選択してください。
該当する認証の種類を選択します。
重要
MCP サーバーが開発中で、認証を実装していない場合、この手順はスキップされます。 サーバーに認証を追加したら、マニフェストに認証を手動で追加する必要があります。
左側のアクティビティ バーで [Microsoft 365 Agents Toolkit ] アイコンを選択します。
[ アカウント ] ウィンドウ で、[Microsoft 365 にサインイン] を選択します。 (既にサインインしている場合は、次の手順に進みます)。
Microsoft 365 アカウントの [ カスタム アプリアップロードが有効] と [ Copilot Access Enabled]\(有効\) の両方が表示されていることを確認します。 そうでない場合は、organization管理者とチェックします。詳細については、「Copilot 機能拡張オプションの要件」を参照してください。
[ ライフサイクル ] ウィンドウで、[ プロビジョニング] を選択します。
メッセージが表示されたら、認証の詳細を追加します。
プロビジョニングが完了したことをツールキットが報告するまで待ちます。
エージェントをテストする
- ブラウザーを開き、https://m365.cloud.microsoft/chat に移動します。
- 左側のサイドバーでエージェントを選択します。 エージェントが表示されない場合は、[すべてのエージェント] を選択 します。
- MCP サーバーを呼び出す操作をエージェントに依頼します。
- プロンプトが表示されたら、エージェントが MCP サーバーに接続できるようにします。
- エージェントは UI ウィジェットをレンダリングします。
サポートされている機能
Microsoft 365 Copilotでは、次の機能がサポートされています。
コンポーネント ブリッジ
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
window.openai.toolInput |
app.ontoolinput |
✅ |
window.openai.toolOutput |
app.ontoolresult |
✅ |
window.openai.toolResponseMetadata |
app.ontoolresult → params._meta |
✅ |
window.openai.widgetState |
— | ✅ |
window.openai.setWidgetState(state) |
直接使用することはできません。 を含む代替メカニズムを使用する app.updateModelContext() |
✅ |
window.openai.callTool(name, args) |
app.callServerTool({ name, arguments }) |
✅ |
window.openai.sendFollowUpMessage({ prompt }) |
app.sendMessage({ ... }) |
✅ |
window.openai.uploadFile(file) |
— | ❌ |
window.openai.getFileDownloadUrl({ fileId }) |
— | ❌ |
window.openai.requestDisplayMode(...) |
app.requestDisplayMode({ mode }) |
✅ (全画面表示のみ) |
window.openai.requestModal(...) |
— | ❌ |
window.openai.notifyIntrinsicHeight(...) |
app.sendSizeChanged({ width, height }) |
✅ |
window.openai.openExternal({ href }) |
app.openLink({ url }) |
✅ |
window.openai.setOpenInAppUrl({ href }) |
— | ✅ |
window.openai.theme |
app.getHostContext()?.theme |
✅ |
window.openai.displayMode |
app.getHostContext()?.displayMode |
✅ |
window.openai.maxHeight |
app.getHostContext()?.viewport?.maxHeight |
✅ |
window.openai.safeArea |
app.getHostContext()?.safeAreaInsets |
✅ |
window.openai.view |
— | ✅ |
window.openai.userAgent |
app.getHostContext()?.userAgent |
✅ |
window.openai.locale |
app.getHostContext()?.locale |
✅ |
| — | app.ontoolinputpartial |
❌ |
| — | app.ontoolcancelled |
❌ |
| — | app.getHostContext()?.availableDisplayModes |
❌ |
| — | app.getHostContext()?.toolInfo |
❌ |
| — | app.onhostcontextchanged |
❌ |
| — | app.onteardown |
❌ |
| — | app.sendLog({ level, data }) |
❌ |
| — | app.getHostVersion() |
❌ |
| — | app.getHostCapabilities() |
✅ |
ツール記述子_meta フィールド
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
_meta["openai/outputTemplate"] |
_meta.ui.resourceUri |
✅ |
_meta["openai/widgetAccessible"] |
_meta.ui.visibility (string[]) |
❌ |
_meta["openai/visibility"] |
_meta.ui.visibility (string[]) |
✅ |
_meta["openai/toolInvocation/invoking"] |
— | ❌ |
_meta["openai/toolInvocation/invoked"] |
— | ❌ |
_meta["openai/fileParams"] |
— | ❌ |
_meta["securitySchemes"] |
— | ❌ |
ツール記述子の注釈
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
readOnlyHint |
readOnlyHint |
✅ |
destructiveHint |
destructiveHint |
❌ |
openWorldHint |
openWorldHint |
❌ |
idempotentHint |
idempotentHint |
❌ |
コンポーネント リソースの_meta フィールド
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
_meta["openai/widgetDescription"] |
— | ❌ |
_meta["openai/widgetPrefersBorder"] |
_meta.ui.prefersBorder |
❌ |
_meta["openai/widgetCSP"] |
_meta.ui.csp |
✅ |
_meta["openai/widgetDomain"] |
_meta.ui.domain |
❌ |
| — | _meta.ui.permissions |
❌ |
CSP オブジェクトのプロパティ
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
connect_domains |
connectDomains |
✅ |
resource_domains |
resourceDomains |
✅ |
frame_domains |
frameDomains |
❌ |
redirect_domains |
— | ❌ |
| — | baseUriDomains |
❌ |
ホスト提供のツールの結果_metaフィールド
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
_meta["openai/widgetSessionId"] |
— | ❌ |
クライアント提供の_meta フィールド
| OpenAI Apps SDK | MCP アプリと同等 | サポートの有無 |
|---|---|---|
_meta["openai/locale"] |
_meta["openai/locale"] |
✅ |
_meta["openai/userAgent"] |
_meta["openai/userAgent"] |
✅ |
_meta["openai/userLocation"] |
_meta["openai/userLocation"] |
✅ |
_meta["openai/subject"] |
— | ❌ |