If you've been anywhere near agent frameworks in the last year, you've seen "MCP" mentioned enough times that it's started to feel like one of those terms everyone nods along to without necessarily having built anything with it. We were in that camp for a while too. Then we actually needed an agent that could check a customer's real account data instead of answering from general knowledge, and MCP stopped being a buzzword and started being the thing that saved us from writing the same integration glue code for the fourth time.
This post is what MCP actually is, why it's grown as fast as it has, and the actual code for wiring an MCP server into a DNotifier agent — not the conceptual version, the one we run.
The one-line version
The Model Context Protocol is an open standard, built by Anthropic, that gives a model a consistent way to talk to external tools and data sources — a filesystem, a database, an internal API — without every single application inventing its own bespoke integration for each one. Think of it as a shared plug shape: build a server once, and any MCP-aware model or platform can use it, instead of writing custom glue per tool per model.
That sounds like a small thing until you've been the person writing the fourth version of "describe this tool to the model in the system prompt, parse whatever comes back, hope the format doesn't drift."
Why it's not just Anthropic's pet project anymore
We didn't take this seriously until we looked at the actual numbers. As of a recent count, there are roughly 15,930 public MCP servers spread across the major registries, with close to 9,700 of those in the official one alone. Monthly SDK downloads are past 97 million. And — this is the part that actually got our attention — Microsoft, Google, and AWS have all built native MCP support into their own platforms (Copilot Studio, Gemini, Bedrock AgentCore). That's an unusual amount of cross-vendor agreement for anything in this space. Companies that compete on basically everything else agreed on this one plug shape.
The protocol also shipped what its maintainers called the biggest revision in its history: the transport layer moved to stateless-by-default, and three older features got put on a 12-month deprecation clock. The major SDKs had compatible releases out within about three weeks of that announcement. That's a protocol being taken seriously enough to move fast on breaking changes, not something coasting on hype.
The honest caveat, because we'd be doing you a disservice not to mention it: independent security scans have found real, exploitable flaws in a meaningful chunk of public MCP servers — enough that the NSA and CISA jointly put out security guidance on it. Fast growth plus low friction to publish a server means you get both real adoption and real sloppiness in the same ecosystem. Whatever server you're about to connect to a production agent deserves the same scrutiny you'd give any other third-party dependency touching your data. "It implements a protocol Anthropic built" is not the same thing as "it's trustworthy."
How this actually fits into DNotifier
DNotifier's AI Foundation layer treats MCP servers as a first-class connection type, right alongside your models and your enterprise data sources. You connect a server once, in the dashboard, and it becomes available to whatever agents need it — the same mental model as connecting an API key.
One agent, two channels. The model side and the tool side are both configured once, in the dashboard — not re-wired into every prompt.
// the agent's own call doesn't change based on which MCP tools are attached —
// tool access is a dashboard-level connection, not something you re-describe
// on every request
const response = await notifier.sendAI({
senderId: userId,
sessionId,
message: { text: "Check the latest invoice for this account and summarize it." },
});
// behind the scenes: the model reasons about the request, decides it needs
// the invoice data, and DNotifier routes that lookup through the connected
// MCP server — none of that plumbing lives in this call
That's genuinely the whole client-side shape of it. The heavy lifting — deciding a tool call is warranted, structuring the call, interpreting what comes back — is the model's job and the protocol's job, not something we're writing per feature anymore.
A real example: grounding a support agent in a live account database
Here's roughly what we had before MCP, for an agent that needed to check account state:
// the old way — a hand-rolled function, described in the prompt,
// parsed manually, and repeated for every new data source
async function checkAccountStatus(accountId) {
const row = await db.query("SELECT * FROM accounts WHERE id = $1", [accountId]);
return row;
}
const systemPrompt = `
You can call checkAccountStatus(accountId) to look up account data.
If the user asks about their account, call this function and use the result.
Respond in this format: ...
`;
// then hand-parse whatever the model decides to output, hope it matches
// the format you asked for, repeat this whole dance for the next tool
That works, technically, for one tool. It gets worse fast once you have four or five data sources, each with its own quirks, each needing its own parsing logic, each one more surface area for the model to accidentally hallucinate a call it never actually makes.
With a database MCP server connected once through DNotifier, the same capability looks like this from the application's side:
const response = await notifier.sendAI({
senderId: customerId,
sessionId,
message: { text: "Why was I charged twice this month?" },
});
// the model recognizes it needs account/invoice data, calls the MCP
// server's exposed tool for it, gets back structured data, and reasons
// over the actual result — no bespoke parsing code on our end
The integration code didn't grow. When we added a second MCP server a few weeks later — this one for an internal ticketing system — the application-side code for the agent's sendAI() call didn't change at all. That's the part that made this worth adopting for us: the cost of adding tool number five is the same as tool number one.
Does this only matter if you're using Claude?
No, but it's worth being straight about why Claude specifically tends to be smoother here. Anthropic didn't just publish the spec and walk away — Claude's own training and tool-use behavior were shaped by being the model built alongside this exact protocol. In practice that shows up as Claude being noticeably more fluent about deciding when a tool call is warranted and structuring it correctly, with less prompt-engineering scaffolding required to hold its hand through the process. We've run MCP-connected tools against other providers through DNotifier too, and it works — it's just that Claude needed less coaxing to use them well, which tracks given who built the protocol.
What we'd actually check before connecting a new server
Not a formal checklist, just what we've started doing by habit: who maintains it, and how actively. Is it in the official registry or some unlisted repo somebody linked in a Discord. What permissions is it actually requesting versus what the task genuinely needs. If any of those answers feel shaky, we don't connect it to anything touching real customer data, full stop — there are enough servers out there now that "just use a different one" is usually a real option, not a hypothetical.
If you're still hand-rolling tool descriptions into system prompts for every integration you add, this is worth the hour it takes to try. The protocol did the annoying part already. What's left is mostly picking servers you trust and wiring them in once.
Top comments (0)