
How to Build an MCP Server for Internal Systems: Read-Only First
Step-by-step guide to building an MCP server for your internal systems: read-only tools, per-user authentication and minimum scope from day one.
Want to apply this in your company?
Book a call with Juan →How to Build an MCP Server for Internal Systems: Read-Only First
To build an MCP server for an internal system, pick one narrow use case, use an official SDK, expose a few read-only tools with clear names, and authenticate every call with the identity of the person asking, always with the smallest scope possible. Only after you have seen real usage in the logs should you consider tools that change data. This path is a little slower at the start and much safer afterward.
Key takeaways
- MCP (Model Context Protocol) is an open standard for connecting AI applications to external systems, and the server is the layer you control.
- Start with read-only tools: the worst possible mistake becomes an inappropriate lookup, not an irreversible change.
- Each tool should have a single purpose, a clear name and a lean response designed for the model, not for a screen.
- Authentication should carry the identity of whoever is asking, and scope should be the minimum the use case needs.
- Write access comes only after a pilot, reviewed logs and human approval designed for the highest-risk actions.
What an MCP server is and when it makes sense to build one
The Model Context Protocol is an open standard that lets AI applications connect to external data sources and tools in a uniform way. In practice, an MCP server is a program you own that sits between the AI assistant and your internal system (ERP, CRM, ticketing system, contract database). It declares which tools exist, what each one accepts and what each one returns.
Building one makes sense when the same system needs to be queried by different assistants, or when you want a single place to enforce access rules, logging and limits. If the need is small and belongs to one person, a local script may be enough. If several people and several AI tools will depend on the access, the MCP server becomes a security boundary, and that is what justifies designing it carefully.
One important point: an MCP server is not just a technical adapter. It decides what the AI can see and do inside your company. That is why the permission design comes before the code.
Why start with read-only tools
The reason is simple: limit the damage. A read tool that fails returns wrong or inappropriate information, which is bad but recoverable. A write tool that fails can cancel an order, change a customer record or trigger a charge, and undoing that costs time, money and trust.
Starting with reads brings other practical benefits:
- You find out which questions people actually ask before deciding which actions to automate.
- The security review is shorter, because the set of risks is smaller.
- Usage logs show where automation helps and where the process has gaps.
- Approvers (IT, legal, the data protection officer) resist less when the access does not change anything.
Reading is not risk-free either. Personal data about customers and employees is still covered by data protection law (in Brazil, the LGPD), and a tool that returns too many fields is a leak waiting to happen. Read-only lowers the severity, but it does not remove the need for authentication, scope and logging. For how to handle data in customer service settings, see the guide on LGPD compliance for AI on WhatsApp: legal basis, consent and records.
How to design read tools the model uses well
An MCP tool is read by a language model, not by a programmer. The name, the description and the parameters are the interface. Anthropic publishes guidance on writing effective tools for agents, and the principles boil down to the following.
First, one tool per intent. Instead of one generic tool that runs any query, create tools such as get_order_status, find_customer_by_tax_id or list_open_tickets_for_customer. Narrow tools are easier to understand, test and protect.
Second, explicit and validated parameters. Define types, formats and limits on the server. If an order ID has a known format, reject anything that does not match. Never accept SQL, file paths or free-form filters from the model and pass them straight to the database.
Third, lean responses. Return only the fields needed to answer the question, with readable names. Oversized responses waste context, confuse the model and widen data exposure. If a list can be long, paginate it and cap the number of items per call.
Fourth, useful error messages. When something fails, say what the caller can fix (invalid format, record not found, no permission) without exposing internal details such as stack traces or table names.
Fifth, honest descriptions. State in the description what the tool does and what it does not do. This reduces wrong calls and helps whoever reviews the server later.
Finally, treat content coming back from the system as untrusted data. A customer notes field or the text of a support ticket can contain instructions written by third parties, and the model may try to follow them. The OWASP guidance on preventing prompt injection describes this risk and the defenses. For that reason, even a read-only tool should not be combined, in the same agent, with tools that send messages or write to other systems without controls.
Authentication and minimum scope: what to decide before coding
This is the part that most separates an experiment from something that can go to production. There are four decisions to make.
Who is asking? The server needs to know the real identity of the person or service that originated the call. If everyone uses a single shared credential, you lose traceability and cannot apply per-user rules. For remote access, MCP provides for OAuth-based authorization; check the current protocol specification for the recommended flow.
What can that identity see? Enforce authorization on the server, on every call, and not only in the assistant's interface. The OWASP authorization guidance recommends principles such as least privilege, deny by default and checking permission on every request. They apply here without adaptation.
Which credential does the server use to talk to the internal system? Create a dedicated service account with read-only permission on only the tables or endpoints needed. Avoid reusing an administrator user. Keep secrets in a vault or protected environment variables, never in the repository or in tool descriptions.
What gets recorded? Log who called, which tool, which parameters, when, and with what outcome (success, error or denied). Do not log the sensitive content that was returned, only what audit requires. Observability concepts such as traces and metrics are well explained in the OpenTelemetry observability primer.
If the server will be accessed by teams that use coding agents, the same permission and isolation principles appear in Claude Code security: permissions, sandbox and secrets for teams.
Step-by-step: building your first server
A lean checklist, in order:
- Choose one real workflow and one frequent question. Example: the support team needs to know an order's status without opening three screens.
- List the minimum data needed to answer that question. Every field not on the list stays out of the response.
- Define the read-only service account and test, outside MCP, that it truly cannot write.
- Pick the official SDK for the language your team already maintains, and the right transport: local for development tests, remote with authentication for shared use.
- Implement one to three narrow tools, with parameter validation, an item limit and clear errors.
- Apply per-user authorization inside each tool, before querying the system.
- Turn on call logging from day one, with user ID, tool and outcome.
- Test with real questions, including bad ones: nonexistent IDs, users without permission, text with malicious instructions in the fields.
- Run a short security review with whoever owns IT and personal data before opening access to more people.
- Release to a small group, watch the logs for an agreed period, and only then decide the next step.
Illustrative scenario: order status in a management system
Illustrative scenario: a distributor has an older management system and a support team that answers customer questions on WhatsApp. The pain is repetitive: finding out where an order is requires checking the system, the carrier and the invoice.
The pilot's MCP server exposes only two tools: get_order_status, which takes the order number and returns status, expected date and carrier, and list_recent_orders_for_customer, which returns a small, capped number of orders. Neither returns negotiated price, margin, full address or payment data.
Authentication identifies the support agent, and the server only returns orders from the accounts that agent handles. The service account in the database has read-only access to the necessary views. Every call is logged. After a few weeks, the team reviews the logs and sees which questions come up most and which tools are never used. Only then do they discuss, with human approval, whether to add a tool that opens a request for an invoice copy, which involves writing and carries higher risk.
For anyone planning to connect this kind of lookup to WhatsApp support, the guide on how to integrate AI into your company's WhatsApp covers the other side of the integration, and the playbook on human handoff for WhatsApp AI agents covers what to do when the AI should not answer alone.
How to measure the pilot and when to release write tools
The method we apply in AI projects has four moves: map, limit, pilot and hand over. Applied to an MCP server, it looks like this.
Map: describe the current process, who looks up what, in which system, and how much time it takes today. Without that starting point, there is no way to know whether the server helped.
Limit: restrict data, tools and actions. This is the stage of read-only access, minimum scope and a dedicated service account described above.
Pilot: run one real workflow, with logs and a success metric agreed in advance. It could be team response time, the share of questions resolved without opening the system, or the number of corrections made by humans. The article on how to measure an AI automation pilot details metrics and decision gates.
Hand over: deliver the documentation, the access setup, the monitoring plan and the decision to expand, adjust or stop. Stopping is also a valid outcome when the pilot shows the gain does not justify the effort.
On writing, use a simple test before releasing any tool that changes data:
- Is the action reversible, or is there a clear way to undo it?
- Is there human approval for higher-impact actions, with a record of who approved?
- Is the tool idempotent, meaning repeating the call does not duplicate the effect?
- Does the credential's scope cover only this action and nothing else?
- Do the read pilot's logs show real demand for this action?
If any answer is no, the tool stays out of the server. To structure approvals, the AI agent approval policy template is a good starting point.
Frequently asked questions
Do I need to know how to code to build an MCP server?
Yes, at least someone on the team does. The official SDKs reduce the protocol work, but you still write the tools, the validation, the authorization and the integration with the internal system. If the company has no technical team, it is worth hiring help for the design while keeping responsibility for the access decisions.
Local or remote MCP server: which should I choose?
Local suits development and individual use, when the server runs on the machine of the person using it. For shared use by a team, a remote server allows central authentication, logging and version control, but it demands more care with network exposure and authorization. If you are going to expose a service to the internet, put it through a review like the one in the OpenClaw Gateway security checklist, which is about evidence before exposure.
Is read-only already safe enough?
Not by itself. Reading lowers the severity of mistakes, but personal data remains protected by data protection law and the content being read can carry malicious instructions. Per-user authentication, minimum scope, lean responses and call logging remain mandatory. For questions about data handling, consult your company's data protection officer and the guidance from your data protection authority (in Brazil, the ANPD).
When does it make sense to add tools that write?
When the read pilot has shown clear demand, the logs are being reviewed, and there is a human approval design for the highest-risk actions. Start with the least critical, reversible action, with its own credential and explicit limits. If there is no way to undo the effect, keep that action with a human.