Dev.to AI ๐Ÿค– Ai ๐Ÿ‘ 0 ๐Ÿ“– 7 min read

One Desktop App Instead of 100+ MCP Server Setups

Giving an AI assistant access to one database is straightforward. Giving it useful access to an application stack raises a more interesting question: who decides what it is allowed to do? A checkout investigation might

One Desktop App Instead of 100+ MCP Server Setups

Giving an AI assistant access to one database is straightforward. Giving it useful access to an application stack raises a more interesting question: who decides what it is allowed to do?

A checkout investigation might span MySQL, Redis, MongoDB, Kubernetes, OpenSearch and InfluxDB. I want the assistant to compare evidence across those systems. I also want to see the exact command before it changes anything, keep service credentials out of its configuration, and inspect what actually ran.

That is the workflow behind GateRook: a desktop application that puts service connections behind a local MCP gateway, with scoped endpoints, access policies, approvals and an Activity history.

Disclosure: GateRook is my project. This article adapts the original walkthrough for developers who want to understand the execution path and its boundaries. The application source is on GitHub.

What โ€œ100+ MCP serversโ€ means here

The number refers to integration coverage. As of November 15, 2026, the integration catalog contains 122 entries: 50 connector types, 71 compatible-service entries and one generic external MCP integration.

Several compatible services share a connector. A managed PostgreSQL service, for example, does not need a separate implementation of the PostgreSQL protocol.

For supported operations, I can configure a connection in GateRook instead of finding, installing and maintaining another service-specific MCP server. This does not mean I previously ran 122 servers, or that GateRook implements every feature of every specialist integration. Existing MCP servers can also sit behind the gateway when their tools are needed.

Most connectors are included. Cassandra, Neo4j, ClickHouse, DuckDB, H2 and Microsoft Access use optional modules and an optional Java runtime; their first download needs internet access. The connector delivery documentation explains the split.

One endpoint, several services, explicit permissions

There are three useful concepts:

  • A connection identifies a service, its credentials and its access constraints.
  • An endpoint exposes a selected set of connections and tools to an AI client.
  • A policy determines how a requested operation may proceed.

For a checkout investigation, the arrangement looks like this:

AI client
    |
    | MCP
    v
GateRook endpoint: shop-investigation
    |
    +-- authentication and endpoint scope
    +-- argument validation and operation classification
    +-- policy decision / approval when required
    +-- execution and Activity record
    |
    +-- MySQL       orders
    +-- Redis       cached availability
    +-- MongoDB     product catalog
    +-- Kubernetes  workloads and logs
    +-- OpenSearch  search documents
    +-- InfluxDB    metrics

The client gets access to the endpoint. GateRook supplies the credentials for the selected service connection. This removes database passwords from the assistant's tool arguments while keeping the actual database and cloud permissions in force.

Six service connections assigned to the shop-investigation endpoint in GateRook.

Connections from the original controlled demo. It uses fictional shop data, five real local services and a local Kubernetes API fixture representing the GKE workflow. The loopback addresses and simplified development authentication are demo settings.

I can give a development assistant and a production investigation assistant different endpoints. Neither needs the entire integration catalog simply because the application supports it.

A prompt is useful; an enforced policy is the boundary

โ€œPlease do not modify productionโ€ is a reasonable instruction to an assistant. I also want that intent represented in the execution layer.

GateRook has four tool modes:

Mode Behavior
Off The tool is unavailable through that endpoint.
Read only Classified reads can run; classified mutations go through approval.
Approval Both reads and changes require review.
Bypass Calls can run without approval; other applicable controls remain.

The distinction between a Read only tool mode and a read-only endpoint matters. A read-only endpoint prohibits mutations and Bypass. For an investigation that must never write, that is the stronger boundary.

The original demo uses 17 read-only tools, two approval tools and 11 disabled tools, with no Bypass. Its Redis key restrictions also exclude session:*.

These controls complement service permissions. A narrowly scoped database user or cloud role still matters, especially when a connector's read-only enforcement depends on the service or its operation classifier. The security documentation describes those details.

Follow one SKU across the stack

Consider order 1001 and product sku-42: the product appears in search, but checkout reports it as unavailable.

A focused investigation request might be:

