Skip to content
Docs
About By Dawn Contact supportOpen By Dawn
  1. Get started
  2. Connect an AI agent (MCP)

Connect an AI agent (MCP)

This page shows you how to connect your own AI agent to By Dawn, so it can read and manage your team’s tickets for you. By the end your agent will answer “What’s open for me this cycle?” from your board, and you’ll know what it may do, how it signs in, and how to cut it off.

By Dawn runs an MCP server. MCP (the Model Context Protocol) is the standard way an AI client such as Claude Code or Cursor is given tools. Once you connect, your agent sees By Dawn’s tools, such as search tickets or move a ticket, and calls them while it works. It acts as you: it sees what you see in By Dawn and can change only what you could change, within the scopes you approve.

The server’s address is:

https://workspace.dev.sawrun.com/mcp

It’s a remote server, so there’s nothing to install. You sign in through your browser the first time, and your agent keeps itself signed in after that.

  • Your organization has to allow it. AI agents are off until an owner or admin turns them on, and they choose which scopes members may hand out. AI agents (MCP) shows them how. Until then, the consent screen shows your organization greyed out with “Your admin hasn’t turned on AI agents”.
  • You need a By Dawn account in that organization. The agent never gets more than you have.
  • Organizations that require SSO or MFA can’t use AI agents yet. An agent’s token isn’t tied to a sign-in, so an organization that requires single sign-on or multi-factor sign-in refuses it, as it refuses the Slack, Discord and Teams integrations. The consent screen shows such an organization greyed out with “Your org requires SSO; AI agents can’t connect yet”, so you can’t approve there.

Add the server to your client, then sign in when it asks. Each client below opens By Dawn in your browser for the sign-in, then shows the consent screen described in Approve the connection.

Add the server from a terminal:

Terminal window
claude mcp add --transport http saw https://workspace.dev.sawrun.com/mcp

That adds it for the project you’re in. Add --scope user to have it in every project.

Then, in Claude Code, run /mcp, pick saw and choose Authenticate. Claude Code opens your browser. Once you approve, /mcp shows saw as connected, and its tools are available in the session.

The first time, your browser opens By Dawn’s consent screen (sign in first if it asks). It names the client, such as “Claude Code”, and where By Dawn will send you back afterwards, so you can check it’s the client you set up a moment ago.

  1. Pick the organization. The agent works in one organization. If you’re in several, connect once for each. An organization that hasn’t turned AI agents on can’t be picked.

  2. Choose the scopes. You see the ones your client asked for, within what your organization allows (see Scopes). Reading tickets is always included. Untick anything you don’t want the agent to do.

  3. Choose Allow. By Dawn sends you back to the client, and the page says you can close the tab.

Choose Deny instead and the client gets nothing. Connecting the same client again later in the same organization updates its scopes, rather than adding a second connection.

A scope is one kind of thing the agent may do. It never widens what you can do: if you can’t move a ticket in By Dawn, your agent can’t either.

Scope Lets the agent Offered by default
tickets:read read projects, tickets, comments, members, columns, labels, cycles and epics always included
tickets:write create and update tickets, move them, comment, link tickets and triage yes
workers:start start and stop an agent worker on a ticket no, an admin has to allow it
mission:answer answer a mission checkpoint (approve or send back a plan, pick an option) or a worker’s question yes

workers:start is off unless an admin allows it, because a worker an agent starts runs on your organization’s seats. There’s no scope for merging, deleting or archiving, or changing settings, so an AI agent can’t do any of those.

A client that doesn’t ask for particular scopes asks for tickets:read and tickets:write. To be offered workers:start or mission:answer, your client has to ask for them too.

The agent sees only the tools its scopes allow. Every tool takes the names you’d use yourself: a ticket as SAW-123, a project by its key or name, a column by its name, a person as me, none, a name or an email, and a cycle as current or its name. If a name matches more than one thing, the tool says so and lists the matches, so the agent can ask you which one.

