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

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

Arcade.dev Team's avatar
Arcade.dev Team
OCTOBER 27, 2025
7 MIN READ
THOUGHT LEADERSHIP
Rays decoration image
Ghost Icon

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 API key with GPT-4 or GPT-5 access
  • Slack workspace admin access for OAuth configuration
  • Basic understanding of async/await patterns

Architecture Overview

The integration uses a three-layer architecture:

GPT ModelArcade MCP ServerSlack API

Arcade sits between your AI model and Slack, handling OAuth flows, token management, and secure API calls. This architecture ensures credentials never reach the language model while maintaining user-specific authentication contexts.

The Arcade Engine serves as both an MCP server and authentication broker, supporting the HTTP streamable transport protocol that OpenAI's agents require. When your GPT agent needs to call Slack tools, Arcade manages the entire authorization lifecycle.

Setting Up the Development Environment

Install Required Packages

For Python implementations:

pip install arcadepy openai agents-arcade

For JavaScript/TypeScript:

npm install @arcadeai/arcadejs openai @openai/agents

Configure Environment Variables

Create a .env file in your project root:

ARCADE_API_KEY=your_arcade_api_key
OPENAI_API_KEY=your_openai_api_key

Get your Arcade API key from the dashboard at api.arcade.dev/dashboard.

Configuring Slack Authentication

Create Slack App Credentials

  1. Navigate to api.slack.com/apps and create a new app
  2. Under "OAuth & Permissions," add these redirect URLs:
    • https://api.arcade.dev/v1/auth/callback (for Arcade Cloud)
    • Your custom domain if self-hosting
  3. Configure the required OAuth scopes:
chat:write
channels:read
channels:history
users:read
im:write

The Slack toolkit requires these scopes for sending messages and reading conversations. Add additional scopes based on your use case.

Register Slack Provider in Arcade

Add your Slack credentials to Arcade via the dashboard or configuration file:

Via Dashboard:

  1. Navigate to OAuth → Providers → Add OAuth Provider
  2. Select Slack from the Included Providers tab
  3. Enter your Client ID and Client Secret
  4. Save the configuration

Via Configuration (Self-Hosted):

Edit your engine.yaml file:

auth:
  providers:
    - id: slack-oauth
      description: "Slack workspace authentication"
      enabled: true
      type: oauth2
      provider_id: slack
      client_id: ${env:SLACK_CLIENT_ID}
      client_secret: ${env:SLACK_CLIENT_SECRET}

Learn more about Slack authentication configuration.

Building the GPT-Slack Agent

Python Implementation with OpenAI Agents

Create a file slack_agent.py:

import os
import asyncio
from arcadepy import AsyncArcade
from agents import Agent, Runner
from agents_arcade import get_arcade_tools
from agents_arcade.errors import AuthorizationError

async def main():
    # Initialize Arcade client
    client = AsyncArcade(api_key=os.getenv("ARCADE_API_KEY"))

    # Get Slack toolkit from Arcade MCP server
    slack_tools = await get_arcade_tools(
        client,
        toolkits=["slack"],
        limit=30
    )

    # Create GPT agent with Slack capabilities
    slack_agent = Agent(
        name="Slack Assistant",
        instructions="""You are a helpful assistant that manages Slack communications.
        You can send messages, read conversations, and help users stay organized.
        Always confirm actions before executing them.""",
        model="gpt-5",  
        tools=slack_tools
    )

    # Unique user identifier for auth
    user_id = "user@company.com"

    try:
        result = await Runner.run(
            starting_agent=slack_agent,
            input="Send a message to #general saying 'Hello from GPT!'",
            context={"user_id": user_id}
        )
        print("Agent response:", result.final_output)

    except AuthorizationError as e:
		    url = getattr(e, "url", str(e))
        print(f"Authorization required. Please visit: {url}")
        print("User must complete OAuth flow before continuing")

if __name__ == "__main__":
    asyncio.run(main())

The agents-arcade package provides seamless integration with OpenAI's agent framework, handling tool conversion and authorization automatically.

JavaScript Implementation

Create slackAgent.js:

import Arcade from '@arcadeai/arcadejs';
import { Agent, run } from '@openai/agents';
import { toZod, isAuthorizationRequiredError } from '@arcadeai/arcadejs/lib';

async function createSlackAgent() {
  const client = new Arcade({
    apiKey: process.env.ARCADE_API_KEY
  });

  // Fetch Slack MCP server tools
  const slackToolkit = await client.tools.list({
    toolkit: 'slack',
    limit: 30
  });

  // Convert to OpenAI agent tools
  const tools = toZod({
    tools: slackToolkit.items,
    client: client,
    userId: 'user@company.com'
  });

  // Create GPT agent
  const agent = new Agent({
    name: 'Slack Assistant',
    instructions: 'Help users communicate effectively on Slack',
    model: 'gpt-5',
    tools: tools
  });

  return { agent, client };
}

async function executeSlackAction() {
  const { agent, client } = await createSlackAgent();

  try {
    const result = await run({
      agent: agent,
      input: 'List my recent Slack messages'
    });

    console.log('Response:', result.text);
  } catch (error) {
    if (isAuthorizationRequiredError(error)) {
      console.log('Please authorize:', error.url);
    }
  }
}

executeSlackAction();

Reference the JavaScript client documentation for additional configuration options.

Handling User Authorization

When users first interact with Slack tools, they must authorize access. Arcade manages this OAuth flow automatically.

Authorization Flow Pattern

from arcadepy import AsyncArcade
from arcadepy.auth import wait_for_authorization_completion

async def handle_authorization(client, user_id, tool_name):
    # Check if authorization needed
    auth_response = await client.tools.authorize(
        tool_name=tool_name,
        user_id=user_id
    )

    if auth_response.status != "completed":
        # User needs to visit authorization URL
        print(f"Authorize at: {auth_response.url}")

        # Wait for user to complete OAuth flow
        await wait_for_authorization_completion(
            client,
            auth_response.id
        )

        print("Authorization complete!")

    # Tool is now ready to use
    return True

The authorization URL directs users to Slack's OAuth consent screen. After approval, Arcade securely stores the access token and handles refresh automatically. Learn more about authorization patterns.

Working with Slack Tools

Available Operations

The Slack MCP server provides these pre-built tools:

Messaging:

  • Slack.SendMessage - Send messages to channels, DMs, or groups
  • Slack.GetMessages - Retrieve conversation history
  • Slack.GetConversationMetadata - Fetch channel details

User Management:

  • Slack.GetUsers - List workspace members
  • Slack.GetUserInfo - Retrieve user profiles

Conversation Management:

  • Slack.ListConversations - Get all accessible channels

Sending Messages Programmatically

# Direct tool execution
response = await client.tools.execute(
    tool_name="Slack.SendMessage",
    input={
        "channel_name": "general",
        "message": "Deployment complete! All systems operational."
    },
    user_id=user_id
)

print(response.output.value)

Retrieving Conversation History

# Fetch recent messages with filtering
messages = await client.tools.execute(
    tool_name="Slack.GetMessages",
    input={
        "channel_name": "engineering",
        "limit": 50,
        "oldest_relative": "01:00:00"  # Last hour
    },
    user_id=user_id
)

for msg in messages.output.value:
    print(f"{msg['user']}: {msg['text']}")

The toolkit supports time-based filtering using relative offsets or absolute timestamps. See the Slack reference documentation for all available parameters.

Building Multi-User Slack Agents

Production applications require managing multiple users' Slack access. Arcade handles per-user token storage automatically.

Multi-User Agent Pattern

