Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
- Prefer file-scoped changes over project-wide modifications when possible
- Always review your own code for consistency, maintainability, and testability
- Always ask for clarifications if the request is ambiguous or lacks sufficient context
- Write transport-agnostic commands that work in both stdio and HTTP modes
- Keep commands stateless and thread-safe for multi-user remote scenarios
- Test commands with different RBAC permissions for OBO scenarios

## Don't
- Use `subscriptionId` parameter name
Expand All @@ -41,6 +44,11 @@
- Skip error handling or comprehensive tests
- Use dashes in command group names (use concatenated lowercase)
- Make project-wide changes when file-scoped changes suffice
- Check transport type in commands (stdio vs HTTP)
- Store per-request state in command instance fields
- Access HttpContext directly from commands
- Make transport-specific decisions in command logic
- Assume single-user scenarios when implementing services

## Commands

Expand Down Expand Up @@ -593,6 +601,63 @@ All new toolsets must be AOT-compatible or excluded from native builds:
- Implement `BaseAzureResourceService` for efficient Resource Graph queries
- Follow retry policy patterns with `RetryPolicyOptions`

## Remote MCP Server Architecture

Azure MCP Server supports **stdio** (local) and **HTTP** (remote) transports with different authentication models.

### Key Differences: Stdio vs Remote HTTP

| Aspect | Stdio Mode | Remote HTTP Mode |
|--------|-----------|------------------|
| **Concurrency** | Single user | Multiple concurrent users |
| **State Management** | Can use instance fields | Must be stateless |
| **Deployment** | Local binaries | Cloud hosting (App Service, AKS) |
| **Configuration** | Simple (no auth) | Requires Entra ID app registration |

### Authentication Strategies

**On-Behalf-Of (OBO) Flow:**
- Per-user authorization with audit trails
- User's RBAC permissions enforced
- Requires API permissions and admin consent
- Command: `--run-as-remote-http-service --outgoing-auth-strategy UseOnBehalfOf`

**Hosting Environment Identity:**
- Service-level permissions using Managed Identity
- Simpler configuration, no token exchange overhead
- All users share server's permissions
- Command: `--run-as-remote-http-service --outgoing-auth-strategy UseHostingEnvironmentIdentity`

### Command Implementation for Remote Mode

**Critical Requirements:**
- Write transport-agnostic commands (work in both stdio and HTTP modes)
- Use `IAzureTokenCredentialProvider` for all Azure authentication
- Keep commands stateless and thread-safe (no instance field state)
- Test with different RBAC permissions for OBO scenarios
- Provide context-aware error messages for remote scenarios

**Key Patterns:**
```csharp
// ✅ Correct: Authentication provider handles both modes
var credential = await GetCredentialAsync(null, CancellationToken.None);
var armClient = new ArmClient(credential);

// ❌ Wrong: Don't check transport type or access HttpContext
if (Environment.GetEnvironmentVariable("ASPNETCORE_URLS") != null) { }
var httpContext = _httpContextAccessor.HttpContext;
```

### Security Best Practices

1. Always use HTTPS in production
2. Implement least privilege RBAC
3. Use OBO for multi-tenant scenarios (preserves user identity)
4. Secure configuration secrets with Azure Key Vault
5. Enable Application Insights for monitoring
6. Validate token claims (audience, issuer, scopes)
7. Use Managed Identity when possible

## External MCP Server Integration

The Azure MCP Server can proxy to external MCP servers via `registry.json`:
Expand Down
83 changes: 82 additions & 1 deletion servers/Azure.Mcp.Server/TROUBLESHOOTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -823,9 +823,90 @@ On Windows, Azure CLI stores credentials in an encrypted format that cannot be a
>
> SSE was deprecated in MCP `2025-03-26` due to [security vulnerabilities and architectural limitations](https://blog.fka.dev/blog/2025-06-06-why-mcp-deprecated-sse-and-go-with-streamable-http/). Users must discontinue use of SSE transport mode and upgrade to version `0.4.0` or newer to maintain compatibility with current MCP clients.

The Azure MCP Server supports remote hosting over HTTP using the **Streamable HTTP transport protocol**. For detailed configuration and deployment guidance, see the [Remote MCP Server section in CONTRIBUTING.md](https://github.com/microsoft/mcp/blob/main/CONTRIBUTING.md#remote-mcp-server-streamable-http-transport).

### Streamable HTTP Transport

See the [contributing guide](https://github.com/microsoft/mcp/blob/main/CONTRIBUTING.md#run-the-azure-mcp-server-in-http-mode) for running the Azure MCP server with Streamable HTTP Transport.
- See the [contributing guide](https://github.com/microsoft/mcp/blob/main/CONTRIBUTING.md#run-the-azure-mcp-server-in-http-mode) for running the Azure MCP server with Streamable HTTP Transport.

### Common Issues

#### 401 Unauthorized - Invalid Token

**Causes:** Token expired, wrong audience, or missing bearer token.

**Resolution:**
1. Verify token acquisition:
```bash
az account get-access-token --resource api://<your-client-id>
```

2. Validate token claims at [jwt.ms](https://jwt.ms):
- `aud`: Must match server's ClientId
- `tid`: Must match server's TenantId
- `scp`: Must include `Mcp.Tools.ReadWrite`

#### 403 Forbidden - Insufficient Permissions

**Causes:** Missing scope/app role or user not assigned to application.

**Resolution:**
1. For delegated permissions, check scope in token:
```bash
az ad app permission admin-consent --id <client-id>
```

2. Verify user assignment in Azure Portal:
- Entra ID → Enterprise Applications → [Your App] → Users and groups

#### OBO Token Exchange Failures

**Causes:** Server app missing API permissions or client token lacks scopes.

**Resolution:**
1. Grant Azure Management API permissions:
```bash
az ad app permission add \
--id <server-client-id> \
--api https://management.azure.com/ \
--api-permissions user_impersonation=Scope

az ad app permission admin-consent --id <server-client-id>
```

2. Add `knownClientApplications` to server's app manifest:
```json
{
"knownClientApplications": ["<client-app-id>"]
}
```

#### Azure Service Access Denied

**Causes:** Missing RBAC permissions on Azure resources.

**Resolution:**

**For OBO (per-user):**
```bash
az role assignment create \
--assignee user@domain.com \
--role "Storage Blob Data Reader" \
--scope /subscriptions/<sub-id>/resourceGroups/<rg>
```

**For Hosting Environment (managed identity):**
```bash
IDENTITY_ID=$(az webapp identity show \
--name <app-name> \
--resource-group <rg> \
--query principalId -o tsv)

az role assignment create \
--assignee $IDENTITY_ID \
--role Reader \
--scope /subscriptions/<sub-id>
```

## Logging and Diagnostics

Expand Down
Loading
Loading