usemotion-mcp-server
by matbour
README.md
# usemotion-mcp-server
MCP server for the [Motion](https://www.usemotion.com) API, running on [Bun](https://bun.sh). Supports two transports, selected with the `MCP_TRANSPORT` environment variable:
- `stdio` (default) — local use; reads `MOTION_API_KEY` from the environment
- `http` — streamable HTTP, deployable to Vercel; each client sends its own Motion API key as a request header (`X-API-Key` or `Authorization: Bearer`), which is forwarded to the Motion API for that request only. The server stores no credentials; requests without a key get a 401.
## Setup
1. Create an API key in Motion (Settings → API).
2. For stdio mode, create a `.env` file in the project root:
```sh
cp .env.example .env # then fill in MOTION_API_KEY
```
3. Install dependencies:
```sh
bun install
```
## Build
Compile a standalone binary (no Bun required at runtime):
```sh
bun run compile # produces bin/usemotion-mcp-server
```
The binary still auto-loads `.env` from the directory it runs in; otherwise set `MOTION_API_KEY` in its environment.
## Usage
### HTTP mode (local)
```sh
MCP_TRANSPORT=http bun run src/index.ts # serves http://localhost:3000/api/mcp (PORT to override)
```
Clients authenticate per request:
```sh
claude mcp add --transport http motion http://localhost:3000/api/mcp --header "X-API-Key: your-key-here"
```
### Deploy to Vercel
`api/mcp.ts` + `vercel.json` (`"bunVersion": "1.x"`) make the repo deployable as-is:
```sh
vercel deploy # then connect clients to https://<your-app>.vercel.app/api/mcp
```
Do not set `MOTION_API_KEY` on the deployment — keys come from client headers and are never stored.
### stdio mode — Claude Code
```sh
claude mcp add motion -- bun run /path/to/usemotion-mcp-server/src/index.ts
```
### Claude Desktop
Add to `claude_desktop_config.json`:
```json
{
"mcpServers": {
"motion": {
"command": "bun",
"args": ["run", "/path/to/usemotion-mcp-server/src/index.ts"],
"env": { "MOTION_API_KEY": "your-key-here" }
}
}
}
```
Note: Bun auto-loads `.env` from the working directory, so the `env` block is only needed if the server isn't started from the project root.
## Tools
| Tool | Description |
|------|-------------|
| `list_tasks` | List tasks with filters (workspace, project, status, assignee, name, label) |
| `get_task` | Get a task by id |
| `create_task` | Create a task (supports auto-scheduling, priority, labels, markdown description) |
| `update_task` | Update a task |
| `delete_task` | Delete a task |
| `move_task` | Move a task to another workspace |
| `unassign_task` | Remove a task's assignee |
| `list_projects` | List projects in a workspace |
| `get_project` | Get a project by id |
| `create_project` | Create a project |
| `list_workspaces` | List workspaces |
| `list_users` | List users (find assignee ids) |
| `get_current_user` | Get the user tied to the API key |
| `list_statuses` | List task statuses in a workspace |
| `get_schedules` | Get schedules used by auto-scheduling |
| `list_comments` | List comments on a task |
| `create_comment` | Comment on a task |
## Notes
- Motion's rate limit is 12 requests/minute on individual plans; the client retries 429s with backoff (honors `Retry-After`).
- List endpoints are cursor-paginated: pass `cursor` from the previous response's `meta.nextCursor`.
## Development
```sh
bun run typecheck # tsc --noEmit
bun run scripts/smoke.ts # stdio smoke test: lists tools, then create → get → update → delete a task
bun run scripts/smoke-http.ts # HTTP smoke test: 401 without key, then list tools + workspaces via header auth
# (start the server first: MCP_TRANSPORT=http bun run src/index.ts)
```
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues