AI assistants (MCP)¶
Workflow is a Model Context Protocol server, so Claude and other AI assistants can work with your issues: find work with a search, read an issue with its comments and timing, file and update issues, move them through their workflow, and report on sprints and flow.
The assistant acts as you: it sees only what you can browse, workflow conditions and validators apply, and every change appears in the issue history under your name, marked with the app's or token's name ("Ada via Claude"), as do its comments. You choose whether it may only read, or also create, edit, comment on and move issues.
Connect¶
Give the assistant the address <WFM_PUBLIC_URL>/mcp (streamable HTTP). When it connects,
your browser opens Workflow's consent page: sign in if needed, choose read only or read
and write, and select Allow access. No token to copy; Workflow is the OAuth authorisation
server for its MCP endpoint (see How sign-in works). Profile → Connect AI
assistants and tools shows these steps with your server's address filled in.
Claude (claude.ai, Claude Desktop and mobile) — Settings → Connectors → Add custom
connector, paste https://wfm.example.com/mcp, then Connect. These connectors reach your
server from Anthropic's network, so the address must be reachable from the internet; Claude Code
and other clients running on your computer only need to reach it from there.
Claude Code
Then run /mcp in Claude Code and choose Authenticate; the browser asks you to approve access.
Other clients that support MCP OAuth (Cursor, VS Code, ChatGPT connectors, Windsurf and others) — add the URL in their MCP settings and sign in when they connect:
Connected apps. Profile → Connected apps lists the assistants you allowed, with their
access and when they were last used; Disconnect revokes them at once (the app has to ask again).
Administrators see and disconnect everyone's under Administration → Connected apps.
Approvals, changes and disconnections are in the audit log (oauth.).
With a personal access token¶
Tokens still work everywhere, for clients without OAuth support, scripts and shared assistants
(service-account tokens). Create one under Profile → Personal access tokens (read and
write, or only read); the dialog then shows the setup for each client with the token filled
in:
claude mcp add --transport http workflow https://wfm.example.com/mcp \
--header "Authorization: Bearer wfm_pat_…"
{
"mcpServers": {
"workflow": {
"type": "http",
"url": "https://wfm.example.com/mcp",
"headers": { "Authorization": "Bearer wfm_pat_…" }
}
}
}
Clients that only launch local servers: install the wfm binary (it relays stdio to /mcp) and
add to their configuration (e.g. claude_desktop_config.json):
{
"mcpServers": {
"workflow": {
"command": "wfm",
"args": ["mcp"],
"env": { "WFM_SERVER": "https://wfm.example.com", "WFM_TOKEN": "wfm_pat_…" }
}
}
}
In Kubernetes, /mcp, /oauth/* and /.well-known/* are served by the web deployment on the
internal ingress, like the UI and API; assistants must be able to reach that address (and
WFM_PUBLIC_URL must be it, since it is the OAuth issuer and the token audience).
Tools¶
| Tool | Does |
|---|---|
whoami |
who the assistant acts as: organisation role, scopes and the connected app |
list_projects |
projects you can browse |
get_project |
issue types (keys for creating issues), boards and columns, open sprints, unreleased releases, labels |
search_issues |
A search, one line per issue, paged (limit up to 100) |
get_issue |
fields, description, parent, children, links, pull requests, recent comments, time tracking (estimated, logged, remaining), lead/cycle time and time in each status, and the transitions available now; for service requests, the request type, SLA clocks and approvals, with each comment labelled reply to customer or internal note |
get_board |
a board's columns and issues (the active sprint on a Scrum board) |
get_sprint_report |
a sprint's commitment, completion, scope change and day-by-day burndown |
get_metrics |
summary, breakdown, cycle_time, created_resolved, cumulative_flow or velocity over projects and a query |
find_users |
people by name or email |
create_issue |
create an issue (type, summary, Markdown description, priority, assignee by email or me, parent, labels, points, sprint, dates) |
update_issue |
change fields; clear empties them |
transition_issue |
run a workflow transition by id, name or target status, with screen fields and a comment |
add_comment |
comment (Markdown); on service requests an internal note unless visibility is public (a reply the customer is emailed) |
log_work |
log time spent (2h, 1d 4h), when it was done, a description; the remaining estimate goes down by the time logged unless remainingEstimate sets it or leaveEstimate keeps it |
link_issues |
blocks, relates, duplicates or clones |
Read tools are annotated read-only; nothing deletes. An app you allowed only to read is offered only the read tools. Errors (the position of a query error, a validator refusing a transition, a missing permission) come back as tool errors with the reason, so the assistant can correct itself.
Things to ask: "What's in progress on PLAT and who's on it?", "File a bug in PLAT for the Safari checkout crash, high priority, assign it to me and put it in the active sprint", "Move PLAT-42 to review with a comment summarising the PR", "How is the sprint going — is scope creeping?", "Which bugs took longest to fix this month?".
How sign-in works¶
Workflow implements the MCP authorization specification (OAuth 2.1):
| Endpoint | |
|---|---|
/.well-known/oauth-protected-resource (also …/mcp) |
protected resource metadata (RFC 9728): resource <WFM_PUBLIC_URL>/mcp, issuer <WFM_PUBLIC_URL>, scopes mcp:read, mcp:write |
/.well-known/oauth-authorization-server (also openid-configuration) |
authorisation server metadata (RFC 8414) |
/oauth/register |
dynamic client registration (RFC 7591) |
/oauth/authorize |
authorisation code with PKCE (S256) and resource indicators (RFC 8707) |
/oauth/token |
code exchange and refresh |
/oauth/revoke |
token revocation (RFC 7009) |
/oauth/consent |
the consent page (web app) |
- An unauthenticated request to
/mcpgets401withWWW-Authenticate: Bearer resource_metadata="…/.well-known/oauth-protected-resource/mcp", scope="mcp:read mcp:write". - The client reads the metadata and identifies itself: with a client ID metadata document
(its
client_idis an https URL serving its name and redirect URIs, which Workflow fetches; Claude Code and claude.ai do this) or by registering at/oauth/register. - It sends you to
/oauth/authorize; you sign in and decide on the consent page. Workflow remembers your answer per app: while it covers what the app asks for, reconnecting skips the page. - The client exchanges the code for an access token (
wfm_oat_…, 1 hour) and a refresh token (wfm_ort_…, 30 days, renewed on each refresh).
Scopes: mcp:read (read tools) and mcp:write (also the tools that change issues; implies
read). An app allowed only to read that calls a write tool gets 403 with error="insufficient_scope",
so clients that support it can ask you for more access.
Security¶
/mcpaccepts onlyAuthorization: Bearertokens — browser cookies are ignored, so a web page cannot drive it on your behalf.- OAuth access tokens are valid for
/mcponly (their audience): the REST API refuses them. Personal access tokens work on both. - Tokens and codes are random, opaque and stored hashed. Codes are single use and expire after two minutes; presenting one twice revokes the tokens it produced. Refresh tokens rotate on every use, and presenting one that was already used revokes the whole chain (the app must ask again).
- PKCE (S256) and
stateare required; redirect URIs must match a registered one exactly, except that loopback addresses (127.0.0.1,[::1],localhost) match on any port, as native apps need. Registered redirect URIs must be https, http on a loopback address, or a private-use scheme of a desktop app (such ascursor://…). Workflow never redirects an error to an address it has not validated; such requests stop on its own page. - The consent page shows who is asking and where you will be sent: the verified host of an app identified by a metadata document, or the name an app registered with and its redirect host, with a warning when the app receives access on your computer. Approval needs your browser session (a token cannot approve) and is protected against cross-site requests and framing.
- Client ID metadata documents are fetched without following redirects, through the same guard
as outbound webhooks (no private or loopback addresses unless
WFM_WEBHOOK_ALLOW_PRIVATEorWFM_OUTBOUND_ALLOWED_HOSTSallow them), limited to 16 KB and cached perCache-Controlbetween 5 minutes and 24 hours. - Registration, token and metadata fetches are rate-limited per client address. Registered apps
nobody approved within a week are deleted.
WFM_OAUTH_DYNAMIC_REGISTRATION=falseturns registration off (metadata-document clients keep working),WFM_OAUTH_CLIENT_METADATA_DOCUMENTS=falseturns metadata documents off, andWFM_OAUTH_ENABLED=falseturns OAuth off entirely (tokens only); see configuration. - Deactivating a person stops their apps at once; disconnecting an app revokes its tokens.
- Personal access tokens expire (1–366 days) and can be revoked on your profile; last used shows activity. Service-account tokens work too, for a shared assistant with its own permissions.