MCP vs API: Why a Model Needs a Different Interface
See how one MCP vs API call plays out in auric-pm, why tools are written for a model caller, and when a plain API fits better.
An agent calls complete_task on the auric-pm server with id 3f9a, a prefix it copied from earlier tool output, and a summary of what it did. Two tickets start with 3f9a. The server refuses to guess and writes nothing.
The agent gets an error back:
Ambiguous ID prefix '3f9a' matches 2 tickets (e.g. 3f9a1c0e-5b2d-4e7a-9c31-8d0f6a2b7e14, 3f9a77b2-0c64-4d1e-b5a8-2e91c3d4f067)
That refusal is the design. An MCP server is an API whose caller is a model, so every tool has to be written for what a model can read and for what it will get wrong at times.
What happens when an agent sends a short ticket ID?
The call fails, and the failure points somewhere. The error repeats the prefix, counts the matches and lists up to five full IDs. It does not say which ticket the agent meant. It cannot know. The agent picks from the candidates, or looks at the ticket list first, and then retries with a full UUID. That costs at least one extra call.
The status stays as it was and the summary is not appended. Both tickets are safe from an arbitrary choice.
The alternative is a wrong ticket marked done while the real work stays unfinished in another terminal. The same reasoning holds for any record an agent can change. Requirements work raises the same need for exact records, covered in AI requirements management.
Is MCP just a different way to call an API?
Somewhat but not entirely. People notice the transport first: JSON-RPC carries the calls, and a child process on stdio answers them, with no port and no socket. That changes deployment. It does not explain why complete_task accepts a prefix at all.
A client lists the available tools with tools/list and calls one with tools/call, as the MCP tools specification describes. The list carries each tool's name, description and parameter schema, so the model reads them as text at the moment it has to decide. It's like delivering a built-in OpenAPI spec whenever somebody tries to use your REST API, which is even more so tuned to handle probabilistic inputs.
That is the real difference between mcp vs api. Fixed client code keeps exact IDs in variables and repeats the same calls. A model may receive an ID in one result, work on something else, then rebuild the ID from memory and lose characters. A string schema cannot tell it that prefixes work, so the parameter description has to. The job is the same: exposing operations. The reader needs words where a developer had documentation, and tolerance where a client had exactness.
Nothing says an MCP server has to wrap a REST API either. auric-pm reads and writes a SQLite file in the project folder, and the tools on top of it are what agents call. No REST layer sits in between.
What does auric-pm do because its caller is a model?
Three things, and a basic assumption: the reader (model) follows instructions well and makes small mistakes.
IDs accept a prefix. Every ticket, epic and goal ID parameter takes a full UUID or a unique prefix of at least four characters. The description says so in the same words, "full UUID or unique prefix", so the rule arrives with the tool and not in a document nobody opens mid-task. A full UUID goes straight through. A prefix with no match throws, and so does one shorter than four characters, each with a plain sentence saying which. The goal lookup goes one step further. When no goal matches, the error adds that a goal can be found by name with find_goals, because an agent often holds a name and not an ID.
Descriptions do the documenting. The ticket list tool tells the model to use status="in_progress" for tickets in progress, and the status filter is a fixed list of values, so the model has nothing to invent. The create tool says that passing a goal ID attaches the new ticket to that goal in the same call. The completion tool says it marks a ticket done and can append a summary to the description. A developer would look for that in a guide. The model finds it where it is already looking.
The overview is small on purpose. get_unfinished_tickets_overview takes no parameters. It returns the tickets that are not done, archived or discarded, grouped by epic. Each ticket carries an ID, a name, a status, a heat count of tickets that depend on it and the names of tickets it depends on. Descriptions are left out. The tool's own text says "Minimal details for context efficiency". A model pays for every token it reads. The first answer lets it scan the whole backlog and nothing more. Full records need a second call.
None of these three choices matters until the server is registered with an agent, because registration is the moment the descriptions and schemas reach the model. The walkthrough on how to build an MCP server covers the setup behind this server.
AuricIDE gives CLI coding agents one local MCP server for tickets, goals, requirements, tests, and history, shaped for model callers down to tolerant IDs and compact overviews. You can inspect that interface in an open-source desktop IDE and judge the trade-offs against your own fleet. Visit AuricIDE to try it.