MCP Connectors

Building your own MCP server · and shaping it so it survives production

When a custom MCP service is worth it, what the protocol looks like on the wire, how to describe a tool, and the five rules that decide the quality of a connector.

Author
SIMOSphere AI
Published
Reading time
7 min read

For the usual systems, ready-made MCP services exist. It gets interesting with the one system that only you have: the line-of-business application from the late nineties, the database behind production control, the service somebody wrote eight years ago that has been running ever since. Those are the cases where you build your own server.

This article shows how, and it starts with the uncomfortable question of whether you should.

The question comes before the code

We are not a software vendor. We build custom software only when it genuinely pays off, and the same standard applies to a connector. Three conditions should hold before anyone starts.

  • The system has an interface stable enough to build on. Scraping a user interface is not a connector, it is an appointment with an outage.
  • At least two workflows benefit from it. For exactly one workflow, an export out of the system is often the more honest answer.
  • Somebody is willing to operate the service. A connector with no owner is debt that comes due at the next version upgrade.

If one of the three is missing, the answer is not necessarily no. It is, for now, wait.

What an MCP server really is

An MCP server is a process that receives and answers JSON-RPC 2.0 messages. That is the whole of it. It runs either as a local process talking over standard input and output, or as a service over HTTP. The authoritative description lives in the Model Context Protocol specification.

The examples here show the protocol on the wire, not a particular library release. That is deliberate: libraries change their call signatures, the protocol does not. Understand the messages and you can use any library, or none.

The first exchange after the handshake is always the same. The client asks which tools exist.

JSON-RPCAsking for the available tools
{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }

The response is where the real work sits. It describes each tool well enough that a model can decide from the description alone whether and how to use it.

JSON-RPCResponse describing one tool
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "read_work_order",
        "description": "Reads a production work order by its number. Returns status, due date and quantity. No prices, no personal data.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "orderNumber": {
              "type": "string",
              "description": "Six-character number, format A-12345"
            }
          },
          "required": ["orderNumber"]
        }
      }
    ]
  }
}

That description is not a comment for humans. It is the instruction the model acts on. Leave anything vague in it and the tool gets used wrongly or not at all, and you will go looking for the cause in the model when it is sitting there in the text.

The call itself is unremarkable by comparison.

JSON-RPCCalling a tool, and the response
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "read_work_order",
    "arguments": { "orderNumber": "A-41207" }
  }
}

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Order A-41207: in production, due 2026-08-21, quantity 400."
      }
    ],
    "isError": false
  }
}

Five rules for shaping tools

What decides the quality of a connector is not the programming language, it is how the tools are cut. Five rules have earned their place.

  • One tool, one job. A tool with a parameter that switches between seven modes is not a simplification, it is one failure mode with seven variants.
  • Separate reads from writes. Merge them into a single tool and you can no longer grant read access without granting write access.
  • The description says what the tool does not do. That line is worth more than any list of what it does, because it prevents the wrong tool from being reached for.
  • The return value is written for a reader. A raw dump of thirty columns burns context and conveys less than three sentences.
  • Errors are named, never swallowed. A model reads an empty response as an absence of data, and then it invents some.

Permissions, audit trail, and the way back

Three things belong inside the service rather than in the calling layer above it, because anything above can be bypassed.

First, permissions. The service acts on behalf of an account and may do only what that account may do. A technical shared account with full access ends the rollout at the first audit.

Second, the audit trail. Timestamp, account, tool, parameters, and result are recorded; the content of the data is not. A log that captures content simply relocates the data protection problem.

Third, the way back. Every write operation needs either a counterpart that reverses it or a human approval before it executes. Which of the two is right is a decision for the business area, not for engineering.

Test it before a model ever sees it

An MCP server can be tested completely without a model. The messages are text, the process reads from standard input, and that makes every call a repeatable test.

bashFetching the tool list from a local service
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' \
  | node ./mcp-production/server.js

We recommend three checks before the first release: every tool once with valid parameters, once with invalid ones, and once with an account that has no permission. The third is the important one, and it is the one people skip.

What we advise against

  • A tool that accepts arbitrary database queries. It is quick to build, and it dissolves every permission model underneath it.
  • A service that stores credentials for a business system itself. Those belong in secret management, not in a connector's configuration.
  • Tools that take free text from the model and pass it through unchecked. Whatever sits behind the interface has no way to judge that text.
  • A custom service for a system that already has a maintained connector. Yours will be better at first and older within two years.

Where to go next

Which systems already ship connected is listed on the MCP connectors page. How a connector fits into the wider architecture is covered in the article on CRM and ERP. If you would rather learn tool design in a week than over a quarter, the academy runs a two-day course for engineers.

Tags

  • MCP
  • Interfaces
  • Engineering
  • JSON-RPC
  • Operations

Back to all posts

See it run on your own data.

A demo walks the platform through a workflow from your own company, not a sample data set. We prepare it together with you.