Skip to main content
Glama

gantt-mcp

An OAuth-protected MCP server that turns a project description into a real schedule. You describe the plan in a conversation — the team, the phases, the tasks and what depends on what — and the server does the project-management maths: it resolves dependencies, respects working calendars, assigns people by skill, levels the load so nobody is booked twice, computes the critical path, and stores the result as JSON. Back you get a shareable chart page plus SVG, PNG, JSON and CSV endpoints. There is no database and no session: the server is stateless, projects live in Vercel Blob (or a local .data/ folder in development) and OAuth tokens are self-contained signed JWTs.

Features

  • Scheduling engine — forward/backward CPM pass, FS/SS/FF/SF dependencies with lag or lead, date constraints, working calendars with holidays and per-day exceptions, effort-driven durations.

  • Team-aware — resources with capacity (FTE), skills, personal calendars and cost; automatic assignment by required skill; resource levelling.

  • Structure — nested groups (WBS) with roll-up dates and progress, milestones, deadlines with warnings, baselines, per-task progress.

  • Rendering — deterministic, dependency-free SVG; PNG rasterisation; CSV export; light and dark themes; five zoom levels from hour to quarter.

  • MCP — six tools over Streamable HTTP (JSON responses), with OAuth 2.1: metadata discovery, dynamic client registration and PKCE.

  • Stateless — no database, no server-side session, safe to run on serverless.

Related MCP server: AroFlo MCP

Quick start

npm install
cp .env.example .env.local
npm run dev

Then open http://localhost:3100/demo for a rendered example chart, or http://localhost:3100 for the landing page. The dev server is pinned to port 3100 so the MCP endpoint you register in a client stays stable even when another project is using port 3000; the landing page always advertises the host it is actually being served from.

For local experiments without the OAuth dance, set MCP_AUTH=off in .env.local and point any MCP client at http://localhost:3100/api/mcp.

Other scripts:

npm test          # vitest run
npm run typecheck # tsc --noEmit
npm run build     # next build

Connecting a client

Every client needs the same single URL: https://<deployment>/api/mcp. The landing page has step-by-step instructions per client (Claude Code, Claude Desktop, Claude web, ChatGPT, Codex CLI, Cursor, VS Code and a generic fallback) at /#connect. The short version:

Client

How

Claude Code

claude mcp add --transport http gantt https://<deployment>/api/mcp, then /mcp to sign in

Claude Desktop / web

Settings → Connectors → Add custom connector → paste the URL

ChatGPT

Enable Developer mode, then add a connector pointing at the URL

Codex CLI

codex mcp add gantt --url https://<deployment>/api/mcp

Cursor

Add {"mcpServers":{"gantt":{"url":"…"}}} to ~/.cursor/mcp.json

VS Code

Add {"servers":{"gantt":{"type":"http","url":"…"}}} to .vscode/mcp.json

stdio-only clients

npx -y mcp-remote@latest <url> --transport http-only

The Claude Desktop and Claude web connectors are called from Anthropic's own infrastructure, so the deployment has to be reachable from the public internet — a localhost URL only works with the CLI and IDE clients.

What happens under the hood:

  • Discovery — the unauthenticated request to /api/mcp answers 401 with a WWW-Authenticate header pointing at /.well-known/oauth-protected-resource (RFC 9728), which points at the authorization server metadata at /.well-known/oauth-authorization-server (RFC 8414). The same document is also served at /.well-known/openid-configuration, for clients that probe that path first, and at /.well-known/oauth-protected-resource/api/mcp for the path-suffixed RFC 9728 form.

  • Dynamic client registration — the client POSTs its redirect URI to /api/oauth/register (RFC 7591) and gets back a client_id. No client secret: the client_id is a signed JWT, so nothing has to be stored.

  • PKCE — the authorization code flow at /authorize uses code_challenge_method=S256, the only method advertised. The one-minute code is exchanged at /api/oauth/token for an access token (1 hour, audience-restricted to /api/mcp) and a refresh token (30 days); /api/oauth/revoke revokes them. Scopes are gantt:read and gantt:write.

Because registration is open, anyone who knows the URL can reach the consent screen. Set AUTH_PASSWORD to require a password there — the authorization request is only approved when the password matches, which effectively locks the deployment down to you. Charts are owned by the token subject, so list_gantts and delete_gantt only ever see your own.

