About Portfolio Cases Services Blog Contact 🎙 Talk to AI
EN DE RU
🎙 Talk to AI
October 21, 2026 · 5 min read

MCP finally reached Go: how to build a production-ready agent server without drowning in custom glue code

I’m Denis Shokhirev, an Agentic AI Systems Architect based in Freiburg im Breisgau, Germany, and at DennisCraft AI Studio I ship production AI systems on Claude, Supabase, n8n, Doppler, and self-hosted Postgres for DACH B2B clients. The moment agent projects usually get messy is not model selection; it’s week 3, when five tools, three auth patterns, and two partial retries have created more custom glue code than business logic. That’s why MCP reaching Go matters. Not because every agent stack s

Denis Shokhirev
Denis Shokhirev
Agentic AI Systems Architect
Telegram LinkedIn

I’m Denis Shokhirev, an Agentic AI Systems Architect based in Freiburg im Breisgau, Germany, and at DennisCraft AI Studio I ship production AI systems on Claude, Supabase, n8n, Doppler, and self-hosted Postgres for DACH B2B clients. The moment agent projects usually get messy is not model selection; it’s week 3, when five tools, three auth patterns, and two partial retries have created more custom glue code than business logic.

That’s why MCP reaching Go matters. Not because every agent stack suddenly becomes simple, but because a standardized server boundary reduces the number of homegrown adapters you need to maintain. If you treat MCP as an engineering surface instead of a demo feature, you can build a stable tool layer with explicit contracts, auditable behavior, and fewer hidden assumptions between the model and your infrastructure.

Why agent integrations fail before the model does

Most teams start with prompts, evaluation, and orchestration. In production, failures usually come from the integration layer: tools return inconsistent shapes, retries duplicate side effects, database permissions are too broad, and logs don’t let you reconstruct what happened. Once an agent can call SQL, internal APIs, and automation flows, you are running a distributed system with real policy and observability requirements.

The common anti-pattern

I keep seeing the same path. A team writes two quick helper functions, wraps them in a custom JSON schema, adds manual parameter validation, then builds another wrapper so the same tool can be consumed by Claude and by an internal runner. It works, but now the team owns a private protocol. Every new tool adds one more place where behavior can drift.

MCP helps because it creates a standard interface for tools and resources. Anthropic’s documentation describes Model Context Protocol as a way to connect models to tools and data sources through a consistent contract: https://docs.anthropic.com/. The immediate benefit is not novelty. It is lower protocol entropy inside your stack.

What a production-ready MCP server actually needs

A server that answers list_tools is not production-ready. A production-grade MCP service should be testable, observable, permissioned, and boring to operate. My minimum checklist looks like this:

LayerWhat to implementWhy it matters
ContractStrict input and output schemasPrevent silent type drift and hidden fields
AuthorizationTool-level and environment-level access controlKeep the agent inside least-privilege boundaries
ObservabilityRequest IDs, audit logs, traceable tool callsSupport incident review and reproducibility
SafetySecret isolation, SQL allowlists, static analysisReduce data exposure and unsafe execution paths
OperationsHealth checks, timeouts, idempotent retriesHandle partial failures without creating chaos

If two or three of those are missing, you do not have an agent platform yet. You have an early integration layer. That distinction matters because the operating assumptions are very different.

Why Go is a practical fit

Go is useful here for plain operational reasons: a small binary, predictable dependency behavior, and a concurrency model that works well for serving multiple tool calls with bounded runtime costs. In client environments where I already have n8n, Postgres, internal APIs, and self-hosted infrastructure, adding a compact Go service is often easier than introducing another heavy runtime just to expose six or seven tools.

A minimal server shape with fewer surprises

The design principle is simple: one tool, one explicit handler, validated input, and a narrow side effect. Even if your development loop uses Claude Code or the Anthropic SDK, the server boundary should stay strict and boring.

export DATABASE_URL="postgres://app:***@db.internal:5432/app"
export MCP_ALLOWED_TABLES="customers,orders"
export TOOL_TIMEOUT_SECONDS="8"

gitleaks detect --source . --no-banner
semgrep --config p/owasp-top-ten .
bandit -r scripts/

