gantt-to

An MCP server your agent writes a plan into.

Connect it, then ask for a timeline. Ten tools, one of which takes an entire plan — tasks, nesting and dependencies — in a single call. What comes back is a chart with a link you can send to whoever asked for it.

Endpoint: https://api.gantt-to.work/mcp — Streamable HTTP, protocol 2025-06-18. The handshake and the tool list need no credential; every tool needs the same bearer key the REST API takes.

Connect

One entry in your client's config.

There is nothing to install and no package to run. It is a remote server over HTTP, so the whole setup is a URL and a header.

{
  "mcpServers": {
    "gantt-to": {
      "type": "http",
      "url": "https://api.gantt-to.work/mcp",
      "headers": { "Authorization": "Bearer gt_live_your_key" }
    }
  }
}

That shape works in Claude Code's .mcp.json and in Cursor's mcp.json. In Claude Code you can add it from the terminal instead:

claude mcp add --transport http gantt-to https://api.gantt-to.work/mcp \
  --header "Authorization: Bearer gt_live_your_key"

Keys are created on the API keys page in the app. A key cannot mint further keys and cannot reach billing, so the one you paste into a client config cannot compound if it leaks.

Sign-in to the app is invite-only while it is in early access, so keys are not self-serve today. Everything on this page that does not need a key — the handshake, the tool list, the example chart and its JSON — is open to anyone right now.

The tools

Ten of them, and each one is a documented route.

Every tool dispatches the REST call it names, through the same router, with the same credential. Authorization, plan limits, validation and the error envelope cannot answer differently depending on how you arrived — because there is only one implementation of each.

Tool What it does The route it is
whoami The account, the organizations it can reach, the limits in force GET /v1/me
list_organizations Every organization, with your role in each GET /v1/orgs
create_organization A new organization — one per client keeps plans apart POST /v1/orgs
list_projects Projects in one organization GET /v1/orgs/{id}/projects
create_project An empty project to write a chart into POST /v1/orgs/{id}/projects
get_chart The whole chart: project, tasks, dependencies GET /v1/projects/{id}/gantt
write_chart Replaces the chart with exactly what you send PUT /v1/projects/{id}/gantt
update_chart Adds and amends, deletes nothing POST /v1/projects/{id}/tasks:batch
critical_path Total float per task, and which tasks have none GET /v1/projects/{id}/critical-path
share_project Publish or unpublish a read-only link PATCH /v1/projects/{id}

Nothing has to exist first. An agent holding one key creates the organization, creates the project, writes the plan and publishes the link, with no person opening the app at any point.

The one thing to read before writing

Two write tools that mean opposite things.

This is the distinction that costs real data when it is guessed at, so the server repeats it in its own handshake instructions rather than trusting a tool list to convey it.

write_chart — the chart is exactly this

Tasks in the project but missing from your call are deleted. Fields missing from a task you did send are reset. Use it when you can state what every task in the project should look like.

update_chart — apply these changes

Creates what is new, updates what you name, and deletes nothing. Fields you leave out are left alone. This is the right tool for keeping a plan current as the work moves.

{
  "tasks": [
    {"ref": "design", "name": "Design",  "start_date": "2026-09-01", "end_date": "2026-09-07"},
    {"ref": "build",  "name": "Build",   "start_date": "2026-09-08", "end_date": "2026-09-25"},
    {"ref": "api",    "name": "The API", "start_date": "2026-09-08", "end_date": "2026-09-18",
     "parent_ref": "build"},
    {"ref": "launch", "name": "Launch",  "start_date": "2026-09-30", "is_milestone": true}
  ],
  "dependencies": [
    {"predecessor_ref": "design", "successor_ref": "build"},
    {"predecessor_ref": "build",  "successor_ref": "launch", "lag_days": 2}
  ]
}

Tasks are addressed by a ref you chose, so nesting and dependencies join by name and no server-generated id is ever returned to you and sent back. One call, one transaction: all of it lands or none of it does.

When the agent gets it wrong

It is refused, and the refusal says why.

An agent cannot notice that a field went missing, so nothing is silently dropped. A failed tool call comes back with the API's own error body as its text — which is the thing the model actually reads before its next attempt.

{"error": {"code": "invalid_request",
           "message": "could not parse the request body: json: unknown field \"owner\""}}

A misspelled field is a refusal, not a dropped value. An unresolvable ref is a refusal. A dependency cycle is refused inside the same database transaction as the insert. In every case the chart is left byte-identical, so a failed call needs no cleanup.

Critical path

Where the slack is, without moving your dates.

critical_path reports how many days each task can slip before it pushes a dependent task or the end of the plan. Zero float is the critical path.

It is a read. Dates here are whatever you set, and nothing rewrites them, so time you left on purpose is reported as slack rather than scheduled away. If you want a tool that moves bars for you, this is not that tool and it is better to know now.

curl https://api.gantt-to.work/v1/public/demo/website-relaunch/critical-path

No key needed — that is the example chart, and it is a fair illustration: its phases were drawn with gaps, so one milestone has zero float and the other eleven tasks carry between three and eighty-one days of it.

Honestly

What it does not do.

Turning the wrong people away early is cheaper than losing them later, and it is the same instinct as the API returning 400 on a typo.

No auto-scheduling

Dates are what you set. Nothing cascades, nothing levels resources, nothing recalculates a schedule for you.

No resources, cost or earned value

Tasks have an assignee as free text. There is no resource model, no capacity and no budget.

No SSO, audit log or ownership transfer

If procurement needs those, this is not ready for you yet, and saying so now costs less than saying it after a trial.

No model inside

There is no AI in the product. It is a place an agent writes to, which is a different and more boring thing.

The API is not an upgrade.

The MCP server, the full REST API, real keys and the whole contract are on the free plan with no card. Paid plans raise how many plans you can keep and who can write to them — never what you can do.