LangChain's Open Agent Platform enables AI agents to execute actions across services through tool integrations. This guide shows how to connect these agents to Slack using Arcade's MCP infrastructure, enabling message sending, channel reading, and workspace interactions with proper OAuth authentication.
What You Need
- Arcade.dev account with API key
- Python 3.8+ or Node.js 16+
- LangChain SDK and LangGraph installed
- OpenAI, Anthropic, or compatible LLM API key
Architecture Overview
Open Agent Platform uses LangGraph for agent orchestration. Arcade provides the MCP server that handles authentication and tool execution:
- User sends prompt to agent
- Agent determines required Slack operation
- Arcade manages OAuth authorization if needed
- Tool executes via Arcade's MCP server
- Result returns to agent
The LLM never accesses authentication tokens. Arcade isolates credentials in its authorization layer while the agent processes task logic.
Environment Setup
Install Packages
Python:
pip install langchain-arcade langchain-openai langgraph arcadepy
JavaScript:
npm install @arcadeai/arcadejs @langchain/openai @langchain/core @langchain/langgraph
Configure Credentials
Create .env file:
ARCADE_API_KEY="your_arcade_api_key"
OPENAI_API_KEY="your_openai_api_key"
Get your API key from the Arcade dashboard. Arcade handles Slack OAuth—no separate Slack app required unless you need custom branding.
Load Slack Tools from Arcade
Arcade provides a pre-built Slack toolkit with tools optimized for LLM consumption.
Initialize Arcade Client
Python:
import os
from langchain_arcade import ArcadeToolManager
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
arcade_api_key = os.environ["ARCADE_API_KEY"]
tool_manager = ArcadeToolManager(api_key=arcade_api_key)
# Load Slack tools
slack_tools = tool_manager.get_tools(toolkits=["Slack"])
JavaScript:
import { Arcade } from "@arcadeai/arcadejs";
import { toZod } from "@arcadeai/arcadejs/lib";
import { tool } from "@langchain/core/tools";
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MemorySaver } from "@langchain/langgraph";
const arcade = new Arcade({ apiKey: process.env.ARCADE_API_KEY });
const toolkitResponse = await arcade.tools.list({
toolkit: "Slack",
limit: 30
});
const slackTools = toolkitResponse.items;
Available Tools
The Slack toolkit includes:
- Send messages to channels and users
- Read channel history
- Search conversations
- Post threaded replies
Each tool includes descriptions and parameter schemas formatted for LLM tool calling.
Create the Agent
Build Agent with Tools
Python:
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
from langgraph.checkpoint.memory import MemorySaver
llm = ChatOpenAI(model="gpt-4o")
model_with_tools = llm.bind_tools(slack_tools)
memory = MemorySaver()
agent = create_react_agent(
model=model_with_tools,
tools=slack_tools,
checkpointer=memory
)
JavaScript:
// Convert Arcade tools to LangChain format
const langchainTools = slackTools.map(arcadeTool =>
tool(async (input, config) => {
const userId = config.configurable?.user_id;
const result = await arcade.tools.execute({
tool_id: arcadeTool.id,
input: input,
user_id: userId
});
return result.output;
}, {
name: arcadeTool.name,
description: arcadeTool.description,
schema: toZod(arcadeTool.input)
})
);
const llm = new ChatOpenAI({ model: "gpt-4o" });
const boundModel = llm.bindTools(langchainTools);
const memory = new MemorySaver();
const agent = createReactAgent({
llm: boundModel,
tools: langchainTools,
checkpointer: memory
});
Implement User Authorization
Handle per-user OAuth when tools require Slack access. Arcade returns an authorization URL when needed.
Python:
import asyncio
from arcadepy import Arcade
async def run_agent_with_auth(user_id: str, query: str):
arcade_client = Arcade(api_key=arcade_api_key)
# Check authorization status
auth_response = await arcade_client.tools.authorize(
tool_name="Slack.SendMessage",
user_id=user_id
)
if auth_response.status != "completed":
print(f"Authorization required: {auth_response.url}")
# Wait for user to complete OAuth
auth_result = await arcade_client.auth.wait_for_completion(
auth_response
)
if auth_result.status != "completed":
return {"error": "Authorization incomplete"}
# Execute agent with user context
config = {
"configurable": {
"thread_id": f"slack-agent-{user_id}",
"user_id": user_id
}
}
result = await agent.ainvoke(
{"messages": [{"role": "user", "content": query}]},
config
)
return result
# Usage
user_id = "user_123"
query = "Send a message to #general saying 'Hello team'"
result = asyncio.run(run_agent_with_auth(user_id, query))
JavaScript:
async function runAgentWithAuth(userId, query) {
const authResponse = await arcade.tools.authorize({
tool_name: "Slack.SendMessage",
user_id: userId
});
if (authResponse.status !== "completed") {
console.log(`Authorization required: ${authResponse.url}`);
const authResult = await arcade.auth.waitForCompletion(authResponse);
if (authResult.status !== "completed") {
return { error: "Authorization incomplete" };
}
}
const config = {
configurable: {
thread_id: `slack-agent-${userId}`,
user_id: userId
}
};
const result = await agent.invoke(
{ messages: [{ role: "user", content: query }] },
config
);
return result;
}
const userId = "user_123";
const query = "Send a message to #general saying 'Hello team'";
const result = await runAgentWithAuth(userId, query);
Handle OAuth Callbacks
Web applications need to detect when users complete OAuth and resume agent execution.
Callback Endpoint
Python (FastAPI):
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.post("/api/oauth/callback")
async def handle_oauth_callback(request: Request):
body = await request.json()
user_id = body.get("userId")
authorization_id = body.get("authorizationId")
arcade_client = Arcade(api_key=arcade_api_key)
# Resume agent execution
return JSONResponse({
"status": "success",
"userId": user_id
})
JavaScript (Express):
import express from 'express';
const app = express();
app.use(express.json());
app.post('/api/oauth/callback', async (req, res) => {
const { userId, authorizationId } = req.body;
// Resume agent execution
res.json({
status: "success",
userId: userId
});
});
app.listen(3000);
Performance Optimization
Cache User Tools
Reduce latency by caching authorized tools per user:
Python:
class SlackAgentManager:
def __init__(self, arcade_api_key: str):
self.arcade = Arcade(api_key=arcade_api_key)
self.user_toolsets = {}
async def get_user_tools(self, user_id: str):
if user_id in self.user_toolsets:
return self.user_toolsets[user_id]
toolkit = await self.arcade.tools.list(
toolkit="Slack",
user_id=user_id,
limit=30
)
self.user_toolsets[user_id] = toolkit.items
return toolkit.items
async def execute_with_context(self, user_id: str, query: str):
tools = await self.get_user_tools(user_id)
user_agent = create_react_agent(
model=ChatOpenAI(model="gpt-4o").bind_tools(tools),
tools=tools,
checkpointer=MemorySaver()
)
config = {"configurable": {"user_id": user_id}}
result = await user_agent.ainvoke(
{"messages": [{"role": "user", "content": query}]},
config
)
return result
Multi-Step Workflows
Execute operations across multiple channels:
async def post_announcement(user_id: str, message: str, channels: list):
manager = SlackAgentManager(arcade_api_key)
channels_str = ", ".join([f"#{ch}" for ch in channels])
query = f"Post this message to {channels_str}: {message}"
result = await manager.execute_with_context(user_id, query)
return {
"success": True,
"channels": channels,
"result": result
}
# Usage
await post_announcement(
user_id="user_123",
message="Deployment complete",
channels=["general", "engineering", "product"]
)
Connect to Open Agent Platform
Configure MCP Server
Add to .env:
NEXT_PUBLIC_MCP_SERVER_URL="https://api.arcade.dev/v1/mcps/arcade-anon/mcp"
ARCADE_API_KEY="your_api_key"
Deploy Agent
Deploy to LangGraph Platform:
# Local development
langgraph dev --port 2024
# Production deployment
langgraph deploy
Configure in Platform
- Add deployment URL and credentials
- Select Arcade MCP server as tool source
- Enable Slack toolkit
- Configure authorization flows
The platform UI handles authorization prompts while Arcade manages OAuth.
Testing
Local Test Script
Python:
import asyncio
async def test_slack_integration():
user_id = "test_user_123"
arcade_client = Arcade(api_key=arcade_api_key)
auth_response = await arcade_client.tools.authorize(
tool_name="Slack.SendMessage",
user_id=user_id
)
if auth_response.status != "completed":
print(f"Complete authorization at: {auth_response.url}")
return
result = await run_agent_with_auth(
user_id=user_id,
query="Send a test message to #test-channel"
)
print("Result:", result)
asyncio.run(test_slack_integration())
Monitor Execution
Track tool calls in the Arcade dashboard:
- Authorization success rates
- Tool execution latency
- Error patterns
- User-specific usage
Security Configuration
Token Management
Arcade handles token storage and refresh. Never:
- Log OAuth tokens
- Pass tokens to LLM context
- Store credentials in code
Custom Verification
For production, implement custom user verification:
# Configure in worker.toml
auth:
providers:
- id: slack-provider
type: oauth2
provider_id: slack
client_id: ${env:SLACK_CLIENT_ID}
client_secret: ${env:SLACK_CLIENT_SECRET}
user_verifier:
type: http
uri: "https://your-domain.com/verify"
Rate Limiting
Arcade implements per-user rate limiting. For high-volume applications:
- Add request queuing
- Implement exponential backoff
- Monitor usage in dashboard
Troubleshooting
Authorization Fails
Check:
- API key validity
- Slack OAuth scope configuration
- Redirect URL configuration
- Logs in Arcade dashboard
Tool Execution Errors
Verify:
- User completed authorization
- Tool names match exactly (case-sensitive)
- Required parameters provided
- Error details in execution logs
Agent Ignores Slack Tools
Check:
- Tools bound to model correctly
- Tool descriptions clear and relevant
- Query mentions Slack operations explicitly
- Agent reasoning in verbose mode
Production Deployment
Cloud Deployment
Deploy using LangGraph Platform:
# Deploy to cloud
langgraph cloud deploy
# Self-host with Docker
docker build -t slack-agent .
docker run -e ARCADE_API_KEY=your_key slack-agent
Scaling
For production scale:
- Use Arcade Cloud for automatic scaling
- Implement connection pooling
- Cache tools per user session
- Monitor in Arcade dashboard
Hybrid Deployment
For security-sensitive environments, use Arcade's hybrid deployment:
# engine.yaml
api:
host: 0.0.0.0
port: 9099
auth:
providers:
- id: slack-provider
type: oauth2
provider_id: slack
client_id: ${env:SLACK_CLIENT_ID}
client_secret: ${env:SLACK_CLIENT_SECRET}
tools:
directors:
- id: default
enabled: true
max_tools: 64
Next Steps
- Explore additional Arcade toolkits
- Build multi-service workflows
- Create custom tools with Arcade's SDK
- Review API reference
For examples, see Arcade's GitHub.



