Agent-Native SaaS: Exposing Your Product to AI Assistants Over MCP
Most products treat AI as a feature you visit — a chat box in the corner. When I built FeedbackRun at Nextbit, I wanted the opposite: an AI assistant should be able to operate the product, the same way a human does, from wherever the user already works. A product manager in Claude Desktop or Cursor should be able to say "find the top revenue-blocking feature requests and mark the duplicates," and it just happens — no tab-switching, no copy-paste.
That's what the Model Context Protocol (MCP) is for, and it's why FeedbackRun ships an MCP server as a real part of the product, not an experiment.
workspaceId from authenticated context, so the agent can't reach a workspace it shouldn't.What "agent-native" actually means
MCP is a standard way to expose your product's capabilities as tools an AI assistant can call. Instead of the assistant guessing at your REST API from documentation, you hand it a typed list of actions — list feedback, search, create, prioritize — and it picks and calls them through natural language. The assistant is the interface; MCP is the wiring.
The design shift is thinking of an agent as a user with different ergonomics. A human clicks through a dashboard; an agent calls tools. Both need the same things: scoped access to one workspace, permission checks, sensible results. So the MCP server isn't a parallel universe — it sits on the same authorization and workspace- scoping model as everything else. An agent operating on behalf of a workspace can only ever see that workspace's data, enforced the same way a browser session is.
Tools are an API you design, not a dump of your database
The temptation is to expose every endpoint you have and call it done. That produces a terrible agent experience. An agent does better with a small set of task-shaped tools than a hundred CRUD operations.
// An MCP tool: a named, typed, task-shaped action the assistant can call.
server.tool(
"search_feedback",
"Search feedback in the current workspace by text, status, or revenue impact.",
{
query: z.string().describe("Natural-language or keyword search"),
status: z.enum(["open", "planned", "in_progress", "shipped"]).optional(),
minMrr: z.number().optional().describe("Only items from users above this MRR"),
},
async (args, { workspaceId }) => {
const results = await feedbackService.search({ ...args, workspaceId }); // same scoping as the UI
return { content: [{ type: "text", text: formatForAgent(results) }] };
},
);
Two things in that snippet carry the whole philosophy. The description and typed
schema aren't documentation — they're the prompt the model reads to decide whether and
how to call the tool, so I write them like I'm briefing a new teammate. And
workspaceId comes from the authenticated context, never from the model's
arguments — the agent can't pass a workspace it shouldn't reach, because it doesn't
get to name one. Authorization is not something you trust the model to respect.
Return results shaped for a model, not a UI
A REST endpoint returns JSON for a component to render. An MCP tool returns text a
model has to reason over. Those are different jobs. Dumping raw rows makes the model
work harder and hallucinate more; a compact, labeled summary ("3 open items, top one
is X blocking $Y in deals") gives it something to act on directly. I spend real effort
on formatForAgent — it's the difference between an assistant that's useful and one
that's confidently wrong.
Why I bothered, and where this is going
Building this so an agent is a first-class operator — not a bolt-on — was ahead of the category, and I think that direction is where products are heading. The honest reason to do it now: the users who reach for AI assistants are exactly the ones who'll pay for a product that meets them there. Exposing your capabilities over a standard protocol means you don't have to guess which assistant wins; you support the protocol and any compliant client — Claude Desktop, Cursor, Windsurf — can drive your product.
It also forces a healthy discipline. To expose your product to an agent cleanly, you have to have clean, task-shaped, well-scoped operations underneath. Building the MCP server made the whole API better, because you can't hand a model a mess and expect it to cope.
Takeaways
- Treat an agent as a user with different ergonomics — put MCP on the same auth and workspace-scoping as your UI.
- Expose task-shaped tools, not raw CRUD. Fewer, higher-level actions beat a hundred endpoints.
- Tool descriptions and schemas are prompts the model reads — write them carefully.
- Derive scope from authenticated context, never model arguments; the agent can't be trusted to stay in its lane on its own.
- Format results for a model to reason over, not for a component to render.
An AI-native product isn't one with a chatbot glued on. It's one an assistant can actually operate — and MCP is how you open that door without picking a winner.
I build AI-native SaaS and platform systems end-to-end. If you're working on something similar, let's talk.