# Preventing Your AI Agent From Messaging #general

> The Slack MCP server lets AI agents post messages, reply to threads, and add reactions. Here's how to rate limit messaging before your agent spams your workspace.

Published: Mon Mar 16

Canonical: https://policylayer.com/blog/secure-slack-mcp-server

It starts innocently. You give your agent access to Slack so it can post a daily standup summary. Twenty minutes later, it has sent 83 messages to #general, replied to the CEO's thread about Q2 planning with a hallucinated revenue forecast, and added the :clown_face: reaction to every message in #engineering. Your phone is vibrating non-stop and three people have already DM'd you asking if you've been hacked.

The Slack MCP server is powerful. That is precisely the problem.

<!--truncate-->

## What the Slack MCP server exposes

The [official Slack MCP server](https://github.com/modelcontextprotocol/servers/tree/main/src/slack) gives agents access to 8 tools. Five are read-only and relatively harmless:

- `slack_list_channels` — list public channels
- `slack_get_channel_history` — read recent messages from a channel
- `slack_get_thread_replies` — read replies in a thread
- `slack_get_users` — list workspace members
- `slack_get_user_profile` — get a user's profile

The other three are where things get interesting:

- **`slack_post_message`** — post a new message to any channel the bot is in
- **`slack_reply_to_thread`** — reply to a specific thread
- **`slack_add_reaction`** — add an emoji reaction to a message

An agent stuck in a reasoning loop can burn through all three at extraordinary speed. Slack's own API rate limits are generous enough that dozens of messages can land before anything throttles. By then, the damage — and the embarrassment — is done.

## Rate limiting messages

PolicyLayer sits between your agent and the Slack MCP server, evaluating every `tools/call` against a YAML policy. Here is the full Slack policy:

```yaml
version: "1"
description: "Policy for modelcontextprotocol/server-slack"
default: "allow"
tools:
    slack_get_channel_history:
        rules: []
    slack_get_thread_replies:
        rules: []
    slack_get_user_profile:
        rules: []
    slack_get_users:
        rules: []
    slack_list_channels:
        rules: []

    slack_add_reaction:
        rules:
          - name: "reaction-rate-limit"
            rate_limit: "20/hour"
            on_deny: "Rate limit: max 20 reactions per hour"

    slack_post_message:
        rules:
          - name: "message-send-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 messages per hour — review message activity before retrying"

    slack_reply_to_thread:
        rules:
          - name: "reply-send-rate-limit"
            rate_limit: "10/hour"
            on_deny: "Rate limit: max 10 thread replies per hour — review message activity before retrying"

    "*":
        rules:
          - name: "global-rate-limit"
            rate_limit: "60/minute"
            on_deny: "Global rate limit: max 60 tool calls per minute across all Slack tools"
```

The read tools have empty rulesets — no restrictions. The three write tools each carry hourly rate limits: 10 messages, 10 thread replies, 20 reactions. The wildcard rule at the bottom adds a global cap of 60 calls per minute across everything, including reads.

When an agent hits a limit, PolicyLayer blocks the call at the transport layer and returns the `on_deny` message. The request never reaches Slack. The agent gets a clear signal to stop, and your workspace stays intact.

The `rate_limit` shorthand expands internally into a stateful counter with calendar-aligned windows — top of each hour, midnight UTC for daily limits. Counters persist across agent restarts, so an agent cannot dodge limits by reconnecting. For more on how this works under the hood, see [Rate Limiting MCP Tool Calls](/blog/rate-limiting-mcp-tool-calls).

## Getting started

Route your Slack MCP server through PolicyLayer — point your MCP client at the gateway URL with a per-person grant token, and the policy above runs on every call before it reaches Slack:

```json
{
  "mcpServers": {
    "slack": {
      "url": "https://proxy.policylayer.com/mcp/<server-uuid>/",
      "headers": { "Authorization": "Bearer <grant-token>" }
    }
  }
}
```

You define and adjust the policy in the [PolicyLayer dashboard](https://app.policylayer.com) — no local proxy to install or run. PolicyLayer proxies all traffic through the policy engine — no code changes to your agent or the MCP server.

Adjust the limits to match your use case. A customer support agent might need 50 messages per hour. An internal reporting bot might need 5. The point is that the ceiling exists, and it is enforced deterministically regardless of what the LLM decides to do.

[Full Slack policy →](/policies/slack)
