Skip to content
Scalekit Docs
Talk to an Engineer Dashboard

CrewAI

Build a CrewAI agent with Scalekit-authenticated Gmail tools via MCP. CrewAI's MCPServerAdapter connects to a Scalekit MCP URL for automatic tool discovery.

Build a CrewAI agent that reads a user’s Gmail inbox. Scalekit handles OAuth, token storage, and exposes tools over MCP. CrewAI’s MCPServerAdapter discovers the tools and their schemas from the server. Some schemas need a small patch, covered below.

Full code on GitHub
  • Create a Gmail connection in AgentKit > Connections. The samples use the connection name gmail, so change it if yours differs. See Set up a connection.
  • Have the .env file from the Quickstart, and add your OpenAI API key as OPENAI_API_KEY to it.
  • Create a Virtual MCP server named gmail-user-tools that includes the Gmail tools. See Create a Virtual MCP server.
  • The samples load .env with load_dotenv() from python-dotenv.
Terminal window
pip install crewai "crewai-tools[mcp]" scalekit-sdk-python python-dotenv
import os
from scalekit import ScalekitClient
from dotenv import find_dotenv, load_dotenv
load_dotenv(find_dotenv())
scalekit_client = ScalekitClient(
env_url=os.environ["SCALEKIT_ENVIRONMENT_URL"],
client_id=os.environ["SCALEKIT_CLIENT_ID"],
client_secret=os.environ["SCALEKIT_CLIENT_SECRET"],
)
actions = scalekit_client.actions
# Connect the user's Gmail account, and wait until it's ACTIVE before calling tools
connection_name = "gmail"
identifier = "user_123" # your app's unique user ID
response = actions.get_or_create_connected_account(
connection_name=connection_name, identifier=identifier
)
if response.connected_account.status != "ACTIVE":
link = actions.get_authorization_link(
connection_name=connection_name, identifier=identifier
)
print("Authorize Gmail:", link.link)
input("Press Enter after authorizing...")
# Fetch the account again to pick up the new status
response = actions.get_or_create_connected_account(
connection_name=connection_name, identifier=identifier
)
if response.connected_account.status != "ACTIVE":
raise RuntimeError(
f"Gmail is {response.connected_account.status}, not ACTIVE. Authorize it and run again."
)

See Authorize a user for production auth handling.

Get the Virtual MCP server URL and mint a session token, then pass both to MCPServerAdapter. CrewAI discovers all available Gmail tools from the MCP server:

from crewai import Agent, Crew, LLM, Task
from crewai_tools import MCPServerAdapter
from datetime import timedelta
# Retrieve config_id by listing Virtual MCP servers filtered by name
list_response = actions.mcp.list_configs(filter_name="gmail-user-tools")
mcp_server_url = list_response.configs[0].mcp_server_url
mcp_id = list_response.configs[0].id
token_response = actions.mcp.create_session_token(
mcp_config_id=mcp_id,
identifier="user_123",
expiry=timedelta(hours=1),
)
with MCPServerAdapter({
"url": mcp_server_url,
"headers": {"Authorization": f"Bearer {token_response.token}"},
"transport": "streamable-http",
}) as tools:
agent = Agent(
role="Email Assistant",
goal="Fetch and summarize the user's unread emails",
backstory="You are a helpful assistant with access to the user's Gmail inbox.",
tools=tools,
llm=LLM(
model=os.getenv("LLM_MODEL", "gpt-4o"),
base_url=os.getenv("OPENAI_BASE_URL"),
api_key=os.getenv("OPENAI_API_KEY"),
),
verbose=True,
)
task = Task(
description="Fetch the last 5 unread emails and provide a brief summary of each.",
expected_output="A list of 5 unread emails with subject, sender, and a one-sentence summary.",
agent=agent,
)
result = Crew(agents=[agent], tasks=[task]).kickoff()
print(result)

CrewAI’s real strength is multi-agent orchestration. For a full example that splits email triage across three specialized agents (scanner, prioritizer, drafter), see the CrewAI email triage cookbook.

The code above reads mcp_server_url from a Virtual MCP server. Create one in the Scalekit dashboard under AgentKit > Virtual MCP Servers, or with the API. See Create a Virtual MCP server.

API reference

The endpoints this page's code calls, with every field and the SDK method for each: