Audit
Two-week diagnostic. We map your data, your agent surface, and where MCP earns its keep.
From $8k →We design, build, and deploy Model Context Protocol (MCP) servers on your infrastructure — so Claude, Gemini, and your in-house agents can reach BigQuery, your DSP, and your CDP.
No pitch deck. No follow-up drip. We tell you if MCP isn't the answer.
All engagements are fixed-fee and time-boxed. We scope, you approve, we ship.
Two-week diagnostic. We map your data, your agent surface, and where MCP earns its keep.
From $8k →Production MCP servers deployed on your infrastructure. Auth, logging, evals, and CI from day one.
From $15k →Fractional senior MCP engineer for new connectors, agent evolution, and a Slack channel.
$12k / mo →Hands-on workshops for your engineering team. We leave with the bus factor at zero.
Custom →Auth, observability, evals, and CI are engineered in from day one. The interesting part is what you wire it to.
No black boxes. Typed inputs, scoped auth, and a repo your engineers can grep.
$ claude mcp add --transport http campaigns https://mcp.acme.corp/mcp
→ oauth: auth.acme.corp (scopes: bq:read, ads:read)
→ registered tools: top_creatives, spend_breakdown
$ claude -- "top creatives last 7d for acme"
→ tool: top_creatives(account="acme") 218ms
→ 10 rows · sorted by roas desc · as dana@acme
Every tool call carries the human identity through the MCP gateway. Audit logs are real. Permissions are real.
| Who | Tool | Scopes | |
|---|---|---|---|
| dana@acme | top_creatives | bq:readads:read | ✓ 218ms |
| jenna@acme | audience_overlap | bq:read | ✓ 92ms |
| j.doe@acme | spend_breakdown | bq:read | denied |
| ops@acme | pacing_check | ads:read | ✓ 410ms |
Four scenarios we see most often. Whichever shape your team is in, we have usually shipped this one before.
Where friction shows up
Our outcome
We design the architecture, ship the first two connectors, and leave your team with a roadmap they can run.
Where friction shows up
Our outcome
We wire your warehouse, CDP, and ad platforms into the agents your team already uses.
Where friction shows up
Our outcome
We replace glue with typed, owned MCP connectors, often paying for itself in vendor savings.
Where friction shows up
Our outcome
We build the gateway pattern: one MCP front door, central observability, and team handoff.
Most teams are still drawing that bridge on whiteboards. We build the production MCP ones with the boring, important things engineered in: per-user auth, eval harnesses, structured logs, and CI.
We host a single MCP gateway per environment. Every connector is just a server behind it.
Boring on purpose. Streamable HTTP transport, OAuth on every request, typed inputs, structured logs, and an eval harness in the repo. See a live version of this pattern at our playground
from mcp.server.fastmcp import FastMCP
from mcp.server.auth.settings import AuthSettings
from .auth import BQTokenVerifier, scoped_bq_client
# A read-only window into the campaigns warehouse, served over HTTP.
mcp = FastMCP(
"campaigns",
token_verifier=BQTokenVerifier(), # validates the caller's OAuth token
auth=AuthSettings(
issuer_url="https://auth.acme.corp",
resource_server_url="https://mcp.acme.corp/mcp",
required_scopes=["bq:read"],
),
)
@mcp.tool()
async def top_creatives(account_id: str, window: str = "7d"):
"""Return the top 10 creatives by ROAS over a window."""
async with scoped_bq_client() as bq: # scoped to the signed-in user
rows = await bq.run(QUERY_TOP_CREATIVES, account_id, window)
return render(rows)
mcp.run(transport="streamable-http")
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js";
import { z } from "zod";
import { scopedBQ, verifier } from "./auth.js";
const server = new McpServer({ name: "campaigns", version: "1.5.0" });
server.registerTool("top_creatives", {
description: "Top 10 creatives by ROAS",
inputSchema: { accountId: z.string(), window: z.string().default("7d") },
}, async ({ accountId, window }, { authInfo }) => {
const bq = await scopedBQ(authInfo); // per-user, not a service account
const rows = await bq.run(Q_TOP, accountId, window);
return { content: [{ type: "text", text: render(rows) }] };
});
// Every /mcp request carries a valid OAuth bearer token — or gets a 401
app.post("/mcp", requireBearerAuth({ verifier, requiredScopes: ["bq:read"] }),
(req, res) => transport.handleRequest(req, res, req.body));
// .mcp.json — point any MCP client at the server.
// OAuth is discovered automatically (RFC 9728) — the client
// opens a browser, the user signs in, tokens stay per-user.
{
"mcpServers": {
"campaigns": {
"type": "http",
"url": "https://mcp.acme.corp/mcp"
}
}
}
// or from the terminal:
// $ claude mcp add --transport http campaigns https://mcp.acme.corp/mcp
Don't see yours? Most MCP connectors are a day or two of focused work.
Internal dev tools, ad-ops, and analytics reachable from one agent surface.
Marketers query segments in plain English while engineering keeps moving.
Optimization agents that read spend from the source instead of guessing.
A hosted MCP server at https://playground.mcpbuilders.dev/mcp with six tools over a MarTech dataset and a hybrid-RAG corpus of public-domain books. Endpoint: https://playground.mcpbuilders.dev/mcp. One-time Google sign-in, then every call is scoped to you. MIT licensed, deployable to Cloud Run.
Same OAuth pattern, same eval harness, same observability we ship to clients. The demo is the docs.
# 1. Add the playground MCP server (streamable HTTP transport)
$ claude mcp add --transport http playground https://playground.mcpbuilders.dev/mcp
# first call → 401 → browser opens for Google sign-in → token cached per-user
$ claude -- "search the Sherlock Holmes stories for a scene with a bicycle"
$ hermes mcp add playground --url https://playground.mcpbuilders.dev/mcp --auth oauth
{
"mcpServers": {
"playground": {
"transport": "http",
"url": "https://playground.mcpbuilders.dev/mcp"
}
}
}
$ claude mcp add --transport http playground \
https://playground.mcpbuilders.dev/mcp
→ Added HTTP MCP server "playground"
# first call → 401 → browser opens for Google sign-in → token cached
$ claude -- "top creatives by ROAS last 30 days"
→ oauth: authorized as [email protected]
→ tool: top_creatives(window="30d") 92ms
Top creatives by ROAS (last 30 days):
1. video_demo_v2 — ROAS 4.8, $12k spend
2. carousel_holiday — ROAS 3.9, $8k spend
3. static_v7 — ROAS 3.2, $14k spend
# six tools total: top_creatives, spend_breakdown, list_campaigns,
# rag_query, list_documents, get_document
top_creatives, spend_breakdown, list_campaigns, rag_query, list_documents, get_document.$ claude -- "search the Sherlock Holmes stories for a scene with a bicycle"
→ tool: rag_query(query="bicycle scene", top_k=5) 218ms
{
"matches": [
{
"doc_id": "adventures-of-sherlock-holmes",
"title": "The Adventures of Sherlock Holmes",
"author": "Arthur Conan Doyle",
"source_url": "https://www.gutenberg.org/ebooks/1661",
"snippet": "…the solitary cyclist…"
}
]
}
Dense (Pinecone) + sparse (BM25) → reciprocal-rank fusion → Cohere rerank. The same pattern we ship to clients, running on public-domain text you can query right now.
Most "RAG demos" you see online run a single dense retriever over a curated corpus and call it a day. That's why RAG has a reputation for confidently missing the obvious. Dense embeddings are great at semantic recall and terrible at proper nouns; sparse retrievers (BM25) are the opposite. The fix is to run both, fuse the results with RRF, and rerank the top slice with a cross-encoder. That's what production RAG looks like. That's what the playground runs.
The corpus is three books from Project Gutenberg — The Adventures of Sherlock Holmes, A Study in Scarlet, The Hound of the Baskervilles — chosen because they're public-domain, long enough to demand chunking, and full of the kind of proper-noun-and-place queries that break dense-only pipelines.
Sample prompts to try:
"Search the Sherlock Holmes stories for a scene with a bicycle.""Which stories take place in Utah?""List the documents available in the corpus."
Army veteran. Ten years shipping infra and data systems for MarTech and AdTech. Spent the last year putting production MCP servers in front of agents that actually have to earn their compute.
When teams hire mcpbuilders, you are not getting handed off to a junior. You work directly with me, end to end.
If yours isn't here, just email.
An MCP (Model Context Protocol) server is a typed, authenticated endpoint that lets AI agents like Claude, Gemini, and ChatGPT call your tools and read your data over a standard transport. It replaces brittle bespoke integrations with a single, observable protocol.
Claude Code, Claude Desktop, Gemini, Cursor, and ChatGPT / OpenAI — anything that speaks streamable HTTP MCP. We test against each client in the eval harness before shipping.
Median time-to-ship for the first production MCP server is under three weeks from kickoff, including OAuth, structured logs, and an eval harness.
On your infrastructure. We deploy into your cloud account or Kubernetes cluster so your data, tokens, and audit logs never leave your perimeter.
Every tool call carries the human identity via OAuth / OIDC through an MCP gateway, with per-tool scopes and row-level authorization. No shared service accounts.
Structured audit logs, scoped tokens, and reproducible CI builds are engineered in from day one so your existing SOC 2 controls extend cleanly to the agent surface.
Yes — one time, with Google. The playground runs AUTH_MODE=required in production, so the first tool call opens a Google OAuth consent screen in your browser. Every subsequent call carries a per-user Bearer token. It's the same OAuth-proxy pattern we ship to clients, just running against Google instead of your identity provider.
The rag_query tool runs a production-shaped retrieval pipeline: Pinecone dense embeddings + BM25 sparse search in parallel, fused with reciprocal-rank fusion, then reranked by Cohere. The corpus is three public-domain Sherlock Holmes books. Try it with prompts like "Search the Sherlock Holmes stories for a scene with a bicycle" or "Which stories take place in Utah?"
Thirty-minute call. We map your stack, name the first connector to ship, and give you a fixed quote by Friday. If MCP isn't the answer, we tell you.