What the company-brain MCP is
The company-brain MCP is a first-party Model Context Protocol server built directly into the Elliptic API. It exposes your workspace as a set of callable tools, so an MCP client like Claude Code, Cursor, or Claude Desktop can read and write the same surfaces you use in the app: tasks and boards, projects, notes, meetings and transcripts, calendar, comments, notifications, teams, the org and its members, the activity feed, the brain, and your AI agents. This is the mechanism that makes Elliptic Jira for your agents. An agent connects as a member and operates the same surfaces you do, on the org's own model key.
The server is a stateless FastMCP app mounted in the API at /api/v1/mcp. Each tool runs through a single boundary that authenticates the caller, enforces the tool's required scope, resolves the org context, and owns the database transaction, committing on success and rolling back on error. Every call is scoped to one organization and acts as the connecting user, so a tool can do exactly what that person can do in the web app, no more. Whatever an agent does through the MCP lands in activity the same way a person's action would.
https://api.elliptic.sh/api/v1/mcp, a single streamable-HTTP MCP endpoint. Self-hosting follows the same path under your own API origin (for local development, http://localhost:8000/api/v1/mcp). Authentication is OAuth 2.1, so there is nothing to copy and paste. The client walks you through a browser consent the first time.Authenticating
The MCP is protected by OAuth 2.1, so you never hand a client a raw API key. The first time a client connects it discovers the authorization server, registers itself, and opens a Elliptic consent screen in your browser. You pick a workspace and approve a set of permissions, and the client receives a token scoped to that org and those permissions. From then on the client refreshes silently.
- Dynamic client registration (RFC 7591). Clients self-register at the registration endpoint as public PKCE clients. There is no manual app setup, and each registered client gets a generated
client_id. - PKCE with S256. The authorization-code flow requires a
code_challengeusing theS256method. Other methods and a missing challenge are rejected, which keeps the flow safe for public and native clients. - Canonical resource binding. A
resourceparameter (RFC 8707) on the authorize and token requests must equal the canonical MCP resource URI, so a code minted for this server cannot be replayed against another audience. Clients that omitresourcestill work: the server binds the request to the canonical URI from its own metadata. - Short-lived codes, rotating refresh. Authorization codes are single-use and expire after 60 seconds. Refresh tokens rotate on every use, and reusing a consumed refresh token revokes the whole token family.
- Signed request envelope. The validated authorize parameters are signed into a request id that the consent page cannot tamper with. It is valid for 10 minutes.
The consent screen
When a client connects you land on the Elliptic authorization page. You choose a single workspace, or pick all your organizations, then approve the permissions the client asked for. The screen groups permissions by domain. Every domain's read scope is the baseline set: it shows as Always on and stays checked and locked, so the standard read surface is always granted. Write and elevated permissions are an explicit, deliberate opt-in. Approve to connect, or decline to cancel. Either way you are returned to the client.
Consent is the only place permissions are decided. The token the client receives carries exactly the scopes you ticked. A client that requested specific scopes caps the grant at its request; a client that requested none (most MCP clients) receives precisely your selection. Nothing the client does later can widen the grant without a fresh consent.
Personal access tokens (the no-OAuth path)
If you would rather not run the OAuth flow, the MCP also accepts a Elliptic personal access token directly. Send your cos_pat_ token as a Bearer header (or as an x-api-key header) and the call is authenticated as you. A PAT is treated like a logged-in session: it acts across every organization you belong to and carries the full scope set, so use it only with clients you trust. OAuth with hand-picked scopes is the safer default for third-party agents.
Single-org versus all-orgs tokens
Your token comes in one of two shapes, decided at consent time.
- Pinned single-org token. You picked one workspace, so the token is bound to that org. Tools target it automatically, and if a call passes an
org_idthat does not match, it is rejected. This is the tightest setup: the agent can only ever touch the one workspace you chose. - Cross-org token (all organizations). You picked all your organizations, so the token carries no fixed org. Every org-scoped tool then accepts an optional
org_idto choose which workspace the call lands in. If you omit it, the call falls back to your earliest-joined org, so always passorg_idwhen you mean a specific one.
Discovery
Clients configure themselves from the endpoint alone, with no hand-entered URLs beyond the MCP address. Two mechanisms make that work.
First, an unauthenticated request to the MCP endpoint returns a 401 with an RFC 9728 Bearer challenge. The WWW-Authenticate header points at the protected-resource metadata, so a client that hits the endpoint cold immediately learns where to begin the OAuth flow:
WWW-Authenticate: Bearer resource_metadata="https://api.elliptic.sh/.well-known/oauth-protected-resource/api/v1/mcp"Second, the well-known documents let the client finish self-configuring:
| Document | Path | What it provides |
|---|---|---|
| Protected-resource metadata (RFC 9728) | /.well-known/oauth-protected-resource/api/v1/mcp | The canonical resource URI, the authorization server to use, the supported scopes, and that bearer tokens go in the header. |
| Authorization-server metadata (RFC 8414) | /.well-known/oauth-authorization-server | The issuer plus the authorize, token, registration, revocation, and JWKS endpoints, the supported grant and response types, and that S256 PKCE is required. |
| JWKS | /api/v1/oauth/jwks.json | The public keys used to verify MCP access tokens. |
Installing
Claude Code
Add the server, then run /mcp and complete the browser consent:
claude mcp add --transport http elliptic https://api.elliptic.sh/api/v1/mcp
# then, inside Claude Code:
/mcp # opens the Elliptic consent screen in your browserCursor
Cursor speaks MCP natively. Add Elliptic to ~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project), then open Cursor Settings, MCP, and complete the browser consent on first use:
{
"mcpServers": {
"elliptic": {
"url": "https://api.elliptic.sh/api/v1/mcp"
}
}
}The first tool call opens the same Elliptic OAuth consent in your browser. No API key is stored in the file.
Claude Desktop and other clients
Point any MCP client at the endpoint. Clients that do not yet speak OAuth-protected HTTP natively can bridge through mcp-remote:
{
"mcpServers": {
"elliptic": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://api.elliptic.sh/api/v1/mcp"]
}
}
}The scope catalog
Permissions are expressed as scopes, grouped by domain. Most domains have a read scope and a write scope: approving the read scope lets the agent see that data, and the write scope lets it create, edit, and delete. The read scope of every domain is the baseline set, so it is always on at consent and cannot be unchecked, which means the standard read surface is granted by default. A handful of scopes are flagged Elevated and stay unchecked until you opt in deliberately. The Root / Admin toggle selects everything at once.
sources:read, sources:write, sources:manage) appears in the catalog and on the consent screen, yet no MCP tool currently requires it, so approving it grants nothing callable over the MCP today. Everything else in the table below is backed by real tools.| Domain | Scopes | MCP tools? |
|---|---|---|
| Tasks | tasks:read, tasks:write | Yes. Also covers projects, boards, sub-tasks, relations, labels, and triage. |
| Notes | notes:read, notes:write | Yes. |
| Meetings | meetings:read, meetings:write | Yes. Transcripts, summaries, chapters, share links, templates, and recipes. |
| Calendar | events:read, events:write | Yes. Events and briefs. |
| Comments | comments:read, comments:write | Yes. Comments and attachments across tasks, notes, and meetings. |
| Notifications | notifications:read, notifications:write | Yes. |
| Activity | activity:read | Yes. The feed and per-entity history. |
| Brain | brain:read | Yes. Catch-me-up, open threads, and resume points. |
| Agents | agents:read, agents:write (Elevated), agents:keys (Elevated) | Yes. AI users, runs, budgets, and provider keys. |
| Teams | teams:read, teams:write | Yes. |
| Views | views:read, views:write | Yes. Saved board views. |
| Vocabulary | vocabulary:read, vocabulary:write | Yes. The org glossary. |
| Workflow | workflow:read, workflow:write | Yes. Custom workflow statuses. |
| Automation | automation:read, automation:write | Yes. Automation rules, including running them. |
| Integrations | integrations:read, integrations:manage (Elevated) | Yes. Slack connection, channels, and posting. |
| Profile | profile:read, profile:write | Yes. Your own user profile. |
| Organization | org:read, org:manage (Elevated), org:create (Elevated) | Yes. Org details, members, roles, invites, creating orgs (org:create), and updating or deleting them (org:manage). |
| All organizations | orgs:all (Elevated) | Not a per-tool scope. Granted by the all-organizations consent option and enforced as the token's cross-org reach. |
| Connected sources | sources:read, sources:write, sources:manage (Elevated) | No. In the catalog but with no MCP tool behind it yet. |
The elevated scopes, the ones that stay unchecked until you opt in, are agents:write, agents:keys, org:manage, org:create, integrations:manage, sources:manage, and orgs:all. Note that there is no separate delete scope: deleting an event uses events:write, deleting a note uses notes:write, and so on. Write is enough to remove what write can create.
The tool catalog
The MCP exposes 144 tools, grouped below by domain. This is most of the member surface, but it is not literal parity with every screen. There are no MCP tools for connected sources or GitHub linking, and there are no cycle, milestone, or PQL-style query tools. Read tools list and fetch, write tools create, edit, move, and delete. Two cross-cutting conventions apply throughout: many creates accept an optional idempotency_key so a retried call never duplicates work, and the most destructive deletes take a confirm flag (call once with confirm=false to preview, again with confirm=true to apply).
org_id. With a pinned single-org token you omit it and the call uses the token's workspace. With an all-organizations token, pass org_id to choose which workspace a call acts on. A couple of user-level tools (create_org, list_my_orgs) act on you across orgs and need no org context.Tasks, boards, labels, and triage
| Tool | What it does |
|---|---|
list_project_tasks, get_task | List a project's tasks with board-style filters, or fetch one task with its identifier, counts, and blocked state. |
create_task, create_tasks_batch | Create a task (sub-tasks, bug kind, severity, mentions, relations), or several at once from a list. |
update_task, transition_task_status | Edit fields, or move a task to a new workflow status. |
delete_task | Delete a task (confirm-gated). |
get_task_board, list_my_tasks, list_subtasks | Read the board grouped into status columns, your assigned / created / subscribed / recent tasks, and a task's sub-tasks. |
subscribe_task, unsubscribe_task | Follow or unfollow a task. |
list_task_relations, add_task_relation, remove_task_relation | List, link, or unlink blocking / blocked-by / related tasks. |
list_labels, create_label, attach_task_labels, detach_task_labels, delete_label | Manage org labels and apply them to tasks (create_label is get-or-create; delete_label is confirm-gated). |
list_triage, accept_triage_task, decline_triage_task | Read incoming triage items and route them. |
Projects
| Tool | What it does |
|---|---|
list_projects, get_project, create_project, update_project | Browse, read, create, and edit projects. |
delete_project, restore_project, list_deleted_projects | Soft-delete, restore, and review deleted projects (delete confirm-gated). |
subscribe_project, unsubscribe_project, get_project_subscription | Follow a project and check your subscription. |
list_project_members, add_project_member, remove_project_member | Manage who is on a project. |
list_project_artifacts, add_project_artifact, remove_project_artifact | Attach and remove linked artifacts. |
Meetings
| Tool | What it does |
|---|---|
list_meetings, get_meeting, create_meeting, import_folio_meeting | Browse and create meetings, or import one from Folio. |
update_meeting, delete_meeting | Edit or delete a meeting (delete confirm-gated). |
list_meeting_segments, list_meeting_chapters, list_meeting_summaries | Read transcript segments, chapters, and summaries. |
summarize_meeting, suggest_meeting_project | Generate a summary, or suggest the project a meeting belongs to. |
ask_meeting, meetings_chat | Q&A on one meeting, or across all meetings. |
run_meeting_recipe | Run a saved meeting recipe. |
get_meeting_share, create_meeting_share, update_meeting_share | Manage public share links. |
list_meeting_templates, create_meeting_template, update_meeting_template, delete_meeting_template | Manage meeting templates (delete confirm-gated). |
list_meeting_recipes, create_meeting_recipe | Browse and create recipes. |
Notes, calendar, comments, and notifications
| Tool | What it does |
|---|---|
list_notes, get_note, create_note, update_note, delete_note | Browse, read, write, edit, and delete notes (delete confirm-gated). |
list_calendar_events, get_calendar_event, create_calendar_event, update_calendar_event, delete_calendar_event | Browse, read, and manage calendar events. |
get_event_brief | Get the AI brief for an event. |
list_comments, get_comment, create_comment, update_comment, delete_comment | Read and write comments on tasks, notes, and meetings (delete confirm-gated). |
get_attachment, view_image_attachment | Read a comment attachment, or view an image attachment inline. |
list_notifications, unread_count, mark_notification_read, mark_all_notifications_read | Read your notifications and unread total, and mark them read. |
archive_notification, snooze_notification | Archive or snooze a notification. |
Organization, teams, members, and invites
| Tool | What it does |
|---|---|
list_my_orgs | List every organization you belong to (works with an all-organizations token). |
get_org, update_org | Read and edit the workspace (update_org needs org:manage). |
create_org, delete_org | Create a new organization with org:create (you become its owner), or delete one with org:manage (confirm-gated). |
list_org_members, update_member_role, remove_org_member | Manage members and roles (remove confirm-gated). |
list_invites, create_invite, revoke_invite | Invite people and revoke invitations. |
list_teams, get_team, create_team, update_team, delete_team | Manage teams (delete confirm-gated). |
list_team_members, add_team_member, remove_team_member | Manage team membership. |
Activity and the brain
| Tool | What it does |
|---|---|
list_activity, get_entity_activity | The org-wide activity feed, and the change history of one task, note, or meeting. |
brain_open_threads | Open loops that still need attention. |
brain_changes_since | What changed since a point in time (catch-me-up). |
brain_resume | Where you left off in a project, to resume work. |
The brain tools are the agent-facing side of the company brain: they exist so an agent can orient itself before it acts, catching up on what changed, finding open threads, and resuming a project without you spelling out the state each time. They are read-only and run under brain:read.
AI agents and keys
| Tool | What it does |
|---|---|
list_ai_users, get_ai_user, create_ai_user, update_ai_user | Manage the org's AI agents (write under elevated agents:write). |
pause_ai_user, set_ai_user_budget, delete_ai_user | Pause, budget, and remove agents (delete confirm-gated). |
list_agent_runs | Recent agent runs. |
list_ai_keys, create_ai_key, update_ai_key, revoke_ai_key | Manage provider API keys (elevated agents:keys; revoke confirm-gated). |
Views, vocabulary, workflow, and automation
| Tool | What it does |
|---|---|
list_views, create_view, update_view, delete_view | Saved board views (delete confirm-gated). |
list_vocabulary, create_term, update_term, delete_term | The org glossary (delete confirm-gated). |
list_workflow_statuses, create_workflow_status, update_workflow_status, delete_workflow_status | Custom workflow statuses (delete confirm-gated). |
list_automations, create_automation, update_automation, delete_automation, run_automation | Manage and run automation rules (delete confirm-gated). |
Integrations and profile
| Tool | What it does |
|---|---|
get_slack_integration, list_slack_channels | Read the Slack connection and its channels. |
post_meeting_to_slack | Post a meeting to a Slack channel (elevated integrations:manage). |
get_my_profile, update_my_profile | Read and update your own profile. |
[label](/__mention/kind/id). See the References & Mentions page for the full format and examples.Managing access
Every consent you give creates a connected-app grant tied to your account, the client, and the org (or, for a cross-org token, no specific org). You can see and revoke these at any time.
- Connected apps (grants). Each connected client shows up as a grant with its name, the org it covers (or all your organizations), its scopes, its status, and when it was granted. Re-approving the same client updates the existing grant rather than stacking duplicates.
- Revoking a grant. Revoking a grant kills the whole token family behind it, every access and refresh token, so the client loses access immediately and must re-consent to reconnect.
- Token revocation (RFC 7009). A client can also revoke its own token at the revocation endpoint. Revoking any token in a family tears down the family, and unknown tokens are a safe no-op.
Confidential bot apps (client_credentials)
For an unattended bot that has no browser to consent through, register a confidential OAuth app. You get a client_id and a one-time client_secret (shown once at creation, stored only as a hash). The app then exchanges those credentials at the token endpoint with grant_type=client_credentials and receives a bot token that acts as you, the owner, across your organizations. Revoking the app deactivates it and stops it from minting new tokens.
client_credentials token is minted as a personal token of the app's owner, so it inherits the owner's full reach. Treat the client secret like a password, store it in a secret manager, and revoke the app the moment it is no longer needed.Conventions
A few rules hold across every tool, so agents behave predictably and safely.
- Org-scoped, acting as you. Every tool resolves to one organization and runs with your membership and role. It can do exactly what you can do in the app, and the result appears in activity the same way.
- Per-call scope checks. A tool runs only if your token carries its required scope. If not, it returns
insufficient_scopeand does nothing. Scopes are checked on every single call, not just at connect time. - Idempotent creates. Pass an
idempotency_keyon a supported create and a retried call returns the original result instead of duplicating work, which makes agent retries safe. - Confirm-gated deletes. The most destructive tools take a
confirmflag. Call once withconfirm=falseto preview what would be removed, then again withconfirm=trueto apply it. - Live membership re-checks. With a cross-org token, your membership of the target org is verified on every call, so losing access to an org takes effect instantly.
/mcp in Claude Code) and approve again. Ticking Root / Admin grants the entire current surface in one step.