How to Connect Open Agents SDK to Slack with Arcade (MCP)

How to Connect Open Agents SDK to Slack with Arcade (MCP)

Arcade.dev Team's avatar
Arcade.dev Team
OCTOBER 21, 2025
5 MIN READ
TUTORIALS
Rays decoration image
Ghost Icon

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:

  1. User sends prompt to agent
  2. Agent determines required Slack operation
  3. Arcade manages OAuth authorization if needed
  4. Tool executes via Arcade's MCP server
  5. 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

  1. Add deployment URL and credentials
  2. Select Arcade MCP server as tool source
  3. Enable Slack toolkit
  4. 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

For examples, see Arcade's GitHub.

SHARE THIS POST

RECENT ARTICLES

Rays decoration image
THOUGHT LEADERSHIP

How to Query Postgres from GPT-5 via Arcade (MCP)

Large language models need structured data access to provide accurate, data-driven insights. This guide demonstrates how to connect GPT-5 to PostgreSQL databases through Arcade's Model Context Protocol implementation, enabling secure database queries without exposing credentials directly to language models. Prerequisites Before implementing database connectivity, ensure you have: * Python 3.8 or higher installed * PostgreSQL database with connection credentials * Arcade API key (free t

Rays decoration image
THOUGHT LEADERSHIP

How to Connect GPT-5 to Slack with Arcade (MCP)

Building AI agents that interact with Slack requires secure OAuth authentication, proper token management, and reliable tool execution. This guide shows you how to connect GPT-5 to Slack using Arcade's Model Context Protocol (MCP) implementation, enabling your agents to send messages, read conversations, and manage channels with production-grade security. Prerequisites Before starting, ensure you have: * Arcade.dev account with API key * Python 3.10+ or Node.js 18+ installed * OpenAI A

Rays decoration image
THOUGHT LEADERSHIP

How to Build a GPT-5 Gmail Agent with Arcade (MCP)

Building AI agents that can access and act on Gmail data represents a significant challenge in production environments. This guide demonstrates how to build a fully functional Gmail agent using OpenAI's latest models through Arcade's Model Context Protocol implementation, enabling secure OAuth-based authentication and real-world email operations. Prerequisites Before starting, ensure you have: * Active Arcade.dev account with API key * Python 3.10 or higher installed * OpenAI API key w

Blog CTA Icon

Get early access to Arcade, and start building now.