Tool Scope What it does
list_projects tickets:read Lists the projects you can see.
list_members tickets:read Lists the people in the organization, or in one project.
list_statuses tickets:read Lists a project’s columns.
list_labels tickets:read Lists the organization’s labels.
list_cycles tickets:read Lists a project’s cycles.
list_epics tickets:read Lists a project’s epics.
search_tickets tickets:read Finds tickets by project, column, assignee, cycle, epic, label or text. Open tickets only, unless asked otherwise. Up to 50 at a time, 25 by default, with a cursor for more.
get_ticket tickets:read Reads one ticket: its details, plan, sub-tickets, links and the last 10 comments.
team_overview tickets:read Shows a project’s open tickets by person and column, the unassigned ones, and the stale ones (not updated in 7 days), for the current cycle or another.
create_ticket tickets:write Creates a ticket, with its description, priority, assignee, column, cycle, epic, labels or parent if given.
update_ticket tickets:write Changes a ticket’s title, description, priority, assignee, cycle, epic, labels or parent.
move_ticket tickets:write Moves a ticket to another column.
comment_on_ticket tickets:write Comments on a ticket.
relate_tickets tickets:write Links two tickets, for example as blocking or related.
triage_ticket tickets:write Accepts, snoozes or declines a ticket waiting in triage.
start_worker workers:start Starts an agent worker on a ticket, to plan or to build, with an optional message.
stop_worker workers:start Stops the worker on a ticket.
answer_checkpoint mission:answer Answers a ticket’s mission checkpoint or its worker’s question.

Each tool answers with a short summary the agent reads, plus the same data as JSON (structuredContent) for clients that use it. When By Dawn refuses something, the tool says why in words, such as “You don’t have permission to …”, and the agent can tell you.

Ask in your own words. The agent picks the tools. For example:

  • “What’s open for me this cycle?”
  • “Give me an overview of the WEB project: who has what, and what’s gone stale?”
  • “Assign SAW-123 to Dana and move it to Review.”
  • “File a bug in WEB: the export button does nothing on Safari. Put it in the current cycle.”
  • “Summarise the comments on SAW-88 and reply that we’ll ship the fix on Friday.”
  • “Which tickets in triage look like duplicates? Decline the ones that are.”

With workers:start and mission:answer, it can also run work: “Start a worker on SAW-140 to plan it”, then later “Approve the plan on SAW-140”.

  • It acts as you, and only as far as you let it. What the agent can do is what your role and project access allow, narrowed to the scopes you approved. Restricted projects you can’t see stay hidden from it too.
  • Everything it does is yours, and labelled. A ticket it creates or a comment it posts shows you as the author, “via MCP (Claude Code)” or whichever client it was, on the ticket’s timeline.
  • Its credential works in one place. The client holds an access token that By Dawn accepts only at the MCP server’s address. Sent to By Dawn’s API or any other By Dawn service, it’s refused. Inside By Dawn, each request is carried out with a separate short-lived token that never leaves By Dawn.
  • Tokens are short-lived. An access token lasts 15 minutes. The client renews it with a refresh token, which changes every time it’s used and expires after 30 days without use. If an old refresh token is ever used again, By Dawn assumes it was stolen and ends that connection’s tokens.
  • A client can tie its tokens to a key it holds. A client that supports DPoP gets tokens that work only alongside a proof signed with its own private key, so a copied token is useless on its own. See Tokens tied to a key.
  • You can cut it off at any time. The Connected agents card in Settings › You › Connections lists your connected clients, with the organization, scopes, when each was connected and last used; choose Disconnect. The client stops working within seconds.
  • You see who published an agent’s details. For a client that identifies itself with a Client ID Metadata Document, the consent screen and Connected agents in Settings › You › Connections show the site that published it next to its name, because the name is whatever the client chose.
  • Your admins stay in control. Owners and admins can turn AI agents off for the organization, which pauses every connection (turning it back on restores them), limit the scopes members may approve, and see and revoke anyone’s connection. Leaving the organization, or having your role lowered, disconnects your agents.

You don’t need this to connect a ready-made client. It’s for writing a client, or working out why one doesn’t connect. By Dawn follows the MCP authorization specification, so a client finds everything from the server’s URL in four steps.

  1. The server says where its metadata is. A request to /mcp without a token, or with one that has expired, gets 401 with a pointer to the server’s own metadata (RFC 9728):

    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Bearer resource_metadata="https://workspace.dev.sawrun.com/.well-known/oauth-protected-resource/mcp"
    WWW-Authenticate: DPoP resource_metadata="https://workspace.dev.sawrun.com/.well-known/oauth-protected-resource/mcp", algs="ES256"

    The second challenge offers DPoP. A client that doesn’t use it can ignore it.

    That document names By Dawn’s authorization server, which is the accounts host:

    {
    "resource": "https://workspace.dev.sawrun.com/mcp",
    "authorization_servers": ["https://accounts.dev.sawrun.com"],
    "scopes_supported": ["tickets:read", "tickets:write", "workers:start", "mission:answer"],
    "bearer_methods_supported": ["header"],
    "resource_name": "SAW",
    "dpop_signing_alg_values_supported": ["ES256"],
    "dpop_bound_access_tokens_required": false
    }
  2. The authorization server lists its endpoints. GET https://accounts.dev.sawrun.com/.well-known/oauth-authorization-server (RFC 8414) gives the authorization_endpoint, token_endpoint, registration_endpoint and revocation_endpoint, all under https://accounts.dev.sawrun.com/oauth/. It supports the authorization code grant with PKCE (S256 only) and the refresh token grant, for public clients (token_endpoint_auth_method none), and says "client_id_metadata_document_supported": true. Its dpop_signing_alg_values_supported (["ES256"]) says the token endpoint accepts DPoP proofs.

  3. The client identifies itself, in one of two ways. Either way there’s no client secret. Redirect URIs must be https, http on a loopback address (127.0.0.1, [::1] or localhost, any port), or an app’s own scheme such as cursor://. The client name is what you see on the consent screen and under Connected agents in Settings › You › Connections.

    • A Client ID Metadata Document. This is what the 2025-11-25 MCP authorization specification recommends. The client publishes its metadata as JSON at an https URL it controls and uses that URL as its client_id, with no registration call. By Dawn fetches the document the first time the client sends someone to /oauth/authorize:

      {
      "client_id": "https://agent.example.com/oauth/client-metadata.json",
      "client_name": "Example Agent",
      "redirect_uris": ["http://127.0.0.1/callback"],
      "token_endpoint_auth_method": "none"
      }

      The document’s client_id must be exactly the URL it’s served from. The URL itself must be https on the default port, use a domain name (not an IP address or localhost), have a path, and carry no query, fragment or ./.. segments. By Dawn reads at most 5 KB and waits at most 5 seconds. It accepts only a 200 response served as application/json, and it doesn’t follow redirects. It refuses any host that resolves to a private, loopback or link-local address. The document must not include a client_secret.

      By Dawn keeps the document for as long as its Cache-Control: max-age says, between 5 minutes and 24 hours (an hour if it doesn’t say), then fetches it again at the next sign-in. If the document is unreachable or no longer valid at that point, sign-in fails until it’s fixed. A document that fails is rejected with invalid_client and the reason, and isn’t fetched again for a minute. Because anyone can publish a document with any name, the consent screen shows the site that published it next to the name.

    • Dynamic registration. POST /oauth/register (RFC 7591) with a client_name and its redirect_uris returns a client_id. This is how Claude Code, Claude Desktop, claude.ai and Cursor connect today.

  4. You sign in and approve, and the client gets tokens. The client opens /oauth/authorize in your browser with its PKCE code_challenge, the scope it wants, and resource set to the server’s URL (RFC 8707). By Dawn shows its consent screen at https://app.dev.sawrun.com/oauth/consent, then sends the browser back to the client’s redirect URI with a code. The client swaps the code and its code_verifier at POST /oauth/token for an access token and a refresh token.

The token response is standard OAuth (not By Dawn’s API envelope):

{
"access_token": "eyJ…",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "…",
"scope": "tickets:read tickets:write"
}

The client sends the access token with every request to /mcp as Authorization: Bearer …. Before it expires, the client posts grant_type=refresh_token to the same token endpoint and keeps the new refresh token it gets back, because the old one stops working. A client can narrow its scopes on a refresh, but never widen them. POST /oauth/revoke (RFC 7009) with the refresh token disconnects it.

A plain access token works for whoever holds it until it expires. With DPoP (RFC 9449, and MCP’s optional DPoP profile, SEP-1932), the client ties its tokens to a P-256 key pair it keeps, so a token copied out of a log or a proxy is useless without the private key. By Dawn offers it and doesn’t require it: a client that doesn’t send proofs keeps getting Bearer tokens. In the TypeScript MCP SDK (2.1.0 and later) a client turns it on with OAuthClientProvider.dpop().

A DPoP proof is a short JWT the client signs for each request: typ dpop+jwt, alg ES256, its public key as jwk in the header, and the request’s method (htm) and URL (htu), the time (iat) and a unique jti in the body. By Dawn accepts each proof once, within a minute of its iat.

  • At the token endpoint. Send a proof in a DPoP header with the code exchange. The response says "token_type": "DPoP", the access token carries the key’s thumbprint (cnf.jkt), and the refresh token is tied to the same key: every refresh needs a proof signed with it. A refresh without one is refused with invalid_dpop_proof, and one signed with another key with invalid_grant. Neither uses up the refresh token, so a stolen copy can’t rotate it or end your connection.
  • At /mcp. Send the token as Authorization: DPoP … (not Bearer), with a proof whose htu is the server’s URL and whose ath is the base64url SHA-256 of the access token. The server also wants a nonce it issued. The first request without one gets 401 with WWW-Authenticate: DPoP error="use_dpop_nonce" and a DPoP-Nonce header, so the client signs a new proof with that nonce and sends the request again. Every successful answer carries the current DPoP-Nonce, so keep the latest one and use it in the next proof.
POST /mcp HTTP/1.1
Host: workspace.dev.sawrun.com
Authorization: DPoP eyJ…
DPoP: eyJ0eXAiOiJkcG9wK2p3dCIs…
Content-Type: application/json

A bad proof gets 401 with WWW-Authenticate: DPoP error="invalid_dpop_proof": a missing or second DPoP header, another key, another URL, an old iat, or a proof used before. A bound token sent as Bearer gets error="invalid_token", because whoever sends it that way may not hold the key.

The consent screen says “Your admin hasn’t turned on AI agents”. Your organization hasn’t allowed them yet. Ask an owner or admin to turn them on (see AI agents (MCP)).

The scope I want isn’t on the consent screen. Either your organization doesn’t allow it, in which case ask an admin, or your client didn’t ask for it. A client that asks for no scopes is offered tickets:read and tickets:write only.

The agent’s requests keep getting 401 with use_dpop_nonce or invalid_dpop_proof. The client is using DPoP and its proofs aren’t accepted. It must sign a new proof for every request, with the latest DPoP-Nonce By Dawn sent and a jti it hasn’t used before, so check that it isn’t reusing one. A clock more than a minute off also makes its proofs look old.

The agent says By Dawn answered 401, or asks you to sign in again. Its tokens no longer work: it was revoked, it went 30 days unused, your organization turned AI agents off, or you left the organization or your role changed. Reconnect it: in Claude Code run /mcp and choose Authenticate again, and in other clients disconnect and reconnect By Dawn.

The consent screen greys out your organization with “Your org requires SSO” (or multi-factor sign-in). Agents can’t connect to an organization that requires SSO or MFA yet. Pick another organization, or choose Deny.

An agent that used to work now fails to refresh, and asks you to authorize again. If your organization started requiring SSO or MFA after you connected it, By Dawn stops issuing it tokens. Authorizing again shows the organization greyed out. The connection is still listed under Connected agents in Settings › You › Connections, where you can disconnect it.

The agent can’t find a project or ticket you know exists. It sees only what you see. A restricted project you aren’t a member of stays hidden from it, and so do its tickets. Check that you can open it in By Dawn.

A tool says “You don’t have permission to …”. Your role in By Dawn doesn’t allow that change, or the connection’s scopes don’t include it. Starting a worker, for example, needs workers:start on the connection and permission to run agents in that project.

The agent’s changes stop with a rate-limit error. Each connection has its own request budget, so a runaway agent can’t use up yours. Wait a moment, then ask again.

  • AI agents (MCP): turning AI agents on for your organization, and managing connections.
  • Authentication: API keys, for a script or service that calls By Dawn’s API without a person.
  • Start a ticket: what happens when a worker starts.