Skip to main content
Glama
kathirt

Azure APIM + MCP Server Demo

by kathirt
README.md
# Azure APIM + MCP Server Demo

This project demonstrates how to expose backend APIs through Azure API Management (APIM) as a Model Context Protocol (MCP) Server, enabling AI assistants and tools to interact with your APIs using the standardized MCP protocol.

## πŸ—οΈ Architecture

```
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   MCP Client     │────▢│   Azure API Management  │────▢│   Azure App Service     β”‚
β”‚  (AI Assistant)  β”‚     β”‚      (Gateway)          β”‚     β”‚   (Express.js API)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        β”‚                         β”‚                              β”‚
        β”‚  MCP Protocol           β”‚  Subscription Key            β”‚  REST API
        β”‚  (JSON-RPC 2.0)         β”‚  Rate Limiting               β”‚  Products/Orders
        β”‚                         β”‚  Monitoring                  β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
```

## πŸ“¦ Components

### Backend API (`backend-api/`)
- **Express.js** application with TypeScript
- REST API endpoints for products and orders
- MCP JSON-RPC endpoint handler
- 5 MCP tools:
  - `get_products` - List all products in the catalog
  - `get_product_by_id` - Get product details by ID
  - `search_products` - Search products by query string
  - `get_orders` - List all orders
  - `create_order` - Create a new order

### Infrastructure (`infrastructure/`)
- **Bicep** templates for Azure deployment
- Azure App Service (Linux, Node.js 20 LTS, B1 Basic)
- Azure API Management (Developer SKU)
- Application Insights for monitoring
- Log Analytics workspace

## 🌐 Endpoints

| Endpoint | Description |
|----------|-------------|
| `https://apimmcp-api-dev.azurewebsites.net/` | Backend root |
| `https://apimmcp-api-dev.azurewebsites.net/api/health` | Health check |
| `https://apimmcp-api-dev.azurewebsites.net/api/products` | Products REST API |
| `https://apimmcp-api-dev.azurewebsites.net/api/orders` | Orders REST API |
| `https://apimmcp-api-dev.azurewebsites.net/api/mcp` | MCP endpoint (direct) |
| `https://apimmcp-apim-dev.azure-api.net/mcp` | **MCP endpoint (via APIM)** ⭐ |

## πŸ“‘ MCP Protocol

The server implements the Model Context Protocol (version 2024-11-05):

### Initialize
```json
{
  "jsonrpc": "2.0",
  "method": "initialize",
  "id": 1,
  "params": {
    "protocolVersion": "2024-11-05",
    "capabilities": {},
    "clientInfo": { "name": "client", "version": "1.0.0" }
  }
}
```

### List Tools
```json
{
  "jsonrpc": "2.0",
  "method": "tools/list",
  "id": 2
}
```

### Call Tool
```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": 3,
  "params": {
    "name": "get_products"
  }
}
```

### Example: Search Products
```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": 4,
  "params": {
    "name": "search_products",
    "arguments": { "query": "smart" }
  }
}
```

### Example: Create Order
```json
{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "id": 5,
  "params": {
    "name": "create_order",
    "arguments": { "productId": "prod-001", "quantity": 2 }
  }
}
```

## πŸš€ Deployment

### Prerequisites
- Azure CLI installed and logged in
- Azure subscription
- Node.js 18+ installed locally

### 1. Create Resource Group
```powershell
az group create --name apim-mcp-demo-rg --location eastus
```

### 2. Deploy Infrastructure
```powershell
az deployment group create `
  --resource-group apim-mcp-demo-rg `
  --template-file ./infrastructure/main-appservice.bicep `
  --parameters location=eastus namePrefix=apimmcp environment=dev apimPublisherEmail="your-email@example.com"
```

> ⚠️ Note: APIM provisioning takes 15-30 minutes on first deployment.

### 3. Build Backend API
```powershell
cd backend-api
npm install
npm run build
```

### 4. Deploy Backend API
```powershell
Compress-Archive -Path "dist\*", "package.json", "web.config", "node_modules" -DestinationPath "deploy.zip" -Force
az webapp deploy --resource-group apim-mcp-demo-rg --name apimmcp-api-dev --src-path deploy.zip --type zip
```

### 5. Get APIM Subscription Key
```powershell
az rest --method post `
  --uri "https://management.azure.com/subscriptions/{subscription-id}/resourceGroups/apim-mcp-demo-rg/providers/Microsoft.ApiManagement/service/apimmcp-apim-dev/subscriptions/mcp-subscription/listSecrets?api-version=2022-08-01" `
  --query "primaryKey" -o tsv
```

## πŸ§ͺ Testing

### Run Test Script
```powershell
.\test-mcp.ps1
```

### Expected Output
```
========================================
  MCP Server Test Suite
========================================

Endpoint: https://apimmcp-apim-dev.azure-api.net/mcp

1. Testing initialize...
   Server: azure-product-catalog-server v1.0.0
   Protocol: 2024-11-05

2. Testing tools/list...
   Found 5 tools:
     - get_products: Retrieve a list of all products in the catalog
     - get_product_by_id: Get details of a specific product by its ID
     ...

3. Testing tools/call (get_products)...
   Found 8 products:
     - Widget Pro: $29.99
     - Gadget Plus: $49.99
     ...
```

### Manual Testing
```powershell
$headers = @{
  "Ocp-Apim-Subscription-Key" = "YOUR_SUBSCRIPTION_KEY"
  "Content-Type" = "application/json"
}

$body = '{"jsonrpc":"2.0","method":"initialize","id":1,"params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'

Invoke-RestMethod -Uri "https://apimmcp-apim-dev.azure-api.net/mcp" -Method POST -Headers $headers -Body $body
```

## πŸ› οΈ Development

### Local Development
```powershell
cd backend-api
npm install
npm run dev
```

The server will start on `http://localhost:3000`.

### Project Structure
```
APIM-MCP/
β”œβ”€β”€ backend-api/
β”‚   β”œβ”€β”€ src/
β”‚   β”‚   β”œβ”€β”€ index.ts      # Express server entry
β”‚   β”‚   β”œβ”€β”€ routes.ts     # REST API routes
β”‚   β”‚   β”œβ”€β”€ mcp.ts        # MCP endpoint handler
β”‚   β”‚   └── data.ts       # Mock data store
β”‚   β”œβ”€β”€ dist/             # Compiled JavaScript
β”‚   β”œβ”€β”€ package.json
β”‚   β”œβ”€β”€ tsconfig.json
β”‚   └── web.config        # IIS configuration for Azure
β”œβ”€β”€ infrastructure/
β”‚   └── main-appservice.bicep   # Azure resources
β”œβ”€β”€ test-mcp.ps1          # Test script
└── README.md
```

## πŸ”§ Configuration

### APIM Settings
- **Subscription Required**: Yes
- **Rate Limiting**: Configurable via APIM policies
- **Authentication**: Subscription key header (`Ocp-Apim-Subscription-Key`)

### App Service Settings
- **SKU**: B1 Basic (Linux)
- **Node Version**: 20 LTS
- **Startup Command**: `node index.js`

## πŸ“Š Monitoring

- Application Insights integrated with both App Service and APIM
- Access logs in Log Analytics workspace
- Health endpoint available at `/api/health`

## πŸ”— Resources

- [Model Context Protocol Specification](https://modelcontextprotocol.io/)
- [Azure API Management Documentation](https://learn.microsoft.com/azure/api-management/)
- [Azure App Service Documentation](https://learn.microsoft.com/azure/app-service/)

## πŸ“„ License

MIT