How to manage issues from Claude Code over MCP
Manage issues from Claude Code over MCP: the setup command, the nine tools, the field-discovery problem every generic tracker MCP hits, and which verbs to withhold.
To manage issues from Claude Code over MCP you need three things: a token, one
claude mcp add command, and a decision about which verbs the assistant gets.
The first two take ten minutes. The third is the one worth thinking about, and
the one most guides skip.
It is for someone who already runs a tracker and is tired of the round trip: read the ticket in a browser, retype it into a prompt, go back and move the card. Done looks like this — you ask what is assigned to you and get an answer without opening a tab, you say "move KEV-42 to In Review and note that it is deployed", and the assistant cannot quietly close six issues while you make coffee.
Step 1: Create a token, and decide how wide it is
Scope first: the cheapest guardrail you will ever set. A Kevta user-wide token, created from Profile → API tokens (MCP), reaches every workspace and board you can reach. A board-scoped one, created from a board's Settings → API tokens, can only ever touch that board, and the scope is enforced server-side: a scoped token handed another board's ID is refused.
Every token has a fixed life of 7, 30 or 90 days — there is no non-expiring option — and Kevta stores only a one-way SHA-256 hash, showing the plaintext once at creation (API tokens has the rest). Take the user-wide one for your own laptop, the board-scoped one for anything that runs while you are not watching.
Step 2: Add the MCP server to Claude Code
MCP is an open-source standard for connecting AI applications to external systems, which modelcontextprotocol.io likens to "a USB-C port for AI applications". Claude Code speaks it over HTTP, in the form Anthropic documents:
claude mcp add --transport http kevta https://YOUR_KEVTA_API/mcp \
--header "Authorization: Bearer kvt_YOUR_TOKEN"
Kevta's endpoint is printed in the MCP docs. Two details from
Anthropic's reference are worth reading before you run it. --scope takes
local, project or user, and local is the default — private to you and
loaded only in the project you added it from — so say --scope user if you want
the server everywhere. And claude mcp add "saves the configuration without
validating credentials"
(code.claude.com), so a bad token fails
silently now and confusingly later — run /mcp and check the server reads as
connected before trusting anything it tells you.
There is no sign-in pop-up; pasting the token is the whole of the auth.
Step 3: Make the board describe itself
This is where a tracker MCP that works separates from one that half-works. An
MCP tool's input schema is static — the same JSON Schema for every user and
every board. Boards are not: the whole point of a custom field is that yours
differs from mine. So create_task cannot have one parameter per column, and
every generic tracker MCP has to resolve that somehow.
The community Jira servers show the usual resolutions. One makes you declare
fields up front: "to work with custom Jira fields, add them to the
JIRA_CUSTOM_FIELDS environment variable"
(fkesheh/jira-mcp-server). Another
ships a detect_project_fields tool emitting "ready-to-copy configuration
snippets for .jira-config.json"
(cfdude/mcp-jira) — discovery that
terminates in a config file you maintain. And when the mapping layer is wrong it
fails quietly: a bug report against sooperset/mcp-atlassian records a custom
field update that did nothing over MCP while the same change succeeded against
the REST API directly
(issue #861, since
closed).
Kevta resolves it with one of its nine tools. describe_board returns every
field on the board — name, type, valid option values, whether it is required,
its semantic role. Names are the contract; column IDs never leave the server.
create_task and update_task then take a fields map keyed by those names,
rejecting anything else with the board's real field list, or the valid options
for the value you got wrong, so the assistant retries correctly rather than
guessing.
The nine, in full:
| Tool | Does | Kind |
|---|---|---|
list_workspaces |
Workspaces you belong to | read |
list_projects |
Boards inside a workspace | read |
describe_board |
A board's fields, types and valid options | read |
list_tasks |
A board's issues, filtered by status or assignee | read |
get_task |
One issue in full, with its comments | read |
create_task |
File a new issue | write |
update_task |
Change title, status, assignee, due date, any field | write |
add_comment |
Comment on an issue | write |
close_task |
Move an issue to its board's done status | write |
Every write tool wants an id, and none of them ask you for it: the assistant walks the read tools until it has one.
Step 4: Run a real session
- "What's open and assigned to me on the Web board?" —
list_workspaces,list_projects, thenlist_tasksfiltered by status and assignee. - "File a bug: login takes eight seconds on Safari. High priority, type Bug,
due Friday." —
describe_boardfirst, so it knows the board has a Type field and what its options are, thencreate_task. NoBugoption, and you get told the valid ones rather than a wrong ticket. - "Move KEV-42 to In Review and comment that the fix is deployed to
staging." —
list_tasksto turn the key into the id the write tools want, thenupdate_taskandadd_comment, resolving "In Review" against the board's real status options.
The third is the one that pays for the setup: it is the update nobody does by hand.
What you can manage from Claude Code, and what you should not
An assistant that can invent an issue will invent five. Not a criticism of the model: it is what happens when a plausible-sounding action is one token away and nothing pushes back.
Claude Code's permission rules are where you push back. They are written against
the tool's full name, mcp__<server>__<tool>, so mcp__kevta__close_task under
deny in settings.json is one line. Allow rules take globs, but only anchored
after a literal server prefix — mcp__kevta__list_* works, a bare mcp__* in
allow is skipped with a warning
(code.claude.com).
The line we would draw: reads auto-approved, create_task and add_comment
prompting, close_task never automatic. The asymmetry is the point. A wrong
issue is visible noise that somebody deletes. A wrong close removes something
from a person's queue, and nobody notices an absence.
Others draw it with a blunter instrument. GitHub's own MCP server ships a
--read-only flag that "will disable all tools that are not read-only even if
they were requested"
(github/github-mcp-server),
and Atlassian's repository carries a request for the same, filed so a client
discovers only the reading tools instead of you switching writes off one at a
time (issue #11),
though its README documents
no such flag today. Kevta has none either: all nine tools are exposed, and the
narrowing happens in your permission rules or the token's board scope. A real
gap, worth knowing before you hand an unattended agent a token.
None of it is a security control either. Anthropic is blunt about that — "servers that fetch external content can expose you to prompt injection risk" (code.claude.com) — and a tracker is exactly such a server. Ticket bodies are written by customers, contractors and bots, so an agent reading one is reading text a stranger wrote. Permission rules bound what a bad instruction can do. They do not stop it arriving.
In fairness, not every workflow wants an interactive gate. OpenAI's Codex
cookbook drives Jira from a GitHub Action with direct REST calls and
approval-mode full-auto, putting the human review on the pull request rather
than the tracker writes
(developers.openai.com).
For a label-triggered pipeline that is a defensible trade. For a session you are
talking to, the gate belongs closer in.
What a board should look like once agents write most of the code is a separate argument, and we make it in an issue tracker for Claude Code.
Kevta's MCP server is on both plans, including Free. For an early invite, a founding-member price at launch and a direct line to what we build next, join the waitlist.
- mcp
- ai-agents
- tooling