@qordo-ai/mcp
v0.16.0
Published
Qordo MCP Server — task management tools for Claude Code and Codex
Maintainers
Readme
Qordo MCP Server
MCP server for Qordo — task management tools for Claude Code, ChatGPT and OpenAI Codex.
Search tasks, create and update tasks, read comments, build intake forms, navigate your workspace hierarchy — all from your AI assistant.
Setup
The server is hosted at https://mcp.qordo.ai/mcp. Clients that sign in with
OAuth need nothing else: they discover the authorization server, register
themselves, and open a Qordo consent screen for you to approve. There is no
token to copy and nothing to install.
Claude Code
claude mcp add --transport http qordo https://mcp.qordo.ai/mcpOr, in .mcp.json:
{
"mcpServers": {
"qordo": {
"type": "http",
"url": "https://mcp.qordo.ai/mcp"
}
}
}OpenAI Codex
codex mcp add qordo --url https://mcp.qordo.ai/mcp
codex mcp login qordoChatGPT
Add https://mcp.qordo.ai/mcp as a connector in settings. ChatGPT registers
itself on first use.
The consent screen names the client and the address it will send you back to — read both before approving, since any client may choose its own display name. Review and revoke what you have approved under Profile > Connected Apps.
Claude Code is the client this flow has been tested against end to end. Codex and ChatGPT follow the same standards and should work unchanged; if either does not, open an issue with the error the client reports.
Clients that do not sign in
Claude Desktop reads a config file and cannot complete an OAuth flow, so it needs a personal API token. Generate one under Profile > API Token in Qordo. It is about a kilobyte long — copy the whole thing, it is not truncated.
A token is a long-lived credential sitting in a plaintext file. Prefer OAuth where the client supports it; a grant is scoped to one client and revocable on its own.
Against the hosted server, the token goes in a header:
{
"mcpServers": {
"qordo": {
"type": "http",
"url": "https://mcp.qordo.ai/mcp",
"headers": {
"Authorization": "Bearer <your-token>"
}
}
}
}To run the server locally over stdio instead:
{
"mcpServers": {
"qordo": {
"command": "npx",
"args": ["-y", "@qordo-ai/mcp"],
"env": {
"QORDO_API_TOKEN": "<your-token>"
}
}
}
}The same stdio form works in Codex (~/.codex/config.toml) and Claude Code
(claude mcp add qordo --env QORDO_API_TOKEN=<your-token> -- npx -y @qordo-ai/mcp),
though both are better served by OAuth above.
Using it
Ask your AI assistant things like:
- "What tasks are assigned to me in Qordo?"
- "Search for tasks related to authentication"
- "Create a task in the Backend > API Endpoints list"
- "Update TASK-42 status to Done"
- "Add a comment to the login bug task"
- "Copy the 海柜预报 form onto every list in the Inbound Container folder"
- "List every automation on the Design Task list and show me which ones are inherited"
Tools
| Tool | Description |
|------|-------------|
| get_me | Get your profile and workspace memberships |
| get_sidebar | Get full workspace hierarchy (spaces > folders > lists) |
| list_spaces | List spaces you can access |
| list_folders | List folders in a space |
| list_lists | List task lists in a folder |
| get_list_inbound_address | A list's Email-to-List address, read-only — never creates one |
| search_tasks | Full-text search across tasks and comments |
| get_task | Get full task details |
| list_tasks | List tasks with filters (status, priority, assignee, due date) |
| create_task | Create a new task |
| update_task | Update task status, priority, assignee, or due date |
| delete_task | Move one task to Trash, subtasks included — recoverable for 30 days |
| restore_task | Restore a trashed task, with whatever its deletion took |
| list_comments | List comments with threaded replies |
| add_comment | Add a comment or reply to a thread |
| list_task_attachments | Every file on a task, comment files and email originals included |
| read_task_attachment | Read a file: text and images up to 1 MB inline, otherwise a download URL |
| list_statuses | List valid statuses for a list |
| list_task_statuses | List valid statuses for one task (per-list; the only route for sprint-held tasks) |
| list_members | List workspace members for task assignment |
| get_task_activity | Get task change history |
| get_activity | Recent changes for one person or one container |
| get_task_dependencies | Get task blockers and blocked tasks |
| list_custom_fields | List the custom fields a list resolves |
| list_scope_custom_fields | List the fields defined directly at a workspace, space, folder or list |
| create_custom_field | Create a custom field at any scope, formula fields included |
| update_custom_field | Rename a field or change its settings or formula |
| add_custom_field_option | Add one option to a dropdown or multi-select field |
| list_forms | List the forms on a list, with their questions |
| get_form | Get one form and its share link |
| create_form | Create a form on a list |
| update_form | Change a form's settings, or enable it |
| delete_form | Delete a form |
| add_form_field | Add a question — a custom field, or a native task property |
| update_form_field | Change a question's wording, hint or required flag |
| get_automation_capabilities | Every trigger, condition operator, action and {{token}} the engine accepts |
| list_automations | List rules for a space, folder or list — inherited ones included |
| get_automation | Get one rule with its conditions and actions in order |
| create_automation | Create a rule; repeating an identical one returns the first |
| update_automation | Replace a rule's configuration |
| set_automation_enabled | Switch a rule on or off without touching its config |
| delete_automation | Delete a rule permanently |
| reorder_form_fields | Set the question order |
| remove_form_field | Remove a question from a form |
| list_task_templates | List the workspace's task templates |
| get_task_template | Read one template and the snapshot it applies |
| list_recent_task_templates | The five templates you used most recently |
| create_task_template | Save an existing task's shape as a template |
| update_task_template | Rename a template or change its visibility |
| update_task_template_from_task | Replace a template's contents — destructive, no undo |
| apply_task_template | Create a task from a template |
| delete_task_template | Delete a template |
| list_tags | The tags defined in a space, with ids and colours |
| create_tag | Define a new tag in a space |
| add_task_tag | Put a tag on a task, by id or by name |
| remove_task_tag | Take a tag off a task |
| list_task_watchers | Who follows a task — individuals and teams |
| add_task_watcher | Add a watcher without changing the assignee |
| remove_task_watcher | Stop someone watching a task |
| add_task_team_watcher | Add a whole team as a follower |
| remove_task_team_watcher | Stop a team following a task |
| list_views | The views saved on a container |
| get_view | One view's full configuration |
| list_view_tasks | The task rows a saved view resolves to, evaluated server-side |
| create_view | Create a view on a workspace, space, folder, list or sprint |
| update_view | Change a view's columns, filters, grouping or visibility |
| duplicate_view | Copy a view into the same container |
| delete_view | Delete a view |
| list_saved_filters | Workspace saved filters |
| create_saved_filter | Save a named, reusable filter |
| update_saved_filter | Rename a saved filter or replace its conditions |
| delete_saved_filter | Delete a saved filter |
| duplicate_saved_filter | Copy a saved filter, privately |
| list_my_focus | Your My Focus list (My Tasks), in your order — private to you |
| add_to_my_focus | Put a task at the bottom of your My Focus |
| remove_from_my_focus | Take a task off your My Focus |
| reorder_my_focus | Set your My Focus order — send every listed id |
| add_to_teammate_my_focus | Put a task on teammates' My Focus and notify them |
| list_task_my_focus_holders | Who has a task in their My Focus |
| remove_from_teammate_my_focus | Take a task off a teammate's My Focus and notify them |
| list_reminders | Your pending task reminders, soonest first |
| create_reminder | Have a task come back to your Inbox at a set time |
| update_reminder | Move a pending reminder |
| cancel_reminder | Delete a pending reminder |
| list_goals | Goals and goal folders you can see, with progress and your rights |
| get_goal | One goal with its targets, values, progress and linked tasks |
| create_goal | Create a goal — workspace-visible or private, optionally in a folder |
| add_goal_target | Add a Number, Currency, True/False or Tasks target to a goal |
| update_goal_target_progress | Set, increase or decrease a target, or tick it done |
A form belongs to one list, so a workspace with one list per customer needs the same form on each. These tools cover the lists that already exist; for a new list, Duplicate list copies the source list's forms across in one step.
Form questions are custom fields — add_form_field takes a
custom_field_definition_id from list_custom_fields, and a form cannot ask
for anything its list does not already carry.
Every tool that creates something takes an optional idempotency_key. If a call
times out you cannot tell whether it happened, and retrying blind creates a second
task, view or task tree; retrying with the same key returns the first result
instead. Keys last 24 hours and are scoped to you. Reusing one with different
arguments is refused rather than replayed, so a key is safe to keep for as long
as the work it describes.
Self-hosting
| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| QORDO_API_TOKEN | On stdio | — | Your personal API token. Ignored in http mode, where each request carries its own. |
| QORDO_API_URL | No | https://api.qordo.ai/api | API base URL (override for self-hosted or local dev) |
| MCP_TRANSPORT | No | stdio | http serves MCP over the network instead of stdin/stdout |
| PORT | No | 3333 | Port to listen on in http mode |
| MCP_PUBLIC_URL | No | http://localhost:<port> | Public origin, used in the metadata clients discover. Set it when serving publicly. |
| QORDO_AUTH_SERVER | No | https://api.qordo.ai | Authorization server named in that metadata |
MCP_TRANSPORT=http PORT=3333 npx -y @qordo-ai/mcpServes POST /mcp, plus GET /.well-known/oauth-protected-resource and
GET /up. Every request must carry its own Authorization: Bearer token — the
server never falls back to QORDO_API_TOKEN, so one user's token can never
serve another's request. A request without one gets a 401 naming the
metadata URL.
Nothing streams, so responses are plain JSON rather than an event stream. Put it behind TLS: the tokens are in the request headers.
Development
git clone https://github.com/Yuanrui-Mdt-Info/qordo-mcp.git
cd qordo-mcp
npm install
npm run build
# Test locally
QORDO_API_TOKEN=<your-token> QORDO_API_URL=http://localhost:80/api node dist/index.jsnpm testMocked fetch, no backend required. Tools run through a real MCP client over an
in-memory transport, so schemas, registration and isError are covered too.
npm test also gates publishing.
License
MIT
