Skip to content

Repository files navigation

MCS Proxy A2A Server

💡 The Problem: You're using an agent that speaks A2A. It can talk to cloud-based agents, OpenAI agents, LangGraph agents, homegrown agents, ERP agents... but it can't talk to Copilot Studio (yet). This proxy fixes that.


🎭 The Scenario: A2A Agent Wants to Talk to Copilot Studio

Here's the situation:

A user is working with an agent that has A2A capabilities. That agent can communicate with:

  • Cloud-based agents (A2A)
  • OpenAI-based agents (A2A)
  • LangGraph agents (A2A)
  • Homegrown agents (A2A)
  • ERP agents (A2A)
  • Any other agent speaking A2A
  • Copilot Studio agents (Direct-to-Engine only)

The Problem: Copilot Studio doesn't speak A2A yet, so it's excluded from the agent ecosystem.

Why it matters: Your Copilot Studio agent has all your company's Power Platform, Dynamics, and Dataverse integrations. It's incredibly valuable, but your A2A agent can't talk to it. That's frustrating.

Without This Proxy

    ┌──────────────────┐
    │      User        │
    └────────┬─────────┘
             │
             ▼
    ┌──────────────────┐
    │   Your Agent     │
    │     (A2A)        │
    └────────┬─────────┘
             │
             │ A2A Protocol (bidirectional)
             │
    ┌────────┼────────┬──────────┬───────────┐
    │        │        │          │           │
    ▼        ▼        ▼          ▼           ▼
┌───────┐ ┌──────┐ ┌────────┐ ┌─────────┐ ┌─────┐
│ Cloud │ │OpenAI│ │LangGraph│ │Homegrown│ │ ERP │
│ Agent │ │Agent │ │ Agent  │ │  Agent  │ │Agent│
│ (A2A) │ │(A2A) │ │  (A2A) │ │  (A2A)  │ │(A2A)│
└───┬───┘ └──┬───┘ └────┬───┘ └────┬────┘ └──┬──┘
    │        │          │          │          │
    └────────┴──────────┴──────────┴──────────┘
                         ▲
                         │
            ✅ Bidirectional A2A communication


     ❌  But it CAN'T talk to Copilot Studio!

                    ┌────────────────┐
                    │ Copilot Studio │
                    │  (Direct-to-   │
                    │   Engine only) │
                    │                │
                    │ + Power        │
                    │ + Dynamics     │
                    │ + Dataverse    │
                    └────────────────┘

With This Proxy 🎉

    ┌──────────────────┐
    │      User        │
    └────────┬─────────┘
             │
             ▼
    ┌──────────────────┐
    │   Your Agent     │
    │     (A2A)        │
    └────────┬─────────┘
             │
             │ A2A Protocol (bidirectional)
             │
    ┌────────┼────────┬──────────┬───────────┬─────────────┐
    │        │        │          │           │             │
    ▼        ▼        ▼          ▼           ▼             ▼
┌───────┐ ┌──────┐ ┌────────┐ ┌─────────┐ ┌─────┐  ┌──────────────┐
│ Cloud │ │OpenAI│ │LangGraph│ │Homegrown│ │ ERP │  │ 🌉 A2A Proxy │
│ Agent │ │Agent │ │ Agent  │ │  Agent  │ │Agent│  │              │
│ (A2A) │ │(A2A) │ │  (A2A) │ │  (A2A)  │ │(A2A)│  │  (Protocol   │
└───┬───┘ └──┬───┘ └────┬───┘ └────┬────┘ └──┬──┘  │  Translator) │
    │        │          │          │          │     └──────┬───────┘
    └────────┴──────────┴──────────┴──────────┘            │
                         ▲                                  │
                         │                                  │ Agent SDK
            ✅ Bidirectional A2A communication               │ (Direct-to-Engine)
                                                            │ + OBO Token Exchange
                                                            │
                                                            ▼
                                                   ┌────────────────┐
                                                   │ Copilot Studio │
                                                   │  + Power       │
                                                   │  + Dynamics    │
                                                   │  + Dataverse   │
                                                   └────────────────┘

