The Policy MCP Server is a Model Context Protocol (MCP) compliant Azure Functions application that exposes policy management capabilities as standardized MCP tools. This server enables AI models and clients to discover, list, and retrieve policy details through the MCP protocol.
- MCP Protocol Compliance - Fully implements MCP 2024-11-05 specification
- Policy Management - Manage and query policies with full metadata
- Tool Discovery - Clients can discover available tools and their schemas
- Error Handling - Robust error handling with JSON-RPC error codes
- Container-Ready - Docker support for easy deployment
- Azure Functions - Hosted on Azure Functions runtime for scalability
- .NET 10.0 SDK - Download
- Azure Functions Core Tools -
npm install -g azure-functions-core-tools@4 - Docker (optional) - For containerized deployment
- Postman (optional) - For testing API endpoints
-
Clone the repository
git clone <repository-url> cd ai-mcp-container-app
-
Navigate to the project
cd source/PolicyMcpServer -
Install dependencies
dotnet restore
Microsoft.Azure.Functions.Workerv2.51.0Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCorev2.1.0Microsoft.Azure.Functions.Worker.ApplicationInsightsv2.50.0.NET 10.0runtime
Build the project:
cd source/PolicyMcpServer
dotnet buildRun the server locally:
func startThe server will start at: http://localhost:7071
Build Docker image:
docker build -t policy-mcp-server:latest .Run in Docker:
docker run -p 8080:80 policy-mcp-server:latestAccess at: http://localhost:8080
-
Import the collection:
- Open Postman
- Click Import → Select
Test/PolicyMCP-Postman-Collection.json
-
Set the base URL variable:
- Go to Collections tab → Policy MCP Server
- Edit
base_urlvariable (default:http://localhost:7071)
-
Run the requests in order:
- MCP Initialize
- List Available Tools
- List All Policies
- Get Policy Details
- Error Handling Test
Clients can discover the server's capabilities by fetching the manifest first:
curl -X GET http://localhost:7071/api/mcp/manifest \
-H "Content-Type: application/json"Expected Response:
{
"mcpVersion": "2024-11-05",
"name": "PolicyMcpServer",
"version": "1.0.0",
"description": "Policy Management Model Context Protocol Server",
"author": "Your Organization",
"license": "MIT",
"tools": [
{
"name": "listPolicies",
"description": "Returns a list of all policies with basic metadata.",
"inputSchema": { "type": "object", "properties": {} }
},
{
"name": "getPolicyDetails",
"description": "Returns full metadata for a single policy by ID.",
"inputSchema": {
"type": "object",
"properties": { "policyId": { "type": "string" } },
"required": ["policyId"]
}
}
],
"endpoints": {
"initialize": "/api/mcp/initialize",
"invoke": "/api/mcp/invoke",
"tools": "/api/mcp/tools",
"manifest": "/api/mcp/manifest"
}
}The manifest provides:
- Server information - Name, version, and description
- Tool definitions - All available tools with input schemas
- Endpoint information - Routes to all MCP endpoints
Clients use this manifest to discover what tools are available before calling the initialize endpoint.
curl -X POST http://localhost:7071/api/mcp/initialize \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"clientInfo": { "name": "TestClient", "version": "1.0.0" }
}
}'Expected Response:
{
"jsonrpc": "2.0",
"id": "1",
"result": {
"protocolVersion": "2024-11-05",
"capabilities": { "tools": { "listChanged": false } },
"serverInfo": { "name": "PolicyMcpServer", "version": "1.0.0" }
}
}curl -X GET http://localhost:7071/api/mcp/tools \
-H "Content-Type: application/json"Expected Response:
{
"jsonrpc": "2.0",
"id": "1",
"result": [
{
"name": "listPolicies",
"description": "Returns a list of all policies with basic metadata.",
"inputSchema": { "type": "object", "properties": {} }
},
{
"name": "getPolicyDetails",
"description": "Returns full metadata for a single policy by ID.",
"inputSchema": {
"type": "object",
"properties": {
"policyId": { "type": "string", "description": "The ID of the policy" }
},
"required": ["policyId"]
}
}
]
}curl -X POST http://localhost:7071/api/mcp/invoke \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "2",
"method": "tools/call",
"params": { "name": "listPolicies", "arguments": {} }
}'Expected Response:
{
"jsonrpc": "2.0",
"id": "2",
"result": {
"type": "text",
"text": "[{\"Id\":\"POL-001\",\"Name\":\"Data Retention Policy\",\"Status\":\"Active\",\"Owner\":\"Compliance\",\"LastReviewed\":\"2025-01-10T00:00:00\"},{\"Id\":\"POL-002\",\"Name\":\"Access Control Policy\",\"Status\":\"Draft\",\"Owner\":\"Security\",\"LastReviewed\":\"2025-02-01T00:00:00\"},{\"Id\":\"POL-003\",\"Name\":\"Incident Response Policy\",\"Status\":\"Active\",\"Owner\":\"CyberOps\",\"LastReviewed\":\"2024-12-15T00:00:00\"}]",
"isError": false
}
}curl -X POST http://localhost:7071/api/mcp/invoke \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "3",
"method": "tools/call",
"params": {
"name": "getPolicyDetails",
"arguments": { "policyId": "POL-001" }
}
}'Expected Response:
{
"jsonrpc": "2.0",
"id": "3",
"result": {
"type": "text",
"text": "{\"Id\":\"POL-001\",\"Name\":\"Data Retention Policy\",\"Status\":\"Active\",\"Owner\":\"Compliance\",\"LastReviewed\":\"2025-01-10T00:00:00\"}",
"isError": false
}
}curl -X POST http://localhost:7071/api/mcp/invoke \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "4",
"method": "tools/call",
"params": {
"name": "getPolicyDetails",
"arguments": { "policyId": "POL-999" }
}
}'Expected Response (Error):
{
"jsonrpc": "2.0",
"id": "4",
"result": {
"type": "text",
"text": "Policy with ID 'POL-999' not found",
"isError": true
}
}| Endpoint | Method | Purpose | Route |
|---|---|---|---|
| Get Manifest | GET | Discover server capabilities and tools | /api/mcp/manifest |
| Initialize | POST | Initialize MCP connection | /api/mcp/initialize |
| List Tools | GET | List all available tools | /api/mcp/tools |
| Invoke Tool | POST | Call a tool | /api/mcp/invoke |
The server includes pre-loaded test policies:
| ID | Name | Status | Owner |
|---|---|---|---|
| POL-001 | Data Retention Policy | Active | Compliance |
| POL-002 | Access Control Policy | Draft | Security |
| POL-003 | Incident Response Policy | Active | CyberOps |
PolicyMcpServer/
├── Models/
│ ├── Policy.cs # Policy domain model
│ ├── ToolPolicy.cs # Tool authorization model
│ ├── ToolConstraints.cs # Tool constraint model
│ ├── ToolLogging.cs # Tool logging configuration
│ └── MCPProtocol/ # MCP Protocol models
│ ├── MCPRequest.cs
│ ├── MCPResponse.cs
│ ├── MCPManifest.cs # Server manifest model
│ ├── InitializeParams.cs
│ └── ToolDefinition.cs
├── Services/
│ ├── IMcpService.cs # MCP service interface
│ └── McpService.cs # Tool registration & invocation
├── Functions/
│ ├── GetPolicyDetails.cs # Legacy HTTP endpoint
│ ├── ListPolicies.cs # Legacy HTTP endpoint
│ └── MCP/
│ ├── InitializeMcp.cs # MCP initialize endpoint
│ ├── InvokeTool.cs # MCP invoke endpoint
│ ├── ListTools.cs # MCP list tools endpoint
│ └── GetManifest.cs # MCP manifest discovery endpoint
├── Program.cs # Application startup
├── Dockerfile # Docker configuration
├── local.settings.json # Local development settings
└── host.json # Azure Functions configuration
az acr build --registry <your-registry> --image policy-mcp-server:latest .
az container create \
--resource-group <your-rg> \
--name policy-mcp-server \
--image <your-registry>.azurecr.io/policy-mcp-server:latest \
--ports 80 \
--environment-variables AZURE_HTTP_USER_AGENT="policy-mcp-server/1.0"func azure functionapp publish <your-function-app-name>We welcome contributions! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow C# naming conventions
- Add XML documentation comments
- Include unit tests for new features
- Update README for significant changes