class SlackAgentManager:
    def __init__(self):
        self.client = AsyncArcade()
        self.user_caches = {}

    async def get_user_tools(self, user_id: str):
        # Cache tools per user for performance
        if user_id not in self.user_caches:
            tools = await get_arcade_tools(
                self.client,
                toolkits=["slack"],
                user_id=user_id
            )
            self.user_caches[user_id] = tools

        return self.user_caches[user_id]

    async def create_agent_for_user(self, user_id: str):
        tools = await self.get_user_tools(user_id)

        return Agent(
            name=f"Slack Agent ({user_id})",
            instructions="Manage Slack communications securely",
            model="gpt-5",
            tools=tools
        )

    async def process_request(self, user_id: str, prompt: str):
        agent = await self.create_agent_for_user(user_id)

        result = await Runner.run(
            starting_agent=agent,
            input=prompt,
            context={"user_id": user_id}
        )

        return result.final_output

This pattern ensures token isolation between users and improves performance through caching. The multi-user authentication guide provides additional patterns applicable to Slack.

Deploying to Production

Cloud Deployment with Arcade Deploy

Arcade Deploy enables serverless hosting of your tools:

  1. Create worker.toml configuration:
[[worker]]
[worker.config]
id = "slack-agent-worker"
secret = "${env:WORKER_SECRET}"
enabled = true
timeout = 30

[worker.pypi_source]
packages = ["arcadepy", "agents-arcade"]
  1. Deploy using the CLI:
arcade deploy
  1. Configure your agent to use the deployed worker endpoint

Self-Hosted MCP Server

For enterprise deployments requiring on-premises hosting:

# engine.yaml
api:
  host: 0.0.0.0
  port: 9099

auth:
  providers:
    - id: slack-prod
      enabled: true
      type: oauth2
      provider_id: slack
      client_id: ${env:SLACK_CLIENT_ID}
      client_secret: ${env:SLACK_CLIENT_SECRET}

workers:
  - id: slack-worker
    enabled: true
    http:
      uri: "http://localhost:8002"
      secret: ${env:WORKER_SECRET}

Start the local engine:

arcade-engine -c engine.yaml

Security Best Practices

Token Management

Arcade handles token encryption, rotation, and storage automatically. Credentials never reach your application code or the language model.

Key security features:

  • OAuth 2.0 with PKCE for authorization
  • Automatic access token refresh
  • Encrypted token storage
  • Per-user permission scoping
  • Audit logging for all tool executions

Rate Limiting

Implement request throttling to prevent API abuse:

from asyncio import Semaphore

class RateLimitedSlackAgent:
    def __init__(self, max_concurrent=5):
        self.semaphore = Semaphore(max_concurrent)
        self.client = AsyncArcade()

    async def execute_with_limit(self, tool_name, input_data, user_id):
        async with self.semaphore:
            return await self.client.tools.execute(
                tool_name=tool_name,
                input=input_data,
                user_id=user_id
            )

Error Handling

Implement comprehensive error handling for production reliability:

from agents_arcade.errors import (
    AuthorizationError,
    ToolExecutionError
)

async def safe_tool_execution(client, tool_name, input_data, user_id):
    try:
        result = await client.tools.execute(
            tool_name=tool_name,
            input=input_data,
            user_id=user_id
        )
        return result.output.value

    except AuthorizationError as e:
        # User needs to reauthorize
        return {
            "error": "authorization_required",
            "url": str(e)
        }

    except ToolExecutionError as e:
        # Tool-specific error (rate limit, invalid input)
        return {
            "error": "execution_failed",
            "message": str(e)
        }

Testing the Integration

Local Testing with MCP Inspector

Use the MCP Inspector to validate tool definitions:

# Point inspector to your local MCP server
arcade serve --mcp

# In another terminal
mcp-inspector http://localhost:8002/mcp

Integration Testing

import pytest
from arcadepy import AsyncArcade

@pytest.mark.asyncio
async def test_slack_message_send():
    client = AsyncArcade()

    response = await client.tools.execute(
        tool_name="Slack.SendMessage",
        input={
            "channel_name": "test-channel",
            "message": "Test message from integration suite"
        },
        user_id="test_user"
    )

    assert response.output.value["ok"] == True

Advanced Patterns

Custom Slack Tools

Build application-specific Slack tools using the Arcade TDK:

from arcade_tdk import tool, ToolContext
from arcade_tdk.auth import Slack
from slack_sdk import WebClient

@tool(
    requires_auth=Slack(
        scopes=["chat:write", "channels:read"]
    )
)
async def send_formatted_report(
    context: ToolContext,
    channel: str,
    data: dict
):
    """Send a formatted report to Slack channel"""
    client = WebClient(token=context.authorization.token)

    blocks = [
        {
            "type": "header",
            "text": {"type": "plain_text", "text": data["title"]}
        },
        {
            "type": "section",
            "fields": [
                {"type": "mrkdwn", "text": f"*Status:* {data['status']}"},
                {"type": "mrkdwn", "text": f"*Timestamp:* {data['timestamp']}"}
            ]
        }
    ]

    response = client.chat_postMessage(
        channel=channel,
        blocks=blocks,
        text=data["title"]
    )

    return {"message_id": response["ts"]}

Integrating Multiple Services

Combine Slack with other toolkits for powerful workflows:

# Get tools from multiple MCP servers
tools = await get_arcade_tools(
    client,
    toolkits=["slack", "gmail", "github"]
)

agent = Agent(
    name="Multi-Service Agent",
    instructions="""
    You can:
    - Send Slack notifications
    - Read and send Gmail
    - Manage GitHub issues

    Coordinate actions across all services.
    """,
    model="gpt-5",
    tools=tools
)

View all available Arcade toolkits.

Monitoring and Observability

Tool Execution Metrics

Track agent performance and tool usage:

import time
from functools import wraps

def track_tool_execution(func):
    @wraps(func)
    async def wrapper(*args, **kwargs):
        start = time.time()

        try:
            result = await func(*args, **kwargs)
            duration = time.time() - start

            print(f"Tool executed in {duration:.2f}s")
            return result

        except Exception as e:
            duration = time.time() - start
            print(f"Tool failed after {duration:.2f}s: {e}")
            raise

    return wrapper

Logging Best Practices

import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

logger = logging.getLogger(__name__)

async def execute_with_logging(client, tool_name, user_id):
    logger.info(
        f"Executing {tool_name}",
        extra={"user_id": user_id}
    )

    result = await client.tools.execute(
        tool_name=tool_name,
        input={},
        user_id=user_id
    )

    logger.info(
        f"Tool execution complete",
        extra={
            "tool": tool_name,
            "user": user_id,
            "success": True
        }
    )

    return result

Performance Optimization

Tool Caching

Cache tool definitions to reduce initialization overhead:

from functools import lru_cache

@lru_cache(maxsize=100)
async def get_cached_tools(toolkit_name: str):
    client = AsyncArcade()
    return await get_arcade_tools(
        client,
        toolkits=[toolkit_name]
    )

Batch Operations

Process multiple Slack operations efficiently:

import asyncio

async def send_bulk_messages(client, messages, user_id):
    tasks = [
        client.tools.execute(
            tool_name="Slack.SendMessage",
            input=msg,
            user_id=user_id
        )
        for msg in messages
    ]

    results = await asyncio.gather(*tasks, return_exceptions=True)
    return results

Conclusion

This implementation provides production-ready integration between GPT models and Slack using Arcade's MCP infrastructure. The architecture ensures secure authentication, reliable tool execution, and scalable multi-user support.

Key takeaways:

  • Arcade handles OAuth complexity automatically
  • MCP provides standardized tool calling
  • Per-user authentication maintains security boundaries
  • Pre-built toolkits accelerate development

For additional resources:

Start building agents that take action with Arcade.dev.

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 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

Rays decoration image
THOUGHT LEADERSHIP

How to Call Custom Tools from Python Agent via Arcade

Python agents execute custom tools through Arcade's API to interact with external services, internal APIs, and business logic. This guide covers tool creation, agent integration, and production deployment. Prerequisites Before starting, ensure you have: * Python 3.10 or higher * Arcade account with API key * Virtual environment for Python dependencies Install Arcade SDK Install the core SDK for building custom tools: pip install arcade-ai For agent integrations using the Pyt

Blog CTA Icon

Get early access to Arcade, and start building now.