✅ Your agent can now communicate bidirectionally with ALL agents including Copilot Studio
✅ Protocol translation happens seamlessly
✅ User identity preserved through OBO token exchange

What This Enables

  • Universal Agent Communication: Your A2A agent can finally talk to Copilot Studio
  • Protocol Translation: A2A ↔ Direct-to-Engine conversion handled automatically
  • User Identity Preservation: OBO flow ensures proper authentication and permissions
  • No Rewrites: Keep your Copilot Studio investments, just add A2A capability
  • Future-Proof: When Copilot Studio adds native A2A, swap proxy for direct connection

⚠️ Important Note

This is a thought exercise and educational implementation. It demonstrates:

  • How A2A protocol integration works
  • OAuth 2.0 On-Behalf-Of authentication patterns
  • Protocol translation architectures

For production use, consider:

  • Microsoft's official A2A support roadmap for Copilot Studio
  • Enterprise-grade load balancing and state management (Redis)
  • Comprehensive monitoring and error handling
  • Security reviews and compliance requirements

This proxy is inspirational - showing what's possible when different AI platforms need to collaborate. Use it to learn, experiment, and prototype your agent orchestration dreams!


🎓 Educational Value

An Agent-to-Agent (A2A) proxy server that forwards requests to Microsoft Copilot Studio agents using OAuth 2.0 On-Behalf-Of (OBO) authentication.

What you'll learn:

  • A2A protocol implementation and design patterns
  • OBO authentication flows and token management
  • Protocol translation and middleware architecture
  • Multi-agent orchestration concepts

🌟 Overview

This proxy server bridges the gap between standard A2A clients and Microsoft Copilot Studio's Direct-to-Engine API, handling the complexity of token exchange and protocol translation.

What It Does

A2A Client  →  [This Proxy]  →  Copilot Studio Agent
   (JWT)         (Validates)         (Responds)
                 (OBO Exchange)
                 (Translates)

Key Features:

  • A2A Protocol Support: Standard JSON-RPC 2.0 interface
  • Azure AD Authentication: JWT token validation with JWKS
  • OBO Token Exchange: Seamless user identity preservation
  • Conversation Management: Context-aware multi-turn conversations
  • Comprehensive Testing: Full test suite with multi-turn and concurrent scenarios

🚀 Quick Start

Prerequisites

  • Python 3.11+
  • Azure AD tenant with app registration
  • Copilot Studio agent (published)
  • Azure CLI (for testing)

Installation

# Clone or download this project
cd mcs_proxy_a2a_server

# Install dependencies (using uv)
pip install uv
uv sync

# Configure environment
cp .env.example .env
# Edit .env with your Azure AD and Copilot Studio credentials

Configuration

Edit .env:

# Azure AD
AZURE_AD_TENANT_ID=your-tenant-id
AZURE_AD_CLIENT_ID=your-app-id
AZURE_AD_CLIENT_SECRET=your-client-secret
AZURE_AD_AUDIENCE=api://your-app-id
AZURE_AD_ISSUER=https://sts.windows.net/your-tenant-id/

# Copilot Studio
COPILOT_ENVIRONMENT_ID=your-environment-guid
COPILOT_AGENT_IDENTIFIER=your-agent-schema-name

# Server
PORT=2009
LOG_LEVEL=DEBUG
AUTH_MODE=microsoft
BASE_URL=http://localhost:2009

Setup Azure AD Permissions

# Run automated setup
./setup_consent.sh

# Or manually in Azure Portal:
# 1. Go to App registrations → Your app → API permissions
# 2. Add Power Platform API (8578e004-a5c6-46e7-913e-12f58912df43)
# 3. Add delegated permission: user_impersonation
# 4. Grant admin consent

Start the Server

# Run directly
uv run python3 proxy.py

# Or in background with logs
uv run python3 proxy.py > /tmp/proxy.log 2>&1 &

Test It

# Check health
curl http://localhost:2009/health

# Run all tests (recommended)
./run_all_tests.sh

