Slack MCP
README.md
# Slack MCP — Python Client + C# Server
A complete **Model Context Protocol (MCP)** implementation with four architectural layers.
| Layer | Language | File(s) |
|-------|----------|---------|
| 1 — Users | Python 3.11+ | `client-python/main.py` |
| 2 — Prompt + Agent | Python 3.11+ | `client-python/agent/agent.py` |
| 3 — MCP Client/Server | Python + C# | `client-python/transport/mcp_client.py` · `server-csharp/` |
| 4 — Slack | C# / .NET 8 | `server-csharp/Services/SlackService.cs` |
---
## Architecture
```
👤 User(s)
(human operators / end-users)
│ natural language input
▼
┌──────────────────────────────────────────────────────────┐
│ Prompt + Agent Layer │
│ │
│ Claude (Anthropic) ──or── External Agent │
│ • interprets user intent │
│ • decides which MCP tool(s) to call │
│ • formats results back to the user │
└──────────────────────┬───────────────────────────────────┘
│ tool calls
▼
┌──────────────────────────────────────────────────────────┐
│ Python MCP Client (client-python/transport/) │
│ │
│ McpClient │
│ └── StdioTransport │
│ ├── spawns: dotnet run SlackMcpServer │
│ └── JSON-RPC 2.0 over stdin / stdout │
└──────────────────────┬───────────────────────────────────┘
│ stdio
┌──────────────────────▼───────────────────────────────────┐
│ C# MCP Server (server-csharp/) │
│ │
│ Program.cs (stdio loop) │
│ └── ToolRegistry (dispatch) │
│ └── SlackService (Slack Web API) │
└──────────────────────┬───────────────────────────────────┘
│ HTTPS
┌──────────────────────▼───────────────────────────────────┐
│ Slack │
│ │
│ • send_message → post to channel or thread │
│ • get_history → read recent messages │
│ • list_channels → browse workspace channels │
│ • create_channel → open a new public channel │
│ • add_reaction → emoji-react to a message │
│ • list_users → enumerate workspace members │
└──────────────────────────────────────────────────────────┘
```
### MCP Protocol Flow
```
Python Client C# Server
│ │
│── initialize ────────────────►│
│◄─ InitializeResult ───────────│
│── initialized (notification) ►│
│── tools/list ────────────────►│
│◄─ ListToolsResult ────────────│
│── tools/call {name, args} ───►│
│◄─ CallToolResult ─────────────│
```
---
## Layer Responsibilities
### Layer 1 — 👤 Users (`main.py`)
Entry point for human operators. Provides an interactive REPL or single-prompt CLI. Has no knowledge of Slack or MCP — it only calls `agent.handle(prompt)`.
### Layer 2 — Prompt + Agent (`agent/agent.py`)
Interprets natural language intent and decides which MCP tool to call. The `_resolve_intent()` method is rule-based by default — **replace it with a real LLM call** (see comments in the file). Formats raw tool output into human-readable responses.
### Layer 3 — MCP Transport (`transport/mcp_client.py` + `server-csharp/`)
Pure protocol layer. The Python side spawns the C# process and speaks JSON-RPC 2.0 over stdio. The C# side receives requests, dispatches to `ToolRegistry`, and writes responses. Neither side knows about user intent.
### Layer 4 — Slack (`server-csharp/Services/SlackService.cs`)
Deepest layer. Each of the six methods maps directly to one Slack Web API endpoint. No MCP concepts here — just HTTP calls and typed DTOs.
---
## Prerequisites
| Tool | Version |
|------|---------|
| Python | 3.11+ |
| .NET SDK | 8.0+ |
| Slack Bot Token | `xoxb-…` |
### Slack Bot Scopes Required
Go to **api.slack.com/apps** → OAuth & Permissions → Bot Token Scopes:
| Scope | Used by |
|-------|---------|
| `chat:write` | send_message |
| `channels:history` | get_history |
| `channels:read` | list_channels |
| `channels:write` | create_channel |
| `reactions:write` | add_reaction |
| `users:read` | list_users |
---
## Quick Start
```bash
# 1. Set your Slack bot token
export SLACK_BOT_TOKEN="xoxb-your-token-here"
# 2. Build the C# server
cd server-csharp
dotnet build
# 3. Run the interactive client
cd ../client-python
python main.py --server-cmd "dotnet run --project ../server-csharp/SlackMcpServer.csproj"
# Or run a single prompt
python main.py --prompt "List all channels"
```
---
## Connecting a Real LLM (Claude)
Open `client-python/agent/agent.py` and replace `_resolve_intent()` with:
```python
import anthropic
def _resolve_intent(self, prompt: str) -> Intent:
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-opus-4-6",
max_tokens=1024,
tools=self._client.tools, # pass MCP schemas directly
messages=[{"role": "user", "content": prompt}],
)
tool_use = next(b for b in response.content if b.type == "tool_use")
return Intent(
tool=tool_use.name,
args=tool_use.input,
explanation=prompt,
)
```
Install the SDK: `pip install anthropic`
---
## Running Tests
```bash
cd client-python
pip install pytest pytest-asyncio
python -m pytest tests/ -v
```
Tests are split by layer:
- `tests/test_agent.py` — Layer 2: intent resolution and response formatting
- `tests/test_transport.py` — Layer 3: JSON-RPC transport and MCP client
---
## Project Structure
```
mcp-slack/
├── server-csharp/ # Layer 3 (server) + Layer 4
│ ├── SlackMcpServer.csproj
│ ├── Program.cs # stdio JSON-RPC loop
│ ├── Models/
│ │ └── McpModels.cs # JSON-RPC + MCP protocol types
│ ├── Services/
│ │ └── SlackService.cs # Layer 4 — Slack Web API
│ └── Tools/
│ └── ToolRegistry.cs # MCP tool definitions + dispatcher
│
└── client-python/ # Layers 1, 2, 3 (client)
├── main.py # Layer 1 — User entry point
├── agent/
│ ├── __init__.py
│ └── agent.py # Layer 2 — Prompt + Agent
├── transport/
│ ├── __init__.py
│ └── mcp_client.py # Layer 3 — MCP transport
├── tests/
│ ├── conftest.py
│ ├── test_agent.py
│ └── test_transport.py
├── pytest.ini
└── requirements.txt
```
---
## Troubleshooting
| Issue | Fix |
|-------|-----|
| `SLACK_BOT_TOKEN is not set` | `export SLACK_BOT_TOKEN="xoxb-..."` |
| `channel_not_found` | Use a Channel ID like `C012AB3CD`, not `#general` |
| `not_in_channel` | Invite the bot to the channel first |
| Server won't start | Run `dotnet build` in `server-csharp/` first |
| Intent not recognized | Extend `_resolve_intent()` or plug in a real LLM |
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues