← Blog
Product5 min readThe Utter team2 viewsUpdated

Why we gave Utter an MCP server, and what it changes

XLinkedIn

If you have wired an AI assistant into a real tool before, you know the tax. You write a wrapper around the API, describe every endpoint to the model in a prompt, keep that description in sync as the API changes, and handle auth by hand. Do it for three tools and you have a small, brittle integration project on your hands.

The Model Context Protocol exists to kill that tax. Here is what it is and why we built one for Utter.

MCP in plain terms

MCP is a standard way for an AI client to discover and call the tools a service offers, without anyone hand-writing the glue. The service runs an MCP server that lists its tools and how to call them. The client, say Claude or Cursor, reads that list and can use the tools right away.

The comparison people reach for is a USB port. Before it, every device had its own cable. After it, you plug in and it works. MCP is trying to be that for AI-to-service connections: one shape that a model already understands, instead of a bespoke adapter per tool.

That is the whole idea. It is not magic, and it is early. But the direction is right, and a project tracker turns out to be one of the clearer places it pays off.

Why a tracker is a good fit

An agent doing real work needs somewhere to write down what it is doing. Not in a chat log that scrolls away, but in a place the whole team already looks: the backlog, the board, the issue with the acceptance criteria.

Without that, agent output is trapped. The model writes a great plan and it lives in a conversation nobody else opens. With a tracker on the other end, the plan becomes issues, the work becomes status changes, and the record becomes something a human can audit later. The tracker is the shared memory.

So the useful move is not "let the agent read your tickets." It is "let the agent run the project the same way a teammate would," and have every action land in the same place, attributed, with the same permissions.

What it looks like in practice

Utter runs a first-party MCP server. In an MCP-native client you add it once with your API key, and the tools show up: create an issue, move it across the board, comment, set custom fields, search the backlog, read what is done and what is still open.

In Claude Code, adding it is one line:

claude mcp add utter-product https://utter.ae/api/mcp/v1/ \
  --header "Authorization: Bearer $UTTER_API_KEY"

In Cursor, the same thing goes in ~/.cursor/mcp.json:

{
  "mcpServers": {
    "utter-product": {
      "url": "https://utter.ae/api/mcp/v1/",
      "headers": { "Authorization": "Bearer YOUR_API_KEY" }
    }
  }
}

You do not have to type either by hand. The developer settings page generates the snippet for Claude Code, Cursor, and VS Code with your key already in place.

Utter's developer settings generating the Claude Code MCP setup command

From there the client discovers the tools by itself. Their names are derived from the REST spec, so they read like the API: list_projects, create_issue, transition_issue, list_issue_comments, who_am_i. When your agent decides to file a bug, what actually crosses the wire is one JSON-RPC call. You can send the same call yourself with curl:

curl -X POST https://utter.ae/api/mcp/v1 \
  -H "Authorization: Bearer $UTTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "create_issue",
      "arguments": { "slug": "acme", "key": "WEB", "title": "Fix login redirect", "type": "bug" }
    }
  }'
const res = await fetch("https://utter.ae/api/mcp/v1", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.UTTER_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: 1,
    method: "tools/call",
    params: {
      name: "create_issue",
      arguments: { slug: "acme", key: "WEB", title: "Fix login redirect", type: "bug" },
    },
  }),
});
console.log(await res.json());
import os
import requests

res = requests.post(
    "https://utter.ae/api/mcp/v1",
    headers={"Authorization": f"Bearer {os.environ['UTTER_API_KEY']}"},
    json={
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/call",
        "params": {
            "name": "create_issue",
            "arguments": {"slug": "acme", "key": "WEB", "title": "Fix login redirect", "type": "bug"},
        },
    },
)
print(res.json())

There is no wrapper to maintain. When we add an endpoint, it appears in the tool list. When we change a field, the description the model sees updates with it. The client does not need a new release for any of that. And every tools/call re-enters the same REST pipeline internally, so auth, scopes, and rate limits are checked once, in one place:

sequenceDiagram
    participant C as MCP client
    participant M as MCP server
    participant R as REST v1 pipeline
    C->>M: tools/list
    M-->>C: tools your key allows
    C->>M: tools/call create_issue
    M->>R: same bearer key, same checks
    R-->>M: issue created
    M-->>C: result

For clients that do not speak MCP yet, the same workspace is reachable two other ways: the plain REST API, and an installable skill bundle that ships a SKILL.md describing your actual projects, keys, and conventions. Same capabilities, three front doors, so you are not stuck waiting for your tool of choice to add support.

flowchart LR
    A[Agent via MCP] --> P[One REST pipeline]
    B[Script via REST] --> P
    S[Agent via skill bundle] --> P
    P --> W[Your workspace]

The honest caveats

MCP is young. The spec is still moving, client support is uneven, and the security model is something you have to take seriously rather than assume. An agent with a write-capable key can do damage if you hand it the wrong scope.

So we default to per-agent keys and let you grant only the tools an agent actually needs. The tool list an agent sees is already filtered to its key's scopes: read the whole board, write only where it should act. Here is an abbreviated tools/list response, the shape the client reads on connect:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      { "name": "who_am_i", "description": "The identity behind the current API key." },
      { "name": "search", "description": "Search issues and docs across the workspace." },
      { "name": "list_issues", "description": "List issues in a project." },
      { "name": "get_issue", "description": "Issue detail." },
      { "name": "create_issue", "description": "Create an issue." },
      { "name": "update_issue", "description": "Update an issue." },
      { "name": "transition_issue", "description": "Move an issue to a new status." }
    ]
  }
}

That is seven of the tools; there are over 180 in total, and the ones a given key actually sees are filtered to its scopes, so a read-only key never gets create_issue or transition_issue back at all.

Per-agent permissions dialog in Utter's agent hub

We also do not think MCP replaces the API. It sits on top of it. The REST surface is still the source of truth, still what you reach for in a script or a CI job. MCP is the convenience layer for agents that support it, not a second system to keep in sync.

Why it matters now

More of the work landing in project tools is going to come from agents, not just people typing into a form. When that is true, the tools that assumed a human on every action start to feel wrong. The ones that treat an agent as a first-class participant, with a key, a scope, and a clean protocol, are the ones that will not need re-plumbing in a year.

A connected agent in Utter's agent hub with its own identity and key

That is the bet behind Utter's MCP server. If you want to try it, add the server to your MCP client with a scoped key and point one agent at a real project. Worst case, you learn where the rough edges are. Best case, you stop writing glue code.

Frequently asked questions

Why does a project tracker need an MCP server?

Because an agent doing real work needs somewhere to write down what it is doing, not a chat log that scrolls away but the backlog and board the whole team already looks at. Over MCP, the agent's plan becomes issues, its work becomes status changes, and every action lands attributed, under the same permissions a teammate would have.

What is MCP in plain terms?

The Model Context Protocol is a standard way for an AI client to discover and call the tools a service offers, without anyone hand-writing glue code: the service runs an MCP server that lists its tools, and a client like Claude or Cursor reads that list and uses them right away. The usual comparison is a USB port: one shape a model already understands instead of a bespoke adapter per tool.

Does MCP replace the REST API?

No, it sits on top of it. The REST surface is still the source of truth and still what you reach for in a script or a CI job; MCP is the convenience layer for agents that support it, not a second system to keep in sync.

Is it safe to give an AI agent write access over MCP?

Only with scoped credentials: an agent with a write-capable key can do damage if you hand it the wrong scope. MCP is young, the spec is still moving, and client support is uneven, so Utter defaults to per-agent keys and lets you grant only the tools an agent actually needs: read the whole board, write only where it should act.

Related reading

أضف تعليقًا

ابدأ النقاش.