# Or run individual test suites:
./test_after_consent.sh       # Basic functionality
./test_multi_turn.sh           # Multi-turn conversations
./test_concurrent.sh           # Concurrent requests
./test_inspector_setup.sh      # Inspector setup

📚 Documentation

Comprehensive guides for learning and implementation:

Document Purpose
ARCHITECTURE.md Technical architecture and design decisions
INTEGRATION_GUIDE.md How to integrate clients (Python, Node.js, C#, bash)
DEPLOYMENT_GUIDE.md Deployment options and Azure AD setup
TESTING_RESULTS.md Complete testing report and findings

🏗️ Architecture

High-Level Flow

┌─────────────┐         ┌──────────────┐         ┌──────────────────┐
│             │  HTTP   │              │  OBO    │                  │
│  A2A Client ├────────►│  MCS Proxy   ├────────►│  Azure AD        │
│             │  +JWT   │  (This app)  │ Token   │                  │
└─────────────┘         └──────┬───────┘ Exchange└──────────────────┘
                               │
                               │ HTTP + MCS Token
                               ▼
                        ┌──────────────────┐
                        │ Copilot Studio   │
                        │ Agent            │
                        └──────────────────┘

Key Components

  1. Authentication Middleware - Validates Azure AD JWTs
  2. A2A Server - Implements JSON-RPC 2.0 protocol
  3. MCS Proxy Executor - Handles OBO exchange and Copilot Studio communication
  4. State Manager - Maps A2A contextId to Copilot Studio conversationId

See ARCHITECTURE.md for detailed diagrams and explanations.


🔐 Security

Authentication Flow

  1. User authenticates with Azure AD → receives JWT token
  2. Client sends request to proxy with JWT (audience: proxy API)
  3. Proxy validates JWT using JWKS from Azure AD
  4. Proxy exchanges token (OBO) for Copilot Studio-scoped JWT
  5. Proxy calls Copilot Studio with MCS token
  6. User identity preserved throughout the flow

Security Features

  • ✅ JWT signature verification (RS256)
  • ✅ Token expiration validation
  • ✅ Audience and issuer verification
  • ✅ HTTPS enforced in production
  • ✅ No token persistence (security by design)
  • ✅ Request/response logging for audit

See ARCHITECTURE.md#security-analysis for threat model.


🧪 Testing

Automated Test Suites

Basic Validation:

./test_after_consent.sh
  • Health check
  • Authentication
  • Agent card retrieval
  • Message send (OBO flow)
  • Copilot Studio integration

Multi-turn Conversations:

./test_multi_turn.sh
  • Context persistence
  • Conversation memory
  • Context isolation

Concurrent Requests:

./test_concurrent.sh 10
  • Parallel request handling
  • Race condition detection
  • Performance metrics

Test Results

Latest Test (2026-01-16):

  • ✅ All authentication flows: PASS
  • ✅ OBO token exchange: PASS
  • ✅ Copilot Studio integration: PASS
  • ✅ Multi-turn conversations: PASS
  • ✅ Concurrent requests (5 parallel): 100% success rate
  • ✅ Average response time: 7.5 seconds

See TESTING_RESULTS.md for complete test report.


📊 Performance

Latency Breakdown

Component Time Notes
JWT Validation ~50ms JWKS cached after first request
OBO Token Exchange ~400ms Azure AD API call
Copilot Studio ~7000ms Agent processing time
Response Parsing ~50ms JSON conversion
Total ~7.5s Dominated by Copilot Studio

Scalability

Current Setup:

  • Single process, in-memory state
  • Good for: 10-100 concurrent users
  • ~10,000 active conversations in memory

Production Scaling:

  • Add Redis for shared state
  • Deploy multiple instances behind load balancer
  • Implement token caching (~50% latency reduction)

See ARCHITECTURE.md#performance-characteristics for details.


🔌 Client Integration

Quick Example (Python)

import requests

# Get token
token = "your-azure-ad-jwt-token"

# Send message
response = requests.post(
    "http://localhost:2009/",
    headers={"Authorization": f"Bearer {token}"},
    json={
        "jsonrpc": "2.0",
        "id": "msg-1",
        "method": "message/send",
        "params": {
            "contextId": "my-conversation",
            "message": {
                "messageId": "msg-1",
                "role": "user",
                "parts": [{"type": "text", "text": "Hello!"}]
            }
        }
    }
)

print(response.json())

More Examples

See INTEGRATION_GUIDE.md for complete examples in:

  • Python (with class wrapper)
  • Node.js/TypeScript
  • C# / .NET
  • Bash/cURL

🚢 Deployment

Local Development (Current)

# Already set up and working!
uv run python3 proxy.py

Perfect for:

  • Learning and experimentation
  • Local testing
  • Documentation and teaching

Production Options

1. Docker

docker build -t mcs-proxy .
docker run -p 2009:2009 --env-file .env mcs-proxy

2. Azure App Service

az webapp create --name mcs-proxy-app --runtime "PYTHON:3.11"
# Configure environment variables
# Deploy via GitHub Actions

3. AWS Elastic Beanstalk

eb init -p python-3.11 mcs-proxy-app
eb create mcs-proxy-env

4. Google Cloud Run

gcloud run deploy mcs-proxy --source .

See DEPLOYMENT_GUIDE.md for detailed instructions.


📖 Learning Resources

What This Project Teaches

1. A2A Protocol

  • JSON-RPC 2.0 structure
  • Task-based async patterns
  • Agent card specification
  • Event queue mechanism

2. OBO Authentication

  • When to use OBO (middle-tier services)
  • Token exchange implementation
  • User identity preservation
  • Permission consent flows

3. Azure AD Integration

  • JWT validation with JWKS
  • Token claims and scopes
  • App registration configuration
  • API permissions management

4. API Design

  • Middleware patterns
  • Error handling strategies
  • State management
  • Async/await patterns

External Resources


🛠️ Project Structure

mcs_proxy_a2a_server/
├── proxy.py                    # Main application
├── .env                        # Configuration (gitignored)
├── pyproject.toml              # Dependencies
├── uv.lock                     # Locked dependency versions
│
├── README.md                   # This file - overview and quick start
├── ARCHITECTURE.md             # Technical architecture
├── INTEGRATION_GUIDE.md        # Client integration examples
├── DEPLOYMENT_GUIDE.md         # Deployment options and Azure AD setup
├── TESTING_RESULTS.md          # Test report
│
├── run_all_tests.sh            # Run all tests (recommended)
├── setup_consent.sh            # Automated consent setup
├── test_after_consent.sh       # Basic test suite
├── test_multi_turn.sh          # Multi-turn conversation test
├── test_concurrent.sh          # Concurrent request test
└── test_inspector_setup.sh     # Inspector setup test

🤝 Contributing

This is an educational project designed for learning and reproduction.

Feel free to:

  • ✅ Use this as a learning resource
  • ✅ Adapt it for your own projects
  • ✅ Share with others learning A2A/OBO
  • ✅ Report issues or suggest improvements

When adapting:

  • Keep the educational documentation
  • Credit the original patterns
  • Share your learnings with the community

📝 License

This project is provided as-is for educational purposes.

Third-party components:

  • A2A SDK: Microsoft
  • MSAL: Microsoft
  • Copilot Studio Client: Microsoft
  • Dependencies: See pyproject.toml

🔧 Troubleshooting

Common Issues

1. "Invalid audience" error

# Solution: Check AZURE_AD_AUDIENCE matches token
# Should be: api://your-app-id (without scope suffix)

2. "OBO failed: invalid_grant"

# Solution: Grant API permission consent
./setup_consent.sh

# If that fails, try:
# 1. Clear token cache
az account clear
az login

# 2. Wait 5-10 minutes for consent to propagate

# 3. Verify consent in Azure Portal:
# Go to: App registrations → Your app → API permissions
# Look for green checkmark next to Power Platform permission

# 4. Run test again
./test_after_consent.sh

3. "Connection refused"

# Solution: Start the server
uv run python3 proxy.py

4. "Power Platform service principal not found"

# Solution: Create the service principal in your tenant
az ad sp create --id 8578e004-a5c6-46e7-913e-12f58912df43

# Then run setup script again
./setup_consent.sh

5. "Access denied" when running setup script

# You don't have admin rights. Ask your admin to run:
az ad app permission admin-consent --id YOUR_CLIENT_ID

# Or use user-level consent URL (setup script will show the URL)

6. Slow responses (7-10s)

# This is normal! Copilot Studio takes 3-8s to process
# Not a bug, just the nature of agent processing

7. A2A Inspector only shows "Task created with status: completed"

This is a known bug in the A2A Inspector UI. The proxy is working correctly.

Root Cause: The Inspector's frontend (script.ts lines 1058-1068) only displays status.state and ignores status.message.parts[0].text for task events.

Verification - The proxy IS working:

# Test with curl to see the actual response
TOKEN=$(az account get-access-token --resource api://YOUR_CLIENT_ID | jq -r .accessToken)
curl -X POST http://localhost:2009/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc":"2.0",
    "id":"1",
    "method":"message/send",
    "params":{
      "contextId":"test",
      "message":{
        "messageId":"1",
        "role":"user",
        "parts":[{"type":"text","text":"Hello"}]
      }
    }
  }' | jq '.'

# The response contains the message at:
# .result.status.message.parts[0].text

Workarounds:

  • Use curl or Postman to test (see above)
  • Build a custom A2A client
  • Use the test scripts which parse the JSON correctly

The inspector is useful for testing connectivity and authentication, but not for reading agent responses.


📊 Project Status

Status: ✅ Fully Functional & Documented (Educational/Inspirational)

Tested: January 16, 2026

Test Results:

  • ✅ Authentication: 100% pass
  • ✅ OBO Exchange: Working
  • ✅ Copilot Studio: Connected
  • ✅ Multi-turn: Working
  • ✅ Concurrent: 100% success rate

What Works:

  • ✅ Complete A2A protocol implementation
  • ✅ OBO token exchange with user identity preservation
  • ✅ Protocol translation (A2A ↔ Direct-to-Engine)
  • ✅ Comprehensive testing and documentation

For Production Deployment, Add:

  • 🔧 Redis for distributed state management
  • 📊 APM monitoring (Application Insights, Datadog, etc.)
  • 🔐 Additional security hardening and audit logging
  • 🚀 Load balancing and auto-scaling
  • 📝 Rate limiting and throttling

🎯 Use Cases

1. Learning & Education

  • Understand A2A protocol
  • Learn OBO authentication
  • Study Azure AD integration
  • Practice API design patterns

2. Development & Testing

  • Test Copilot Studio agents
  • Prototype A2A integrations
  • Validate authentication flows
  • Performance testing

3. Production Use

  • A2A client integration
  • Copilot Studio proxy
  • User identity preservation
  • Centralized authentication

💡 Key Takeaways

For Learners:

  • Complete working example of OBO pattern
  • Production-ready code structure
  • Comprehensive documentation
  • Hands-on testing tools

For Implementers:

  • Ready-to-deploy proxy server
  • Battle-tested authentication
  • Scalable architecture
  • Multiple deployment options

For Teachers:

  • Documented design decisions
  • Clear architecture diagrams
  • Practical examples
  • Troubleshooting guides

📞 Support

Documentation: See guides in this repo Issues: Check troubleshooting sections Questions: Review ARCHITECTURE.md for implementation details

For Azure AD issues: Contact your tenant administrator For Copilot Studio issues: Check Microsoft Copilot Studio docs


🌟 Acknowledgments

Built using:

  • A2A SDK by Microsoft
  • MSAL (Microsoft Authentication Library)
  • Copilot Studio Client by Microsoft
  • FastAPI/Starlette web framework
  • PyJWT for JWT validation

Documented for educational purposes with ❤️


🚀 Getting Started Checklist

  • Clone/download project
  • Install dependencies (uv sync)
  • Configure .env file
  • Run ./setup_consent.sh
  • Start server (uv run python3 proxy.py)
  • Run tests (./test_after_consent.sh)
  • Read INTEGRATION_GUIDE.md
  • Build your first client!

Ready to start? See QUICKSTART.md for the 3-step setup guide!

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages