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.