Skip to content
Article

We Run Our Agency on MCP

How Endertech runs MCP in production on our own Symfony + API Platform portal—so Cursor agents can act on tickets, blog, and GitLab—and what that means for client MCP servers.

How running Model Context Protocol on our own agency portal—in production, before we sell it—taught us what clients actually need.

Most AI demos stop at chat. The interesting work starts when an assistant needs to do something: open a ticket, publish a post, query a repo, update taxonomy—without becoming a liability.

That is the job Model Context Protocol (MCP) was designed for: give assistants a coherent set of tools, resources, and prompts against real systems, with auth and boundaries you can defend. At Endertech we did not wait for a client project to learn those boundaries. We wired MCP into the same portal we use to run the agency—tickets, blog, GitLab, and the operational glue around them—so Cursor agents could act inside our workflow the way a trusted teammate would.

We are writing this for two audiences at once. If you buy or build software, you care about whether MCP is hype or a shippable pattern. If you run a business that wants AI that acts, you care about governance, reliability, and whether your vendor has scars from production. We have both.

This post is that story: what broke when Cursor met a real Symfony + API Platform MCP server, the production patterns we would reuse for a client, and how that maps to the MCP server work we offer.

The problem: assistants need governed actions, not clever paste

Generic LLM chat is great at drafting. It is terrible at being accountable. The moment you ask an agent to touch tickets, content, or source control, you inherit a familiar systems problem:

  • Who is the agent? Service identity, API keys, and a system user that maps cleanly to your ACL model—not a shared admin cookie.
  • What can it do? Tools with schemas, scopes, and honest capability declarations—not a kitchen-sink wrapper around every internal endpoint.
  • What happens when it fails? Structured errors, empty-but-valid handlers where the protocol expects a response, and session behavior that does not silently die mid-conversation.
  • How do you know it worked? Logs, traces, and tests that treat tool calls like API traffic.

Copy-paste RAG and “just give the model the API docs” fall apart under those questions. MCP is useful when you treat it the way we treat any production integration: threat model, contracts, ship, observe.

Our own agency systems were the right place to prove that. If MCP cannot survive daily use on our portal, we should not sell it as a client architecture.

We run MCP on the systems we actually use every day

