Skip to main content
This is the inbound direction: Microsoft calls ForceAI. A Copilot Studio REST tool or a Microsoft 365 declarative-agent API plugin invokes an approved ForceAI logical agent over POST /api/v1/agents/{agent_id}/invoke, authenticating with a delegated Entra token. The adapter fixes the model and policy server-side and forwards to the gateway with a per-tenant key.
Do not confuse this with Microsoft 365 Copilot (A2A), which is the outbound direction, where the gateway calls a Microsoft agent hosted as an A2A server. That page is for reaching into Microsoft; this page is for Microsoft reaching into ForceAI.

What it governs, and what it does not

The adapter governs the actions a Microsoft-orchestrated agent takes when it calls ForceAI, not the whole conversation. A Copilot Studio or declarative agent runs on Microsoft’s own foundation model, and only the specific tool-call reaches ForceAI. The chat, the agent’s other tools, and every answer Microsoft composes never pass through ForceAI guardrails. To govern every turn of a conversation you need a custom engine agent, where ForceAI is the agent’s model engine, which is a separate integration.
When a call does arrive through the adapter it is fully governed: the caller cannot choose the model, gateway guardrails and per-tenant budget apply, the data classification is enforced, and every call is audited with a correlation id and a hashed user id.

How the connection works

There is no persistent connection. Microsoft imports the adapter’s OpenAPI document as a tool and calls it on demand. The Microsoft access token is verified and stops at the adapter; it is never forwarded to the gateway or a provider.

Set up

1

Register an Entra app for the adapter

In Microsoft Entra ID create an app registration, single tenant. Under Expose an API, set the Application ID URI (api://<client-id>) and add a delegated scope named ForceAI.Invoke (Admins and users, Enabled). Note the client id and tenant id. The full runbook, including the Copilot Studio OAuth wiring, is in the repo at docs/forceai/how-to-m365-adapter-entra-setup.md.
2

Configure the adapter

Set the environment on the control plane and restart it:
The endpoint returns 503 until FORCEAI_M365_ADAPTER_AUDIENCE is set, so an unconfigured adapter never accepts a token by accident.
3

Mint a per-tenant virtual key

Scope it to the model group the logical agents use and give it a budget, so spend attributes to the tenant and a leaked key reaches no further.
4

Create a logical agent

The caller selects only this agent id; the server decides everything else.
The response carries usable. If it is false, the agent has no tenant or no classification granted and every call would return 404.
5

Import into Copilot Studio

Fetch the generated Swagger 2.0 document, which is served pre-filled with your host, tenant and scope, and import it as a REST API tool. Configure the OAuth 2.0 connection with the client secret and redirect URI from the app registration.
For a declarative agent, use the OpenAPI 3.0 document and the plugin manifest instead:

The invoke contract

The caller supplies only content and a classification. It never names a model or generation settings; sending any of model, provider, temperature, max_tokens or similar is refused with 400, so an attempt to route around policy is recorded rather than silently dropped.
sourceUrl is present only when a real user-accessible page exists; it is never fabricated to satisfy the response shape.

Troubleshooting by rejection reason

The adapter names why it rejected a request, and each reason points at a specific fix.