MCP Integration
Align runs a Model Context Protocol (MCP) server. AI assistants and other MCP clients, such as Claude, can use it to read your Align data and act in Align on behalf of a person.
MCP is turned on for each organisation by the Align team. If it is off, eight context and identity tools still answer (get_active_context, get_current_user, get_organization, list_org_members, find_member, list_my_organizations, switch_organization and switch_project), but every other tool returns a feature_disabled error, and the sign-in screen says MCP Not Enabled. Contact support@alignsoft.us to have it turned on.
Connecting a client
Server URL: https://app.alignsoft.us/mcp
Admins can find the server URL and the OAuth endpoints in Settings → Developer → MCP once MCP is on for the organisation.
There are two ways to authenticate.
OAuth 2.0 (for clients that act for a person)
Align is an OAuth 2.0 authorization server with PKCE, dynamic client registration and discovery. A client that supports MCP authorization finds everything it needs from the server URL. When you connect:
- Your client opens Align's Authorize Access screen in the browser. Sign in to Align if asked.
- Check the requested permissions. If you belong to more than one organisation where MCP is on, choose the Workspace to authorise. It defaults to the workspace you are working in.
- Click Approve.
The client then acts as you, starting in the workspace you chose, with your role and your project access there. With OAuth, the switch_organization tool can move the connection to another organisation you belong to.
API key (for scripts and server-side use)
Send an Align API key as a Bearer token:
Authorization: Bearer <your-api-key>
An X-Api-Key: <your-api-key> header works too.
The session acts as the user who created the key, with that user's role and project access, and it stays in the key's organisation. Create keys in Settings → Developer → API Keys (see API Keys).
A project-scoped key works too, but it is locked to its project: resources are refused, and only the project tools are available: get_active_context, get_current_user, get_organization, list_projects, get_project, and the tools for entries, attachments, releases, epics, milestones, teams, the dependency graph, release readiness, code quality and reports, plus task_link, task_sync_from_external and draft_replit_task. Search, cost and organisation-wide member tools are refused.
What you can do
Your access follows your Align role in the workspace:
- Reading follows your project access. A
clientuser sees only projects they own or were given access to, and no internal comments. - Writing (creating and updating entries, releases, epics and milestones, commenting, and the external-task tools
task_link,task_sync_from_externalanddraft_replit_task) needs thealign:writescope and one of these roles:developer,tech_lead,product_owner,devops_engineer,tester,manageroradmin.viewer,userandclientcannot write through MCP. While the organisation's payment is past due, writes are refused and reads keep working. - Retrying safely:
entry_createtakes an optionalidempotencyKey. Repeating a call with the same key returns the original result instead of creating a second entry. - Cost tools have their own role rules, given in each tool's description.
- Code quality (
get_code_quality) is for the workspace's staff only, by the role you hold in that workspace:client,userandviewerare refused, whatever their role elsewhere.
Every tool call is recorded in an audit log. Only a SHA-256 hash of the tool's arguments is stored, not the arguments themselves. Admins can view up to 500 recent calls in Settings → Developer → MCP, under MCP Audit Log.
Tools
Context and identity
| Tool | What it does |
|---|---|
get_active_context | Shows the active organisation and project for this connection. Call it first. |
get_current_user | Your profile, role, feature flags and integration health |
get_organization | The current organisation's name, type, feature flags, integrations and member count |
list_my_organizations | The organisations you belong to |
switch_organization | Switches the active organisation |
switch_project | Sets the active project, so later tools can omit projectId |
list_org_members | Lists organisation members, optionally filtered by role or name |
find_member | Resolves a partial name or email to a user ID |
Each connection keeps its own active organisation and project, so switching project in one client does not move another.
Projects and entries
| Tool | What it does |
|---|---|
list_projects | Lists the projects you can access |
list_programs | Lists programs (groups of projects) with their project counts |
get_project | Full details of a project |
list_entries | Lists a project's entries, filtered by status, type, priority, epic, milestone or work type |
get_entry | Full details of an entry, with comments, history, GitHub links and cost estimates |
entry_create | Creates an entry |
entry_update | Changes an entry's title, description, type, priority or release |
entry_update_status | Changes an entry's status, priority or assignee |
entry_add_comment | Comments on an entry |
list_entry_attachments | Lists an entry's attachments (metadata only) |
get_dependency_graph | A project's dependency graph: what blocks what |
search_global | Keyword search across entries and projects, or lookup by GitHub reference |
semantic_search | Search by meaning, with cited excerpts |
Releases, epics and milestones
| Tool | What it does |
|---|---|
list_releases, create_release, update_release | List, create and update releases. Changing a release's status with update_release needs an admin or manager of the workspace; other write roles can change its name, description and dates. |
get_release_readiness | Assesses whether a release is ready, with blockers |
list_epics, get_epic, create_epic, update_epic | Work with epics and their progress |
list_milestones, get_milestone, create_milestone, update_milestone | Work with milestones and their progress |
milestone_add_item, milestone_remove_item | Add or remove a release, epic or entry in a milestone |
Marking a release released or completed with update_release meets the project's release checks. In block mode the call is refused with reason: "release_checks_open" and the blocking and warnings lists while the release's approval workflow, its entries' client approval or a cost sign-off is unfinished. An admin of the workspace can override with overrideReason, which is recorded in the audit log. In warn mode the release is updated and the result carries releaseChecks with what was open.
Teams and reports
| Tool | What it does |
|---|---|
list_teams, get_team_members | A project's teams and their members |
report_list_capabilities | The reports and sections available for a project |
get_report | Generates a report (weekly, monthly, release, status, production health or engineering health) |
Code quality
| Tool | What it does |
|---|---|
get_code_quality | A project's SonarQube code quality as Align last read it: the quality gate's status and its failing conditions, the key measures (issues, coverage, duplication, size), when the main branch was last analysed, and the gates of other branches and pull requests. Pass releaseId to ask whether a release's gate is green, or entryId for the SonarQube issues linked to an entry and their last-known status. |
get_code_quality is read-only and answers from what Align stored when SonarQube last reported, so it never sends anything to SonarQube; stale and lastError say when that snapshot is out of date. The answer's status is bound, not_bound (the project is not bound to a SonarQube project) or not_connected (SonarQube is not connected in the workspace). For a release, release is the release check's own decision, the one the release page shows and the check applies when the release is marked shipped: its state (passed, failed, warn, missing or stale, or null when the project is not bound or SonarQube is not connected), its message, the branch and analysis it read (analysedAt, analysedVersion), versionMatch and versionMatches (whether that analysis was run with the release's version, ignoring a leading v and letter case), stale (an analysis nothing has refreshed for 24 hours is stale, and never blocks), canBlock, mode and blocksShipping (whether the gate would stop the release being marked shipped now). basis is release_check. For a release, summary is the release check's sentence. Pass at most one of releaseId and entryId. Only the workspace's staff can use it: anyone else gets staff_only, whatever they ask for. No SonarQube token or response is ever returned.
Cost
| Tool | What it does |
|---|---|
cost_get_project, cost_get_entry | Cost overview of a project or an entry (admin, manager or client) |
list_pending_cost_approvals | Committed costs waiting for your approval: entries in approvals, and releases in releaseApprovals (each with kind: "release_cost") |
cost_commit_entry | Commits an entry's cost (admin or manager) |
cost_approve_entry, cost_reject_entry | Approve or reject a committed cost at its current stage |
cost_estimate_entry | Generates an AI cost estimate for an entry (admin or manager) |
cost_get_release | A release's own committed cost: its low–high range, approval status, the step it waits at and who can act there, its revision, and its history |
cost_commit_release | Commits a cost for a release as a whole, within its range. Changing an existing commitment needs a reason. |
cost_submit_release | Submits a release's committed cost for approval (admin or manager) |
cost_approve_release, cost_reject_release | Approve or reject a release's committed cost at the step it waits at. A rejection needs a reason. |
cost_reopen_release | Reopens an approved release cost so it can change, with a reason (admin or manager) |
Submit, approve, reject and reopen for a release take the revision that cost_get_release returned. If the commitment has changed since (a new amount, or someone else's decision), the call is refused with conflict: read it again and decide on what is there now.
External tasks
| Tool | What it does |
|---|---|
task_link | Links an entry to a task in another system (GitHub, Jira, Linear and others) |
task_sync_from_external | Creates or updates an entry from an external task, keeping the link |
draft_replit_task | Generates a Replit Agent prompt from an entry. Needs a Replit workspace set in the project's settings. |
Administration
| Tool | What it does |
|---|---|
delete_organization | Archives, restores or schedules deletion of an organisation. Align platform admins only. |
Most tools that take a projectId fall back to the active project when you omit it.
Resources
Resources are read-only and need an organisation-scoped credential.
| URI | Description |
|---|---|
align://projects | Projects, with limit and offset |
align://projects/{id} | One project |
align://projects/{id}/entries | A project's entries, filterable by status, type, priority and assignee |
align://entries/{id} | One entry, with comments |
align://releases | Releases, optionally for one projectId |
align://task-mappings | Links between entries and external tasks |
Prompts
| Prompt | Arguments | What it does |
|---|---|---|
summarise_project_status | projectId | A project health summary prompt filled with current figures |
create_issue_from_context | context, optional projectId | Guides the assistant to draft a well-formed entry from free text |
Transports
| Transport | Endpoint |
|---|---|
| Streamable HTTP | POST, GET and DELETE /mcp |
| HTTP + SSE (older clients) | GET /mcp/sse, then POST /mcp/messages |
Live resource updates (SSE only)
On the SSE transport, a client can subscribe to a resource with resources/subscribe and receives notifications/resources/updated when it changes:
| URI | Notified when |
|---|---|
align://projects | An entry or release is created or changes anywhere in the organisation |
align://projects/{id} | An entry or release in that project is created or changes |
align://projects/{id}/entries | An entry in that project is created, updated, changes status, is reassigned or gets a comment |
align://entries/{id} | That entry is updated, changes status, is reassigned or gets a comment |
align://releases | A release is created, changes status or is released |
Subscriptions end when the SSE connection closes. The Streamable HTTP transport does not push updates.
OAuth reference
For client developers. Most MCP clients do all of this for you.
| Endpoint | Purpose |
|---|---|
GET /.well-known/oauth-authorization-server | Authorization server metadata (RFC 8414) |
GET /.well-known/oauth-protected-resource | Protected resource metadata (RFC 9728) |
POST /oauth/clients | Dynamic client registration (RFC 7591). Send client_name, redirect_uris (HTTPS, or http://localhost) and optionally scope. Returns client_id and client_secret. |
GET /oauth/authorize | The consent screen. Requires response_type=code, code_challenge and code_challenge_method=S256. |
POST /oauth/token | Exchanges a code (grant_type=authorization_code, with code_verifier) or a refresh token (grant_type=refresh_token). Client credentials can be sent in the body or with HTTP Basic. |
POST /oauth/revoke | Revokes an access or refresh token |
Admins can also register a client by hand in Settings → Developer → MCP, under OAuth Applications, with Register OAuth App. The client secret is shown only once.
Scopes: align:read (read workspace data) and align:write (create and update). If a client asks for no scope, it gets align:read. The older names mcp:read and mcp:write are still accepted.
Tokens: access tokens last 24 hours and refresh tokens 30 days. Each refresh issues a new pair and revokes the old refresh token. Authorization codes last 10 minutes and work once. Align stores only SHA-256 hashes of tokens.
PKCE with S256 is required; plain is refused.
Limits
- Each API key, or each OAuth user, may make 600 requests per minute. An API key shares this limit with its use of the REST API. Responses carry
X-RateLimit-Limit,X-RateLimit-RemainingandX-RateLimit-Reset(seconds until reset). - Each organisation may make 3,000 MCP requests per minute in total.
- Over a limit, Align returns
429with aRetry-Afterheader. - Requests from a browser must come from an allowed origin, such as
https://claude.ai. Other origins get403. Requests without anOriginheader (servers, scripts) are not checked.
Troubleshooting
| Error | Meaning |
|---|---|
401 | Credentials missing, invalid, revoked or expired (API key or OAuth token) |
Tool result feature_disabled | MCP is not turned on for the organisation |
Tool result project_key_forbidden | A project-scoped key tried a resource or a tool outside its project |
Insufficient scope (align:write required), reason insufficient_scope | The OAuth token was granted read-only access |
Tool result reason role_not_authorised | Your role can't write through MCP (for example viewer, user or client) |
Tool result staff_only | get_code_quality is for the workspace's staff; your role in this workspace is client, user or viewer |
Tool result reason billing_past_due | The organisation's payment is past due. Writes are refused until the payment method is updated in Settings → Billing; reads still work. |
| MCP Not Enabled on the consent screen | None of your organisations has MCP turned on |
| Organization Mismatch on the consent screen | The OAuth client was registered for an organisation you do not belong to |
400 invalid_grant | The code is invalid, used or expired; the redirect_uri or client_id does not match; or the PKCE code_verifier does not match |
400 invalid_client | Unknown client_id or wrong client_secret |
400 invalid_request | A required parameter is missing |
400 unsupported_grant_type | Only authorization_code and refresh_token are supported |
423 | The organisation is suspended for billing |
429 | A rate limit was exceeded; wait for Retry-After seconds |