An MCP server is not something you bolt on

An MCP server can only offer what the application under it was built to do. Why software built screen first gets little from adding one later.

An MCP server is how Claude, ChatGPT and other assistants reach an application. It lists tools, each with a name, a description and the input it takes, and the assistant calls them.1

Most of that software was built screen by screen, years ago. If it has an API, the API was added later, and an MCP server would be added on top of that. Each layer can only offer what the one under it was built to do.

What bolting on looks like

In software built for screens, the screen holds the business rules: the check that a deposit covers the order, the buttons a job allows in its current state, and the words that explain a problem to the person in front of it.

An API added later reaches around the screens to the data underneath, or exposes the handful of things an integration partner asked for. Its key belongs to an integration rather than a person, and often can do everything. Its errors are codes written for a developer.

An MCP server wrapped around that API inherits all of it. The assistant sees whatever the API exposes, gets no list of what is allowed next, and runs under the integration's key. Tool descriptions matter a great deal to how well an assistant uses tools,2 but a description cannot supply a rule the API never enforced.

What built around the API looks like

Retavon was built the other way. Its first commit was an API module, and the web app people use is a client of that same API. Every change a person makes on a screen is an API call, checked by the same rules an assistant meets.

The API, as of this writing, has 484 operations, each with a written description. They are named for what happens at the store: takePayment, completeWorkOrder, addWorkOrderCharges, cancelWorkOrder. Completing a work order has its own rules, and the operation says them:

POST /v1/work-orders/{work_order_id}/completecompleteWorkOrder
Closes the job with what was found and done. Final: what was asked
for and done is then fixed, and sending it again changes nothing.
Its charges are still handed over and paid on the sales order.

An assistant reading that knows the call is final and that sending it twice is safe.

A record with a status carries a next list: the operations its current state allows, each with the reason. The web app draws its buttons from the same list, so a person on the screen and an assistant in the API see the same choices.

GET /v1/work-orders/1099200, shortened
{
  "work_order_number": 1099,
  "status": "open",
  "next": [
    { "operation_id": "addWorkOrderCharges",
      "why": "Charge parts and labor, on a new sales order for this job." },
    { "operation_id": "completeWorkOrder",
      "why": "Record what was done and close the job." },
    { "operation_id": "cancelWorkOrder",
      "why": "The work will not be done." }
  ]
}

When the system refuses, it says why, with the numbers, and what would work instead, as the MCP specification asks of tool errors1 and RFC 9457 asks of API errors.3 Every write that takes money or moves stock takes an idempotency key, so a retry after a dropped connection cannot take a deposit twice. Every key is issued by a person and acts with that person's permissions, which is the model MCP's own authorization follows: requests made on behalf of the person who signed in.4

A day of work

On an application built this way, the MCP server is a day of work. Its tools are generated from the same schemas that produce the OpenAPI document and grouped by the jobs people do, so the server and the API say the same thing, and everything an assistant needs to act well is already in the API it calls.

On an application built for screens, the MCP server is the visible part of a much larger job: moving the business rules out of the screens and into an API, and rebuilding permissions around people instead of integrations.

Where we learned this

We came to Retavon from AGLedger, change control for AI agents, which agents use through one API. We have built and rebuilt its MCP server many times, and each time the server was only as good as the API under it.

Sources

  1. Model Context Protocol specification, tools: modelcontextprotocol.io
  2. Claude, defining tools: platform.claude.com
  3. RFC 9457, Problem Details for HTTP APIs: rfc-editor.org/rfc/rfc9457
  4. Model Context Protocol specification, authorization: modelcontextprotocol.io