Compare order 1001 with the cached availability, product document, search document, checkout logs and recent metrics for sku-42. Return the evidence and a proposed fix. Do not make changes yet.

The original demo produces the following evidence:

Tool Observation
sql_query Order 1001 is pending and uses inventory version 18.
redis_get The cached product reports zero available units and version 17.
mongo_find The catalog reports 12 units and version 18.
opensearch_query The search document also reports 12 units and version 18.
k8s_get / k8s_logs The Kubernetes fixture returns a running pod and a sample cache-version mismatch.
influxdb_query Seeded checkout metrics provide latency and error context.

The SQL read is deliberately small:

SELECT id, status, inventory_version, total
FROM orders
WHERE id = 1001;

The mismatch suggests stale cache data. It does not prove that the cache caused every checkout error. In a real investigation, I would also check timestamps, the cache update path and subsequent behavior.

What changes operationally is that all these reads pass through one configured access point and appear in one history.

Approve the command that will actually run

The proposed fix in the demo updates one existing Redis key to inventory version 18 and gives it a five-minute expiry.

Here is the Redis command, formatted for readability:

SET "product:sku-42" '{"sku":"sku-42","available":12,"inventory_version":18}' XX PX 300000

There are two details worth reviewing before approval:

  • XX requires the key to exist. It does not compare its previous value and is not compare-and-swap.
  • PX 300000 sets an explicit five-minute expiry, so the replacement does not accidentally become permanent.

In a real application, I would prefer its supported cache-refresh operation if that operation performs additional consistency checks.

GateRook approval request showing the exact Redis SET command, connection, endpoint, expiry and approval controls.

The approval is attached to a concrete command and target, with a choice to deny or execute it.

Under the hood, GateRook stores the prepared action and its digest. Before execution, it rechecks the approval, expiry, applicable policy and action integrity. The core executes the stored payload, so the client cannot replace the reviewed command with another one after approval.

This is the control I care about: reviewing โ€œset this key to this value with this expiryโ€ before the write reaches Redis. A follow-up read in the demo confirmed 12 available units, version 18 and a remaining expiry.

Keep the execution history next to the controls

An assistant's summary is useful, but I also want the underlying calls.

GateRook Activity showing eight allowed reads, one approved Redis write and one read denied by policy.

The original demo recorded ten calls across six connections: eight allowed reads, one approved write and one policy-denied read.

The denied request tried to read session:demo-user. The session:* restriction blocked it before the Redis operation ran. That is a useful test of the boundary: a normal product lookup succeeds while a session-key lookup fails.

Activity brings together the tool, connection, caller, decision, duration and execution outcome. For an approved action, I can inspect the review and whether execution matched the approved payload. These records establish what happened at the tool layer; they do not establish that the model's diagnosis was correct.

A large catalog should not become a giant prompt

There is another scaling problem: loading every tool definition into an assistant's context.

GateRook's automatic discovery mode switches to searched tool lists when the endpoint exceeds 40 tools or 100 KB of definitions. It exposes the core tools and ten most-used tools, while the rest remain discoverable through find_tools and callable through call_tool or call_read_tool.

Those wrappers preserve the underlying tool's policies, approval requirements, limits, masking and audit behavior. Discovery changes how a tool is found, not its permission boundary. The architecture documentation explains the mechanism.

What control means in practice

My goal is to control access, review changes and retain evidence. The scope of that control is explicit:

  • GateRook governs calls routed through it. Separate shell access or another MCP connection needs its own controls.
  • Keeping service credentials local does not keep all query results local. Allowed results reach the AI client and may reach its model provider.
  • Approval is only useful if the proposed action is understood. It cannot make an incorrect fix correct.

For a first setup, I would choose one non-production workflow, add only its required connections, verify an allowed read and a denied request, then test approval for one narrowly scoped change. The getting-started guide covers setup, and the AI app guides cover client connections.

For me, the benefit of one desktop app is being able to answer three questions in one place: what can the assistant reach, what am I approving, and what actually ran?

The original article contains the full walkthrough. You can explore GateRook or inspect the source on GitHub.

How do you currently separate an AI assistant's permission to investigate from its permission to change infrastructure?

๐Ÿ“ฐ Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes โ€” full credit and traffic to the original publisher.