Skip to main content
Glama
README.md
# basecamp-mcp-server

An [MCP](https://modelcontextprotocol.io) server for **Basecamp 5** — gives your AI assistant
access to projects, to-dos, messages, campfire chat, documents, and card tables.

Works with Claude Code, Claude Desktop, Cursor, OpenAI Codex, and VS Code.

```
You: What's on my plate in Basecamp this week?

→ basecamp_my_assignments
→ Two things are assigned to you, both in Fieldwork Study:
    • Send Robin the drafted survey instrument — due today, 2 subtasks
    • Review the pilot analysis — due Friday
```

## Requirements

- **Python 3.11+**
- A **Basecamp 5** account
- Credentials, via either:
  - the [Basecamp CLI](https://github.com/basecamp/basecamp-cli) — recommended, because it keeps a
    self-refreshing OAuth token in your OS keyring and this server never touches your disk; or
  - a `BASECAMP_ACCESS_TOKEN` environment variable (expires after 14 days, with no refresh)

## Quick start

```bash
# 1. Authenticate, if you have not already
basecamp auth login

# 2. Check that everything resolves — this makes a real API call
uvx basecamp-mcp-server doctor

# 3. Add it to your client (Claude Code shown; others below)
claude mcp add basecamp -- uvx basecamp-mcp-server serve
```

`doctor` prints the resolved credential source, your Basecamp accounts, and a paste-ready config
block for every supported client. Start there if anything below does not work.

## Client configuration

The formats genuinely differ between clients — the key name, the file, and whether it is JSON or
TOML. Copy the one you need.

### Claude Code

```bash
claude mcp add basecamp -- uvx basecamp-mcp-server serve
```

Verify with `claude mcp list`; it should report `✔ Connected`.

### Claude Desktop

`claude_desktop_config.json` — **macOS** `~/Library/Application Support/Claude/`,
**Windows** `%APPDATA%\Claude\`:

```json
{
  "mcpServers": {
    "basecamp": {
      "command": "uvx",
      "args": ["basecamp-mcp-server", "serve"]
    }
  }
}
```

### Cursor

`.cursor/mcp.json` in the project, or `~/.cursor/mcp.json` globally. Same `mcpServers` shape as
Claude Desktop.

### VS Code

`.vscode/mcp.json`. Note the key is **`servers`**, not `mcpServers`, and `type` is required:

```json
{
  "servers": {
    "basecamp": {
      "type": "stdio",
      "command": "uvx",
      "args": ["basecamp-mcp-server", "serve"]
    }
  }
}
```

### OpenAI Codex

`~/.codex/config.toml` — TOML, and the table is `mcp_servers` with an underscore:

```toml
[mcp_servers.basecamp]
command = "uvx"
args = ["basecamp-mcp-server", "serve"]
```

## Permissions

The server has three modes. **Tools you have not enabled are not registered at all**, so the model
never sees them and never proposes an action you have forbidden.

| Mode | Flag | Tools | What it can do |
|---|---|---:|---|
| Read-only | `--read-only` | 19 | Look at everything; change nothing |
| Default | *(none)* | 28 | Create and edit; remove nothing |
| Full | `--allow-destructive` | 29 | Also trash and archive, and only with `confirm: true` |

```bash
# See exactly what a given configuration exposes
uvx basecamp-mcp-server tools list --read-only
```

Read-only is worth considering if you mainly want your assistant to *answer questions* about
Basecamp. You can always restart with writes enabled.

## What it can do

**Find things** — `list_projects` · `get_project` · `search` · `my_assignments` · `list_people`

**To-dos** — `list_todolists` · `list_todos` · `get_todo` · `create_todo` · `update_todo` ·
`complete_todo`

**Messages and chat** — `list_messages` · `get_message` · `create_message` · `list_comments` ·
`create_comment` · `list_campfire_lines` · `create_campfire_line`

**Docs and cards** — `list_documents` · `get_document` · `get_card_table` · `list_cards` ·
`create_card` · `move_card`

**Anything else** — `basecamp_request` reaches any Basecamp endpoint these tools do not cover
(GET only), and `basecamp_write_request` covers POST and PUT.

Start with `basecamp_get_project`: it returns a `tools` map giving the ids every other tool in
that project needs, so your assistant does not have to guess them.

## Configuration

Everything is optional; the defaults are chosen to be safe rather than fast.

| Variable | Default | Notes |
|---|---|---|
| `BASECAMP_ACCESS_TOKEN` | — | Only needed without the Basecamp CLI |
| `BASECAMP_ACCOUNT_ID` | auto | Required only if you belong to several Basecamp accounts |
| `BASECAMP_MCP_READ_ONLY` | `false` | Same as `--read-only` |
| `BASECAMP_MCP_ALLOW_DESTRUCTIVE` | `false` | Same as `--allow-destructive` |
| `BASECAMP_MCP_USER_AGENT` | this project | Must contain a contact URL or email, or Basecamp rejects every request with a `400` |
| `BASECAMP_MCP_MAX_PAGES` | `25` | Upper bound on auto-pagination per call. Capped at 200 |
| `BASECAMP_MCP_MAX_RESULT_CHARS` | `25000` | Size ceiling for one tool result |
| `BASECAMP_MCP_LOG_LEVEL` | `INFO` | Logs go to stderr, never stdout |

## Notes

**Responses are projected, not passed through.** Basecamp payloads are built for a rich web
client: one to-do is ~5 KB of JSON and a single message can be 37 KB. Unprojected, a hundred
to-dos would be around 530 KB — enough to end a conversation. Every response is reduced to the
fields that let a model answer and chain to the next call, which is a 12–60× cut depending on
type, with every id preserved.

**Content from Basecamp is untrusted input.** To-do titles, message bodies and comments are
written by other people. The server tells your assistant to treat them as data to report on
rather than instructions to follow, but that is a mitigation, not a guarantee — bear it in mind
before enabling writes on an account with people you do not know.

**Edits preserve fields you did not mention.** `update_todo` reads the record, overlays your
changes and writes it back, so setting a due date does not erase the assignees. The cost is that
it is two requests rather than one, and a concurrent edit in between is overwritten.

## Development

```bash
uv sync
uv run ruff check . && uv run ruff format --check . && uv run mypy && uv run pytest
```

See [AGENTS.md](AGENTS.md) for architecture, layer rules, and a list of verified upstream
behaviours that look like bugs until you read the source.

## License

MIT — see [LICENSE](LICENSE).