An MCP (Model Context Protocol) server that lets any MCP client schedule Google Calendar events and search Google Contacts through natural language. Authentication and Google access are handled by Descope's Agentic Identity Hub, and the actual work is done by a CrewAI multi-agent crew running on Claude (Opus 4.8).
The server exposes a single MCP tool, run_crew, which an authenticated client (e.g. MCP Inspector) calls with a request like "Schedule a meeting with Kevin tomorrow at 2pm".
- Python 3.10–3.13
- MCP (
mcpSDK) over Streamable HTTP, served with Starlette + uvicorn - CrewAI — multi-agent orchestration
- Claude Opus 4.8 via LiteLLM (
anthropic/claude-opus-4-8) - Descope Agentic Identity Hub — MCP Server (inbound auth) + Connections (outbound Google tokens)
- Google API Python Client — Calendar v3 and People API
- PyJWT — agentic token validation against Descope JWKS
- Python 3.10–3.13 and
uv - An Anthropic API key
- A Descope project with the Agentic Identity Hub enabled
- A Google Cloud project with the Calendar API and People API enabled, and an OAuth 2.0 Client
- Enable the Google Calendar API and Google People API.
- Create an OAuth 2.0 Client ID (Web application).
- Add the redirect URI:
https://api.descope.com/v1/outbound/oauth/callback - Add your account as a Test user (or publish the consent screen). Calendar/Contacts are restricted scopes.
Create two Connections under Agentic Identity Hub:
| Connection ID | Google scope |
|---|---|
google-calendar |
https://www.googleapis.com/auth/calendar |
google-contacts |
https://www.googleapis.com/auth/contacts.readonly |
For each, set the Google Client ID and Client Secret from step 1.
- Create an MCP Server with URL
http://localhost:5001/mcp. - Add two scopes, each linked to its Connection and marked mandatory:
google-calendar→google-calendarconnectiongoogle-contacts→google-contactsconnection
The inbound consent flow (e.g. inbound-apps-user-consent) must provision the outbound tokens, or the Google vault stays empty (E152102). In the flow editor, after user consent and before END, add an Agentic Hub / Connect step for each connection:
- one with default outbound app
google-calendar, scopehttps://www.googleapis.com/auth/calendar - one with default outbound app
google-contacts, scopehttps://www.googleapis.com/auth/contacts.readonly
cp .env.example .envFill in .env:
# Descope
DESCOPE_PROJECT_ID=your_descope_project_id
DESCOPE_MANAGEMENT_KEY=your_management_key
MCP_SERVER_ID=your_mcp_server_id
# MCP Server
MCP_SERVER_URL=http://localhost:5001
# Google
GOOGLE_CALENDAR_ID=primary
# AI Model
MODEL=anthropic/claude-opus-4-8
ANTHROPIC_API_KEY=your_anthropic_api_key
.envis gitignored — never commit it.
# Install dependencies
uv sync
# Start the MCP server (port 5001)
uv run python src/descope_agentic_crew/api.pyConnect an MCP client. With the MCP Inspector:
npx @modelcontextprotocol/inspector@latest \
--transport http --server-url http://localhost:5001/mcpOpen the printed ?MCP_PROXY_AUTH_TOKEN=... URL, click Connect, complete the Descope login and Google consent (Calendar + Contacts), then call the run_crew tool:
user_request: Schedule a meeting with Kevin tomorrow at 2pm
The crew searches your contacts for "Kevin", creates the event on your calendar, and emails the invite.
| Param | Type | Description |
|---|---|---|
user_request |
string | Natural-language calendar/contacts request |
Returns the crew's final result (event confirmation, attendees invited, assumptions made).
- Task Planner — breaks the request into an execution plan.
- Contacts Finder — searches Google Contacts (lists + filters connections for reliability) and returns only real, tool-sourced contact data.
- Calendar Manager — parses date/time (relative dates resolved against today's date, times in
America/Los_Angeles) and creates the event, inviting the contact when an email was found.
crewai-app/
├── src/descope_agentic_crew/
│ ├── api.py # MCP server: auth (JWKS), run_crew tool, Starlette app
│ ├── crew.py # CrewAI crew, agents, Claude LLM config
│ ├── config/
│ │ ├── agents.yaml # Agent roles/goals/backstories
│ │ └── tasks.yaml # Task definitions
│ └── tools/
│ └── custom_tool.py # Google Calendar + Contacts tools (Descope Connection tokens)
├── .env.example
├── pyproject.toml
└── README.md
- Model Context Protocol
- Descope Agentic Identity Hub
- CrewAI
- Claude API
- Google Calendar API · People API