Runn MCP Server
Connects AI assistants to the Runn.io resource planning platform to manage projects, people, assignments, and financial forecasts. It provides 37 tools for accessing real-time data and comprehensive reports with built-in caching and role-based access control.
README
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 Team (Custom Connector with OAuth)
The server supports OAuth 2.0 Client Credentials flow, which integrates with Claude's custom connector feature for team-wide access.
Setup in Claude Admin Console:
- Go to your Claude team's Admin Settings → Connectors → Add Custom Connector
- Fill in:
| Field | Value |
|---|---|
| Name | Runn |
| Remote MCP server URL | https://mcp-runn.gigaplayops.com/mcp |
| OAuth Client ID | Your client ID (from OAUTH_CLIENTS env var) |
| OAuth Client Secret | Your client secret (from OAUTH_CLIENTS env var) |
- Click Add
Claude will automatically discover the OAuth metadata endpoints, exchange credentials for a Bearer token, and authenticate all MCP requests.
How it works under the hood:
- Claude connects to
/mcp→ receives 401 withWWW-Authenticateheader - Claude fetches
/.well-known/oauth-protected-resource→ learns the auth server - Claude fetches
/.well-known/oauth-authorization-server→ learns the token endpoint - Claude POSTs
client_credentialsto/oauth/token→ receives a Bearer token (1-hour TTL) - Claude uses the Bearer token for all subsequent
/mcprequests - When the token expires or the container restarts, Claude re-authenticates automatically
Claude Desktop (Remote with Static Token)
{
"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.
Authentication
The HTTP server supports two authentication methods that can be used simultaneously:
Method 1: OAuth 2.0 Client Credentials (for Claude Team)
Configure OAuth clients via the OAUTH_CLIENTS environment variable:
OAUTH_CLIENTS={"claude-team":{"secret":"long-random-secret","role":"god"}}
Each entry maps a client_id → { secret, role }:
- client_id: Any string identifier (e.g.,
claude-team,claude-executive) - secret: A long, random string (generate with
openssl rand -hex 32) - role: One of
god,executive, orproject-manager
Multiple OAuth clients can be configured:
OAUTH_CLIENTS={"claude-god":{"secret":"aaa...","role":"god"},"claude-pm":{"secret":"bbb...","role":"project-manager"}}
OAuth Endpoints:
| Endpoint | Purpose |
|---|---|
GET /.well-known/oauth-protected-resource |
Protected Resource Metadata (RFC 9728) |
GET /.well-known/oauth-authorization-server |
Authorization Server Metadata (RFC 8414) |
POST /oauth/token |
Token endpoint — client_credentials grant |
POST /oauth/register |
Dynamic Client Registration (RFC 7591) |
Tokens are issued with a 1-hour TTL and stored in-memory. Container restarts clear all issued tokens — clients simply re-authenticate.
Method 2: Static Bearer Tokens (for Cline / Claude Desktop)
Configure static tokens via the MCP_AUTH_TOKENS environment variable:
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)
Both methods are optional
- Set only
OAUTH_CLIENTS→ only OAuth authentication works - Set only
MCP_AUTH_TOKENS→ only static Bearer token authentication works - Set both → both methods work simultaneously
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 |
OAUTH_CLIENTS |
No* | JSON mapping client_id → { secret, role } for OAuth 2.0 |
MCP_AUTH_TOKENS |
No* | JSON mapping roles to static bearer tokens |
MCP_BASE_URL |
No | Public base URL for OAuth metadata (e.g., https://mcp-runn.gigaplayops.com) |
PORT |
No | HTTP port (default: 3000) |
* At least one of OAUTH_CLIENTS or MCP_AUTH_TOKENS should be set, otherwise all requests will be rejected.
Running Locally (HTTP mode)
npm run build
# With OAuth (for Claude Team connector testing):
RUNN_API_KEY=your-key \
OAUTH_CLIENTS='{"claude-team":{"secret":"test-secret","role":"god"}}' \
MCP_BASE_URL=http://localhost:3000 \
npm run start:http
# With static tokens (for Cline/Claude Desktop):
RUNN_API_KEY=your-key \
MCP_AUTH_TOKENS='{"god":"test-token"}' \
npm run start:http
# With both:
RUNN_API_KEY=your-key \
OAUTH_CLIENTS='{"claude-team":{"secret":"test-secret","role":"god"}}' \
MCP_AUTH_TOKENS='{"god":"test-token"}' \
MCP_BASE_URL=http://localhost:3000 \
npm run start:http
Docker
# Build
docker build -t runn-mcp .
# Run
docker run -p 3000:3000 \
-e RUNN_API_KEY=your-key \
-e OAUTH_CLIENTS='{"claude-team":{"secret":"long-random-secret","role":"god"}}' \
-e MCP_AUTH_TOKENS='{"god":"token-aaa","executive":"token-bbb"}' \
-e MCP_BASE_URL=https://mcp-runn.gigaplayops.com \
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,OAUTH_CLIENTS,MCP_AUTH_TOKENS,MCP_BASE_URL,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
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.