Skip to main content
Glama
mdlopresti
by mdlopresti
README.md
# Stoat MCP Server

[![PyPI version](https://img.shields.io/pypi/v/stoat-mcp)](https://pypi.org/project/stoat-mcp/)
[![Python versions](https://img.shields.io/pypi/pyversions/stoat-mcp)](https://pypi.org/project/stoat-mcp/)
[![CI](https://github.com/mdlopresti/stoat-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/mdlopresti/stoat-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server for the [Stoat](https://stoat.chat/) chat platform. Gives AI assistants structured access to Stoat servers, channels, messages, and users.

Built with [FastMCP](https://gofastmcp.com/) and [stoat.py](https://stoatpy.readthedocs.io/).

## Installation

```bash
pip install stoat-mcp
```

Or run from source:

```bash
git clone https://github.com/mdlopresti/stoat-mcp.git
cd stoat-mcp
pip install -e ".[dev]"
```

## Quick Start

Set required environment variables:

```bash
export STOAT_TOKEN="your-bot-token"
export STOAT_SERVER_ID="your-server-id"
```

Run the server:

```bash
stoat-mcp
```

## Configuration

All configuration is via environment variables:

| Variable | Required | Default | Description |
|----------|:--------:|---------|-------------|
| `STOAT_TOKEN` | Yes | — | Bot authentication token |
| `STOAT_SERVER_ID` | Yes | — | Stoat server ID to operate on |
| `STOAT_ENABLE_WRITE` | No | `false` | Master switch for all write operations |
| `STOAT_ENABLE_SEND_MESSAGE` | No | `false` | Enable `send_message` tool |
| `STOAT_ENABLE_SEND_DM` | No | `false` | Enable `send_direct_message` tool |
| `STOAT_CHANNEL_ALLOWLIST` | No | `""` | Comma-separated channel IDs (empty = all allowed) |
| `STOAT_CHANNEL_BLOCKLIST` | No | `""` | Comma-separated channel IDs (empty = none blocked) |

### Write Operations

All write operations (sending messages, creating channels, etc.) are **disabled by default**. To enable them:

```bash
# Enable all write operations
export STOAT_ENABLE_WRITE=true

# Or enable specific operations
export STOAT_ENABLE_SEND_MESSAGE=true
export STOAT_ENABLE_SEND_DM=true
```

### Channel Filtering

Restrict which channels the MCP server can access:

```bash
# Only allow these channels (empty = all channels)
export STOAT_CHANNEL_ALLOWLIST="channel-id-1,channel-id-2"

# Block these channels (applied before allowlist)
export STOAT_CHANNEL_BLOCKLIST="private-channel-id"
```

The blocklist takes precedence: a channel in both lists is blocked.

## MCP Client Configuration

### Claude Desktop

Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "stoat": {
      "command": "stoat-mcp",
      "env": {
        "STOAT_TOKEN": "your-bot-token",
        "STOAT_SERVER_ID": "your-server-id"
      }
    }
  }
}
```

### Claude Code

Add to your project's `.mcp.json`:

```json
{
  "mcpServers": {
    "stoat": {
      "command": "stoat-mcp",
      "env": {
        "STOAT_TOKEN": "your-bot-token",
        "STOAT_SERVER_ID": "your-server-id"
      }
    }
  }
}
```

## Available Tools

| Category | Tool | Tier | Description |
|----------|------|------|-------------|
| Channels | `list_channels` | Read | List all accessible text channels |
| Channels | `get_channel_info` | Read | Get metadata for a specific channel |
| Channels | `create_channel` | Write | Create a new text channel |
| Channels | `delete_channel` | Write | Delete a text channel |
| Messages | `get_channel_messages` | Read | Read message history from a channel |
| Messages | `send_message` | Write | Send a message to a channel |
| Users | `list_users` | Read | List server members |
| Users | `get_user_info` | Read | Get profile data for a specific user |
| DMs | `get_direct_messages` | Read | Read DM history with a user |
| DMs | `send_direct_message` | Write | Send a direct message to a user |
| Search | `search_messages` | Read | Search messages across channels |
| Threads | `get_thread_replies` | Read | Get replies in a message thread |
| Threads | `reply_to_thread` | Write | Reply to a message thread |
| Reactions | `add_reaction` | Write | Add an emoji reaction to a message |
| Reactions | `remove_reaction` | Write | Remove an emoji reaction from a message |
| Files | `upload_file` | Write | Upload a file to a channel |

## Comparable Projects

- [Discord MCP](https://github.com/v-3/discord-mcp) — MCP server for Discord
- [Slack MCP](https://github.com/modelcontextprotocol/servers/tree/main/src/slack) — Official MCP server for Slack

stoat-mcp is the first MCP server for the Stoat (formerly Revolt) platform.

## Security

### The Lethal Trifecta

This MCP server creates a combination that requires careful consideration:

1. **AI with access to private messages** — the AI can read chat history
2. **AI with ability to send messages** — the AI can communicate externally
3. **User-controlled message content** — messages may contain prompt injection attempts

This combination means a malicious message in a channel could potentially instruct the AI to exfiltrate private data from other channels by sending it somewhere attacker-controlled.

### Mitigations

- **Write operations are disabled by default.** Only enable `STOAT_ENABLE_WRITE` or `STOAT_ENABLE_SEND_MESSAGE` when you specifically need the AI to send messages.
- **Use the channel blocklist** to prevent the AI from reading sensitive channels: `STOAT_CHANNEL_BLOCKLIST="private-channel,admin-channel"`
- **Use the channel allowlist** to restrict the AI to only specific channels: `STOAT_CHANNEL_ALLOWLIST="ai-channel,support-channel"`
- **Review AI actions** before approving message sends in your MCP client.

### Recommendations

- Start with read-only access and only enable writes when needed
- Use the most restrictive channel filtering that meets your needs
- Never put secrets or credentials in channels the AI can read
- Monitor AI-sent messages for unexpected behavior

## Development

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run specific test file
pytest tests/test_config.py
```

## License

MIT