MCP Strategy
Olly uses the Model Context Protocol (MCP) as the internal tooling spine that lets operators, engineers and automation agents drive the platform through a single, declarative tool catalogue. We adopted a standard protocol because the clients will churn - Claude Code today, IDE plugins and CI agents tomorrow - but the tools (peek Kafka, query a trace, look up an ontology term) are stable Olly capabilities we want to define exactly once. MCP is explicitly not a customer-facing API; external integration goes through the Go service gateway via APISIX.
Position
MCP gives humans-with-AI-assistants and AI-driven automation a structured, auditable way to read and act on Olly's running system without copy-pasting CLI output or hand-crafting REST calls. It is a tooling layer over services we already run - APISIX arbitrates production traffic, OpenBao holds secrets, OpenMetadata owns the catalogue. MCP exposes a curated, authorised slice of those systems to clients that speak the protocol.
What MCP is at Olly (internal tooling layer; consumed by ops, dev, automation)
The olly-platform MCP server at mcp.dev.hiolly.com serves three internal populations:
- On-call engineers and ops - investigating incidents from a Claude Code session: pulling a trace, tailing logs, peeking at a Kafka consumer group, checking a triage session's path.
- Developers - exploring services from inside an MCP-enabled IDE without leaving the editor.
- Automation pipelines - scheduled agents and CI hooks doing structured introspection (ontology drift sweep, scenario validators, doc-review skills).
Everything MCP exposes is something a developer or operator could already do via psql, kubectl, the Grafana UI, or a curl to an internal service. MCP packages those operations behind authorised, observable, schema-validated tool calls so an AI client can use them safely and a human can audit what was called and by whom.
What MCP is explicitly NOT (not a customer integration surface; not a partner API; that is the Go service gateway via APISIX)
MCP is not the integration story for members, employers, providers, brokers or downstream partners. Those audiences talk to Olly through the APISIX gateway (api.dev.hiolly.com) and its versioned, contract-tested HTTP APIs. The reasons are deliberate:
- The gateway carries the SLAs, rate-limiting, ABAC policies, audit logging and partner-credential issuance that external traffic requires. MCP does not.
- MCP's tool catalogue is defined for internal convenience, not backwards compatibility. Tools get renamed, retired, or scoped down when our needs change; partners cannot live on that surface.
- Third-party MCP clients are not invited to connect. The server is registered, allow-listed and bound to internal identities; it is not a marketplace endpoint.
If a capability matters to a customer or partner, it lives in a Go service behind APISIX. MCP may also expose it for ops, but the gateway is the source of truth.
Tool surface (broad categories: triage debug, db introspection, kafka peek, log query, ontology lookup - name categories not implementations)
The server presents a small number of stable categories, each scoped to a specific operational need:
- Service health and domain operations - health checks across the Go services and read/light-write operations against each domain (claims, eligibility, enrollment, billing, provider, policy-admin, care, broker, consent, documents).
- Triage debug - pull a session's merged debug payload (session + turns + tool calls + Langfuse trace), recent failures, pathway tree, judgement output.
- Database introspection - read-only row counts and schema-level queries against service databases.
- Kafka peek - consumer-group lag and topic-level inspection for ops triage.
- Observability - trace fetch and search via Tempo, log queries via Loki, active alerts.
- Ontology / catalogue lookup - read glossary terms and table descriptions from OpenMetadata so an assistant has the same semantic ground truth as a developer.
- Auth and infra introspection - Keycloak user/role lookup and Kubernetes pod/node listing for incident response.
Each category is intentionally narrow. We add tools when an internal workflow keeps reaching for them; we resist tools that exist "in case someone wants them".
Authorization model (per-tool authz; Keycloak JWT bearer; least-privilege roles; destructive tools gated behind explicit confirmation)
Every tool call carries a Keycloak JWT bearer identifying the human or automation principal. Authorisation is per tool, not per server: an operator can run logs_query without being able to run payment_record, and a broker-portfolio tool only resolves if the bound JWT has the broker role.
Least privilege
MCP tools inherit the same role model as the underlying Go services. Holding an MCP session does not promote a user beyond the roles their Keycloak token already carries - MCP is a thinner client, not a privilege bridge.
Tools that mutate state (claim submission, prior-auth decisions, consent records, payment recording) are tagged destructive and require an explicit confirmation step by the calling client before the server executes them. This prevents an AI client from "accidentally" submitting on the user's behalf when the user only asked for a dry-run.
Why a standard protocol matters (client choice: Claude Code today, IDE tools tomorrow, automation pipelines; tools defined once)
We pay one cost - defining the tool catalogue and its schemas - and earn client choice. Today most calls come from Claude Code; tomorrow they will come from IDE-integrated agents, scheduled automations, doc-generation pipelines, and review bots. None of those clients need a bespoke integration; they speak MCP, and they get the same authorised tool surface.
This is the same argument we make for OIDC over per-app SSO and for OpenTelemetry over vendor-specific tracing: pick the protocol the ecosystem is converging on, and stop re-implementing the boring middle. If Claude Code stops being the right driver, the tools and their authz model do not change.
Observability (every tool call traced via OTel + Langfuse; full call history queryable)
Every MCP request is instrumented twice:
- OpenTelemetry spans flow into the standard
otel-collector→ Tempo pipeline, so an MCP call is correlated with the downstream service calls it triggered. A trace reads "claude-code → mcp tool X → triage-service → postgres" as one connected story. - Langfuse records the LLM side of the conversation - which client invoked which tool with which arguments, and what was returned - so the agent-level audit is queryable independently of infrastructure traces.
An auditor can answer "who ran which tool against which session on which day" without grepping container logs, and MCP latency and error rates feed the same Grafana dashboards as the rest of the platform.
What we explicitly do NOT do
- Expose PHI through MCP without authz. Every PHI-touching tool requires a valid Keycloak JWT with the role the underlying service would already require - MCP is never a back door.
- Allow destructive actions without explicit confirmation. Mutating tools refuse to execute on a single round trip; the client must affirm intent.
- Permit production database writes through MCP. Database tools are read-only. State changes go through the owning Go service, behind its existing validations and outbox.
- Let third-party MCP clients connect to internal tooling. The
olly-platformMCP endpoint is for internal principals only. External integration uses the Go service gateway via APISIX, with its own contract, SLAs and rate limits.
