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
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 ofmodel, 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.