Runn MCP Server
An MCP (Model Context Protocol) server for Runn.io - a resource planning and project forecasting platform. This server allows AI assistants like Claude, ChatGPT, and Cline to interact with your Runn data.
Features
37 tools covering all Runn API endpoints, with built-in in-memory caching to reduce API calls:
People
| Tool | Description |
|---|---|
get_all_people | Fetches all people from Runn (with optional filters) |
get_person_by_id | Fetches a specific person by their ID |
get_person_by_email | Fetches a specific person by their email address |
Projects
| Tool | Description |
|---|---|
get_all_projects | Fetches all projects from Runn (with optional filters) |
get_project_by_id | Fetches a specific project by its ID |
get_project_phases | Fetches all phases for a project |
get_project_milestones | Fetches all milestones for a project |
Clients
| Tool | Description |
|---|---|
get_all_clients | Fetches all clients from Runn (with optional filters) |
get_client_by_id | Fetches a specific client by its ID |
get_client_projects | Fetches all projects for a specific client |
Assignments
| Tool | Description |
|---|---|
get_all_assignments | Fetches all assignments (who is assigned to what) |
get_active_assignments | Fetches only currently active assignments |
Actuals (Logged Time)
| Tool | Description |
|---|---|
get_all_actuals | Fetches all logged time with optional filters |
get_person_actuals | Fetches logged time for a specific person |
get_project_actuals | Fetches logged time for a specific project |
Roles
| Tool | Description |
|---|---|
get_all_roles | Fetches all job roles defined in Runn |
get_role_by_id | Fetches a specific role by its ID |
Contracts
| Tool | Description |
|---|---|
get_all_contracts | Fetches all employment contracts |
get_person_contracts | Fetches contracts for a specific person |
Time Off & Holidays
| Tool | Description |
|---|---|
get_all_holidays | Fetches all public holidays |
get_all_time_off | Fetches all time off/leave entries |
get_person_time_off | Fetches time off for a specific person |
Milestones
| Tool | Description |
|---|---|
get_all_milestones | Fetches all project milestones |
get_project_milestones | Fetches milestones for a specific project |
Other Resources
| Tool | Description |
|---|---|
get_all_rate_cards | Fetches all billing rate cards |
get_all_placeholders | Fetches all placeholder resources |
get_all_tags | Fetches all tags/labels |
get_account | Fetches account information and settings |
Cache Management
| Tool | Description |
|---|---|
clear_cache | Clears the in-memory cache to force fresh data on next request |
Reports - Utilization & Revenue
| Tool | Description |
|---|---|
get_all_people_metrics | BETA: Utilization metrics for all people |
get_person_metrics | BETA: Person utilization metrics (billable %, revenue, costs, capacity) |
get_all_project_metrics | BETA: Financial metrics for all projects |
get_project_metrics | BETA: Project financial metrics (revenue, profit, margin, budget) |
Reports - Hours
| Tool | Description |
|---|---|
get_person_hours_report | Day-by-day hours report for a person |
get_project_hours_report | Day-by-day hours report for a project |
Reports - Totals
| Tool | Description |
|---|---|
get_all_project_totals | Aggregated totals for all projects |
get_project_totals | Aggregated totals for a specific project |
Reports - Composite
| Tool | Description |
|---|---|
get_weekly_schedule_vs_actuals_report | Compares scheduled hours vs actual timesheet hours per project for a given week |
get_weekly_person_schedule_vs_actuals_report | Compares scheduled hours vs actual timesheet hours per person for a given week |
get_schedule_variance_report | Person × project variance showing over-scheduled assignments over multiple weeks |
get_project_schedule_vs_actuals_report | Project-level schedule vs actuals for any date range |
get_timesheet_compliance_report | Flags people who haven't logged enough hours against their schedule |
get_availability_report | Shows who has available capacity (bench time) for a given week |
get_project_health_report | Portfolio health summary with red/amber/green status for all active projects |
get_revenue_forecast_report | Compares forecasted revenue against actual recognized revenue |
get_client_profitability_report | Aggregates revenue, costs, profit, and margin by client across all projects |
In-Memory Caching
All API responses (except actuals and reports) are cached in-memory with automatic TTL-based expiration. This significantly reduces redundant API calls when the same data is requested multiple times within a session.
Cache TTL Tiers
| TTL | Category | Endpoints |
|---|---|---|
| 10 minutes | Stable reference data | Roles, tags, holidays, rate cards, account, placeholders |
| 5 minutes | Semi-stable data | People, clients, contracts, time off |
| 2 minutes | Dynamic data | Projects, assignments, milestones, phases |
| No cache | Time-sensitive data | Actuals, all reports (metrics, hours, totals) |
Manual Cache Invalidation
Use the clear_cache tool to immediately invalidate all cached entries when you need guaranteed fresh data. The cache is also automatically cleared when the MCP server process restarts.
Prerequisites
- Node.js 20.0.0 or higher
- A valid Runn API key
Installation
1. Clone and Build
# Navigate to the project directory
cd runn-mcp
# Install dependencies
npm install
# Build the project
npm run build
2. Get Your Runn API Key
- Log in to Runn
- Go to Settings → API
- Generate a new API key
- Copy the key for use in configuration
Configuration
The server supports two transport modes:
- stdio — for local development (runs as a child process)
- HTTP — for production deployment (runs as a web server)
Local Mode (stdio) — For Development
Claude Desktop
Add the following to your Claude Desktop configuration file:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"runn": {
"command": "node",
"args": ["/absolute/path/to/runn-mcp/build/index.js"],
"env": {
"RUNN_API_KEY": "your-runn-api-key-here"
}
}
}
}
ChatGPT Desktop
{
"mcpServers": {
"runn": {
"command": "node",
"args": ["/absolute/path/to/runn-mcp/build/index.js"],
"env": {
"RUNN_API_KEY": "your-runn-api-key-here"
}
}
}
}
Cline (VS Code Extension)
{
"mcpServers": {
"runn": {
"command": "node",
"args": ["/absolute/path/to/runn-mcp/build/index.js"],
"env": {
"RUNN_API_KEY": "your-runn-api-key-here"
}
}
}
}
Important: Replace /absolute/path/to/runn-mcp with the actual absolute path to your runn-mcp directory.
Remote Mode (HTTP) — For Production / Team Access
When deployed as an HTTP server, coworkers connect via URL instead of running the server locally.
Claude Desktop (Remote)
{
"mcpServers": {
"runn": {
"url": "https://mcp-runn.gigaplayops.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN_HERE"
}
}
}
}
Cline (Remote)
Same format — point to the URL with the auth header in your MCP server settings.
Role-Based Access Control
The HTTP server supports three access tiers. Each bearer token is mapped to a role, and the role determines which tools are available.
| Role | Description |
|---|---|
god | Full access to all tools |
executive | All tools (customizable — can restrict to financial/portfolio views) |
project-manager | All tools (customizable — can restrict to operational tools only) |
Currently all roles have access to all tools. To restrict tools per role, edit src/tool-permissions.ts and change the minimum role for each tool.
Token Configuration
Set the MCP_AUTH_TOKENS environment variable as JSON:
MCP_AUTH_TOKENS={"god":"token-aaa","executive":"token-bbb,token-ccc","project-manager":"token-ddd,token-eee"}
- Each role maps to one or more bearer tokens (comma-separated)
- Tokens must be unique across all roles
- Use long, random strings for production tokens (e.g.,
openssl rand -hex 32)
Production Deployment
Environment Variables
| Variable | Required | Description |
|---|---|---|
RUNN_API_KEY | Yes | Your Runn API key |
MCP_AUTH_TOKENS | Yes (HTTP mode) | JSON mapping roles to bearer tokens |
PORT | No | HTTP port (default: 3000) |
Running Locally (HTTP mode)
npm run build
RUNN_API_KEY=your-key MCP_AUTH_TOKENS='{"god":"test-token"}' npm run start:http
Docker
# Build
docker build -t runn-mcp .
# Run
docker run -p 3000:3000 \
-e RUNN_API_KEY=your-key \
-e MCP_AUTH_TOKENS='{"god":"token-aaa","executive":"token-bbb"}' \
runn-mcp
Health check: GET /health
AWS App Runner
The server is designed for AWS App Runner with Docker image source from ECR.
One-time setup:
- Create an ECR repository named
runn-mcp - Create an App Runner service with:
- Source: ECR image (
<account>.dkr.ecr.<region>.amazonaws.com/runn-mcp:latest) - Port: 3000
- Health check: HTTP
/health - Environment variables:
RUNN_API_KEY,MCP_AUTH_TOKENS,PORT=3000
- Source: ECR image (
- Add custom domain
mcp-runn.gigaplayops.comin App Runner console - Create CNAME in Route53 pointing to the App Runner domain
GitHub Actions CI/CD
The repo includes .github/workflows/deploy.yml that automatically builds and deploys on push to main.
Required GitHub Secrets:
| Secret | Description |
|---|---|
AWS_ACCESS_KEY_ID | IAM credentials with ECR + App Runner permissions |
AWS_SECRET_ACCESS_KEY | Corresponding secret key |
AWS_REGION | e.g. us-east-1 |
ECR_REPOSITORY | ECR repository name (e.g. runn-mcp) |
APPRUNNER_SERVICE_ARN | ARN of the App Runner service |
The workflow:
- Checks out code and builds TypeScript
- Builds Docker image and pushes to ECR (tagged with commit SHA +
latest) - Triggers App Runner deployment via
aws apprunner start-deployment
Usage Examples
Once configured, you can ask your AI assistant questions like:
People:
- "Show me all active people in Runn"
- "Find the person with email john@example.com in Runn"
Projects:
- "What projects are currently active?"
- "Show me details for project ID 12345"
Clients:
- "List all our clients"
- "What projects does client X have?"
Assignments:
- "Who is assigned to which projects?"
- "Show me all active assignments"
Available Tools
People Tools
get_all_people
Fetches all people from Runn with optional filtering.
onlyActive(optional, boolean): If true, only returns active peoplemodifiedAfter(optional, string): ISO 8601 date string to filter by modification date
get_person_by_id
Fetches a specific person by their unique ID.
personId(required, string): The unique identifier of the person
get_person_by_email
Fetches a specific person by their email address.
email(required, string): The email address of the person
Project Tools
get_all_projects
Fetches all projects from Runn with optional filtering.
onlyActive(optional, boolean): If true, only returns active projectsmodifiedAfter(optional, string): ISO 8601 date string to filter by modification date
get_project_by_id
Fetches a specific project by its unique ID.
projectId(required, string): The unique identifier of the project
Client Tools
get_all_clients
Fetches all clients from Runn with optional filtering.
onlyActive(optional, boolean): If true, only returns active clientsmodifiedAfter(optional, string): ISO 8601 date string to filter by modification date
get_client_by_id
Fetches a specific client by its unique ID.
clientId(required, string): The unique identifier of the client
get_client_projects
Fetches all projects assigned to a specific client.
clientId(required, string): The unique identifier of the client
Assignment Tools
get_all_assignments
Fetches all assignments from Runn with optional filtering.
onlyActive(optional, boolean): If true, only returns active assignmentsmodifiedAfter(optional, string): ISO 8601 date string to filter by modification date
get_active_assignments
Fetches only currently active assignments from Runn.
- No parameters required
Actuals Tools
get_all_actuals
Fetches all logged time (actuals) from Runn with optional filtering.
minDate(optional, string): Minimum date filter (YYYY-MM-DD format)maxDate(optional, string): Maximum date filter (YYYY-MM-DD format)projectId(optional, string): Filter by project IDpersonId(optional, string): Filter by person IDroleId(optional, string): Filter by role ID
get_person_actuals
Fetches logged time for a specific person.
personId(required, string): The unique identifier of the personminDate(optional, string): Minimum date filter (YYYY-MM-DD format)maxDate(optional, string): Maximum date filter (YYYY-MM-DD format)
get_project_actuals
Fetches logged time for a specific project.
projectId(required, string): The unique identifier of the projectminDate(optional, string): Minimum date filter (YYYY-MM-DD format)maxDate(optional, string): Maximum date filter (YYYY-MM-DD format)
Reports Tools
get_person_metrics
BETA: Fetches utilization metrics for a person (billable utilization, revenue, costs, capacity).
personId(required, string): The unique identifier of the personstartDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)todayDate(optional, string): Reference date for calculations (YYYY-MM-DD)
get_project_metrics
BETA: Fetches financial metrics for a project (revenue, profit, costs, margin, budget).
projectId(required, string): The unique identifier of the projectstartDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)todayDate(optional, string): Reference date for calculations (YYYY-MM-DD)
get_person_hours_report
Fetches day-by-day hours report for a person (scheduled vs actual).
personId(required, string): The unique identifier of the personstartDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)
get_project_hours_report
Fetches day-by-day hours report for a project (scheduled vs actual).
projectId(required, string): The unique identifier of the projectstartDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)
get_all_project_totals
Fetches aggregated totals for all projects (hours, revenue, costs).
startDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)todayDate(optional, string): Reference date for calculations (YYYY-MM-DD)
get_project_totals
Fetches aggregated totals for a specific project.
projectId(required, string): The unique identifier of the projectstartDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)todayDate(optional, string): Reference date for calculations (YYYY-MM-DD)
get_all_people_metrics
BETA: Fetches utilization metrics for all people.
startDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)todayDate(optional, string): Reference date for calculations (YYYY-MM-DD)
get_all_project_metrics
BETA: Fetches financial metrics for all projects.
startDate(required, string): Start date for the report period (YYYY-MM-DD)endDate(required, string): End date for the report period (YYYY-MM-DD)todayDate(optional, string): Reference date for calculations (YYYY-MM-DD)
Roles Tools
get_all_roles
Fetches all job roles defined in Runn.
- No parameters required
get_role_by_id
Fetches a specific role by its unique ID.
roleId(required, string): The unique identifier of the role
Contracts Tools
get_all_contracts
Fetches all employment contracts from Runn.
- No parameters required
get_person_contracts
Fetches all employment contracts for a specific person.
personId(required, string): The unique identifier of the person
Holidays Tools
get_all_holidays
Fetches all public holidays configured in Runn.
- No parameters required
Time Off Tools
get_all_time_off
Fetches all time off (leave/vacation) entries.
personId(optional, string): Filter by person IDminDate(optional, string): Minimum date filter (YYYY-MM-DD)maxDate(optional, string): Maximum date filter (YYYY-MM-DD)
get_person_time_off
Fetches time off for a specific person.
personId(required, string): The unique identifier of the personminDate(optional, string): Minimum date filter (YYYY-MM-DD)maxDate(optional, string): Maximum date filter (YYYY-MM-DD)
Milestones Tools
get_all_milestones
Fetches all project milestones from Runn.
projectId(optional, string): Filter by project ID
get_project_milestones
Fetches all milestones for a specific project.
projectId(required, string): The unique identifier of the project
Phases Tools
get_project_phases
Fetches all phases for a specific project.
projectId(required, string): The unique identifier of the project
Rate Cards Tools
get_all_rate_cards
Fetches all billing rate cards from Runn.
- No parameters required
Placeholders Tools
get_all_placeholders
Fetches all placeholder resources from Runn.
- No parameters required
Tags Tools
get_all_tags
Fetches all tags/labels from Runn.
- No parameters required
Account Tools
get_account
Fetches your Runn account information and settings.
- No parameters required
Cache Management Tools
clear_cache
Clears the in-memory cache for all Runn API responses. Use this if you need fresh data immediately without waiting for cached entries to expire.
- No parameters required
Composite Report Tools
get_weekly_schedule_vs_actuals_report
Generates a composite report comparing scheduled assignment hours vs actual timesheet hours per project for a given week (Monday–Sunday). Fetches assignments, actuals, and projects in parallel, calculates overlap days, and returns structured JSON with per-project and total rows including a delta (scheduled − actual).
weekOf(optional, string): Any date (YYYY-MM-DD) within the desired week. The tool automatically resolves to the Monday–Sunday window containing that date. Defaults to last week if omitted.
get_client_profitability_report
Aggregates financial metrics (revenue, costs, profit, margin) by client across all their projects. Ranks clients from most to least profitable, with per-project breakdowns nested within each client. Also shows projects with no client assignment. Useful for executives to understand which clients are most/least profitable and where to focus account management.
startDate(optional, string): Start date for the report period (YYYY-MM-DD). Defaults to first day of current month.endDate(optional, string): End date for the report period (YYYY-MM-DD). Defaults to last day of current month.
Development
# Install dependencies
npm install
# Build the project
npm run build
# Watch mode (auto-rebuild on changes)
npm run dev
# Run the server (for testing)
npm start
Troubleshooting
"RUNN_API_KEY environment variable is required"
Make sure you've added the RUNN_API_KEY to your MCP server configuration's env section.
Server not connecting
- Verify the path to
build/index.jsis correct and absolute - Ensure you've run
npm run buildafter any changes - Check that Node.js 20+ is installed:
node --version
API errors
- Verify your Runn API key is valid
- Check that your Runn account has API access enabled
- Ensure you have permissions to access the requested data
License
MIT
Credits
- Uses the runn-api-client npm package
- Built with the Model Context Protocol SDK