Lab 10: Connect Declarative Agent to OAuth-Protected MCP Server
Key concepts before you build
In this lab, you'll run an OAuth 2.0 protected Model Context Protocol (MCP) server for Zava Insurance's claims system and integrate it with a Declarative Agent in Microsoft 365 Copilot. While Lab 08 demonstrates an anonymous MCP server, this lab adds Microsoft Entra ID authentication for secure, enterprise-grade access to claims data.
Scenario
Exercise 1: Set Up Your Development Environment
In this exercise, you'll clone Zava's authenticated MCP server codebase and set up your local development environment.
Step 1: Clone the Repository
Open your terminal and run:
git clone https://github.com/microsoft/copilot-camp.git
cd copilot-camp/src/extend-m365-copilot/path-e-lab10-mcp-auth/zava-mcp-server
Step 2: Install Dependencies
Install all required packages:
npm install
This installs key dependencies.
Step 3: Examine the Project Structure
Open the project in VS Code:
code .
Key directories:
src/- TypeScript source codesrc/auth/- OAuth authentication module (new in this lab)data/- Sample JSON data files
The src/auth/oauth.ts file contains the OAuth 2.0 implementation for token validation and protected resource metadata.
Your codebase is now ready with sample data and authentication support.
Exercise 2: Create Microsoft Entra ID App Registration
Before running the authenticated MCP server, you need to register an application in Microsoft Entra ID to handle OAuth 2.0 authentication.
Step 1: Create App Registration
- Go to Azure Portal → Microsoft Entra ID → App registrations
- Click New registration
- Configure:
- Name:
Zava Claims MCP Server - Supported account types:
Accounts in any organizational directory (Any Microsoft Entra ID tenant - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox) - Redirect URI: Leave blank for now (we'll configure this in the next step)
- Click Register
- Copy the Application (client) ID - you'll need this later
Step 2: Configure Platform Redirect URIs
After registration, configure redirect URIs for different platforms. Redirect URIs are critical in OAuth 2.0 authentication—they specify where Microsoft Entra ID sends the user (along with authorization tokens) after successful authentication. Each redirect URI must exactly match a URL your application uses to receive these tokens, ensuring that authorization codes and tokens are only sent to legitimate, registered endpoints.
-
Go to Authentication in the left navigation
-
Add the first Web redirect URI:
- Click Add a platform (or if using the new preview UI, click Add redirect URI)
- Select Web
- Add the first redirect URI:
https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect -
Click Configure
-
Add additional redirect URIs:
- After the initial configuration, click Add URI (or Edit in the preview UI) to add more redirect URIs
- Add:
https://vscode.dev/redirect -
Click Save
-
Add the localhost redirect URI via Manifest:
Important: Non-HTTPS URIs require manual configuration
The Azure Portal UI only supports adding redirect URIs that use HTTPS or
localhost. Since MCP Inspector useshttp://127.0.0.1:33418(notlocalhost), you must add this URI manually through the app manifest. -
Go to Manifest in the left navigation
- Find the
"web"section and"redirectUris" - Add
http://127.0.0.1:33418to the redirect URIs array. The section should look similar to:"web": { "redirectUris": [ "https://teams.microsoft.com/api/platform/v1.0/oAuthRedirect", "https://vscode.dev/redirect", "http://127.0.0.1:33418" ], ... } -
Click Save at the top of the page
-
Verify your configuration:
- Go back to Authentication
- Under Platform configurations → Web, confirm all three redirect URIs are listed:
https://teams.microsoft.com/api/platform/v1.0/oAuthRedirecthttps://vscode.dev/redirecthttp://127.0.0.1:33418
- Under Implicit grant and hybrid flows, ensure both options remain unchecked (disabled)
Step 3: Create Client Secret
- Go to Certificates & secrets → Client secrets
- Click New client secret
- Add description (e.g.,
zava-mcp-secret) and select expiration (recommended: 24 months) - Click Add
- Copy the secret value immediately - it won't be shown again!
Step 4: Expose an API
- Go to Expose an API
- Click Add next to Application ID URI and accept the default format:
api://your-client-id - Click Add a scope and configure:
- Scope name:
access_as_user - Who can consent: Admins and users
- Admin consent display name:
Access Zava Claims System - Admin consent description:
Allows the app to access Zava Claims data on behalf of the signed-in user - User consent display name:
Access Zava Claims System - User consent description:
Allows this app to access your Zava Claims data on your behalf - State: Enabled
- Click Add scope
Your Microsoft Entra ID app registration is now complete!
Exercise 3: Configure Environment and Start Local Database
In this exercise, you'll configure the OAuth environment variables and start the local database.
Step 1: Set Up Public Access with Dev Tunnel
Copilot and OAuth clients need a public HTTPS address to reach your local MCP server. Create that endpoint first using VS Code Dev Tunnel.
1: Forward port 3001
- In VS Code's terminal panel, select the Ports tab.
- Click Forward a Port and enter port
3001.
2: Make it public
- Right-click the forwarded port address and select Port Visibility → Public.
- Copy the tunnel URL (for example:
https://abc123def456.use.devtunnels.ms).
Save this URL. You'll use it in the next step for environment configuration.
Step 2: Configure Environment Variables
Create a new .env file in the root of the zava-mcp-server directory (at the same level as package.json, not inside the src folder):
Important: File location matters
The .env file must be created in the project root directory. If you create it inside the src folder or elsewhere, the environment variables will not be loaded correctly.
# OAuth Configuration (Required for authentication)
OAUTH_CLIENT_ID=<your-application-client-id>
OAUTH_CLIENT_SECRET=<your-client-secret-value>
OAUTH_AUTHORITY=https://login.microsoftonline.com/common
OAUTH_REDIRECT_URI=http://localhost:6274/oauth/callback/debug
OAUTH_SCOPES=api://<your-application-client-id>/access_as_user
# Resource Identifier (for MCP Inspector and RFC 9728 metadata)
RESOURCE_IDENTIFIER=<your-tunnel-url>
# CORS Configuration
ADDITIONAL_ALLOWED_ORIGINS=<your-tunnel-url>,http://localhost:6274
SERVER_BASE_URL=<your-tunnel-url>
# Server Configuration
PORT=3001
HOST=127.0.0.1
NODE_ENV=development
# Storage Configuration
AZURE_STORAGE_CONNECTION_STRING="DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;TableEndpoint=http://127.0.0.1:10002/devstoreaccount1;"
Replace the placeholders:
<your-application-client-id>- Application (client) ID from Entra ID app registration<your-client-secret-value>- Client secret value you copied<your-tunnel-url>- Dev tunnel URL from Step 1 (e.g.,https://abc123def456.use.devtunnels.ms)
Step 3: Start Azure Storage Emulator
In Terminal 1, start the Azurite emulator:
npm run start:azurite
You should see:
Azurite Blob service is starting at http://127.0.0.1:10000
Azurite Queue service is starting at http://127.0.0.1:10001
Azurite Table service is starting at http://127.0.0.1:10002
Keep this terminal running - it's your local database server.
Step 4: Load Sample Claims Data
In Terminal 2, initialize Zava's sample data:
npm run init-data
This loads realistic data including:
- Claims - Storm damage, water damage, fire damage cases
- Contractors - Roofing specialists, water restoration, general contractors
- Inspections - Scheduled and completed inspection tasks
- Inspectors - Available field inspectors with specialties
You should see confirmation messages for all tables being initialized.
Exercise 4: Launch the OAuth-Protected MCP Server
Now you'll start Zava's authenticated MCP server that validates OAuth tokens before allowing access.
Step 1: Build and Start the MCP Server
In Terminal 2 (keeping Azurite running in Terminal 1):
npm run build
npm run start:mcp-http
You should see a message indicating OAuth is enabled:
🚀 Zava Claims MCP HTTP Server started on 127.0.0.1:3001
Security: OAuth 2.0 authentication enabled
...
🔍 Protected Resource Metadata Endpoints (RFC 9728):
GET /.well-known/oauth-authorization-server - Standard OAuth metadata
...
Step 2: Verify OAuth is Enabled
Open a browser and visit:
http://127.0.0.1:3001/health
You should see a JSON response confirming OAuth is enabled:
{
"status": "healthy",
"timestamp": "2025-01-21T10:00:00.000Z",
"service": "zava-claims-mcp-server",
"authentication": "OAuth enabled"
}
Notice the "authentication": "OAuth enabled" - this confirms the server is running in authenticated mode.
Step 3: Test OAuth Discovery Endpoint
Visit the OAuth discovery endpoint:
http://127.0.0.1:3001/.well-known/oauth-authorization-server
You should see OAuth metadata including:
issuer- Your server's base URLauthorization_endpoint- Microsoft login URLtoken_endpoint- Token exchange URLscopes_supported- Available OAuth scopes
This RFC 9728 compliant endpoint allows MCP clients to discover authentication requirements.
Step 4: Verify Authentication is Required
Try accessing the MCP tools without authentication:
curl -X POST "http://127.0.0.1:3001/mcp/tools/call" \
-H "Content-Type: application/json" \
-d '{"name":"get_claims","arguments":{}}'
You should receive a 401 Unauthorized response with a WWW-Authenticate header:
{
"error": "Missing Authorization header",
"description": "Please include Bearer token in Authorization header",
"auth_url": "https://your-tunnel-url/oauth/authorize",
"resource_metadata_url": "https://your-tunnel-url/.well-known/oauth-authorization-server"
}
This confirms that authentication is working correctly.
Exercise 5: Create a New Declarative Agent Project
In this exercise, you'll use the Microsoft 365 Agents Toolkit to create a new Declarative Agent project that connects to Zava's authenticated claims system.
Step 1: Create New Agent using Microsoft 365 Agents Toolkit
- Open a new window in VS Code
- Click the Microsoft 365 Agents Toolkit icon in the Activity Bar (left sidebar)
- Sign in with your Microsoft 365 developer account if prompted
- In the Agents Toolkit panel, click Create a New Agent/App
- Select Declarative Agent from the template options
- Choose Add an Action to add to your agent
- Select Start with an MCP server
- Enter the publicly accessible MCP Server URL from Exercise 3 (your tunnel URL +
/mcp/messages) - Choose the default folder to scaffold the agent (or choose a preferred location)
- When prompted for project details, enter:
- Application Name:
Zava Claims Assistant (Auth)
- Application Name:
Step 2: Configure MCP Server Authentication
You'll be directed to the newly created project with the .vscode/mcp.json file open. This is the MCP server configuration file.
- Select the Start button to fetch tools from your server
- A dialog appears indicating that your MCP Server requires authentication and doesn't support Dynamic Client Registration. You'll need to register manually
- Since you already configured your Entra ID with the redirect URIs (
https://vscode.dev/redirectandhttp://127.0.0.1:33418), select Copy URIs & Proceed - The Agents Toolkit wizard prompts for OAuth credentials. Enter the client ID and secret from your Entra ID app registration
- The toolkit asks you to authenticate with your MCP Server
- A browser opens to the Microsoft Entra ID authorization endpoint (
https://login.microsoftonline.com/...). Sign in with your Microsoft 365 account. After successful authentication, you'll be redirected tohttp://127.0.0.1:33418where you'll see the sign-in success screen. Close the browser and return to your project

Step 3: Add Tools and Provision the Agent
- The server is now started. You'll see the number of tools and prompts available
-
Select ATK: Fetch action from MCP to choose which tools to add to the agent
Don't see the ATK: Fetch action from MCP option?
If you don't see the ATK: Fetch action from MCP option, try restarting VS Code and reopening the project.
-
When prompted, select the plugin manifest file you want to update (typically
appPackage/ai-plugin.json) - Select the
get_claimstool for testing - When prompted to configure the agent in Teams Developer Portal, follow the directions
- Select Authentication Type: OAuth (with static registration). The toolkit creates your plugin manifest
- Select Provision to provision the agent to your tenant
- The wizard prompts for the client ID and secret again. Enter them as before. This is for OAuth registration with the Developer Portal - the toolkit doesn't store these credentials
- Add scope:
api://<your-client-id>/access_as_user - Select Confirm to start provisioning
Once provisioned, notice how the Developer Portal token is automatically created for the agent and appears in the .env.dev file as a variable like MCP_DA_AUTH_ID_XXXX.
OAuth registration in Developer Portal
Read more about configuring OAuth registration in Developer Portal. Here Agents Toolkit automatically configures it for your agent.
You now have a Declarative Agent connected to your OAuth-protected MCP Server.
Exercise 6: Test the Authenticated Agent Integration
Test your Declarative Agent to ensure it can successfully authenticate and communicate with the OAuth-protected MCP server.
Step 1: Ensure MCP Server is Running
Before testing, verify your MCP server from previous exercises is still running:
- Open the window where the zava-mcp-server project is running
- Verify Azurite is running:
npm run start:azurite - Verify MCP server is running:
npm run start:mcp-http - Verify the Dev Tunnel port forwarding is active
Step 2: Test in Microsoft 365 Copilot
- Open Copilot at https://m365.cloud.microsoft/chat/
- In the left sidebar under Agents, find and select Zava Claims Assistant (Auth)
- Type a prompt like: "Find all claims"
- Copilot may first ask you to confirm sending data to the plugin. Select Confirm or Allow to proceed
- The agent then prompts you to sign in before fetching data. Select Sign in

- After signing in, the agent responds with the claims information
- Check the MCP Server project's terminal - you'll see the successful authentication and tool call

CONGRATULATIONS!
Key Differences from Lab 08
| Aspect | Lab E08 (Anonymous) | Lab 10 (Authenticated) |
|---|---|---|
| Authentication | None - all endpoints public | OAuth 2.0 with Microsoft Entra ID |
| Token Validation | None | JWT validation against JWKS |
| Security Headers | None | WWW-Authenticate with metadata URLs |
| Discovery | None | RFC 9728 protected resource metadata |
| Enterprise Ready | Development only | Production-ready security |