--- name: azure-connectornamespace description: | Azure Connector Namespace — manage namespaces, connections, triggers, and MCP server configs. Connect external SaaS services (Office 365, Teams, SharePoint, OneDrive, Forms, GitHub, Azure Blob) to any user-provided webhook URL via event-driven triggers, expose selected connector operations as an MCP server endpoint, or call connector operations on demand via dynamicInvoke. Use when: - Managing connector namespaces and connections - Creating trigger configs that POST to a callback URL - Subscribing to connector events (email, file, list-item, form response) - Wiring event sources to a webhook, Function App, Logic App, or API - Recurrence / sliding-window triggers that fire on a schedule - Exposing connector operations as MCP tools at a namespace endpoint - Calling connector APIs (send email, post Teams message, upload files) Triggers: "connector namespace", "connector", "trigger config", "webhook trigger", "recurrence trigger", "on new email", "callback url", "mcp", "send email", "post teams message" --- # Azure Connector Namespace (generic) Manage Microsoft.Web connector namespaces, their connections, trigger configs, and MCP server configs. This skill is **sandbox-agnostic** — it does not assume your callback target. Callbacks can be any HTTP(S) URL (Function App, Logic App, App Service, ngrok, anywhere) and you choose how the namespace authenticates to it. > If you specifically need to fan events into an Azure Container Apps sandbox group > (with declarative `gatewayConnections[]` wiring and sandbox callbacks), use the > companion skill at `plugin/skills/aca-sandboxes` instead. > **Naming note.** This skill was previously called "Connector Gateway". The > resource is now displayed as **"Connector Namespace"** everywhere (matching > the portal rename). > **The ARM resource type is still `Microsoft.Web/connectorGateways`** (legacy > URL segment kept for backwards compatibility) and the property `gatewayConnections[]` > on sandbox groups also keeps its name. Do not rewrite those API strings. ## Three patterns this skill supports | Pattern | When to use | Output | |---|---|---| | **A) Trigger config** | "Notify my webhook when X happens" / "Run my workflow every N minutes" | A `triggerConfigs/{name}` resource that POSTs to your `callbackUrl` | | **B) MCP server config** | "Expose these connector operations as MCP tools to an LLM client" | A `mcpServerConfigs/{name}` resource with a public `mcpEndpointUrl` | | **C) Direct API call** | "Send an email" / "Post a Teams message" — one-off operation | One `dynamicInvoke` POST against the connection | ## Rules (MUST follow) | Rule | Details | |------|---------| | **No hallucination** | Check `references/` for details. Use `az rest --help` for syntax. | | **No generated notebooks/scripts** | Walk the user through interactively. Do NOT generate a standalone notebook or script. | | **No guessing dynamic values** | `x-ms-dynamic-*` → call the API, present results, STOP. Never assume a team/channel/folder/site/list. | | **No guessing the callback URL** | The callback URL is **always** user-provided. Ask for it explicitly. Do NOT invent one. | | **MSI audience: ask, then default** | For `ManagedServiceIdentity` callback auth, **ask the user for `audience`** (the AAD-protected resource the namespace should acquire a token for, e.g. an AAD app they own, `https://graph.microsoft.com/`, etc.). If the user doesn't provide one, default to `https://management.azure.com/`. **Never** use the callback URL as the audience. | | **Execute, don't ask** | Once you have inputs, run the commands. Don't ask "Can I run this?" | | **`az rest` only** | No `az connectornamespace` (or legacy `az connectorgateway`) extension exists. Use `az rest` for ARM and `az rest --resource` for data-plane. | | **Always `@$tmpFile`** | For `az rest --body` in PowerShell — inline JSON breaks quoting. See [gotchas.md](references/gotchas.md). | | **Trigger body schema** | Properties root contains: `type` OR `connectionDetails`+`operationName`+`parameters`, plus `notificationDetails` (`callbackUrl`+`authentication`+`body?`). **Body-sourced leaves (top-level body param + every nested sub-property) are aggregated into ONE `parameters[]` entry whose `name` is literally `"body"` and whose `value` is the nested object** (dotted leaf names like `filter.labels` get rolled up via `setNestedValue`). The wrapper name `"body"` is independent of the Swagger body parameter's own name. Non-body dotted leaves are grouped under their root segment. See [trigger-setup.md](references/trigger-setup.md) §2b. | | **Trigger needs `namespace-acl`** | For connector-event triggers, the namespace MI must have an access policy on the connection. See [trigger-setup.md](references/trigger-setup.md) Step 4. | | **MCP user params** | Each `userParameters[]` entry is a **fixed value** for a connector-operation parameter (resolved via `dynamic-values` against the connection at config time). Each `agentParameters[]` entry declares a JSON-Schema input the **caller (LLM) supplies** at tool-call time. **Every required parameter (including required body sub-properties) MUST appear in one of the two arrays** — the runtime rejects the call with `missing required property ''` otherwise. See [mcp-server-config.md](references/mcp-server-config.md). | | **MCP per-parameter triage** | **STOP and ask the user, for each operation parameter (path/query/body field, including each required body sub-property), whether it should be a fixed `userParameter`, a caller-supplied `agentParameter`, or skipped (optional only).** Do this **before** the `mcpServerConfigs` PUT, even when no `x-ms-dynamic-*` markers are present. Decompose the body's object schema and triage each leaf. **For MCP, body wrapper name = the Swagger body param's own name (e.g. `emailMessage`).** See [mcp-server-config.md](references/mcp-server-config.md) §"Per-parameter triage workflow". | | **Parallel execution** | Run independent ops (connections, ACLs, dynamic-value lookups, MCP operations) as parallel tool calls. | **When to STOP and ask the user:** subscription/resource group, namespace name, connection name, any parameter with dynamic values (teams/channels/folders/sites/lists), callback URL, callback authentication type, **MSI `audience` (if MSI auth chosen — default to `https://management.azure.com/` if user doesn't provide one)**, OAuth consent completion, **MCP per-parameter triage (`userParameter` vs `agentParameter` vs skip — for every path/query/body field, including each body sub-property)**. **When to EXECUTE immediately:** namespace/connection/trigger/MCP-config/access-policy CRUD, role assignments, dynamic-value lookups. --- ### Step 0: Prerequisites & Azure context 1. Check `az account show`. If missing, see [prerequisites.md](references/prerequisites.md). 2. **Select subscription** — list, ask user to pick: ```bash az account list --query "[].{name:name, id:id, isDefault:isDefault}" -o table ``` Set if non-default: `az account set --subscription "{sub}"`. Store `{sub}` for all subsequent commands. 3. **Select resource group**: - Existing: `az group list --query "[].{name:name, location:location}" -o table` → user picks. - New: ask for name + location, then `az group create --name {rg} --location {location}`. **Stop and wait for the user's answers before continuing.** --- ### Step 1: Namespace setup > **ARM base:** `https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/connectorGateways` > **API version:** `2026-05-01-preview` Ask the user: "Do you have an existing connector namespace, or should I create a new one?" - **Existing:** ask for the name and fetch it: ```bash az rest --method GET \ --url "https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/connectorGateways/{namespace}?api-version=2026-05-01-preview" \ --query "{name:name, location:location, principalId:identity.principalId, tenantId:identity.tenantId, identityType:identity.type, userAssigned:identity.userAssignedIdentities}" ``` - **New:** ask for `{namespace}` name + location. **Create with a SystemAssigned managed identity** (required for trigger event subscriptions on connector-event triggers AND for `ManagedServiceIdentity` callback auth): ```powershell $namespaceBody = @{ location = "{location}"; identity = @{ type = "SystemAssigned" } } | ConvertTo-Json -Compress $tmp = New-TemporaryFile; Set-Content $tmp $namespaceBody az rest --method PUT ` --url "https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/connectorGateways/{namespace}?api-version=2026-05-01-preview" ` --body "@$tmp" ` --query "{name:name, principalId:identity.principalId, tenantId:identity.tenantId}" Remove-Item $tmp ``` **Capture `principalId` and `tenantId`** — needed later for the `namespace-acl` access policy and (optionally) for `ManagedServiceIdentity` callback authentication. > If a user later wants to call their callback URL using a **user-assigned** identity, > they'll need to add that identity to the namespace separately. See > [notification-authentication.md](references/notification-authentication.md). --- ### Step 2: Connection(s) + OAuth consent Required for **trigger configs**, **MCP server configs**, and **direct API calls**. Recurrence / sliding-window triggers with no connector-event source can skip this. Create connections in parallel: ```powershell $connBody = @{ properties = @{ connectorName = "office365" }; location = "{location}" } | ConvertTo-Json -Compress $tmp = New-TemporaryFile; Set-Content $tmp $connBody az rest --method PUT ` --url "https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/connectorGateways/{namespace}/connections/o365-conn?api-version=2026-05-01-preview" ` --body "@$tmp" Remove-Item $tmp ``` Then generate consent links and open in the browser — **see [consent.md](references/consent.md)** for the exact body format and `Start-Process` pattern. Verify status `Connected` before continuing. See also [connections.md](references/connections.md) for the full CRUD reference. > **For trigger configs:** also create a `namespace-acl` access policy granting the > namespace MI access to the connection (required for the namespace to subscribe to > connector events). See [trigger-setup.md](references/trigger-setup.md) Step 4. --- ### Step 3: Choose the pattern Ask the user: - **A) Trigger config** — push notifications to your callback URL when events happen, or on a schedule. - **B) MCP server config** — expose selected connector operations as MCP tools at a namespace endpoint, callable by any MCP client (Claude Desktop, VS Code, etc.). - **C) Direct API call** — one-off `dynamicInvoke` (send an email now, list items now). **Stop and wait for the user's answer.** - A → **Step 4A** - B → **Step 4B** - C → **Step 4C** --- ### Step 4A: Trigger config → **Full details:** [trigger-setup.md](references/trigger-setup.md) | **Auth options:** [notification-authentication.md](references/notification-authentication.md) | **Dynamic params:** [dynamic-values.md](references/dynamic-values.md) 1. **Pick the trigger source.** Ask the user: - **Connector event** (e.g., new email, new file, new form response) — needs the connection from Step 2. - **Recurrence** — fires every N seconds / minutes / hours / days. - **Sliding window** — fires on time intervals with `startTime`/`endTime` window state. 2. **Connector event:** discover trigger operations on the connector: ```bash az rest --method GET \ --url "https://management.azure.com/subscriptions/{sub}/providers/Microsoft.Web/locations/{location}/managedApis/{connector}/apiOperations?api-version=2016-06-01" \ --query "value[?properties.trigger != null].{name:name, summary:properties.summary, trigger:properties.trigger}" -o table ``` Pick one with the user. **Enumerate every parameter — including each sub-property of a `body` object** (resolve `$ref`, recurse into nested objects and array `items`). Triage each leaf: - `x-ms-dynamic-*` → resolve via [dynamic-values.md](references/dynamic-values.md). **STOP at every dynamic param.** - Static enum → present choices and **STOP** for user pick. - Free-form with obvious default (e.g., `folderPath=Inbox`) → use default, inform user. - Free-form with no default → **STOP and ask the user.** **When assembling `parameters[]`, build a nested object — do NOT emit dotted leaf names.** All body-sourced leaves (top-level body + every nested sub-property) collapse into ONE entry whose `name` is **literally the string `"body"`** (NOT the Swagger body parameter's name) and whose `value` is the nested object. Non-body dotted leaves group under their root segment. See [trigger-setup.md](references/trigger-setup.md) §2b for the exact pattern and worked examples. 3. **Recurrence / sliding window:** ask for `frequency` (Second/Minute/Hour/Day) and `interval`. 4. **Callback URL — ask the user explicitly.** Do NOT invent one. Format examples: - Function App: `https://{app}.azurewebsites.net/api/{fn}?code={key}` - Logic App HTTP trigger: full SAS URL from the Logic App's "When a HTTP request is received" - Custom API: any `https://...` endpoint 5. **Callback authentication — ask the user.** Options (full reference in [notification-authentication.md](references/notification-authentication.md)): | Type | Use when | |---|---| | *(none)* | Callback URL already contains its own auth token (e.g., Logic App SAS in querystring) | | `QueryString` | Add a `?key=value` automatically (e.g., Function App key) | | `Raw` | Send a literal `Authorization: ` header | | `Basic` | HTTP Basic with `username`/`password` | | `ManagedServiceIdentity` | Namespace acquires a token for `audience` using its own MI (system- or user-assigned). **Ask the user for `audience`** — if they don't provide one, default to `https://management.azure.com/`. Never use the callback URL as the audience. See [notification-authentication.md](references/notification-authentication.md). | | `ActiveDirectoryOAuth` | Namespace authenticates as an Entra app (tenant/clientId/secret/audience) | | `ClientCertificate` | Mutual TLS with a `pfx`/`password` | 6. **Create the trigger config** (one PUT). See [trigger-setup.md](references/trigger-setup.md) Step 3 for the canonical body templates for each source × auth combination. 7. **Create the `namespace-acl`** (only for connector-event triggers). See [trigger-setup.md](references/trigger-setup.md) Step 4. 8. **Verify** the trigger state is `Enabled`: ```bash az rest --method GET \ --url "https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/connectorGateways/{namespace}/triggerConfigs/{name}?api-version=2026-05-01-preview" \ --query "properties.state" -o tsv ``` --- ### Step 4B: MCP server config → **Full details:** [mcp-server-config.md](references/mcp-server-config.md) | **Dynamic params:** [dynamic-values.md](references/dynamic-values.md) 1. **Pick connector(s) + operation(s).** Discover them: ```bash az rest --method GET \ --url "https://management.azure.com/subscriptions/{sub}/providers/Microsoft.Web/locations/{location}/managedApis/{connector}/apiOperations?api-version=2016-06-01" \ --query "value[?properties.trigger == null].{name:name, summary:properties.summary, description:properties.description}" -o table ``` Each MCP "tool" maps to one connector operation under one connection. 2. **For each operation, triage every parameter — including each body sub-property.** First enumerate every parameter from the Swagger: - All `parameters[]` entries (`path` / `query` / `body` / `header`). - For each `body` parameter whose schema is an object (resolve `$ref`), enumerate its `properties` and the inner `required` array. Recurse into nested objects and `items` of arrays. Then resolve dynamic markers — the four extension kinds (`x-ms-dynamic-values`, `-list`, `-tree`, `-schema`) **all apply** here, exactly like trigger setup: - `x-ms-dynamic-values` / `-list` → `dynamicInvoke` the lookup operation, **STOP** for user pick, store the `value-path` value. - `x-ms-dynamic-tree` → walk the tree (root → children), **STOP** at each level, store the final opaque token. - `x-ms-dynamic-schema` / `-properties` → resolve schema after parents are picked. Bake the parents so the LLM gets a stable tool shape. - Cascading params (e.g., channel depends on team): always resolve parents first; pass their `value` (not display name) to child lookups. **STOP and ask the user, for every parameter (and every required body sub-property)**, whether it should be: | Choice | What it means | |---|---| | **`userParameter`** | Bake a fixed value now (`{name, value}`). LLM cannot change it. Use this for enumerable connector IDs (team/channel/site/list/folder/file/db/table) and for org-default fields. | | **`agentParameter`** | LLM supplies on each call (`{name, schema}`). Use this for free-form content (subject/body/recipient) and for required fields with no fixed value. | | **skip** | Only valid if the field is optional (not in the Swagger `required` array). | **Required fields cannot be skipped.** Body sub-properties are nested under one `agentParameter` whose `schema.type` is `"object"` and whose `schema.properties` mirrors the body. See [mcp-server-config.md](references/mcp-server-config.md) §"Per-parameter triage workflow" and [dynamic-values.md](references/dynamic-values.md). 3. **PUT the MCP server config.** Body shape: ```json { "properties": { "description": "...", "connectors": [ { "name": "office365", "displayName": "Office 365", "connectionName": "o365-conn", "operations": [ { "name": "Send_Email_(V2)", "displayName": "Send Email", "description": "Send an email via Office 365.", "userParameters": [ { "name": "from", "value": "alerts@contoso.com" } ], "agentParameters": [ { "name": "emailMessage", "schema": { "type": "object", "required": true, "properties": { "To": { "type": "string", "required": true }, "Subject": { "type": "string" }, "Body": { "type": "string" } } } } ] } ] } ] } } ``` PUT to: `.../connectorGateways/{namespace}/mcpServerConfigs/{name}?api-version=2026-05-01-preview` > **Always serialize with `ConvertTo-Json -Depth 20`** (or higher). The > default depth (2) silently flattens nested body schemas to the literal > string `"System.Collections.Hashtable"`. GET the config after the PUT and > verify the nested properties are real objects. 4. **GET the config** and return `properties.mcpEndpointUrl` — that's the URL the MCP client points at. See [mcp-server-config.md](references/mcp-server-config.md) for the auth-mode + access-policy details. --- ### Step 4C: Direct API call via `dynamicInvoke` → **Full details:** [direct-api.md](references/direct-api.md) | **Dynamic params:** [dynamic-values.md](references/dynamic-values.md) 1. Get the connector Swagger (`managedApis/{connector}?export=true`) → operationId → path table 2. Resolve any `x-ms-dynamic-*` parameters with [dynamic-values.md](references/dynamic-values.md). **STOP at every dynamic param.** 3. POST to `dynamicInvoke` with the resolved `method` + `path` (+ optional `queries`, `body`, non-`Content-*` headers). --- ### Final verification checklist **For trigger configs (path A):** - ✅ Namespace exists; for `ManagedServiceIdentity` callback auth, namespace has the requested identity - ✅ For connector-event triggers: connection `Connected`, `namespace-acl` exists on the connection - ✅ Trigger `properties.state` is `Enabled` - ✅ User-provided callback URL is reachable + accepts the chosen auth **For MCP server configs (path B):** - ✅ All referenced connections are `Connected` - ✅ `properties.mcpEndpointUrl` is populated in the GET response - ✅ For Hosted MCP servers with `AuthenticationMode != NotSpecified`: `resourceAuth` is set (see [mcp-server-config.md](references/mcp-server-config.md)) - ✅ Access policies on the MCP server config grant the consuming clients access **For direct API (path C):** - ✅ Connection `Connected` - ✅ `dynamicInvoke` returns `response.statusCode` in 2xx ## Quick reference ```bash # ARM base: https://management.azure.com/subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/connectorGateways # API ver: api-version=2026-05-01-preview # Namespace az rest --method GET --url ".../connectorGateways/{namespace}?api-version=2026-05-01-preview" # Connections az rest --method GET --url ".../connectorGateways/{namespace}/connections?api-version=2026-05-01-preview" # List trigger operations + summaries az rest --method GET --url ".../locations/{location}/managedApis/{connector}/apiOperations?api-version=2016-06-01" # Get Swagger (paths, parameters, x-ms-dynamic-*) az rest --method GET --url ".../locations/{location}/managedApis/{connector}" --url-parameters "api-version=2016-06-01" "export=true" # Dynamic invoke az rest --method POST --url ".../connectorGateways/{namespace}/connections/{conn}/dynamicInvoke?api-version=2026-05-01-preview" --body '{"request":{"method":"GET","path":"/..."}}' # Trigger configs az rest --method GET --url ".../connectorGateways/{namespace}/triggerConfigs?api-version=2026-05-01-preview" az rest --method POST --url ".../connectorGateways/{namespace}/triggerConfigs/{name}/disable?api-version=2026-05-01-preview" az rest --method POST --url ".../connectorGateways/{namespace}/triggerConfigs/{name}/enable?api-version=2026-05-01-preview" # MCP server configs az rest --method GET --url ".../connectorGateways/{namespace}/mcpServerConfigs?api-version=2026-05-01-preview" az rest --method GET --url ".../connectorGateways/{namespace}/mcpServerConfigs/{name}?api-version=2026-05-01-preview" --query "properties.mcpEndpointUrl" -o tsv ``` ## References - [prerequisites.md](references/prerequisites.md) — required tooling and Azure setup - [quickstart.md](references/quickstart.md) — minimal commands to list everything - [connections.md](references/connections.md) — connection CRUD + ACLs - [consent.md](references/consent.md) — OAuth consent link generation (exact body format) - [dynamic-values.md](references/dynamic-values.md) — `x-ms-dynamic-{values,list,tree,schema}` resolution algorithms - [trigger-setup.md](references/trigger-setup.md) — trigger config creation (all source types, all auth types) - [notification-authentication.md](references/notification-authentication.md) — callback authentication reference - [mcp-server-config.md](references/mcp-server-config.md) — MCP server config CRUD - [direct-api.md](references/direct-api.md) — `dynamicInvoke` recipes - [trigger-flow.md](references/trigger-flow.md) — end-to-end architecture diagram - [tutorial.md](references/tutorial.md) — walkthrough: recurrence trigger → user webhook - [gotchas.md](references/gotchas.md) — common issues