Our portal sits on Symfony and API Platform—the same family of APIs we build for clients who need durable backends, not throwaway demos. On top of that stack we stood up MCP so Cursor could reach the work we already do by hand:

  • Tickets and operational actions so agents can move work forward instead of only summarizing it.
  • Blog tooling—publish, update, pin, taxonomy, and list—so content workflows are first-class tools, not side-channel scripts (shipped as blog MCP tools in our portal work; #6).
  • GitLab topic discovery to support AI-assisted blog ideation against real repository signal (#7).

The point was not to automate the agency into a black box. The point was to force every MCP design choice through the same constraints clients bring us: auth that fails closed, tools that match policy, and an implementation that keeps working when the IDE client has opinions about sessions, keepalives, and capability negotiation.

If you are evaluating MCP for custom software, this is the transfer: lessons from governing our tools become the starting playbook for governing yours.

What broke when Cursor met a real remote MCP server

Protocol specs and IDE clients do not always move in lockstep. Remote MCP with Cursor exposed gaps that would never show up in a happy-path local demo.

Streamable HTTP and API key auth for remote MCP

Cursor’s remote MCP path wants a server you can reach over the network with credentials you can rotate. We implemented Streamable HTTP with API key auth so agents authenticate like any other integration: keys in configuration, validated on the request path, tied to a system identity we control (PR #9).

That sounds basic until you have lived through “the agent works on my laptop because my session cookie is in the browser.” Production MCP for clients almost always means remote access, shared team use, and keys that can be revoked without redeploying an IDE. Auth is the first governed-tool decision, not a polish pass.

Null-env hardening: unset config must not TypeError

Configuration that is “usually set in production” will eventually be missing in a staging box, a fresh clone, or a miswired deploy. We hardened the server so unset MCP_API_KEYS and MCP_SYSTEM_USER_ID fail safely instead of throwing TypeErrors that take the whole process down (#11, #13).

This is unglamorous work. It is also the difference between an MCP spike and something operations will run. Clients rarely ask for null-env hardening by name; they ask why the agent “randomly died” on Friday afternoon. We would rather answer that with tests and defensive defaults.

Cursor keepalive: pings, probes, and honest empty handlers

Long-lived MCP sessions with Cursor expect the server to answer keepalive-style traffic and capability probes. Missing handlers are not “optional”—they are a quiet way to kill the session. We added ping and probe handlers, plus empty prompts/list handlers, so the session stays alive even when we intentionally expose no prompts yet (#14, #15).

That last part matters for product honesty. Declaring capabilities you do not implement—or failing to respond to lists the client always calls—creates flaky agent behavior that looks like model failure. It is usually protocol hygiene. Production MCP means:

  1. Advertise only what you support.
  2. Still answer the methods the client will call.
  3. Return empty collections when the feature is intentionally off, not 500s or silence.

Those three rules transfer directly to client servers in CRM, commerce, ticketing, or internal ops.

Production patterns we would reuse for any client MCP

Running MCP on our own portal compressed years of “we should probably…” into a short list we now treat as defaults.

1. Auth and identity before tool breadth

Start with API keys or OAuth, a mapped system user, and tool-level authorization that respects your existing roles. Widen tools only after identity is boring. Our MCP development practice leads with governed tools, auth, and observability for exactly this reason: the demo that skips identity becomes the incident that teaches you why you needed it.

2. Capability honesty beats a long tool menu

Agents behave better with a small, well-described toolkit than with fifty vaguely named endpoints. Blog publish/update/pin/taxonomy/list is a good shape: verbs the model can plan around, schemas that validate, and outcomes a human can audit. GitLab topic discovery is another: one job, clear inputs, useful output for a downstream writing workflow.

3. Empty handlers and keepalive as first-class design

If your client (Cursor or otherwise) probes prompts/list, resources/list, or ping-style methods, implement them—even when empty. Session death mid-task is an agent UX bug that users blame on “AI.” Fix the server.

4. Fail closed on config; fail loud in tests

Unset secrets should not TypeError deep in a request. Unit and integration tests should cover missing env, bad keys, and unauthorized tool calls. Treat MCP like an API surface: contract tests, auth tests, and a few end-to-end agent paths against staging.

5. Observability per tool invocation

Structured logs for who called which tool with which outcome. When something wrong ships to production content or a ticket state, you need a trail. That is the same discipline we apply to API Platform backends—MCP is just another interface on top.

6. Narrow high-value tools first, then expand with telemetry

We did not expose every portal endpoint on day one. Tickets, blog, and GitLab discovery earn their place because they map to real jobs. Client programs should start the same way: one or two high-value, low-risk actions, evaluation against staging data, then expansion when the metrics say the tools are safe and useful.

What we would build for a custom software client

If you are a technical buyer evaluating MCP—or a business owner who wants assistants that act on tickets, catalogs, or internal ops—the shape of a serious engagement looks like this:

Discovery. Which systems matter, which actions are allowed, where human-in-the-loop is mandatory, and what PII or tenancy rules constrain every tool call.

Tool contracts. JSON schemas, examples, validation, and naming that models can plan with. Resources and prompts only where they earn their keep.

Server implementation. Language chosen for your ops reality (TypeScript, Python, Go, or—as in our portal—PHP/Symfony where that is the system of record), plus Streamable HTTP or the transport your clients require, with auth that matches your security team’s expectations.

Hardening. Rate limits, structured errors, null-config safety, keepalive/probe handlers, capability honesty, kill switches and dry-run modes for destructive tools.

Operate. Metrics and tracing per invocation, versioned rollouts, and a path to add tools without rewriting the agent every quarter.

That is the same arc described on our MCP solutions page—feasibility spike, MVP server, or platform layer—because it is how we already run the work internally. Our portal is the reference deployment: we use MCP on our own agency systems first, then we sell the same discipline to clients.

We also stay first-party about scope. We build MCP servers and the APIs behind them. We do not invent fictional case studies to sell the pattern. Mattress retail, furniture ecommerce, and our own agency portal are enough proof that governed tools beat ad hoc agent scripts.

Who this is for

  • Teams shipping custom software who need MCP as a product capability—not a weekend plugin.
  • Operators who will own auth, keys, and on-call when an agent writes to a system of record.
  • Leaders who want AI leverage without giving a model unbounded access to production data.

If your assistant still lives in a chat window while your real work lives in tickets, CMS, ERP, or Git, MCP is the bridge—when it is built like software.

Let’s talk about your MCP surface

We run ours in production against Cursor, Symfony, and API Platform so the failure modes are ours first. If you want the same discipline on your stack—governed tools, auth you can revoke, observability you can audit—start with the systems and policies, not the model name.

Tell us what the agent should be allowed to do on Monday morning. We will help you scope the tools that ship safely.

Endertech builds custom software and production MCP servers for teams that need AI assistants to act inside real business systems—with the same engineering standards we apply to our own portal.