README.md•8.01 kB
# ClickUp-MCP
ClickUp-MCP is a Model Context Protocol server scaffold providing a foundation for integrating ClickUp tooling with deterministic TypeScript infrastructure.
## Getting Started
Install dependencies:
```
npm i
```
Build the project:
```
npm run build
```
Run in development mode:
```
npm run dev
```
The project now exposes dedicated launchers for each transport so you can iterate locally without touching the main entrypoint:
```sh
npm run dev:stdio
npm run dev:http
```
Run tests:
```
npm test
```
Stdout streams structured JSON logs while ClickUp-MCP communicates over standard IO transport.
To verify tools, run ClickUp-MCP with an MCP client and list the available tools.
## Local stdio run
After building the project you can launch the production bundle over stdio:
```
CLICKUP_TOKEN=xxxxx node dist/hosts/stdio.js
```
The host will validate configuration, start the MCP server, and emit a single readiness line:
```
{"event":"ready","transport":"stdio"}
```
Send `SIGINT` (`Ctrl+C`) or `SIGTERM` to trigger a graceful shutdown.
## Transport self-check
Run these probes once the HTTP bridge is listening on port 8081:
```
curl -s http://127.0.0.1:8081/healthz
curl -s -X POST http://127.0.0.1:8081/ -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0.0.1"}}}'
curl -s -X POST http://127.0.0.1:8081/mcp -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
```
`MCP_DEBUG=1` enables structured HTTP request logs and JSON-RPC traces. Toggle it off (set to `0`) to keep the bridge quiet during automated runs.
## Smithery quick-start
Smithery talks to ClickUp-MCP-Server over Streamable HTTP. Use the provided dev script to run the bridge with the same Express entrypoint that Smithery expects:
```sh
npm run dev:http
```
From another terminal, exercise the end-to-end handshake, tool listing, and ping tool that Smithery relies on:
```sh
npm run verify:http # raw JSON-RPC via curl
npm run verify:inspector:http # MCP Inspector exercising HTTP transport
npm run verify:smithery # Smithery-compatible client calling ping and reading the hello://world resource
```
All three checks connect to `POST /mcp`, confirm the server advertises the `ping` tool and `hello://world` resource, and execute a ping round-trip.
When publishing a Smithery build, point the configuration at the Streamable HTTP endpoint (`http://<host>:<port>/mcp`) or run the stdio entrypoint (`npm run dev:stdio`) if you prefer the default transport. The examples under `examples/basic/` mirror both launch modes and are safe to copy into a Smithery project.
## Deploying with Smithery
To deploy ClickUp-MCP-Server on Smithery:
1. The server uses a forgiving configuration approach that accepts partial or missing credentials, **matching Python MCP server behavior exactly**.
2. Configure secrets in your Smithery environment (all optional, with fallbacks):
- `CLICKUP_TOKEN` - Falls back to empty string if not provided
- `CLICKUP_DEFAULT_TEAM_ID` - Falls back to undefined if not provided
3. Optional tuning:
- `CLICKUP_AUTH_SCHEME` (override auth detection to `auto`, `personal_token`, or `oauth`)
- `MAX_ATTACHMENT_MB` (default 8)
- `MAX_BULK_CONCURRENCY` (default 10)
- `CHARACTER_LIMIT` (default 25000)
4. Deploy using:
```bash
smithery deploy
```
The server will start successfully even without credentials. Tools requiring authentication will fail with clear error messages until credentials are provided. Logs are emitted in JSON lines to stdout.
### Startup Diagnostics
At server startup, comprehensive diagnostics are printed to console showing:
- Resolved configuration values (with sensitive data masked)
- Session configuration state
- Environment variable values
- Complete fallback chain for troubleshooting
This helps verify which configuration source is being used and troubleshoot credential issues.
### Configuration Fallback Chain
The server uses a three-tier fallback pattern for all configuration values:
1. **Smithery UI Config** (highest priority) - Values explicitly provided in the Smithery configuration UI
2. **Environment Variables** (medium priority) - Values from `CLICKUP_TOKEN`, `CLICKUP_DEFAULT_TEAM_ID`, etc.
3. **Defaults** (lowest priority) - Sensible defaults like empty string for token, undefined for team ID
This pattern matches the Python server behavior and ensures the server never crashes due to missing configuration during initialization.
## Deploy on Smithery (TypeScript runtime)
Smithery's TypeScript runtime can instantiate the MCP server directly from the exported factory without using the HTTP bridge.
1. Create or update `smithery.yaml` so it uses the TypeScript runtime and points `startCommand.commandFunction` at `src/server/smithery.ts#createServerFromSmithery`.
2. Provide credentials via Smithery UI or environment variables (all optional):
- `CLICKUP_TOKEN` - Optional, falls back to environment or empty string
- `CLICKUP_DEFAULT_TEAM_ID` - Optional, falls back to environment or undefined
- Set `CLICKUP_AUTH_SCHEME` if the automatic token detection should be overridden (`auto`, `personal_token`, `oauth`).
3. Configure optional runtime tuning variables as needed (for example `LOG_LEVEL`, `FEATURE_PERSISTENCE`, `MCP_HTTP_*`, `MAX_ATTACHMENT_MB`, or `MAX_BULK_CONCURRENCY`).
4. Deploy with:
```bash
smithery deploy
```
The server will initialize successfully regardless of credential availability. Missing credentials trigger warnings in logs, but tools requiring authentication will return clear error messages when invoked.
## Smithery TS runtime
Smithery loads the MCP server by invoking `createServer` from `src/server/factory.ts` inside the TypeScript runtime. The runtime initialises the server without starting transports, allowing Smithery to manage connectivity.
The Smithery configuration UI maps to the runtime config. **All fields are optional, matching Python MCP server behavior exactly**. The server accepts empty, partial, or full configuration:
- **Empty config** `{}` - Server uses environment variables or defaults, initializes successfully
- **Partial config** `{ apiToken: "..." }` - Server merges with environment for missing fields
- **Full config** `{ apiToken: "...", defaultTeamId: 123 }` - Server uses provided values
Environment variables such as `CLICKUP_TOKEN`, `CLICKUP_DEFAULT_TEAM_ID`, and related ClickUp settings act as fallbacks when Smithery UI values are not provided. Explicitly setting values in the UI overrides environment variables for the active session.
### Python Parity
This TypeScript implementation maintains full parity with the Python ClickUp MCP server:
1. **No required configuration fields** - Server never crashes during initialization, regardless of config shape
2. **Environment fallback chain** - Same three-tier precedence: config > env > defaults
3. **Graceful degradation** - Tools fail at invocation time with clear error messages
4. **Startup diagnostics** - Comprehensive logging for troubleshooting (unconditionally printed)
5. **Flexible deployment** - Deploy first, configure credentials later
6. **Defensive normalization** - Invalid values (NaN, Infinity, malformed JSON) are normalized to safe defaults instead of causing initialization failures
The server accepts and gracefully handles:
- Empty configs (`{}` or `undefined`)
- Partial configs (only some fields provided)
- Invalid field values (NaN, Infinity, empty strings, whitespace)
- Malformed data types (wrong types are coerced or defaulted)
- Missing environment variables (all env vars are optional)
The `.well-known/mcp-config` endpoint publishes a JSON schema documenting all available configuration fields and their fallback behavior.