Perdoo MCP Server
by nevilhulspas
README.md
# Perdoo MCP Server
An [MCP (Model Context Protocol)](https://modelcontextprotocol.io) server that integrates with the [Perdoo](https://www.perdoo.com) OKR platform via its GraphQL API. Provides 19 tools for managing objectives, key results, initiatives, KPIs, and strategic pillars.
## Features
- **Full CRUD** for objectives, key results, initiatives, KPIs, and strategic pillars
- **Helper tools** for looking up timeframes, users, and groups
- **Cursor-based pagination** on all list operations
- **Resilience stack**: rate limiting, circuit breaker, retry with exponential backoff, request queuing
- **Session-based** HTTP transport (Streamable HTTP)
- **Instructions resource** at `perdoo://instructions` for LLM guidance
## Tools
| Category | Tools |
|----------|-------|
| Objectives | `list_objectives`, `get_objective`, `create_objective`, `update_objective` |
| Key Results | `list_key_results`, `get_key_result`, `create_key_result`, `update_key_result` |
| Initiatives | `list_initiatives`, `get_initiative`, `create_initiative`, `update_initiative` |
| KPIs | `list_kpis`, `get_kpi`, `create_kpi`, `update_kpi` |
| Strategic Pillars | `list_strategic_pillars`, `get_strategic_pillar` |
| Helpers | `list_timeframes`, `list_users`, `list_groups` |
## Setup
### Prerequisites
- Node.js >= 18
- A Perdoo API token ([generate one in Perdoo settings](https://www.perdoo.com))
### Install and run
```bash
git clone https://github.com/nevilhulspas/perdoo-mcp.git
cd perdoo-mcp
npm install
cp .env.example .env
# Edit .env and add your PERDOO_API_TOKEN
npm run build
npm start
```
The server starts on port 3001 by default.
### Development
```bash
npm run dev # Watch mode with tsx
```
### Docker
```bash
npm run docker:build
npm run docker:run
```
## Configuration
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PERDOO_API_TOKEN` | Yes | - | Bearer token for the Perdoo GraphQL API |
| `PORT` | No | `3001` | HTTP server port |
| `NODE_ENV` | No | `development` | Environment (`development` or `production`) |
## MCP Client Configuration
### Local
```json
{
"mcpServers": {
"perdoo": {
"url": "http://localhost:3001/mcp"
}
}
}
```
### Remote
When deployed to a remote server with a domain:
```json
{
"mcpServers": {
"perdoo": {
"url": "https://perdoo-mcp.yourdomain.com/mcp"
}
}
}
```
## Remote Deployment (Dokploy)
This server is designed to run remotely via its HTTP transport. The included Dockerfile makes it straightforward to deploy on any container platform. Below are instructions for [Dokploy](https://dokploy.com) on a VPS (e.g. Hetzner).
### 1. Create the application
In your Dokploy dashboard:
1. Create a new **Application**
2. Set source to **Git** and point it to this repo (`https://github.com/nevilhulspas/perdoo-mcp.git`)
3. Set build type to **Dockerfile** (it will auto-detect the `Dockerfile` in the repo root)
### 2. Configure environment variables
In the application's **Environment** tab, add:
```
PERDOO_API_TOKEN=your-bearer-token-here
PORT=3001
NODE_ENV=production
```
### 3. Configure the domain
In the **Domains** tab:
1. Add your domain (e.g. `perdoo-mcp.yourdomain.com`)
2. Enable HTTPS (Dokploy handles Let's Encrypt automatically via Traefik)
3. Set the container port to `3001`
### 4. Health check
Configure the health check in Dokploy to use:
- **Path**: `/health`
- **Port**: `3001`
- **Expected status**: `200`
### 5. Deploy
Click **Deploy**. Dokploy will build the Docker image and start the container.
### Security considerations
> **The MCP endpoint has no built-in authentication.** Anyone who can reach your server can use the Perdoo tools with your API token.
For production deployments, secure the endpoint using one of these approaches:
- **Traefik BasicAuth middleware** - Add basic auth via Dokploy's Traefik config labels
- **API key middleware** - Add a custom Express middleware that checks an `Authorization` header (see [Auth section](#adding-authentication) below)
- **IP allowlisting** - Restrict access to known IPs via firewall rules or Traefik's `ipAllowList` middleware
- **VPN/Tailscale** - Run the server on a private network only accessible via VPN
### Session persistence
Sessions are stored in-memory. A container restart (deploy, crash, scaling) drops all active MCP sessions. Clients will need to re-initialize. This is expected behavior for MCP's Streamable HTTP transport.
### Resource sizing
The server is lightweight (single-concurrency request queue, no database). A minimal VPS (1 vCPU, 512 MB RAM) is sufficient.
## Endpoints
| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/mcp` | MCP request handler (creates sessions on initialize) |
| `GET` | `/mcp` | SSE endpoint for server notifications |
| `DELETE` | `/mcp` | Session termination |
| `GET` | `/health` | Health check (status, version, active sessions) |
## Architecture
```
src/
├── server.ts # Express HTTP server with session management
├── lib/
│ ├── env.ts # Environment validation (Zod)
│ ├── errors.ts # Typed error classes
│ └── logger.ts # Structured logging
├── mcp/
│ ├── index.ts # MCP server factory
│ └── tools/ # Tool definitions (one file per entity)
└── services/perdoo/
├── client.ts # GraphQL client with resilience stack
├── types.ts # TypeScript types and enums
├── operations/ # GraphQL queries and mutations
├── circuit-breaker.ts # Fails-open after 5 failures
├── rate-limiter.ts # Token bucket (30 capacity, 3/sec)
├── request-queue.ts # Single concurrent request
└── retry.ts # Exponential backoff (queries only)
```
## Resilience
The client applies a resilience stack in order:
1. **Request Queue** - Ensures only one request at a time
2. **Circuit Breaker** - Opens after 5 consecutive failures, resets after 30s
3. **Retry** - Exponential backoff for queries only (mutations are never retried)
4. **Rate Limiter** - Token bucket with 30 capacity, refilling at 3 tokens/sec
## Adding Authentication
The server does not include authentication out of the box. For production use, add a shared-secret middleware:
1. Add a `MCP_API_KEY` environment variable
2. Add middleware to `src/server.ts` that checks the `Authorization: Bearer <key>` header on `/mcp` routes
3. Configure your MCP client to send the header:
```json
{
"mcpServers": {
"perdoo": {
"url": "https://perdoo-mcp.yourdomain.com/mcp",
"headers": {
"Authorization": "Bearer your-mcp-api-key"
}
}
}
}
```
Alternatively, use Traefik's built-in BasicAuth middleware at the reverse proxy level (no code changes required).
## License
MIT
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues