linear-strict
An unofficial, opinionated MCP server for Linear that treats the ticket description as state and the comments as a log, enforcing one team's workflow rules in the server itself.
Read a ticket whole with
get_issue: full description, every comment oldest-first across all pages, relations, children, attachments, linked PRs, plusfindings,drift,claimand anomittedlist so gaps are never silent.See the description's past with
description_history: saved versions with who made each and a diff, andblamenaming the version behind every current line.List without cursors —
list_issues(up to 2000 matches, filterable by team/state/open/cycle/project/assignee/delegate),list_teams,list_cycles,list_projects,list_initiativesall walk every page server-side.Work the inbox:
notificationsandget_principal_notificationsreturn pointers (no excerpt text), andmark_notifications_read/mark_principal_notifications_readclose them out.Claim a ticket (
claim) to snapshot its description before working, thencheck_claimbefore opening or merging a PR to see if the description moved, with a diff.Patch the description in named sections (
Impact,Observed,Cause,Fix,Done when) withset_state, passingbase(thedescription_sha) so a write is refused if the description changed since your read.Keep format honest:
Observedlines must readYYYY-MM-DD · source · result,Done whenlines must be checklist items, andfindingstells the agent to repair tickets written from other clients.Reconcile drift: move the reconciled marker with
reconciled_through+accounts_for, so the server reports comments after it, comments edited since it, and outside description edits.Post typed comments (
comment):evidence,correction(must carry the patch that makes it true),ask,answer(flips its question row),closed_by(sets the Linear relation).Pass a Done gate:
set_statusto a completed state needs everyDone whenitem ticked and cited, cited PRs merged into main, and a live claim.Change everything else with
set_fields: title, priority, assignee/delegate, labels, cycle, project, milestone, parent, dates, estimate, relations and linked PRs — never description or state.File new tickets with
create_issue, which validates sections and makes you place the work against the team's closest open tickets (widen, parent, or arguenew_because/distinct_from).Get sign-off on descopes: dropping an unticked
Done whenitem asks the person at the client (via Claude Code hooks,AskUserQuestion, or an elicitation form) or a model judge underLINEAR_STRICT_SIGN_OFF=judge.Respect a hands-off label (
no-agentsby default): a ticket carrying it refuses every write but still reads.Go through the same rules from a script via the
linear-strict/libraryexport (StrictLinear,OverlapRefusal,linearGql,memoryClaimStore).Audit citations offline with
linear-strict audit export/audit check, which re-verifies everypath:lineand commit hash cited in tickets against a git checkout.Identify yourself with
whoami, and install optional Claude Code hooks to block writes through other Linear servers.
Provides tools for interacting with Linear issues, comments, projects, teams, cycles, and initiatives. Enforces structured ticket descriptions, comment typing, drift detection, validated section patches, claim-based completion, Done-gate checks, and hands-off labels for agent workflows.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@linear-strictread ENG-412 whole, report drift, then claim it"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
linear-strict
Unofficial and opinionated. This is an independent project, not affiliated with or endorsed by Linear. It enforces one team's way of keeping tickets current, and it refuses writes that other Linear servers would make. For Linear's own MCP server, see linear.app/docs/mcp.
An MCP server for Linear for teams where agents keep tickets up to date. It reads a ticket whole and treats the description as the ticket's current state. The rules are enforced in the server, so a prompt that goes unread or a client hook that stops matching can't switch them off.
It has one runtime dependency, the MCP SDK. It began as a fork of tacticlaunch/mcp-linear (MIT), whose OAuth login it keeps.
The problem it addresses
Linear keeps full history, yet agents working from it drift:
State ends up in comments. A comment answers the ticket's open question and the description still says it is open. Nothing marks which claim is current.
Reads are lossy without saying so. Listings cut descriptions short, comment APIs default to newest first, and summaries read like the whole ticket.
Tickets change after they are read. An agent works from a snapshot, acceptance criteria are added later, and the work ships without them.
Rules in client hooks go dark when a server is renamed and the matcher no longer fires.
Related MCP server: Linear MCP Server
How it works
Description is state, comments are the log. The description has named sections:
Observed,Cause,Fix,Done when,Open questions. It changes only through validated section patches. AnObservedline must readYYYY-MM-DD · source · result(a time after the date is fine), andDone whenlines must be checklist items.A reconciled marker is the description's HEAD. It records the last comment the description accounts for, when that was checked, and the hash of the description it was checked against. It lives in one attachment on the ticket, titled "linear-strict: description reconciled through …", so the description stays clean. Every read reports comments after it, comments edited since the check, and edits to the description made outside this server, as
drift.Repair on read. Not everyone on a team will use this server.
get_issuereports formatfindingsanddrifton tickets written from any client, and tells the agent to fold them into the description.Whole reads. Every comment, oldest first, across all pages.
list_issuesand the workspace lists (teams, cycles, projects, initiatives) walk every page too, so an agent never holds a cursor it can stop following. Anything not fetched is listed inomitted; a gap is never silent.Typed comments.
evidence,correction,ask,answerandclosed_by. A correction must carry the description patch that makes it true. An answer flips its question row.closed_byalso sets the Linear relation.Writes name what they were written against.
get_issuereturns a hash of the description,description_sha. A patch passes it asbaseand is refused, with what changed, if the description moved since that read. Linear has no conditional update, so this is how a patch shows it was built from the current text.Claim, then a Done gate.
claimrecords the description as it stands. Moving to a completed state needs aDone whensection with every item ticked and cited (- [x] item · <SHA, PR, file:line, link, CI run, Observed 2, or a command and its result>), any cited PR that is linked to the ticket merged, and your claim, and is refused with a diff if the description changed since then. Priority or label changes don't count. Dropping an unticked item needs a reason and a yes from the person at the client, or from a model judge in unattended sessions.Shipped-state facts. A ticket marked Done or Merged with no linked pull request, or with PRs merged only into a non-main branch, gets a finding. The facts come from Linear's GitHub attachment metadata.
A hands-off label. A ticket labelled
no-agents(configurable) is people-only: every write through this server is refused, and reads still work.Authorship. An agent (app) token writes as the agent. A personal key writes comments headed
🤖 <agent> via <person>. Each comment on a read is markedagentorperson, with the basis for that call.
Related work
Linear's agent best practices warn that "Comments may not be reliable to read from, as they are editable and may have changed since your agent’s last run." Their answer, Agent Activities, covers agents running in Linear's Agent Sessions. Here,
driftlists comments edited after the description accounted for them.Linear's agent team found it "more effective to encode constraints into the design of Linear Agent’s tools than to spell them out in a prompt", which is the approach this server takes.
claimfollows their delegation model: a person stays the assignee, accountable for the result, and the agent is the delegate.Linear keeps version history and text attribution for documents.
description_historyreads the same snapshots for an issue's description.OpenAI's Symphony keeps an agent's progress in one persistent comment per ticket and tells the agent to leave Backlog tickets alone. This server keeps that state in the description, which Linear versions and every client shows first, and enforces the hands-off label in the server rather than in the prompt.
Cyrus has each sub-issue's agent hand back verification commands for the parent to run, and openclaw-linear-plugin has a separate auditor so the worker "cannot self-certify". The Done gate here asks for cited evidence but still lets the agent that did the work supply it.
Staleness in the wild: herdr-factory#97 shipped work against a ticket snapshot that lacked acceptance criteria added later, trac-mcp#57 had an agent stop trusting an MCP server after silent data loss, and beads#3708 and catalyst-otel#68 had Linear mirrors go stale without saying so.
Install
Quickstart (Claude Code)
Get a Linear credential. A personal API key (Linear → Settings → Security & access → Personal API keys) writes as you. An agent (app) token, an OAuth token for a Linear app with
actor=appstarting withlin_oauth_, writes under the agent's own identity and can be set as a ticket's delegate.Add the server and the sign-off hooks:
npm install -g https://github.com/justinstimatze/linear-strict/releases/download/v0.2.0/linear-strict-0.2.0.tgz claude mcp add linear-strict -e LINEAR_API_TOKEN=<token> -- linear-strict linear-strict installReconnect with
/mcp, then ask the agent to read a ticket.
You need Node 22 or later. Each GitHub release carries the built package; it is not on npm. To upgrade, npm install -g the newer release's .tgz, then run linear-strict install again and reconnect.
To work on it, run it from a checkout instead:
git clone https://github.com/justinstimatze/linear-strict.git
cd linear-strict && npm ci && npm run build
claude mcp add linear-strict -e LINEAR_API_TOKEN=<token> -- node "$PWD/dist/index.js"
node dist/index.js installAfter a git pull, run npm run build again and reconnect the server.
Pin the version, and give the server its own name, linear-strict. Tool names such as get_issue also exist on Linear's official server, so the server name is what tells an agent and any hook matcher which rules apply. To sign in through the browser instead of pasting a token, see OAuth login.
The two hook installers
linear-strict installadds the sign-off hooks to~/.claude/settings.json, once per machine.install --statussays whether they are installed and whether they can still run;install --uninstallremoves them and nothing else. Installed through npx, the hooks run the same pinned version through npx, since npm prunes the cache npx runs from. After upgrading, runinstallagain so the hooks match the server; until then the server asks through the form.examples/claude-code-hooks/install.shis optional and per project: it refuses ticket writes through other Linear servers and runs a project's own Linear checks on strict writes (Blocking writes through other Linear servers). Its hooks run its scripts by path, so run it from a checkout or the global install above, not through npx.
The two write different entries and can both be installed.
Other clients
Claude Desktop, in claude_desktop_config.json, after the global install above:
{
"mcpServers": {
"linear-strict": {
"command": "linear-strict",
"env": { "LINEAR_API_TOKEN": "<token>" }
}
}
}Everything except sign-off works the same in any MCP client. Sign-off depends on what the client offers:
Client | How a descope is approved |
Claude Code with |
|
Claude Code without the hooks | An elicitation form, with rows of about 100 characters |
Other clients that support MCP elicitation | That client's elicitation form |
Clients without elicitation, Claude Desktop included as far as its docs say | Refused; a person makes the edit in Linear, or run with |
Hooks are a Claude Code feature, so no other client gets the preview route.
Sign-off
Dropping or rewording an unticked Done when item removes a check that has not passed, so someone other than the agent approves it. LINEAR_STRICT_SIGN_OFF picks who:
person(the default): the person at the client. In Claude Code with the sign-off hooks installed,set_statehands the agent anAskUserQuestionto put to them, and the change is shown in full in its preview box. A hook refuses the question if the agent changes a word of it, another hook records the answer, and the retry is approved from that record, never from what the agent says. Elsewhere, and in Claude Code without the hooks, the server asks through an MCP elicitation form, which Claude Code shows as rows of about 100 characters.judge: a model with no stake in the ticket decides, so an unattended session never waits for someone who isn't there. It reads the ticket's description, the change, the reason and the risk, approves only when the description backs the reason, and the descope comment names the model and gives its reason for a person to review later. It needs an Anthropic API key:linear-strict auth judge-key setsaves one from a hidden prompt to$XDG_CONFIG_HOME/linear-strict/anthropic-api-key(mode 600), next to theauth logincredentials, or setANTHROPIC_API_KEYin the server's environment, which wins. A key of its own, in a workspace with a spend limit, keeps the judge's cost on its own line.LINEAR_STRICT_JUDGE_MODELoverrides the model (defaultclaude-opus-5-5). Each verdict is one API call of about 2 seconds, roughly 900 input tokens (most of them the cached brief) and 90 output tokens, well under a cent at Opus 5.5's rates (measured 2026-09-27). If the call fails (no credit, an outage, a refusal), the descope is refused with the error and nothing changes. MCP sampling would let the judge run on the client's own model with no key, but Claude Code doesn't offer it to servers (2.1.283 declareselicitationandrootsonly).
The hooks only guard against an agent cutting corners. An agent with a shell could still write an answer record by hand; a third hook refuses tool calls that name the records' directory, which closes the obvious route.
Blocking writes through other Linear servers
The server can only enforce its rules on writes that go through it. If Linear's official server is also connected, an agent can still edit a ticket there. examples/claude-code-hooks has Claude Code hooks that refuse ticket writes through other Linear servers and run a project's own Linear checks on strict writes. They are optional, and they are the only part of this setup that lives in the client.
OAuth login
linear-strict auth login signs in through the browser and stores a refreshing token, which the server uses when no token is set in its environment. It needs a Linear OAuth application of your own: create one at https://linear.app/settings/api/applications/new with the redirect URI http://localhost:8734/callback, then:
linear-strict auth login --client-id <client id> # global install
node dist/index.js auth login --client-id <client id> # from a checkoutThe flow uses PKCE, so a client secret is optional. auth status shows whether you're signed in and when the token expires. auth logout revokes the token and deletes it. Credentials live in $XDG_CONFIG_HOME/linear-strict/credentials.json, readable only by you.
Configuration
Variable | Default | Purpose |
| — | Personal API key, or a |
| — | Any OAuth access token, sent as Bearer |
|
| Branch a PR must merge into for Done to count as shipped |
|
| Environment named in |
|
| Comma-separated labels that make a ticket people-only: every write through this server is refused, reads still work |
|
| Who approves dropping an unticked |
|
| The model that decides when |
|
| How |
| — | The judge's key, if not saved with |
|
| Where claim records and pending sign-offs are kept |
|
| Where |
|
|
|
| — |
|
Claim records live on the machine running the server. A Done check from a machine with no claim on record is refused.
One server per connection
Claude Code's /mcp reconnect starts a new server and leaves the old one running with its pipes open, so the old one never sees its input close. Each server records its pid under LINEAR_STRICT_STATE_DIR/instances, keyed by its parent process and launch settings. When a newer server has replaced it and it has served no tool call for a minute since, the older one exits. A server whose parent exits, or whose input closes, exits too.
Reconciled marker
Each ticket this server has reconciled carries one attachment titled "linear-strict: description reconciled through date". It records the last comment the description accounts for, when that was checked, and a hash of the description at the time, so the next agent to read the ticket knows which comments are new and whether the description was edited elsewhere since. Deleting it does no harm: agents then check the whole thread again, and the next reconcile puts it back. It is written by whoever runs this server, not by Linear.
Tools
Tool | What it does |
| Whole ticket, plus |
| Past versions of the description with who made each and a diff; |
| Every matching ticket in one call, paged to the end by the server: identifier, title, state, assignee, delegate and |
| Take a ticket and snapshot its description; refuses one another agent holds |
| Whether the description changed since your claim, with a diff |
| Patch description sections and/or move the reconciled marker |
| Typed comment: |
| Move to a workflow state; completed states pass the Done gate |
| Priority, owner, labels, cycle, project, milestone, parent, dates, relations and linked PRs; never the description or state |
| New ticket with validated sections, under a parent or in a project, placed against the closest open tickets |
| Teams with their workflow states in board order |
| Cycles, active and next by default; pair a number with |
| Open projects and initiatives with status, owner and dates |
| Your inbox as pointers (ticket, type, actor, time), no excerpt text, paginated |
| The same, for the human this identity acts for, on their own credential — needs |
| Mark the principal's notifications read: ones |
| Mark handled notifications read |
| The user or app behind the token, which is who claims and |
The server also returns these rules as MCP instructions on initialize, so an agent learns the workflow when it connects. TOOLS.md has each tool's arguments, and docs/design.md the reasoning behind the rules, their limits, and what is still open.
From a script
A program that files tickets, such as a CI job turning test findings into tickets, can go through the same rules without an agent in between:
import { StrictLinear, OverlapRefusal, linearGql, memoryClaimStore } from 'linear-strict/library';
const strict = new StrictLinear({ gql: linearGql({ token }), claims: memoryClaimStore() });
try {
await strict.createIssue({ team: 'ENG', title, sections, project_id });
} catch (error) {
if (!(error instanceof OverlapRefusal)) throw error;
// error.candidates: the closest open tickets. Comment on the one this repeats,
// file under one with parent, or retry with new_because and distinct_from.
}Citation audit
Tickets cite code by path:line and by commit hash, and nothing checks either once the ticket is written. The audit does, offline, in two steps:
linear-strict audit export --team ENG --out eng.jsonl
linear-strict audit check --export eng.jsonl --repo ~/src/appexport writes each ticket's description, every saved version of it, and its comments, open tickets first. That is about three API calls per ticket, spaced one ticket every --pace seconds (20 by default, about a fifth of a key's hourly quota), so a long export doesn't crowd out the key's other users. It saves every 25 tickets. A rerun with the same --out fetches only tickets updated since, and carries on where --max-fetch (500 by default), a rate limit or an interruption stopped the last run.
check reads that file and a git checkout and makes no network calls. Each citation is dated by the description version or comment it first appears in, then compared with the cited branch (--ref, default origin/main; a repo that lands work on a branch such as develop before main passes that) as it was on that date and as it is now:
Verdict | Meaning |
| The cited lines read the same today |
| The same lines are elsewhere in the file now; the finding gives the new line |
| The cited lines say something else now; the finding gives both |
| The file is no longer on the branch |
| The cited line is a brace or blank, so it can't anchor anything |
| The branch didn't have that line or file on the day it was cited, so it was cited from somewhere else |
| More than one file ends with the cited path |
A commit-shaped hex string is on_main, off_main (--main, default origin/main), or not_a_commit_here, which is often a different kind of id: a comment, a request, a deployment. --json prints every finding; --issue narrows to named tickets.
Development
npm test # typecheck, lint, format and unused-code checks, unit tests, MCP smoke test, and the sign-off routes end to end
npm run build
node scripts/e2e/sign-off.mjs --live-judge # the same, with the judge on the real API (one call, well under a cent)
npm run test:live # against a real workspace: creates temporary tickets on LIVE_TEAM and deletes them
npm run eval # a model works tickets in the fake Linear through the strict tools; graded on final state
npm run format # Prettier; `npm test` fails on unformatted codegit config core.hooksPath hooks once, after cloning, turns on the tracked pre-commit hook: a non-blocking CodeScene delta check on staged changes when cs is on PATH. It warns and never blocks the commit.
npm run test:live needs LINEAR_API_TOKEN and LIVE_TEAM (a team key). It writes to that workspace. npm run eval needs ANTHROPIC_API_KEY; evals/README.md covers cases, caching and results.
License
MIT. See LICENSE.md; the OAuth login code is from tacticlaunch/mcp-linear and keeps its notice.
Available Tools
19 toolscheck_claimARead-onlyIdempotent
Whether the description changed since your claim, with a line diff. Run before opening or merging a PR for the ticket.
| Name | Required | Description | Default |
|---|---|---|---|
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds the temporal scoping ('since your claim') and the diff output shape. However, it doesn't say what happens when no claim exists or what the diff looks like in edge cases, leaving gaps beyond the annotation coverage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences with zero filler; the core behavior and the invocation trigger are both front-loaded. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With rich annotations, a fully documented parameter, and an existing output schema, the description covers what the tool does and when to call it. Only minor edge-case behavior (no prior claim, empty diff) is missing, which is not essential for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and the single `issue` parameter is fully documented in the schema with a format example (ENG-123 or UUID). The description adds nothing parameter-specific, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific check: whether the ticket description changed since the caller's claim, plus a line diff of the change. It's phrased as a question rather than a verb+resource statement, but an agent can identify the operation. It relates to the `claim` and `description_history` siblings without explicitly distinguishing itself from them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit timing guidance: 'Run before opening or merging a PR for the ticket.' This gives clear context for invocation. It does not name alternatives (e.g., description_history) or state when not to use it, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
claimADestructive
Take a ticket and record the description as it stands, so a later Done check can tell whether it changed underneath you. Sets assignee to you when the ticket is unowned; sets delegate to you when a human owns it and you are an agent (app) identity. Refuses a ticket another agent holds. Claiming again after a change is how you acknowledge the new description.
| Name | Required | Description | Default |
|---|---|---|---|
| as | No | Override the automatic choice | |
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID | |
| take_over | No | Take the assignment from the person who holds it. Only when they handed it to you; a ticket held by another agent is never taken. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations flag it as destructive, non-read-only and non-idempotent, and the description adds substantial context beyond them: the refusal rule for other agents, the identity-dependent assignee/delegate behavior, and that re-claiming after a change is an acknowledgement act. These are behavioral traits the annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tightly packed sentences that lead with the core action and effect, then the routing rules, then the re-claim case. Dense but every clause carries information; no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described. Combined with the annotations, the description covers identity semantics, refusal conditions, and the acknowledgement workflow, leaving no significant gap for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the schema baseline is 3; the description adds meaning by explaining the automatic assignee/delegate choice that the 'as' override modifies, and reinforcing the take_over restriction. It goes beyond restating the schema, though it does not detail format for 'issue'.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
It states a specific verb and resource ('Take a ticket and record the description as it stands') and immediately differentiates the action from its sibling check_claim by explaining the later Done check that consumes the record. An agent can tell what this does without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit about when it applies (assignee when unowned, delegate when a human owns and you are an app identity), when it refuses (a ticket held by another agent), and the re-claim workflow as acknowledgement. This is when/when-not guidance rather than implied usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
commentADestructive
Post a typed comment. evidence: a finding, optionally with an Observed patch. correction: must carry the description patch that makes the description say the corrected thing. ask: adds an OPEN row to Open questions. answer: must name the row it closes (answers: "Q3") and flips it to ANSWERED with a link. closed_by: this ticket's work landed under another ticket; names it (closed_by), sets the Linear relation (relation "duplicate" or "fixed_there") and records it under Fix. Move the state separately with set_status.
| Name | Required | Description | Default |
|---|---|---|---|
| base | No | Required with patch. description_sha of the description this patch was written against: from get_issue, or from your last write to this ticket. The write is refused, with what changed, if the description has moved since. | |
| body | Yes | Comment text, without a header: the server writes the header from kind and drops a copy typed here. For ask, the first line becomes the question row. | |
| kind | Yes | ||
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID | |
| patch | No | Description sections to change. Impact is the one plain-language line at the top saying who notices this work (mode replace). Observed lines must be "YYYY-MM-DD · <source: command, SHA or query> · <what it showed>". Done when lines must be checklist items ("- [ ] <check that proves it>"). Open questions changes only through comment kinds ask and answer. | |
| ask_to | No | For kind ask: who should answer | |
| answers | No | For kind answer: the question id, e.g. Q3 | |
| relation | No | For kind closed_by: duplicate (same problem) or fixed_there (a different ticket whose change fixed this one) | |
| closed_by | No | For kind closed_by: the ticket that carried the work | |
| author_label | No | Agent name for the comment header, e.g. the model. With a personal API key the header reads "<author_label> via <you>"; with an agent (app) token it defaults to the agent identity. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only declare the safety profile (destructive, non-idempotent, closed-world); the description goes further by disclosing the side effects of each kind — ask opens a row in Open questions, answer flips it to ANSWERED with a link, closed_by writes a Linear relation and records under Fix, patches mutate description sections. It does not mention the base/description_sha concurrency refusal (that lives only in the schema) or duplicate-post behavior, which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first three words, and each following clause is a compact kind:behavior pair with no filler. It reads as a dense colon-separated block rather than flowing prose, but nothing in it is redundant against the schema or annotations.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 10-parameter, five-mode write tool with annotations and an output schema, the description covers the mode semantics and the sibling boundary that an agent needs. It leaves the return payload to the output schema (correct) and only omits failure/duplicate behavior that the schema's base note partially covers.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 90%, so the baseline is 3, but the description adds cross-parameter semantics the schema cannot express: which patch/kinds pair with which field (evidence → optional Observed patch, correction → mandatory description patch, answer → answers id, closed_by → closed_by + relation). That mapping is genuine added meaning over the enum listing.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a concrete verb+resource ("Post a typed comment") and then enumerates the five kinds, so an agent knows this is a polymorphic write endpoint rather than a generic note-taker. It also carves out scope against set_status ("Move the state separately"). The tool name "comment" alone is vague, but the description disambiguates it well.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Each kind carries its own condition of use and its prerequisite: correction "must carry the description patch", answer "must name the row it closes (answers: \"Q3\")", closed_by names the carrying ticket and sets the relation. It also states explicitly that state changes belong to set_status, which is a real exclusion. This is about as close to per-kind when-to-use guidance as a tool gets.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_issueA
Create a ticket. Before filing, ask whether the work is part of a ticket that already exists: widening that ticket, or filing under it with parent, keeps one change in one place. A new ticket needs a home, parent or project_id, and ends up in a project: a sub-ticket goes in its parent's, and a parent with no project is refused until it has one. A team with no open projects is exempt. Without a parent, the server finds the team's open tickets closest to this one and refuses until you've placed the work: under one of them (parent), into one of them (widen it and file nothing), or apart from all of them (new_because and distinct_from). The result lists what you filed on this team that no agent has taken up; filing a ticket is not doing the work, so see each into a queue. Its description is built from named sections (Observed, Cause, Fix, Done when), checked the same way set_state checks them. Include a Done when section if the ticket will be closed through set_status.
| Name | Required | Description | Default |
|---|---|---|---|
| team | Yes | Team key, e.g. ENG | |
| title | Yes | ||
| parent | No | The ticket this work is part of, identifier or UUID. A sub-ticket skips the check for close open tickets. | |
| sections | No | Description sections to change. Impact is the one plain-language line at the top saying who notices this work (mode replace). Observed lines must be "YYYY-MM-DD · <source: command, SHA or query> · <what it showed>". Done when lines must be checklist items ("- [ ] <check that proves it>"). Open questions changes only through comment kinds ask and answer. | |
| project_id | No | The project this ticket belongs to; list_projects gives the ids. | |
| new_because | No | Why this work is separate from every close open ticket the server named, in one sentence of at most 300 characters. Posted on the new ticket. | |
| distinct_from | No | Each close open ticket the server named, by identifier, that this one is separate from. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations declare the mutating, non-idempotent, non-destructive profile, and the description adds substantial behavior beyond that: the server auto-discovers the team's closest open tickets and refuses until placed, parent-without-project is refused, and the result lists filed tickets no agent has claimed. It also ties section validation to set_state and explains the Done-when/set_status dependency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
It is front-loaded with the core action, but the remaining prose is a long run-on chain of dependent clauses ('A new ticket needs a home... and ends up in a project...') that is harder to parse than necessary. Every sentence carries useful information, so it is not padding, but the structure could be tighter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-param, mutating tool with conditional server-side refusals, the description covers the branching logic, required sections, and return summary well; an output schema exists so return values need no explanation. It leaves only minor gaps such as the exact shape of the refusal response, which is acceptable.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 86%, so baseline is 3, but the description adds real meaning on top: new_because is capped at 300 characters and posted on the ticket, distinct_from names the server-named tickets, and Done when sections must be checklist items. Only marginal gaps remain for `team`/`title`/`project_id` semantics, which the schema covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource ('Create a ticket'), and the rest of the text clearly delineates it from siblings like comment, set_status and set_state by describing filing semantics. It is unambiguous for an agent, though the purpose statement is buried under a dense block of constraints rather than front-loaded crisply.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit when-to-use branches: widen an existing ticket, file under one with `parent`, or file apart using `new_because`/`distinct_from`. It also states the exemption (team with no open projects), the refusal conditions, and the requirement that a parent with no project is refused. This is a full decision tree, not vague guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
description_historyARead-onlyIdempotent
The description's past versions, from the snapshots Linear saves as it is edited: when, by whom, and a line diff against the version before. current says whether the live description is in a version yet, with a diff if not. With blame, every line of the current description names the version that introduced it and who made that version. Use it to see when and by whom a section or tick changed before overwriting or disputing it.
| Name | Required | Description | Default |
|---|---|---|---|
| blame | No | Also attribute each current line to the version that introduced it | |
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the safe read-only, idempotent, non-destructive profile, so the bar is lower. The description adds behavioral context beyond annotations by explaining snapshots, line diffs against the previous version, what `current` means, and how blame attributes each line to a version and author.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with a clear definition and proceeds logically through return semantics, blame behavior, and usage. It is appropriately sized for a tool with an output schema, though the `current` and `blame` sentences overlap somewhat with structured documentation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With annotations covering safety and an output schema covering return fields, the description supplies all remaining context an agent needs: what the tool retrieves, what blame does, and when to reach for it. Nothing essential for correct invocation is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters, establishing a baseline of 3. The description elaborates on the `blame` effect and mentions `current`, but adds little syntax or meaning beyond what the schema already provides for `issue` and `blame`.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the resource: past versions of a description, with when, by whom, and line diffs. It is specific about what the tool returns, though it does not explicitly differentiate itself from sibling tools like get_issue or comment.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly says when to use it: to see when and by whom a section or tick changed before overwriting or disputing it. No alternative tools or when-not conditions are named, so it stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_issueARead-onlyIdempotent
Read one ticket whole: full description, every comment oldest-first (all pages), who edited the description and when, relations, children, attachments. omitted lists anything not returned; an empty list means nothing was left out. findings lists format problems in the description and drift.unreconciled_comments lists comments the description may not reflect yet, and drift.edited_after_reconcile comments edited after it accounted for them. When drift.needs_reconcile is true, fold what those comments establish into the description with set_state (reconciled_through = newest comment id) before acting on the ticket. Tickets written from other clients get repaired this way. Pass issue.description_sha as base to the write that patches the description.
| Name | Required | Description | Default |
|---|---|---|---|
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID |
Output Schema
| Name | Required | Description |
|---|---|---|
| claim | No | Your claim on this ticket and whether the description changed since |
| drift | No | Comments after the reconciled marker, needs_reconcile and next_step |
| issue | No | Full description and fields, description_sha (pass it as base when you patch the description), and open_questions parsed from the description |
| omitted | No | Anything not fetched, with the reason; empty means nothing was left out |
| children | No | Sub-issues |
| comments | No | Every comment, oldest first, each with author_kind (agent or person) and its basis |
| findings | No | Format and shipped-state problems to fix with set_state |
| relations | No | Blocks, duplicates and related tickets, both directions |
| attachments | No | Other attachments |
| comment_order | No | Always oldest first |
| pull_requests | No | Linked GitHub PRs with status, target branch and merge time |
| description_edits | No | Who changed the description and when, oldest first |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so safety is covered. The description goes further by disclosing retrieval behavior (all comment pages, oldest-first) and the semantics of derived fields like `omitted` and `drift.unreconciled_comments`, plus the repair workflow for tickets edited by other clients. Return format details are partly duplicated by the output schema, but the drift semantics are genuinely additive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first clause, and every subsequent sentence carries substantive meaning for a tool with this many return structures. The middle sentences are dense run-ons packing several field semantics together, which costs a little readability but not enough to call it bloated.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description does not need to spell out every returned field, and it correctly focuses on interpretation (omitted, findings, drift) and the reconcile-first workflow. An agent has enough to call the tool and act on results, though the relationship to description_history for non-full reads is left unstated.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% with a single parameter already documented in-schema as 'Issue identifier (e.g. ENG-123) or UUID'. The description adds no syntax or format nuance for `issue` itself (description_sha is a field of the ticket, not the argument), so the baseline of 3 for high-coverage schemas applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource ('Read one ticket whole') and enumerates exactly what is retrieved: description, comments oldest-first across all pages, editors, relations, children, attachments. This clearly separates it from list_issues (multiple tickets) and comment (writes) among the siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete follow-up guidance: when drift.needs_reconcile is true, fold the flagged comments into the description via set_state using reconciled_through, and pass issue.description_sha as the base for the description patch. That names the alternative tool and the triggering condition, though it never explicitly says when to prefer get_issue over description_history.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_principal_notificationsARead-onlyIdempotent
The inbox of the human this identity acts for — a different person's notifications from notifications, which is this identity's own. Same shape, deliberately a separate tool rather than a parameter, so which inbox you're reading is never ambiguous. Errors if LINEAR_PRINCIPAL_TOKEN isn't configured for this identity, or if it resolves to someone other than LINEAR_PRINCIPAL_ID.
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | next_cursor from the previous call | |
| first | No | How many to return, default 50 | |
| since | No | Only notifications created on or after this date, e.g. 2026-09-24 | |
| unread_only | No | Default true |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | How to use these results |
| order | No | How results are ordered |
| has_more | No | True when more results exist; pass next_cursor as after |
| next_cursor | No | Cursor for the next page |
| unread_count | No | Linear's unread count |
| notifications | No | Pointers: id, type, time, read, actor, actor_kind and the ticket |
| stopped_early | No | Present when a later page failed; next_cursor resumes there |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, closed world), so the bar is lower. The description still adds genuinely new behavior: it errors when LINEAR_PRINCIPAL_TOKEN is unconfigured or resolves to someone other than LINEAR_PRINCIPAL_ID, and it notes the payload mirrors `notifications`.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three front-loaded sentences that state what it reads, why it is separate from the sibling, and when it fails; nothing is redundant. The em-dash stacking makes it slightly denser than necessary, keeping it out of the top band.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists so return values need not be described, and annotations carry the safety profile. What remains — identity/principal semantics and the token-resolution error conditions — is exactly the context an agent needs before invoking, and it is all present.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% (all four params documented, including defaults and formats), so the schema does the heavy lifting. The description adds only the hint that the shape matches `notifications`; it gives no additional parameter semantics. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (the principal's inbox) and immediately distinguishes it from the sibling `notifications`, which reads this identity's own inbox. The sentence 'Same shape, deliberately a separate tool rather than a parameter' makes the boundary with the sibling unambiguous without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description names the alternative (`notifications`) and the condition that selects it ('a different person's notifications'), plus the failure conditions under which this tool must not be used. It stops short of an explicit trigger phrase such as 'use when acting on behalf of the human', leaving a small amount of inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_cyclesARead-onlyIdempotent
Cycles, earliest first. Defaults to the active and next cycle. Use a cycle number with list_issues (cycle + team) to see its tickets.
| Name | Required | Description | Default |
|---|---|---|---|
| team | No | Team key; omit for every team | |
| when | No | current (active and next, default), upcoming, past or all |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnly, idempotent, non-destructive, and non-open-world behavior, so the safety profile is covered. The description adds genuinely useful behavior the annotations cannot convey: results are ordered earliest-first and the default window is the active and next cycle.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with ordering and default scope front-loaded ahead of the cross-reference. Every clause carries information an agent can act on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so the description need not explain return values, and the annotations cover safety. What remains is ordering and default scope, both stated; only a brief note on pagination or team-scoping behavior is absent, which is minor.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both the team key and the when enum are fully documented in the schema; the description restates the default value ('active and next cycle') without adding format or syntax detail. The reference to a 'cycle number' describes a list_issues parameter rather than this tool's own inputs, so there is no real gain over the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The fragment 'Cycles, earliest first' names the resource and its ordering, and the follow-up sentence clarifies scope by noting the default of active-plus-next cycles. The verb is only implied (list), but the content is specific enough to separate it from list_issues, list_teams, and other siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It states the default scope and explicitly routes the agent to list_issues with a cycle number plus team to see a cycle's tickets, which is a concrete handoff condition. It does not state when-not to use this tool or contrast it with other listing tools, so it falls short of full when/when-not coverage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_initiativesARead-onlyIdempotent
Initiatives with status, owner and target date. Unfinished ones only unless include_closed.
| Name | Required | Description | Default |
|---|---|---|---|
| include_closed | No | Include completed initiatives |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the safety burden is lifted. The description adds a real behavioral fact not in the annotations: the default result set silently excludes completed initiatives unless include_closed is set. That is the kind of default-behavior disclosure that prevents miscalls.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, front-loaded sentences with no filler. Slightly telegraphic ('Initiatives with status, owner and target date' reads as a fragment), but every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, return values need no explanation, and annotations cover the safety profile. The description supplies the only missing piece an agent needs — the default filtering behavior — so it is essentially complete for a one-parameter list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single parameter's description ('Include completed initiatives') is already documented structurally. The description reinforces the include_closed semantics by stating the default filter, but adds no format or edge-case detail beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names the resource (initiatives) and the fields it surfaces (status, owner, target date), so the agent knows what listing this returns. It does not differentiate from the many list_* siblings (list_issues, list_projects, list_cycles, list_teams), but the resource itself is unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The second sentence defines the default scope ('Unfinished ones only unless include_closed'), which is genuinely useful selection guidance. However, there is no statement of when to prefer this tool over alternatives or any prerequisite context.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_issuesARead-onlyIdempotent
Every ticket matching the filters, in one call: the server pages through Linear to the end, so the answer is the whole set (total, by_state, and one row per ticket under columns). Rows hold identifier, title, state, assignee, delegate and updatedAt; there are no description excerpts, so read a ticket with get_issue before acting on it. More than 2000 matches is refused; narrow with open, state, cycle, project, assignee_is_me or delegate_is_me. When a task covers a set, work every row.
| Name | Required | Description | Default |
|---|---|---|---|
| open | No | Only tickets not in a completed or canceled state | |
| team | No | Team key, e.g. ENG | |
| cycle | No | Cycle number within team (list_cycles gives them); needs team | |
| query | No | Full-text search term. Omit to list by most recently updated. | |
| state | No | Workflow state name, e.g. "In Progress" | |
| project | No | Project name or id | |
| assignee_is_me | No | ||
| delegate_is_me | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| rows | No | One array per ticket: identifier, title, state, assignee, delegate, updatedAt; no descriptions |
| total | No | How many tickets match; rows holds every one of them |
| columns | No | Names of the values in each row, in order |
| by_state | No | Count of matching tickets per workflow state |
| complete | No | Always true: a partial set is refused, never returned |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover the safety profile, but the description adds substantial non-obvious behavior: server-side pagination to completion, a hard refusal above 2000 matches, and the exact row columns returned. These are operational traits the annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three dense sentences, front-loaded with scope, then return shape, then constraints and routing. No filler; every clause carries information (cap, pagination, columns, alternative tool).
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even though an output schema exists, the description clarifies what the rows actually contain and the failure mode at 2000 matches. Combined with annotations and schema, an agent has everything needed to call and interpret this tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 75%, so the schema already documents most params. The description enumerates the narrowing filters, which adds modest signal about which params constrain the result set, but does not add format or syntax detail beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Every ticket matching the filters, in one call') and distinguishes itself from get_issue by noting rows hold no description excerpts. An agent can tell what it returns and how it differs from the sibling detail tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent: 'read a ticket with get_issue before acting on it', and 'narrow with open, state, cycle, project, assignee_is_me or delegate_is_me' when matches exceed 2000. Also names the use case 'when a task covers a set, work every row'. Covers when-to-use, when-not (too broad), and the alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_projectsARead-onlyIdempotent
Projects with status, lead, teams, dates and progress. Open projects only unless include_closed.
| Name | Required | Description | Default |
|---|---|---|---|
| team | No | Team key | |
| include_closed | No | Include completed and canceled projects |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and destructiveHint=false, so the safety profile is covered. The description adds non-obvious behavior beyond that: results are filtered to open projects by default, which an agent would not know from the schema alone. It does not mention any pagination or result-limit behavior, keeping it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, no filler, with the returned-field summary front-loaded and the filtering caveat placed last where it is actionable. Nothing here is wasted or redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description need not explain return values, and it correctly covers the default filtering behavior for a simple two-parameter read tool. The only mild gap is the team scoping parameter, which is left entirely to the schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents both parameters (team key, include_closed flag), making 3 the baseline. The description restates include_closed's semantics ('Open projects only unless include_closed') but says nothing about the team parameter's scoping behavior, so it adds little beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names the resource (projects) and enumerates the returned fields (status, lead, teams, dates, progress), which combined with the tool name 'list_projects' makes the operation unambiguous. It is distinguishable from sibling list_* tools (list_teams, list_issues, list_cycles), though it never states the verb explicitly and reads as a field listing rather than an action.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The clause 'Open projects only unless include_closed' tells the agent when the default behavior applies and how to widen it, which is real usage guidance. However, no alternatives are named and there is no statement about when to prefer this tool over, say, list_issues or list_cycles when scoping a query.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_teamsARead-onlyIdempotent
Every team with its key and workflow states in board order. State names are what set_status takes.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already establish readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered. The description adds genuinely useful context beyond them: entries are returned in board order and the returned state names are the valid inputs for set_status, which is a cross-tool contract not captured anywhere in structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short, declarative sentences with no filler, and the content description is front-loaded before the set_status cross-reference. Every sentence carries information an agent can act on.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description is not obliged to detail return values, and the annotations cover the safety profile. The set_status linkage supplies the main missing rationale for calling it, leaving little an agent needs that is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline of 4 applies; there is nothing for the description to disambiguate. Schema coverage is reported at 100% with an empty property set, leaving no semantic gap to fill.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource (teams) and enumerates what each entry contains (key plus workflow states in board order), so an agent knows exactly what comes back. It does not explicitly distinguish itself from sibling list tools like list_projects or list_cycles, but the resource naming makes the boundary self-evident.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is implied rather than stated: by noting that 'state names are what set_status takes,' it signals this is the lookup to run before calling set_status. There is no explicit when-to-use or when-not-to-use framing and no named alternative to prefer in other situations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mark_notifications_readAIdempotent
Mark notifications read once you have handled them. Reports each id separately.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | Yes | Ids from notifications |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare idempotentHint=true, destructiveHint=false and readOnlyHint=false, so the safety and repeatability profile is covered. 'Reports each id separately' hints at per-id outcome reporting, but with an output schema present that detail is already documented structurally, so the description adds only modest value.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, zero filler, with the action and the timing cue front-loaded ahead of the reporting note.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-required-param tool with full schema coverage, annotations, and an output schema, the description covers the intent and the per-id reporting behavior. It is complete enough to invoke correctly, though it could say more about bulk failure handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the single 'ids' array parameter is fully described in the schema as 'Ids from notifications'. The description adds no syntax, ordering, or batch-limit meaning beyond that, so baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('mark notifications read') and scopes it with 'once you have handled them'. It is clearly distinguishable from the read-oriented sibling 'notifications', though it never names or contrasts with a sibling explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'once you have handled them' gives an implied precondition for use, but there is no when-not guidance and no mention of alternatives such as the 'notifications' listing tool. Adequate but leaves routing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
mark_principal_notifications_readAIdempotent
Mark notifications in the inbox of the human this identity acts for as read — the write twin of get_principal_notifications, separate from mark_notifications_read so which inbox is written is never ambiguous. Only notifications get_principal_notifications returned in this server can be marked; others are refused per id. Pass ids, or only_agent_actors: true to mark every unread one an agent or integration caused (fleet bookkeeping), optionally only those created before a date. Needs a principal token with write access; a read-only one is refused with what to tell your user.
| Name | Required | Description | Default |
|---|---|---|---|
| ids | No | Ids from get_principal_notifications | |
| before | No | With only_agent_actors: only those created before this date, e.g. 2026-10-02 | |
| only_agent_actors | No | Mark every unread notification an agent or integration caused, among those get_principal_notifications returned |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond annotations: per-id refusal of notifications not returned by the sibling read tool, the required principal token with write access, and the read-only-token failure mode with the message to relay to the user. Annotations cover the safety profile (idempotent, non-destructive), and the description adds prerequisite and partial-failure semantics.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the core action and the disambiguation before anything else, and every sentence carries new information. Slightly dense as a single paragraph with several parentheticals, but nothing is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present the return shape need not be described, and the description still covers scope, selection modes, prerequisite auth, and partial-refusal behavior. Nothing an agent needs to call this correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3; the description adds meaning by framing only_agent_actors as 'fleet bookkeeping' and clarifying the interaction between before and only_agent_actors (only unread agent-caused notifications created before a date).
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (mark read) and resource (notifications in the principal's inbox), and explicitly positions itself as the write twin of get_principal_notifications and as distinct from the similarly named mark_notifications_read. An agent can disambiguate among siblings without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Names the two selection modes explicitly (pass ids, or only_agent_actors: true for agent/integration-caused unread notifications) and the alternative tools it must not be confused with. It also states the constraint that only notifications previously returned by get_principal_notifications are markable.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
notificationsARead-onlyIdempotent
Your Linear inbox, newest first, as pointers: ticket, notification type, who did it (agent or person) and when. Excerpt text is left out, so read the ticket with get_issue before acting. Unread only by default; paginated with next_cursor.
| Name | Required | Description | Default |
|---|---|---|---|
| after | No | next_cursor from the previous call | |
| first | No | How many to return, default 50 | |
| since | No | Only notifications created on or after this date, e.g. 2026-09-24 | |
| unread_only | No | Default true |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | How to use these results |
| order | No | How results are ordered |
| has_more | No | True when more results exist; pass next_cursor as after |
| next_cursor | No | Cursor for the next page |
| unread_count | No | Linear's unread count |
| notifications | No | Pointers: id, type, time, read, actor, actor_kind and the ticket |
| stopped_early | No | Present when a later page failed; next_cursor resumes there |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare a safe, idempotent read, so the bar is lower, yet the description adds real value: excerpt text is deliberately omitted, so a follow-up get_issue call is required before acting, and unread-only filtering is the default. It doesn't mention rate limits or the notification-type vocabulary, but the behavioral caveat it does give is the one an agent would otherwise get wrong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, front-loaded with what the tool is, then the critical caveat, then defaults. No sentence is filler; each carries a distinct fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need no explanation, and the description still covers the three things an agent needs: the pointer-only return shape, the pre-action read requirement, and pagination/default filtering. Nothing required to call it correctly is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so 'unread_only' default true and cursor paging are already documented in the schema; the description only restates them at a high level. Baseline 3 is appropriate — no new syntax, format, or constraint meaning is added.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific resource ('Your Linear inbox') plus ordering ('newest first') and the exact shape of each row (ticket, notification type, actor, timestamp). An agent can distinguish it from sibling list tools like list_issues and from the mutating mark_notifications_read without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly routes the agent onward ('read the ticket with get_issue before acting') and states the default filter and paging behavior. What's missing is a direct comparison point against mark_notifications_read or list_issues, but the when-to-use context is otherwise clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_fieldsADestructive
Change a ticket's fields other than its content: title, priority, assignee or delegate, labels, cycle, project, milestone, parent, due date, estimate, relations to other tickets, and linked GitHub pull requests. The description changes only through set_state and the workflow state only through set_status. Names are resolved to ids first and the whole call is refused if any is unknown or ambiguous, so nothing is half-applied. Taking a ticket from its current assignee needs take_over; another agent's ticket is refused, and so is one delegated to someone else unless it is assigned to the human this identity acts for (LINEAR_PRINCIPAL_ID): then take_over moves the delegation and a comment records it.
| Name | Required | Description | Default |
|---|---|---|---|
| cycle | No | Cycle number, "current", "next", or null to remove it from its cycle | |
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID | |
| title | No | ||
| blocks | No | Issue identifiers this ticket blocks | |
| parent | No | Parent issue identifier, or null | |
| project | No | Project name or id, or null | |
| assignee | No | Name, display name, email or id, "me", or null to unassign | |
| delegate | No | Agent (app) user to delegate to, "me", or null to clear | |
| due_date | No | YYYY-MM-DD, or null | |
| estimate | No | ||
| link_prs | No | GitHub pull request URLs to link to this ticket, such as the promotion PR that carried the work to main. Linear's GitHub integration then records where each merged, which the Done gate reads. | |
| priority | No | 0 none, 1 urgent, 2 high, 3 medium, 4 low | |
| milestone | No | Milestone name in the ticket's project (or the project set in this call), or null | |
| take_over | No | Required to change a person's assignment to someone else, or to move a delegation off another agent on a ticket assigned to the human you act for | |
| add_labels | No | Label names on the team or workspace. Labels are not created here. | |
| blocked_by | No | Issue identifiers that block this ticket | |
| related_to | No | Issue identifiers to mark as related | |
| remove_labels | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations only declaring destructive=true, non-idempotent, and not read-only, the description adds critical behavioral context: names are resolved to IDs first, the entire call is refused if any name is unknown or ambiguous, and nothing is half-applied. It also discloses permission rules around reassignment, take_over, and delegations, which an agent could not infer from annotations alone.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four dense sentences, all of which earn their place: purpose, alternatives, atomic validation behavior, and permission rules for assignment changes. It is front-loaded with the primary action and does not repeat annotation or schema content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given 18 parameters, destructive annotations, an output schema, and 83% schema description coverage, the description supplies the missing high-level context: alternatives, atomic refusal behavior, and reassignment/delegation constraints. It does not need to explain return values because an output schema exists, and it covers the complexity inherent in this mutation tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 83%, so most parameters are already documented in the schema. The description lists the mutable field categories but does not add format, syntax, or edge-case meaning beyond what the schema provides for individual parameters. Baseline 3 is appropriate when structured fields carry the parameter semantics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Change a ticket's fields other than its content.' It then enumerates the field categories and explicitly distinguishes the tool from set_state and set_status, which handle description and workflow state respectively. An agent can identify this as a field-mutation tool without opening the schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description names explicit alternatives and constraints: description changes go through set_state, workflow state through set_status, taking over an assignment needs take_over, and other agents' tickets are refused. It gives clear when-not conditions and routing guidance for an agent's own identity and for the human principal case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_stateADestructive
Change what the ticket says is true by patching named description sections (Observed, Cause, Fix, Done when). The description is current state; comments are the log. Pass reconciled_through (a comment id) to record that the description now reflects the thread through that comment, with accounts_for saying how each skipped comment was handled. Tick a Done when item only once its check has run, and cite what showed it after the item text: "- [x] · ", where evidence is a commit SHA, a PR (#123), a file:line, a link, a CI run, "Observed 2" for a line under Observed, or command → result. A merge, a deploy, or being told something shipped is not the check; if nobody has run it, leave it open and say so. Removing or rewording an unticked Done when item needs descope_reason and descope_risk, and your user is asked to approve it from those two alone, so write them for someone without the ticket open. In Claude Code the call may come back asking you to put a question to your user with AskUserQuestion first; do exactly that, then retry with the sign_off token it gives.
| Name | Required | Description | Default |
|---|---|---|---|
| base | Yes | description_sha of the description this patch was written against: from get_issue, or from your last write to this ticket. The write is refused, with what changed, if the description has moved since. | |
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID | |
| patch | No | Description sections to change. Impact is the one plain-language line at the top saying who notices this work (mode replace). Observed lines must be "YYYY-MM-DD · <source: command, SHA or query> · <what it showed>". Done when lines must be checklist items ("- [ ] <check that proves it>"). Open questions changes only through comment kinds ask and answer. | |
| sign_off | No | The token from a set_state refusal that asked you to put a sign-off question to your user. Retry the same call with it after they answer. | |
| accounts_for | No | With reconciled_through: for each comment the marker moves past, whether it was folded into this call's patch or changes nothing (with a reason). Typed comments that already changed the description count on their own. {comment: "*"} covers every comment not named. | |
| descope_risk | No | Required with descope_reason: what stops being checked if your user approves, and what could get through because of it. At most 100 characters; they see it on one line as "If you accept". | |
| descope_reason | No | Required when the patch removes or rewords an unticked Done when item: why that check no longer applies. At most 100 characters; your user sees it on one line as "Why the agent wants it", and it is recorded as a comment. Keep the detail in Observed. | |
| reconciled_through | No | Id of the newest comment the description now reflects |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already flag destructive=true and non-idempotent, and the description adds substantial behavior beyond them: the base-SHA optimistic-concurrency refusal ('The write is refused, with what changed, if the description has moved since'), the sign_off/AskUserQuestion retry flow, and the user-approval path for descopes. This tells the agent exactly what can go wrong and how the call may return without mutating.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core purpose and its contrast with comments are front-loaded, and most sentences carry non-obvious rules. It is dense and runs long with several parenthetical asides (source lists, Claude Code sign-off), which slightly taxes readability but each clause is doing work.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and annotations carry the safety profile. Given the tool's complexity (8 params, nested patch array) the description covers the concurrency, sign-off, and descope flows that an agent would otherwise guess wrong; nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 100% schema coverage the baseline is 3, but the description adds real meaning the schema lacks: the evidence format for ticked Done when items ('- [x] <item> · <evidence>'), what qualifies as a check versus a merge/deploy, and the semantics of reconciled_through/accounts_for ('accounts_for saying how each skipped comment was handled'). This meaningfully enriches several parameters beyond their structured definitions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb+resource: 'Change what the ticket says is true by patching named description sections (Observed, Cause, Fix, Done when).' It immediately distinguishes itself from the sibling comment tool ('The description is current state; comments are the log'), so an agent can tell it apart from comment/set_status without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives clear conditional guidance: pass reconciled_through to record the description reflects a thread, tick a Done when item only once its check has run, and require descope_reason/descope_risk when removing unticked items. It contrasts with comments as the alternative, though it never states when *not* to use set_state versus a plain comment.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
set_statusADestructiveIdempotent
Move a ticket to a workflow state by name. Moving to a completed state (Done) needs a Done when section with every item ticked and cited, any cited PR linked here merged, a linked PR merged into the main branch when any merged at all (link a promotion PR with set_fields link_prs), and your claim, and refuses, returning the diff, if the description changed since you claimed it. This call carries no evidence of its own: write it into the description with set_state first, where this check and any close gate a project hooks onto this tool read it. Moving to a canceled state skips those checks, so it needs reason, which is posted as a comment.
| Name | Required | Description | Default |
|---|---|---|---|
| issue | Yes | Issue identifier (e.g. ENG-123) or UUID | |
| state | Yes | Workflow state name | |
| reason | No | Why the work stops. Required for a canceled state, optional otherwise; posted as a comment. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations by disclosing refusal behavior ('refuses, returning the diff, if the description changed since you claimed it'), the empty-evidence contract ('this call carries no evidence of its own'), external gate checks a project can hook, and the side effect that canceled reasons are posted as a comment. This is unusually rich behavioral disclosure layered on top of destructiveHint/idempotentHint.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose is front-loaded in the first clause, but the remainder is a single tangled run-on sentence ('...and your claim, and refuses, returning the diff, if the description changed since you claimed it') that is grammatically broken and hard to parse. The content mostly earns its place, but the structure does not.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be explained, and the description still covers refusal/diff behavior. For a tool with conditional gates and mutation semantics, it conveys enough that an agent can call it correctly in both the completed and canceled paths, though the set_state cross-reference stays muddy.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds genuine semantic meaning about the 'state' parameter: completed names trigger Done-when gates and canceled names bypass checks and consume 'reason'. It does not add anything about 'issue' beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Opens with a specific verb+resource+scope: 'Move a ticket to a workflow state by name.' That is unambiguous about what the tool does. However, it does not differentiate itself from the confusingly similar sibling set_state, which it references as a separate tool for writing evidence, leaving the agent to disambiguate the two names on its own.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit conditional guidance: completed states require the Done-when checklist, merged PRs, and a claim, while canceled states skip those checks and need a reason. This is real when-to-use context. It stops short of stating when to prefer this over set_state or set_fields for state changes.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
whoamiARead-onlyIdempotent
Who this server acts as: the Linear user or app behind the token. Claims, assignee_is_me and delegate_is_me all mean this identity.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| id | No | Linear user id |
| app | No | True for an app (agent) identity, false for a person |
| name | No | User name |
| displayName | No | Display name |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover readOnly/idempotent/non-destructive safety, so the bar is lower; the description adds meaningful context by explaining what the returned identity semantically drives (claims, self-referential fields). It does not need to explain return values since an output schema exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences, the core meaning front-loaded before the clarifying note about claims. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With zero params, a full output schema, and complete annotations, the description only needs to convey the identity's meaning and its relationship to related fields. It does so adequately.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters, so the baseline is 4. There are no argument semantics to clarify beyond the empty schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States specifically what the tool reveals: the Linear user or app behind the token. It clearly identifies the resource and scope, though it does not explicitly name which sibling (e.g. check_claim vs claim) it differs from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by tying the result to claims, assignee_is_me, and delegate_is_me, giving the agent context for interpretation. However, it never states when to call this tool versus alternatives like check_claim, so guidance remains implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.2.0- Changed
create_issue4 fields changed- added
Input schema / properties / distinct_fromAdded value: +{ + "description": "Each close open ticket the server named, by identifier, that this one is separate from.", + "items": { + "type": "string" + }, + "type": "array" +} - added
Input schema / properties / new_becauseAdded value: +{ + "description": "Why this work is separate from every close open ticket the server named, in one sentence of at most 300 characters. Posted on the new ticket.", + "type": "string" +} - changed
Input schema / properties / parent / descriptionPrevious value: -"Parent issue identifier or UUID"New value: +"The ticket this work is part of, identifier or UUID. A sub-ticket skips the check for close open tickets." - added
Input schema / properties / project_id / descriptionAdded value: +"The project this ticket belongs to; list_projects gives the ids."
- Added
mark_principal_notifications_read - Changed
set_fields1 field changed- changed
Input schema / properties / take_over / descriptionPrevious value: -"Required to change a person's assignment to someone else"New value: +"Required to change a person's assignment to someone else, or to move a delegation off another agent on a ticket assigned to the human you act for"
3 tool updates
v0.1.1- Changed
comment1 field changed- changed
Input schema / properties / body / descriptionPrevious value: -"Comment text. For ask, the first line becomes the question row."New value: +"Comment text, without a header: the server writes the header from kind and drops a copy typed here. For ask, the first line becomes the question row."
- Added
get_principal_notifications - Changed
set_fields1 field changed- added
Input schema / properties / link_prsAdded value: +{ + "description": "GitHub pull request URLs to link to this ticket, such as the promotion PR that carried the work to main. Linear's GitHub integration then records where each merged, which the Done gate reads.", + "items": { + "type": "string" + }, + "type": "array" +}
17 tool updates
v0.1.0- First observed
check_claim - First observed
claim - First observed
comment - First observed
create_issue - First observed
description_history - First observed
get_issue - First observed
list_cycles - First observed
list_initiatives - First observed
list_issues - First observed
list_projects - First observed
list_teams - First observed
mark_notifications_read - First observed
notifications - First observed
set_fields - First observed
set_state - First observed
set_status - First observed
whoami
TDQS
Scored across 19 tools
The set is largely distinct and even deliberately splits near-twins (mark_notifications_read vs mark_principal_notifications_read, notifications vs get_principal_notifications) with explicit rationale. The one real risk is the set_state / set_status / set_fields triple, which share a prefix and could be mis-picked at a glance, though the descriptions clearly delimit each (content vs workflow state vs other fields).
Most tools follow a verb_noun snake_case pattern (list_issues, create_issue, set_status, mark_notifications_read) with consistent prefixes for related operations. Minor deviations exist (whoami, notifications as a bare noun, claim), but overall the convention is readable and predictable.
19 tools sits just above the well-scoped band, but the strict workflow governance (claim, check_claim, set_state, set_status, comment typing, principal-inbox separation) justifies most of them. Few tools appear redundant; the count is slightly heavy rather than bloated.
Issue lifecycle is well covered (create, read, list, field edits, state transitions, claims, comments, history) plus teams, projects, cycles, initiatives and notifications. Gaps are minor: no delete/archive, no single-team/user lookups, and no global search beyond list_issues filters.
Maintenance
Related MCP Connectors
Read and write a CRM built for agents. Every change carries who asserted it and how.
MCP server for Linear project management and issue tracking
Shared boards for agents: live text, reliable appends, and immutable UTC revision history.
Task management for people and AI agents, with scoped OAuth access to issues, projects, and docs.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables AI agents to manage a file-backed ticketing system directly within a local repository using a structured state machine and directory hierarchy. It enforces strict markdown schemas and provides specialized tools for claiming tasks, appending work logs, and validating ticket metadata.-
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to manage Linear workspace resources such as issues, projects, teams, cycles, and comments via Streamable HTTP MCP, with LLM-optimized tools and batch operations.82 npmMIT
- AlicenseNot gradedqualityAmaintenanceEnables agents to manage an event-sourced, git-backed ticket store through MCP tools, supporting operations like ticket creation, claiming, and transitions.54 PyPI4Apache 2.0
- FlicenseAqualityBmaintenanceEnables reading and managing Linear issues by human-readable ID, with tools for searching, creating, updating, commenting, and resolving teams, states, labels, and assignees by name.11-