# Using this server from Microsoft Foundry and Copilot Studio

This server is a standard remote MCP server (Streamable HTTP, `POST /mcp`), so
it is consumable from Microsoft's agent surfaces — but those surfaces differ
sharply in how much of the MCP authorization spec they implement. Copilot
Studio speaks the full spec and connects to this server's `oauth` mode
unchanged. Foundry Agent Service does not do OAuth discovery or Dynamic Client
Registration, so it needs either the server's `static` mode or a manually
pre-registered OAuth client. This page covers both, plus networking, gateway,
and distribution options. Verified against Microsoft Learn as of 2026-07.

## What works today

| Surface | Auth that works with this server | Status |
|---|---|---|
| Foundry Agent Service (new Foundry) | `static` bearer token via key-based connection; per-user via custom OAuth identity passthrough | MCP tool GA |
| Copilot Studio | Full MCP OAuth — `oauth` mode with dynamic discovery, no changes needed | Available |
| Microsoft Agent Framework (SDK) | `static` bearer via `MCPStreamableHTTPTool` headers | SDK |
| Logic Apps Standard (MCP client/server) | Connection-defined | Preview |
| Azure SRE Agent (MCP connectors) | Connector-defined | Preview |
| Azure Government Foundry | None — MCP tools are not supported there at all | Not supported |

Classic Azure AI Foundry agents are deprecated and retire 2027-03-31; everything
below assumes the **new** Foundry portal and SDKs.

## Foundry Agent Service

The MCP tool is GA in the new Foundry. Docs:
<https://learn.microsoft.com/azure/foundry/agents/how-to/tools/model-context-protocol>.

Attach the server to an agent either way:

- **Portal**: ai.azure.com → your project → **Build → Tools → Add tool →
  Custom → Model Context Protocol** → give it a name, the endpoint
  `${PUBLIC_BASE_URL}/mcp`, and an authentication method.
- **SDK / REST**: add an `mcp` tool with `server_url`, `server_label`,
  optional `allowed_tools`, `require_approval` (default `"always"`), and a
  `project_connection_id` that carries the credentials. In Python this is
  `MCPTool` from `azure.ai.projects.models`.

