Skip to content
Scalekit Docs
Talk to an Engineer Dashboard

LangChain

Build a LangChain agent with Scalekit-authenticated Gmail tools. Scalekit returns native LangChain tool objects; no schema reshaping needed.

Build a LangChain agent that reads a user’s Gmail inbox. Scalekit handles OAuth, token storage, and returns tools in native LangChain format. Your agent code needs no Scalekit-specific logic beyond initialization.

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.
  • The samples load .env with load_dotenv() from python-dotenv.
Terminal window
pip install scalekit-sdk-python python-dotenv langchain-openai
import os
import scalekit.client
from dotenv import load_dotenv
load_dotenv()
scalekit_client = scalekit.client.ScalekitClient(
client_id=os.getenv("SCALEKIT_CLIENT_ID"),
client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
env_url=os.getenv("SCALEKIT_ENVIRONMENT_URL"),
)
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.

actions.langchain.get_tools() returns native StructuredTool objects. Bind them to your LLM and run the tool-calling loop:

from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, ToolMessage
tools = actions.langchain.get_tools(
identifier="user_123",
connection_names=["gmail"],
page_size=100, # avoid missing tools when a connector has more than the default page
)
tool_map = {t.name: t for t in tools}
llm = ChatOpenAI(model="gpt-4o").bind_tools(tools)
messages = [HumanMessage("Fetch my last 5 unread emails and summarize them")]
while True:
response = llm.invoke(messages)
messages.append(response)
if not response.tool_calls:
print(response.content)
break
for tc in response.tool_calls:
result = tool_map[tc["name"]].invoke(tc["args"])
messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))

LangChain connects to MCP servers with langchain-mcp-adapters. Pass the Virtual MCP server URL and a session token for this user:

Terminal window
pip install "langchain-mcp-adapters>=0.3,<1"
import asyncio
import os
from datetime import timedelta
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage, ToolMessage
# Returned by create_config when you created the Virtual MCP server
config_id = os.environ["SCALEKIT_MCP_CONFIG_ID"]
mcp_url = os.environ["SCALEKIT_MCP_SERVER_URL"]
# Mint a fresh session token for this user before each agent run
mcp_token = actions.mcp.create_session_token(
mcp_config_id=config_id,
identifier="user_123",
expiry=timedelta(hours=1),
).token
async def run():
client = MultiServerMCPClient(
{
"scalekit": {
"transport": "streamable_http",
"url": mcp_url,
"headers": {"Authorization": f"Bearer {mcp_token}"},
}
}
)
tools = await client.get_tools()
tool_map = {t.name: t for t in tools}
llm = ChatOpenAI(model="gpt-4o").bind_tools(tools)
messages = [HumanMessage("Fetch my last 5 unread emails and summarize them")]
while True:
response = await llm.ainvoke(messages)
messages.append(response)
if not response.tool_calls:
print(response.content)
break
for tc in response.tool_calls:
result = await tool_map[tc["name"]].ainvoke(tc["args"])
messages.append(ToolMessage(content=str(result), tool_call_id=tc["id"]))
asyncio.run(run())

See Create a Virtual MCP server and Mint session tokens to create the server, check the user’s connections and mint a token.

API reference

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