MCP tools

Tool

Arguments

What it does

create_gantt

name*, tasks*, description, start, end, calendar, resources, groups, options

Validates and schedules a new project, stores it, returns the report and the links.

add_tasks

id*, tasks*, groups, resources

Appends tasks (and optionally new groups/resources) and reschedules. Use it to build large plans in batches of 50–80.

update_gantt

id*, name, description, start, end, calendar, resources, groups, tasks, options

Replaces only the fields you send. Sending tasks replaces the whole task list.

get_gantt

id*, includeTasks, maxTasks

Recomputes and returns dates, critical path, resource load, warnings and links.

list_gantts

limit

Your charts, most recently updated first.

delete_gantt

id*

Permanently deletes a chart and its stored JSON.

* required.

Task fields: id, name, group, duration + durationUnit, work + workUnit, start, end, milestone, progress, assignees, requiredSkill, requiredResources, dependencies, constraint, priority, color, notes, tags, deadline, baselineStart, baselineEnd.

Resource fields: id, name, role, skills, capacity, calendar, color, costPerHour, email. Group fields: id, name, parentId, color, collapsed, order.

The authoritative JSON Schemas are in src/lib/mcp/schemas.ts; the Zod contract they mirror is in src/lib/domain/schema.ts.

The scheduling model

Time. Every instant is an absolute number of minutes since the Unix epoch, in UTC. YYYY-MM-DD means UTC midnight. Nothing depends on the machine's timezone, so the same input always yields the same schedule.

Working calendars. A calendar declares workdays (0 = Sunday … 6 = Saturday, default Mon–Fri), hoursPerDay (default 8), dayStartHour (default 09:00 UTC), holidays and per-date exceptions (a day off, or an exceptional / shorter working day). Resources may override the project calendar with their own — part-time hours, personal holidays. Work is only ever placed inside working windows.

Units. Durations are working units: an hour is 60 minutes, a day is hoursPerDay, a week is the calendar's working days, and a month is a flat 4 working weeks (~20 days, the MS-Project convention). minute is also available.

Duration vs work. duration is elapsed working time — the task takes that long whoever does it. work is effort: the duration is derived by dividing the effort by the assigned units, so two full-time people halve it and a half-time person doubles it. Give work whenever the size of the task is what you know.

Dependencies. A plain string is a finish-to-start link with no lag. The object form takes a typeFS (finish→start), SS (start→start), FF (finish→finish), SF (start→finish) — and a lag in any duration unit; a negative lag is a lead, i.e. an overlap. Cycles are detected and reported as warnings instead of hanging the scheduler.

Constraints. asap (default), snet (start no earlier than), fnlt (finish no later than), mso (must start on), mfo (must finish on). An explicit start pins a task manually. A deadline does not move anything — it raises a warning if the task finishes later.

Auto-assignment. With options.autoAssign on (default), a task carrying a requiredSkill is given to the least-loaded resource that has that skill; requiredResources asks for more than one. Assignees can be given as ids/names, or as {"resourceId":"ana","units":0.5} to book part of someone.

Resource levelling. With options.levelResources on (default), tasks are pushed later until no resource is over-booked. priority decides who wins when two tasks compete; the delay applied to each task is reported.

Critical path. A backward pass computes late start/finish and total float. Zero-float tasks are the critical path and are highlighted in the chart.

Groups / WBS. Groups nest through parentId. A group's dates, duration and progress roll up from its children, so a phase bar always spans its tasks.

Milestones, progress, baselines. milestone: true is a zero-duration diamond. progress is 0–100 and is drawn inside the bar and rolled up to groups. baselineStart / baselineEnd draw the original plan under the current bar so slippage is visible.

Chart URLs

Every chart is identified by a random 12-character id.

URL

Returns

/g/<id>

The shareable HTML page.

/api/gantt/<id>/svg

image/svg+xml.

/api/gantt/<id>/png

image/png, rasterised from the same SVG.

/api/gantt/<id>/json

The project spec plus a schedule summary.

/api/gantt/<id>/csv

One row per task (text/csv, always an attachment).

Appearance is driven by query parameters, each falling back to the option stored on the project (see src/lib/gantt/render.ts). They apply to the page, the SVG and the PNG:

Parameter

Values

Meaning

zoom