**Foundry does not implement the MCP authorization spec.** It never calls
`/register` (no DCR) and it ignores the `401` + `WWW-Authenticate`
`resource_metadata` challenge this server emits on `/mcp`. Instead, Foundry
supports five fixed auth methods
(<https://learn.microsoft.com/azure/foundry/agents/how-to/mcp-authentication>):
key-based custom header, Entra agent identity, Entra project managed identity,
OAuth identity passthrough (managed or custom), and unauthenticated. The two
Entra methods send Microsoft tokens this server cannot validate, so the
workable options are the key-based header (pair with `static` mode) and custom
OAuth identity passthrough (pair with `oauth` mode).

### Option A — static mode + key-based connection (simplest)

One shared Clio account; every agent run uses the same token. Deploy the server
with `MCP_AUTH_MODE=static` (or `hybrid`) and a token in
`CLIO_HTTP_AUTH_TOKENS` — see [deployment-azure.md](deployment-azure.md).

1. In the Foundry portal, create the MCP tool connection with authentication
   **Key-based** (a project connection with custom headers).
2. Set the header name to `Authorization` and the value to
   `Bearer <one of CLIO_HTTP_AUTH_TOKENS>` — include the `Bearer ` prefix,
   this server expects a standard bearer scheme on `/mcp`.
3. Save. Foundry stores the header in the project connection and sends it on
   every `/mcp` call, including tool discovery.

Use a dedicated token from the comma-separated `CLIO_HTTP_AUTH_TOKENS` list for
Foundry so it can be rotated or revoked independently of other callers.

### Option B — per-user OAuth (custom identity passthrough)

Each Foundry user signs in to their own Clio account. Foundry's "custom OAuth
identity passthrough" runs an authorization-code flow against this server's
`/authorize` and `/token` endpoints, but because Foundry does no DCR you must
pre-register the OAuth client yourself.

1. Begin creating the MCP tool connection in Foundry with authentication
   **OAuth identity passthrough → custom**. Foundry generates a **redirect
   URL** for the connection — copy it.
2. Register a client on this server with that redirect URL (one-time; the
   `/register` endpoint is open in `oauth`/`hybrid` mode). Or reuse an
   existing `client_id` whose `redirect_uris` you extend to include it:

   ```bash
   curl -sS -X POST "${PUBLIC_BASE_URL}/register" \
     -H "Content-Type: application/json" \
     -d '{
       "client_name": "Microsoft Foundry",
       "redirect_uris": ["<redirect URL shown by Foundry>"],
       "grant_types": ["authorization_code", "refresh_token"],
       "response_types": ["code"],
       "token_endpoint_auth_method": "none",
       "scope": "clio:read clio:write offline_access"
     }'
   ```

   The response contains the `client_id` to paste into Foundry.
3. Finish the Foundry connection form:

   | Field | Value |
   |---|---|
   | Client ID | from the `/register` response |
   | Authorization URL | `${PUBLIC_BASE_URL}/authorize` |
   | Token URL | `${PUBLIC_BASE_URL}/token` |
   | Refresh URL | `${PUBLIC_BASE_URL}/token` (same endpoint) |
   | Scopes | `clio:read clio:write offline_access` |

4. On first use, each user is taken straight to Clio's own sign-in and consent
   screen; the access tier comes from the scopes the client requested.

Constraints from the Foundry side: users need the **Foundry Agent Consumer**
role on the project and must be in the same Entra tenant as the project, and
consent is granted per tool connection per project (a user re-consents for
each project that wires up the connection).

One open point: Microsoft does not document whether Foundry sends PKCE or a
client secret on the token exchange. This server accepts public clients with
PKCE (S256); if Foundry turns out to send a client secret instead, re-register
the client with the matching `token_endpoint_auth_method`
(`client_secret_post` / `client_secret_basic`). Test the full connect flow once
before rolling out.

### Limits and gotchas

- **Tool discovery vs. `oauth` mode.** Foundry calls `tools/list` when you
  attach the server — before any user has authorized. In pure `oauth` mode
  `/mcp` requires auth, so discovery can fail with a 401 until a connection
  exists. If this bites, run the server in `hybrid` mode and give Foundry a
  static token for discovery, or use Option A outright.
- **100-second tool-call timeout.** Foundry's MCP tool calls are non-streaming
  and time out at 100 seconds. Large paginated pulls (`clio_list_*` with high
  limits, `clio_api_request` sweeps) should be narrowed with filters and
  `CLIO_MAX_PAGE_SIZE`.
- **Schema restrictions.** Foundry rejects tool input schemas that use
  `anyOf`/`allOf` or multi-type parameters. If a tool fails to import, exclude
  it via `allowed_tools` rather than abandoning the server.
- **Azure Government** Foundry does not support MCP tools at all.

### Governance recommendations

- Keep `require_approval` at its default `"always"` for anything that writes —
  at minimum `clio_create_*`, `clio_update_*`, `clio_delete_*`, and
  `clio_api_request`.
- Use `allowed_tools` allowlists per agent instead of exposing all 48 tools.
- For reporting/analyst agents, grant only the `clio:read` scope tier (Option
  B) so the session cannot write even if the agent tries.
- Leave `CLIO_ALLOW_DESTRUCTIVE=false` unless a specific agent needs deletes.

## Copilot Studio

Copilot Studio implements the full MCP authorization spec — discovery, Dynamic
Client Registration, and PKCE — so this server's `oauth` mode works unchanged,
exactly like the Claude connector flow. Copilot Studio supports Streamable
HTTP transport only, which is what this server speaks. Docs:
<https://learn.microsoft.com/microsoft-copilot-studio/mcp-add-existing-server-to-agent>
and
<https://learn.microsoft.com/microsoft-copilot-studio/agent-extend-action-mcp>.

1. In your Copilot Studio agent: **Tools → Add a tool → Model Context
   Protocol → add an existing server**.
2. Enter the server URL `${PUBLIC_BASE_URL}/mcp` and choose **OAuth 2.0** with
   **Dynamic discovery**.
3. Copilot Studio discovers `/.well-known/oauth-authorization-server`,
   registers itself via `/register`, and runs the PKCE flow. The maker (and
   later each end user, depending on the connection's sharing settings) signs
   in through Clio's own consent screen.

No pre-registration, no static tokens, no server-side changes.

## Networking and APIM

- **Public endpoint.** The default Azure deployment (public Container Apps
  ingress) is reachable from both Foundry Basic and Standard agent setups and
  from Copilot Studio.
- **Private endpoint.** To keep `/mcp` off the public internet for Foundry,
  you need a Standard agent setup with bring-your-own VNet and the Container
  App switched to internal-only ingress; Foundry then reaches it over the
  VNet. Working reference: sample `19-private-network-agent-tools` in the
  `microsoft-foundry/foundry-samples` GitHub repo. Note that Copilot Studio
  and the OAuth browser redirects still need a reachable endpoint, so private
  networking realistically pairs with `static` mode.
- **APIM AI Gateway.** Azure API Management can front this server as an MCP
  endpoint to add rate limiting, subscription keys, policy enforcement, and
  OpenTelemetry tracing without touching the server:
  <https://learn.microsoft.com/azure/api-management/expose-existing-mcp-server>.
  If APIM terminates the public hostname, set `PUBLIC_BASE_URL` to the APIM
  hostname so the OAuth issuer and Clio redirect URI match what clients see.

## Distribution and discovery

There is no public cross-organization Foundry marketplace for MCP servers.
Inside your organization you can make the server discoverable:

- **Foundry private tool catalog** (preview) — an org-scoped catalog backed by
  Azure API Center, so project builders can find and attach the server from
  the portal:
  <https://learn.microsoft.com/azure/foundry/agents/how-to/private-tool-catalog>.
- **Azure API Center MCP registration** (preview) — register
  `${PUBLIC_BASE_URL}/mcp` as an MCP server asset for org-wide inventory and
  governance:
  <https://learn.microsoft.com/azure/api-center/register-discover-mcp-server>.

## Other Microsoft consumption paths

- **Microsoft Agent Framework** — `MCPStreamableHTTPTool` takes custom
  headers, so pass `Authorization: Bearer <token>` against `static` mode.
- **Logic Apps Standard** — can act as an MCP client (or server) in preview,
  connecting workflows to `/mcp`.
- **Azure SRE Agent** — supports custom MCP connectors, useful for wiring
  operational runbooks to Clio lookups.
