Read-only by construction: an MCP server that can't write to Redis

Learn how to build an MCP server that is read-only by construction for Redis. No write tools registered, no write credentials. Secure your LLM interactions.

miércoles, 29 de julio de 2026 • 5 min read • Q2BSTUDIO Team

MCP read-only: cómo evitar escrituras no autorizadas en Redis

When artificial intelligence agents start interacting with operational databases, the first instinct is often to politely ask them not to make modifications. But trusting a textual instruction to keep a language model well-behaved is like putting a 'do not touch' sign in front of a curious child: it works until the child finds a way around it. In the world of system-to-AI integration, especially when dealing with Redis work queues exposed through the MCP (Model Context Protocol), the only real way to guarantee that an agent does not alter data is to physically remove the possibility of doing so. That is exactly what we propose in this article: building a read-only MCP server for Redis where security does not depend on what the model 'understands,' but on how the system is wired.

The challenge begins when a team wants an AI assistant to inspect the state of a process queue to diagnose bottlenecks or locate failed jobs. The natural move is to expose read tools like listing queues, viewing statistics, or fetching a specific job. But the same model that uses those tools might also, if prompted or if a prompt injection induces it, attempt to re-queue or delete jobs. If the re-queue tool is registered, even if the model is told not to use it, the risk persists. The conventional solution would be to add validation in the handler, but that still leaves the door open for a well-targeted attack to call the function. The only robust approach is not to register those tools at all when the mode is read-only.

This approach, which we call 'security by construction,' means the attack surface is defined at the moment the MCP server starts, not in tool descriptions or system instructions. By splitting the registration logic into two blocks — read tools always present, and write tools conditional on a flag — we ensure that a server launched with the --read-only parameter never has access to state-mutating functions. If the model, or an attacker controlling the input, tries to invoke retry_job or delete_job, the protocol itself returns an 'unknown tool' error. There is no handler to validate, no authorization to bypass: the write path simply does not exist in the process.

But registration is not the only layer. No matter how careful the code, there is always the possibility of human error or a future modification that inadvertently introduces a tool. That is why the second barrier is the credential the server uses to connect to Redis. Instead of using a user with full permissions, it is far safer to set up an ACL (Access Control List) user that only has access to read commands. Redis allows defining command categories: +@read enables all read commands, while -@dangerous removes those that, although read operations, can be dangerous — such as KEYS, which scans the entire keyspace and can block the server. With this configuration, even if a handler contains a bug or a new developer inadvertently adds a write tool, Redis will reject the operation with a NOPERM error. The database itself acts as the final guardian.

If an even harder line is desired, the MCP server can be pointed at a read-only replica of Redis. In that case, any write attempt, regardless of command or user, receives a READONLY error. This option is ideal when ACL configuration cannot be changed or when a physical separation between read and write operations is required.

This design has direct implications for the architecture of systems that integrate AI agents with existing infrastructure. At Q2BSTUDIO, a company specialized in custom software development, we apply this principle every time a client needs to connect language models to production databases. It is not enough to tell the model 'read-only'; the system must be designed so that it cannot write. This is especially relevant when working with cloud services like AWS or Azure, where credentials and security groups must align with the principle of least privilege.

However, security by construction is not a magic wand. A read-only server guarantees that data is not modified, but it does not protect against other equally important risks. The first is information disclosure: a read tool like get_job can expose payloads containing tokens, email addresses, or internal identifiers. When processed by the model and sent to an external service, this data could leak sensitive information. Therefore, it is mandatory to sanitize or filter fields before returning them, and to apply additional encryption and access control policies.

The second is cost and operational load. A read query can be expensive if it scans thousands of jobs without pagination, or if the model decides to execute the same tool in a loop while 'exploring.' Without strict limits — timeouts, default pagination, result caps — the server can become a denial-of-service vector for the infrastructure itself. That is why, alongside the read-only mode, usage controls must be implemented: a timeout on each handler, a result limit per call, and a rate-limiting system at the connection level.

The third risk is second-order injection. The data the model reads from Redis may contain text designed to influence its behavior. If the same model has access to other tools (for example, to send emails or modify records in another database), reading a queue with malicious payloads could trigger unwanted actions. This risk is not solved by a read-only server, but by an architecture that segregates contexts and limits the scope of each tool.

Finally, the protection scope is per connection, not global. A system may have multiple MCP servers loaded: one read-only for queries and another with full permissions for administration. If both are available to the same model, the protection of the first does not prevent the model from invoking tools on the second. Security by construction must be applied to each connection and each server independently, and the overall architecture must ensure that the model never has simultaneous access to both if strict control is desired.

In short, the lesson is clear: when the interlocutor is a language model, security barriers should not be written in text, but soldered into the system's wiring. The combination of conditional registration, ACL credentials, and read-only replicas offers a defense in depth that does not rely on the model's goodwill. At Q2BSTUDIO we help companies design and implement such architectures, integrating AI solutions with legacy systems, process automation, and Business Intelligence platforms like Power BI. Because security is not an adjective; it is a property of design.

A BREAK?

Play for a moment before you go

OUR SERVICES

How we can help you

Do you have a project in mind?

Tell us your vision and we'll turn it into a software solution. Whatever the scope, we make your idea real.