Skip to main content
Glama
shivankj11

slack-file-upload-mcp

by shivankj11
README.md
# slack-file-upload-mcp

A one-tool MCP server that does the thing the normal Slack MCP can't: **post a local file to Slack, with a message.**

The Slack MCP sends text (`slack_send_message`) and reads files, but has no way to put a file from your disk into a channel. Run this alongside it and an agent can share a screenshot, CSV, log, or PDF directly.

## The tool

### `slack_upload_file`

| Arg | Required | Meaning |
|---|---|---|
| `file_path` | ✅ | Absolute local path (`~` expanded). Must be a regular, non-empty file. |
| `channel` | ✅ | Channel id (`C…`/`G…`), DM id (`D…`), `#channel-name`, or a user id (`U…`) to DM. |
| `message` | | Text posted with the file (Slack's `initial_comment`). Slack mrkdwn: `*bold*`, `_italic_`, `<url\|label>`. |
| `title` | | File title in Slack. Defaults to the filename. |
| `filename` | | Override the stored name. Defaults to the local basename. |
| `thread_ts` | | Post as a reply in this thread instead of the channel root. |

Returns one line: `Uploaded report.csv (4821 bytes) to C09ABCD1234 · file_id=F0… · ts=1756… · https://…`. The `ts` is the share timestamp, so the Slack MCP can thread replies under the uploaded file.

Uploads go through Slack's current `files.getUploadURLExternal` → upload → `files.completeUploadExternal` flow (via `slack_sdk`'s `files_upload_v2`); the retired `files.upload` endpoint is not used.

## Setup

1. **Token.** A user token (`xoxp-…`) or bot token (`xoxb-…`) with:
   - `files:write` — required.
   - `channels:read` + `groups:read` — only needed to resolve `#name` → id. Passing a `C…` id works without them.
   - `im:write` — only needed to DM a `U…` user id.

   A bot token must be invited to the channel (`/invite @yourapp`); a user token posts as you.

   `manifest.yaml` in this repo creates an app with exactly those scopes:
   [api.slack.com/apps](https://api.slack.com/apps) → **Create New App** → **From a manifest** →
   pick the workspace → paste the file → Create → **Install to Workspace** (admin approval may
   be required) → **OAuth & Permissions** → copy the **User OAuth Token** (`xoxp-…`).

   It's deliberately a separate app from any existing one: adding a scope to an installed app
   forces a reinstall, which rotates that app's token and breaks whatever else was using it.

2. **Register the server** (token lives in the MCP env, not in the repo):

   ```bash
   claude mcp add slack-file-upload --scope user \
     --env SLACK_MCP_TOKEN=xoxp-your-token \
     -- uv run --directory /path/to/slack-file-upload-mcp slack-file-upload-mcp serve
   ```

3. **Verify:** `SLACK_MCP_TOKEN=… uv run slack-file-upload-mcp whoami`

## Configuration

| Env var | Default | Purpose |
|---|---|---|
| `SLACK_MCP_TOKEN` | — | The token. Falls back to `SLACK_USER_TOKEN`, `SLACK_BOT_TOKEN`, `SLACK_TOKEN`. |
| `SLACK_FILE_UPLOAD_ALLOWED_DIRS` | unset (any path) | Comma-separated directory prefixes the server may read from. Set it to confine a prompt-injected agent to e.g. `~/Desktop,/tmp` instead of letting it exfiltrate `~/.ssh`. |
| `SLACK_FILE_UPLOAD_MAX_MB` | `1024` | Reject files larger than this before contacting Slack. Slack's own ceiling is 1 GB. |

## Guardrails

- Path must be absolute and resolve to an existing regular file; directories and symlink targets outside `SLACK_FILE_UPLOAD_ALLOWED_DIRS` are rejected (the path is `resolve()`d *before* the allowlist check).
- Empty files are rejected up front — Slack's upload-URL endpoint requires a non-zero length and fails opaquely on 0 bytes.
- Slack API errors are translated into actionable text (`not_in_channel` → "invite the app to the channel", `missing_scope` → which scopes).

## CLI

```bash
uv run slack-file-upload-mcp serve                       # stdio MCP (also the bare default)
uv run slack-file-upload-mcp whoami                      # verify the token
uv run slack-file-upload-mcp upload ~/x.png '#general' -m 'here you go'
```

`upload` runs the exact code path the MCP tool runs — useful for smoke tests without a client.

## Tests

```bash
uv run pytest              # offline; the Slack client is stubbed
```

TDQS

A4.9/5.0

Scored across 1 tool

Disambiguation5/5

Only one tool exists, so there is no possibility of confusion with other tools. Its purpose is singular and clearly described.

Naming Consistency5/5

The single tool name follows a clear verb_noun pattern with a server prefix: slack_upload_file. This is consistent and intuitive.

Tool Count4/5

The server is intentionally scoped to a single file-upload operation, so one tool is reasonable. It is slightly under the typical 3-15 range but not excessive or sparse given the narrow purpose.

Completeness5/5

The tool covers the core upload workflow with support for file path, channel, message, title, filename, and thread replies. No obvious missing operations are needed for the stated file-upload focus.

Maintenance

ActivityMaintained
ResponsivenessNo issues