hour, day, week, month, quarter

Timeline granularity.

groupBy (alias group)

group, resource, none

How rows are grouped.

theme

light, dark

Colour scheme.

deps

0/false/no to disable

Draw dependency arrows.

critical

idem

Highlight the critical path.

progress

idem

Draw progress inside bars.

today

idem

Draw the "today" marker.

rowHeight

18–64

Row height in pixels.

columnWidth

4–400

Width of one timeline column.

maxRows

1–5000

Truncate very large charts.

collapsed

comma-separated group ids

Collapse those groups.

The viewer stores the chosen theme in a gantt-theme cookie so the server renders the right palette on the first paint; an explicit ?theme= in the URL always wins.

Endpoint-specific parameters:

  • /svgdownload (any value, or empty): serve as an attachment instead of inline.

  • /pngscale (device pixel ratio, default 2); inline to serve inline, otherwise the PNG is sent as an attachment.

  • /jsonfull to include every task, group and resource with resolved dates, instead of just the project and the summary.

Example: /api/gantt/abc123def456/png?zoom=day&theme=dark&scale=3&critical=0

Deployment on Vercel

  1. Import the repository into Vercel (framework preset: Next.js — vercel.json already pins it and gives the PNG and MCP routes a 60 s maxDuration).

  2. Create a Blob store on the project's Storage tab. Vercel injects BLOB_READ_WRITE_TOKEN automatically; without it the app falls back to writing JSON under .data/, which is fine locally but useless on serverless (the filesystem is ephemeral and per-instance).

    Charts are stored as private blobs (access: 'private') and read back with the authenticated SDK, so the raw project JSON is only reachable through this app. Note that a chart page is still deliberately public to anyone holding its link — /g/<id> and the export routes are unauthenticated by design, because that link is what the MCP tools hand back. Private storage means no second, CDN-served copy of the data outside the app, not that charts are private.

  3. Set the environment variables:

    • APP_URL — the canonical deployment URL, e.g. https://gantt.example.com. It is the OAuth issuer and the base of every generated link, so it must be stable. If unset it is inferred from VERCEL_PROJECT_PRODUCTION_URL / VERCEL_URL.

    • AUTH_SECRETopenssl rand -base64 48. Signs client ids, authorization codes and tokens; rotating it invalidates everything already issued.

    • AUTH_PASSWORD — optional, locks the consent screen.

    • MCP_AUTH — leave unset (required) in production.

  4. Deploy, then add https://<deployment>/api/mcp as a custom connector in Claude.

Architecture

src/
  app/                     routes only — parse the request, call a service, respond
    api/mcp/route.ts         MCP endpoint (POST; GET/DELETE are 405)
    api/gantt/[id]/          svg | png | json | csv
    api/oauth/               register | token | revoke
  components/              shared UI (logo, copy field, marketing blocks)
  lib/
    domain/                the contract: types, Zod schema, normalisation, time, defaults
    schedule/              pure engine: calendar, graph, CPM passes, auto-assign, levelling, roll-up
    render/                pure geometry (layout) → SVG → PNG; theme and text metrics
    storage/               the only I/O layer: Blob | local .data/ | memory, project keys
    oauth/                 metadata, dynamic registration, PKCE, JWT tokens
    mcp/                   JSON-RPC protocol, tool definitions, HTTP + auth glue
    gantt/                 service tying it together: validate → schedule → store → links,
                           plus the text report and the chart loader used by the routes
    config.ts              environment-derived configuration and URL builders

The dependency direction is strictly one-way: appgantt → {schedule, render, storage} → domain. The engine layers are pure functions — no I/O, no clock, no randomness — which is what makes the output reproducible and the tests cheap.

Testing

npm test

Unit tests sit next to the code they cover (src/**/*.test.ts): the scheduler and its levelling, the dependency graph, the layout and timescale, the SVG output, the OAuth flow, the MCP protocol and the storage adapters. tests/render-preview.test.ts renders full charts end to end; set PREVIEW_DIR to keep the generated files somewhere you can look at them.

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • MCP server for generating rough-draft project plans from natural-language prompts.

  • Streamable HTTP MCP server for Google Calendar and Sheets with OAuth login.

  • MCP server for Argo RPG Platform — connects AI assistants to campaign data via OAuth2

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rioukkevin/gantt-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server