go test ./...
go build -o mcp-server ./cmd/server
./mcp-server

I still run gitleaks and semgrep around the repository because the server is only part of the risk surface. CI files, shell scripts, migration helpers, and automation code are often where secrets and unsafe execution paths leak in. If the repo includes Python utility scripts, bandit is worth adding as well.

version: "3.9"
services:
  mcp-server:
    image: ghcr.io/example/mcp-server:latest
    environment:
      DATABASE_URL: ${DATABASE_URL}
      MCP_ALLOWED_TABLES: customers,orders
      TOOL_TIMEOUT_SECONDS: "8"
    read_only: true
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "/app/mcp-server", "healthcheck"]
      interval: 30s
      timeout: 3s
      retries: 3

The important part is not Docker itself. It is the policy around the server. Your MCP service should not run with unrestricted database credentials. If a tool only needs to read customer and order data, give it a read-only database role and restrict the tables it can touch at the application layer too. On three recent agent deployments I reviewed, over-permissioned database access was the single most common issue before launch.

Where teams get the tool layer wrong

1. They build a universal tool executor

The “one executor for everything” pattern sounds efficient but usually creates vague contracts. Six narrow tools with clean schemas are easier to test and safer to operate than one giant tool with a dozen modes.

2. They mix orchestration with policy

n8n is useful for orchestration and integration flows. Policy decisions such as which tables may be queried or which domains can be called should live in the MCP server and its configuration. Otherwise your control surface becomes fragmented.

3. They log too little

It is not enough to know that a tool was called. You need caller identity, validated inputs, result metadata, duration, error code, and a trace ID that lets you connect the tool call to the larger agent run.

4. They only test happy paths

Test timeouts, cancellations, malformed arguments, empty result sets, and duplicate calls after partial failure. Those cases affect production behavior far more than the successful IDE demo.

External guidance worth using

OWASP Top 10 2021 highlights Broken Access Control and Insecure Design as major application risks: https://owasp.org/www-project-top-ten/. That maps directly onto MCP server design. The server becomes the choke point where permissions, validation, and error handling are either disciplined or dangerously loose.

OpenAI’s cookbook also consistently pushes structured tool usage and schema-defined interfaces in function-calling patterns: https://cookbook.openai.com/. Even if your primary runtime is Claude, the broader lesson is the same: standardized tool contracts reduce operator pain and make multi-model architectures easier to sustain.

FAQ

Is MCP only useful with Claude?

No. The main value is the contract between models and tools. Even in a mixed-model environment, a standard server boundary reduces adapter sprawl.

Should I expose all internal capabilities as MCP tools?

No. Start with a small set of high-value tools with narrow permissions. Wide tool catalogs create larger failure surfaces and usually degrade governance.

Can I place Supabase behind an MCP server?

Yes, as long as you separate service roles from agent-facing access and keep strict read or write boundaries. MCP does not replace data governance; it gives you a cleaner execution boundary.

Where should secrets live?

Not in prompts and not hardcoded in tool wrappers. I usually keep them in Doppler or another secret manager and inject only the environment-specific values the server needs.

When is MCP overkill?

If you have one local script and one external API, a dedicated MCP server may be unnecessary. Once you have multiple tools, permission tiers, and audit requirements, the standard boundary becomes much more valuable.

Which part of your current LLM stack creates the most production pain: tool contracts, access control, auditability, or incident debugging after release? I’d genuinely like to know, because that bottleneck usually says more about system maturity than the model choice does.

I run a free 30-min stack audit for DACH founders building AI in regulated markets. DM me on LinkedIn or write to @ger_dennis_ai.

Continue reading
AI coding agents are drowning in context: how to cut tool-output noise by 98% without losing session memory
The MCP tool sprawl is already breaking teams: how to pick one agent runtime instead of 10 incompatible tools
AI Assistant for Blender: How Multi-Agent Workflows Cut Weeks Off Manual 3D Work
Why Your AI Agents Fail in Production: How Trigger.dev Solves Reliability and Orchestration
All articles →
Where this is applied
Services — what we build
Talk to the voice agent
Case studies
Ready to build?

Turn your process into an AI system

Production quality. DACH B2B focus.

Start a project → ← All articles