PySide6 desktop client for exploring and using Agent 365 MCP servers through a single chat UI.
- Connects to 14 Agent 365 MCP servers (Mail, Calendar, Teams, Word, Excel, PowerPoint, OneDrive/SharePoint, Files, Knowledge, Me, Search, Dataverse, Copilot)
- Discovers tools over StreamableHTTP and routes tool calls through a local proxy
- Uses Azure OpenAI for chat and tool-calling
- Provides quick-action buttons for common Microsoft 365 tasks
- Shows discovered servers and tools in the side panel
- Python 3.13+
- uv package manager
- A365 CLI (for agent setup)
- Azure OpenAI deployment
- Frontier Preview enrollment for Agent 365 access
a365 config init # interactive wizard β creates a365.config.json
a365 develop add-mcp-servers <name> # adds MCP servers β generates ToolingManifest.json
a365 setup blueprint # creates Entra blueprint app
a365 setup permissions mcp # grants MCP OAuth2 permissionsThis creates:
- An agent blueprint app in Entra ID
- A
ToolingManifest.jsonfile that records tenant and MCP server metadata for that agent
ToolingManifest.json is not generated by this desktop app. It is produced by a365 develop add-mcp-servers and then read by this app at startup for default tenant, blueprint, endpoint, scope, and server metadata.
Entra objects used by this project:
- Agent blueprint app: created by
a365 setup blueprint; used for gateway discovery headers and agent-scoped metadata lookup - MCP desktop client app: created manually in Entra; placed in
MCP_CLIENT_ID; used for interactivedevice-codeauthentication - Tenant: comes from
MCP_TENANT_ID, or falls back toToolingManifest.jsonif omitted
The blueprint app created by a365 setup blueprint cannot do interactive (delegated) auth β it's a special agentIdentityBlueprint type. You need a standard Entra app registration:
- Go to Entra ID β App registrations β New registration
- Name: anything (e.g. "MCP Desktop Client"), single tenant, no redirect URI
- Under Authentication β set Allow public client flows to Yes
- Add the Agent 365 delegated permissions using one of these paths:
- API permissions β Add a permission β APIs my organization uses, search
Work IQ Tools(ea9ffc3e-8a23-4a7d-836d-234d7c7565c1), then add the delegated scopes below
- API permissions β Add a permission β APIs my organization uses, search
- Required Delegated permissions:
McpServers.Calendar.AllMcpServers.CopilotMCP.AllMcpServers.DASearch.AllMcpServers.Dataverse.AllMcpServers.Excel.AllMcpServers.Files.AllMcpServers.Knowledge.AllMcpServers.Mail.AllMcpServers.Me.AllMcpServers.OneDriveSharePoint.AllMcpServers.PowerPoint.AllMcpServers.SharepointLists.AllMcpServers.Teams.AllMcpServers.Word.AllMcpServersMetadata.Read.All
- Click Grant admin consent

- Copy the Application (client) ID β this is your
MCP_CLIENT_ID
See docs/mcp-server-access-issue.md for the full auth story and why this is necessary.
cp .env.template .envEdit .env:
# Required for MCP auth
# Public client app registration used only for device-code sign-in
MCP_CLIENT_ID=<your-mcp-desktop-client-app-id>
# Required unless you want to inherit tenantId from ToolingManifest.json
MCP_TENANT_ID=<your-azure-tenant-id>
# Recommended for full 14-server access
MCP_AUTH_MODE=device-code
# Required β Azure OpenAI
AZURE_OPENAI_ENDPOINT=https://<your-resource>.cognitiveservices.azure.com/
AZURE_OPENAI_AUTH_MODE=azure-cli
AZURE_OPENAI_DEPLOYMENT=gpt-5.4-mini
AZURE_OPENAI_API_VERSION=2025-04-01-previewuv sync
uv run mcp-clientOn first connect, a browser opens for device-code sign-in. After that, credentials are cached silently.
| Mode | All 14 servers? | Notes |
|---|---|---|
device-code |
Yes | Interactive public client flow β recommended |
azure-cli |
3 only | az login token lacks most MCP scopes |
a365-cli |
3 only | Same limitation as azure-cli |
client-secret |
No | App-only tokens have roles, not scp β MCP servers reject them |
bearer |
Depends | Pass-through; works only if the token already has the right scopes |
auto |
Varies | Tries each in order: bearer β a365-cli β device-code β fallback |
AGENTIC_APP_ID= # Optional override for the blueprint app ID used in gateway discovery; normally inherited from ToolingManifest.json
MCP_PLATFORM_ENDPOINT= # Default: https://agent365.svc.cloud.microsoft
MCP_PLATFORM_AUTH_SCOPE= # Default: ea9ffc3e-8a23-4a7d-836d-234d7c7565c1/.default (well-known Agent 365 Tools resource)
MCP_CLIENT_SECRET= # Only for client-secret auth mode
MCP_BEARER_TOKEN= # Static token overrideUse a Python launch configuration with the workspace .env file and the project root as the working directory.
Recommended .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Agent 365 MCP Client",
"type": "debugpy",
"request": "launch",
"module": "mcp_client",
"cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/.env",
"console": "integratedTerminal",
"justMyCode": true
},
{
"name": "Agent 365 MCP Bridge",
"type": "debugpy",
"request": "launch",
"module": "mcp_bridge",
"cwd": "${workspaceFolder}",
"envFile": "${workspaceFolder}/.env",
"console": "integratedTerminal",
"justMyCode": true
}
]
}Required debugger inputs:
.envpresent in the workspace rootToolingManifest.jsonpresent in the workspace root, unless you fully override tenant, endpoint, scope, and blueprint values via environment variables- Python environment selected in VS Code with project dependencies installed via
uv sync
| Command | Description |
|---|---|
uv run mcp-client |
Desktop GUI |
uv run mcp-bridge |
MCP stdio server (for Claude Code, VS Code agents) |
uv run python -m mcp_client |
Alternative GUI launch |
