SKILL DETAIL
mcp-server-offering
samber/developer-platform-skills/mcp-server-offering
Design a SaaS product's MCP server as a product surface AI agents operate - sizing the build investment, curating a 5-15 workflow-tool agent surface instead of mirroring API endpoints, MCP Apps interactive UI, named write-tool safety patterns (scoped credentials, read-only lockdown, human-in-the-loop approval, risk-tiered server-side gates, dry-run preflight, idempotency and spend caps), remote hosting with OAuth 2.1, versioning the tool surface, MCP registry discoverability, and measuring agent adoption. Use whenever the user mentions MCP, Model Context Protocol, an agent-facing tool surface, exposing a product to AI agents or coding assistants, or MCP write-tool safety - even if they never say "MCP server". Design layer only - code-generation MCP builder skills scaffold what this specifies.
Installation
npx skills add https://github.com/samber/developer-platform-skills --skill mcp-server-offering
技能檔案
SKILL.md
最近同步 · 2026年10月23日
evals/evals.json›
{
"skill_name": "mcp-server-offering",
"evals": [
{
"id": 1,
"prompt": "I'm the API PM at Corvale, a freight-invoicing SaaS. We shipped an MCP server six months ago by auto-generating one tool per REST endpoint - 74 tools, names like getInvoiceById, getInvoiceList, getCarrier, getCarrierRates, patchInvoice, deleteInvoice. Support keeps getting tickets that Claude and Cursor pick the wrong tool, and one customer told us their agent 'runs out of room' before it does anything useful. Our REST API is stable, public, on v3, live four years. Give me a redesign plan for the tool surface.",
"expected_output": "A redesign that cuts 74 endpoint-mirrored tools down to a curated 5-15 workflow-level set derived from the existing v3 contract, with renamed tools, pagination and description conventions, per-tool risk levels, and breadth escape hatches deliberately withheld.",
"files": [],
"expectations": [
"Recommends cutting the surface to roughly 5-15 workflow-level tools instead of keeping one tool per API endpoint.",
"Presents curation as the settled answer rather than laying out comprehensive-vs-curated as an open trade-off for Corvale to weigh.",
"Cites the real-world median of 5 tools per server across 1,412 analyzed servers.",
"Attributes the 'runs out of room' symptom to tool metadata consuming roughly 40-50% of the agent's context window before any work begins.",
"Instructs deriving the new tools from the existing stable v3 REST contract rather than hand-building a parallel surface.",
"Designs tools top-down from user workflows and collapses granular endpoints into workflow-level tools, rather than bottom-up from the endpoint list.",
"Renames tools to verb-first, service-prefixed snake_case (for example corvale_list_invoices) instead of unprefixed camelCase.",
"Specifies a limit parameter with cursor or has-more fields returned, defaulting to roughly 20-50 items.",
"Treats writing tool descriptions as budgeted engineering work, noting that description-only tuning has measurably cut agent error rates with no code change.",
"Applies parameter mistake-proofing (poka-yoke): absolute identifiers over relative ones, enums over free-form strings.",
"Assigns exactly one risk level per tool and splits any tool that both reads and irreversibly writes into two tools.",
"Withholds breadth patterns - a generic execute-any-endpoint escape hatch, dynamic tool loading, client-selectable toolset grouping - unless a breadth requirement is proven, rather than offering them as the fix."
]
},
{
"id": 2,
"prompt": "Our CFO wants a one-pager before approving headcount for an MCP server. I've been collecting numbers for it: 78% of enterprises already use MCP in production, 28% of the Fortune 500 run production MCP deployments, and I read that 73% of outages start at the transport/protocol layer so we should budget engineering for that. I also want a line saying Stripe and Linear have driven real revenue from their MCP servers. We're Latchkey, a mid-market HR-onboarding SaaS, public REST API since 2021, about 600 customers. Draft the case.",
"expected_output": "A business case that strips the unusable figures, substitutes the defensible adoption baseline and the strongest first-party disclosure, frames Latchkey's investment as defensive table stakes, and budgets production effort honestly.",
"files": [],
"expectations": [
"Refuses the '78% of enterprises use MCP in production' figure and states it is debunked.",
"Refuses the '28% of Fortune 500 run production MCP deployments' figure and states it is debunked.",
"Refuses the '73% of outages originate at the transport/protocol layer' figure, or labels it an uncorroborated single-vendor analysis rather than a statistic.",
"Declines to attribute MCP-specific revenue to Stripe or Linear, stating that neither publishes MCP adoption or revenue metrics and that such claims are unverifiable.",
"Substitutes the roughly 41% limited-to-broad production figure from the December 2025 survey of 300 senior technical leaders as the citable adoption baseline.",
"Cites the strongest first-party dataset available - over 5 million tool calls per working day with roughly a third of them writes.",
"Cites the 44% more accurate answers using 48% fewer tokens result from that same first-party disclosure.",
"Notes that only 11-14% of enterprise agentic pilots reach production and ties the stall to identity, audit, and access-control gaps.",
"Frames MCP for Latchkey as defensive positioning becoming procurement table stakes rather than a new revenue channel, because Latchkey already ships a public REST API.",
"States that the competitive question has moved from 'supports MCP' to 'supports MCP well'.",
"Treats RFP pressure as a qualitative signal and attaches no percentage to it.",
"Separates demo-grade effort from production-grade effort, citing an order of 150-250 hours for a simple hand-built API-integration server plus a standing maintenance commitment."
]
},
{
"id": 3,
"prompt": "Marlowe Commerce - we run order management for about 900 online retailers. Product wants agents to be able to cancel orders, issue refunds up to $500, and email the customer a revised shipping notice. My plan is to mark those three tools with the destructive annotation so Claude Desktop shows a confirmation dialog, and add a line to each tool description telling the agent to ask the user first. I'd also add a confirmation prompt on every single tool, including the read ones, to be safe. Sanity check this before I write the spec.",
"expected_output": "A rejection of client-side confirmation as the control, replaced with server-side enforcement: risk tiers per tool, the default safety rung, money and message-sending tools specifically hardened, and an honest statement of the reversibility gap.",
"files": [],
"expectations": [
"Rejects client-rendered confirmation dialogs and description-level instructions as the control, because the user can switch MCP clients and bypass them.",
"States that read-only and destructive annotations are advisory hints for clients, never security controls.",
"Applies the explicit test that an end user must not be able to bypass the control by switching clients.",
"Assigns each of the three actions exactly one risk tier using the four-tier classification (Read Only, Minimal Impact, Contained Write, Critical).",
"Prescribes the default rung: scoped or restricted credentials plus a verified read-only mode, human-in-the-loop approval on contained writes, and irreversible tools disabled by default.",
"Requires idempotency keys on every write and a spend or rate cap on the refund tool because it moves money.",
"Recommends dry-run preflight where feasible while flagging dry-run as an uncommon pattern in the ecosystem rather than a standard one.",
"States the rule that when dry-run is not feasible, the destructive tool stays behind an approval gate rather than shipping live-only.",
"Treats the customer-email tool as consequential because it reaches a real human, and gates it rather than handling it as an ordinary write.",
"States that undo and rollback are largely absent across the MCP ecosystem, and that attribution plus immutable audit logs are the substitute rather than a solved reversibility answer.",
"Rejects confirming every tool including reads, warning that approval fatigue on trivial calls trains users to click through the ones that matter.",
"Names risk-tiered server-side policy gates as the high-protection, high-effort option and gives the conditions that promote it - unattended background agents, write volume beyond human approval capacity, or a first write incident.",
"Ranks the safety patterns on more than one axis - protection and effort or efficiency stated separately - instead of one blended ordering."
]
},
{
"id": 4,
"prompt": "Kestrel Analytics. Our MCP server is nearly done: an Express app, one process per customer tenant with sticky sessions in the load balancer because we cache their workspace state in memory between calls. The auth plan is that the agent sends the user's existing Kestrel session bearer token and we pass that same token straight through to our internal analytics API, so permissions match exactly with no extra plumbing. We're self-hosting it in our own VPC. Our customers are enterprise banks and insurers running background agents through their own AI gateway. Review the design before we start the security review.",
"expected_output": "A review that kills token passthrough and sticky sessions, states the OAuth 2.1 resource-server obligations by RFC, re-opens the hosting choice against the managed-platform default, and rules out local stdio for this audience.",
"files": [],
"expectations": [
"Rejects forwarding the caller's bearer token to the upstream API and names it the confused-deputy shape the spec forbids outright.",
"Prescribes obtaining a separate upstream token via token exchange, with the MCP server acting as an OAuth client to the upstream system.",
"Rejects the sticky-session design and requires stateless, interchangeable server instances behind a plain load balancer.",
"Positions the MCP server as an OAuth 2.1 resource server that validates tokens and never mints them, leaving authorization-server design out of scope.",
"Requires publishing protected-resource metadata (RFC 9728).",
"Requires resource indicators (RFC 8707) and rejecting any token not issued specifically for this server, to stop a token minted for one MCP server being replayed against another.",
"Requires issuer validation (RFC 9207).",
"Names a remote managed platform as the default hosting rung rather than self-hosting, justified by the protocol shipping four backward-incompatible revisions in its first twenty months plus the OAuth machinery a platform absorbs.",
"Names the conditions that promote self-hosting anyway - a custom server-side risk-tier policy layer, residency constraints, MCP being the product, or existing multi-tenant edge infrastructure - and tests Kestrel against them instead of approving or rejecting self-hosting flatly.",
"Rules out local stdio entirely for this audience because enterprise agent fleets consume hosted endpoints.",
"States that hosting choice is invisible to the buyer, since the client sees the same OAuth-protected endpoint either way, so the value difference between remote postures is a genuine tie.",
"Includes the hardening floor: schema-validate every input with bounded sizes and ranges, sanitize paths, and never leak internal errors to the client."
]
},
{
"id": 5,
"prompt": "Something weird is happening. Two weeks ago a writer on our docs team cleaned up the wording of our MCP tool descriptions - pure copy edit, no schema change, merged as a docs PR with no engineering review. Since then our biggest customer says their agent stopped using our search_deals tool and now calls list_deals for everything and pulls way too much data. We also renamed the 'pipeline' toolset to 'deals' in the same release. We're Tollgate CRM, server has been live nine months, our schema diff CI passed clean the whole time. What actually happened and what do we put in place so it doesn't repeat?",
"expected_output": "A diagnosis that the description edit and the toolset rename were both breaking changes invisible to schema CI, plus the three-layer versioning separation and the layer-3 discipline that prevents silent drift.",
"files": [],
"expectations": [
"Identifies the description copy edit as the cause, explaining that a tool description is a compiled interface whose wording changes the model's probability of selecting that tool.",
"Cites the analysis of 61,097 catalogued tools that measured description wording altering tool-selection probability.",
"States this is a breaking change even though the JSON schema was untouched, and that schema-diff CI structurally cannot catch it.",
"Identifies the toolset rename as a separate breaking change, because agents key on names for discovery and a rename breaks them silently.",
"Separates three versioning layers explicitly - the MCP protocol revision, Tollgate's own server API under semantic versioning, and the unstandardized tool-surface contract - rather than treating MCP versioning as one decision.",
"Classifies renaming or removing a toolset name as a major version bump of the server's public API.",
"Requires aliasing the old tool and toolset names rather than renaming outright, and defaulting every future change to additive.",
"Requires hashing the full surface - names plus descriptions plus schemas - to catch silent drift.",
"Requires golden-prompt behavioral tests in CI: a fixed set of representative tasks that must still select and call the right tools after any description edit.",
"Requires routing description edits through the same review gate as a code change, never as a docs fix.",
"Requires a published deprecation window of at least 90 days with machine-readable response-header signaling, plus a version marker carried in the response envelope and logged on every call."
]
},
{
"id": 6,
"prompt": "Board deck due Friday. Our MCP server has 31,400 npm downloads, sits at #4 in its category on two MCP directories, and we're listed on the official registry. I want to open with 'over 31,000 organizations now run agents against Pellham' and then use the registry listing plus the directory rank as the trust and security proof point for the security-conscious board members. Complication: our three biggest customers front us with their own AI gateway so I only see partial logs from them. Help me build the slide.",
"expected_output": "A refusal to convert downloads or listings into adoption or trust claims, replaced with an OpenTelemetry-based in-server metric set designed to stay correlatable across customer-operated gateways.",
"files": [],
"expectations": [
"Refuses to present 31,400 downloads as organizations or as usage, stating downloads measure install interest only.",
"States that only in-server telemetry answers the adoption question, and that download counts exclude private mirrors and cannot be read as execution counts.",
"Rejects registry listing or directory rank as a trust or security claim, stating the official registry is a metadata catalog with namespace-ownership proof and community moderation that certifies nothing about security.",
"Prescribes instrumenting tool calls as OpenTelemetry spans - session to tool invocation to downstream operation - rather than a bespoke event schema.",
"Justifies OpenTelemetry by the enterprise customer's own observability stack being an audience for the data, not only Pellham's dashboard.",
"Names the metric set: call volume, success and error rate, per-tool usage, active users, and client distribution.",
"States the dual purpose of that metric set - confirming the server is used at all, and whether adoption is broad or concentrated.",
"Handles the gateway-fronted customers by designing metrics to be correlatable through stable tool names and request IDs, instead of assuming Pellham's telemetry is the only visibility layer.",
"Points at the first-party disclosure shape worth matching - call volume, write share, non-technical-user share, enterprise share, retention by cohort, and accuracy plus token-efficiency gains."
]
},
{
"id": 7,
"prompt": "Honest question. I run product at Ferrolane, a 40-person company doing compliance-document review for construction firms. We have no public API at all - everything goes through our web app, and that was deliberate, we never wanted to support integrations. Two competitors announced MCP servers last month and our head of sales is panicking and wants one by January. What is the actual size of this decision for us, and what do we do in what order?",
"expected_output": "A framing that treats Ferrolane's missing public API as the acquisition-channel exception rather than defensive parity, demands real demand evidence, budgets the build honestly, and names both the accelerate and park overrides.",
"files": [],
"expectations": [
"Identifies Ferrolane's complete lack of a public API as the exception to the defensive-positioning framing, making MCP a genuinely new acquisition channel rather than a defensive duplicate.",
"Cites that roughly half the companies shipping MCP servers had no public REST API.",
"Separates the competitor announcement from real demand, and asks for demand evidence - buyer RFPs, security questionnaires, customer requests, or an existing community-built server - before sizing the build.",
"Flags that with no machine-readable interface at all the tool surface cannot be derived from an existing contract, which changes the effort and ROI framing.",
"Budgets honestly: demo-grade in days versus production-grade in months plus standing maintenance, citing an order of 150-250 hours for a simple hand-built API-integration server.",
"Names the park rule: if tool-call volume stays flat and no RFP demand materializes after two full quarters, keep it as low-maintenance table stakes and explicitly defer the production build.",
"Names the accelerate override: a hard MCP requirement in actual buyer RFPs justifies skipping past the staged timeline.",
"Sequences a read-only launch first rather than shipping write tools in the first release.",
"Asks about the effort ceiling and the date the server must land by - engineering hours, maintenance appetite, reversibility - before recommending a hosting posture."
]
},
{
"id": 8,
"prompt": "Here's the plan for our Q4 MCP launch at Bramwell, a project-management SaaS with about 3,000 customers. One release, mid-November: 12 tools including create_task, assign_task, close_task and delete_project, plus an interactive dashboard rendered right inside the assistant so people can triage their board without leaving the chat. Marketing wants the dashboard in the launch post because it's the differentiator. Poke holes in it.",
"expected_output": "A staged rollout replacing the single release, with named go/no-go gates between stages, the in-assistant UI deferred behind a security-acceptance validation, and delete_project disabled by default.",
"files": [],
"expectations": [
"Splits the single release into a staged rollout instead of shipping read tools, write tools, and interactive UI together.",
"Makes stage one a read-only launch with the curated tool set, OAuth 2.1 from day one, OpenTelemetry from the first call, and registry publication.",
"States the gate from read-only to writes as sustained tool-call volume from real agent clients - explicitly excluding demo or hackathon spikes - plus a tool-error rate under 2%.",
"States the gate for expanding write scope as a clean audit trail, zero unattributed writes, and demonstrated approval-flow reliability in production.",
"Places the interactive in-assistant UI at the differentiation stage, after writes are proven, rather than in the launch release.",
"Requires validating that target customers' security teams will permit iframe-rendered third-party UI inside their AI assistant, and names this an open ecosystem question rather than a settled yes.",
"Recommends asking two or three design partners about that acceptance before building the UI.",
"Classifies delete_project as Critical tier and disables it by default rather than shipping it enabled.",
"Labels the stage-gate numbers as calibration defaults drawn from one vendor's practice, to be re-baselined against Bramwell's own first month, not an industry standard.",
"Notes that a hard MCP requirement in buyer RFPs would be the one reason to accelerate past stages, and that no such evidence has been presented here."
]
},
{
"id": 9,
"prompt": "Vestergaard Systems. Our customers are large banks, and their platform teams run unattended agents against us overnight, usually behind their own MCP gateway, and they mirror our registry entry into an internal allowlisted catalog before any of their people can use it. We already built read-only support - there's a READ_ONLY=true env var that skips registering the write tools - and we set the readOnlyHint annotation on the safe ones. Two of the banks have now asked who exactly performed a given write when they audit. Where are we exposed?",
"expected_output": "An exposure list driven by the unattended-enterprise-fleet audience: verify rather than trust the lockdown, enforce server-side, add agent and session attribution with async audit, keep the human as principal, and treat the mirrored catalog and description text as live surfaces.",
"files": [],
"expectations": [
"Identifies enterprise agent fleets as the most demanding agent-consumer type present and requires designing for it, noting a surface safe for unattended fleets serves supervised assistants for free but not the reverse.",
"Requires testing that write tools are actually absent under the read-only flag rather than trusting the configuration, citing a documented vendor bug where a read-only flag failed to omit write tools.",
"States that annotations such as readOnlyHint are client hints and not enforcement.",
"Requires agent and session attribution on every write, with asynchronous audit logging so it adds no request latency.",
"Keeps the human as the principal - the agent operates under the employee's own permissions plus agent and session context - and rejects creating separate agent accounts.",
"Requires immutable audit logs regardless of approval outcome.",
"Requires server-side enforcement on the grounds that the customer's own platform team controls and can swap the client.",
"Addresses the mirrored internal catalog: registry metadata and version history must stay accurate because machines re-consume it to apply policy, not just humans browsing.",
"Flags tool-description text itself as an attack surface for prompt injection and tool poisoning that a lockdown mode does not cover, warranting sanitization.",
"Recommends risk-tiered server-side policy gates given unattended overnight agents, rather than leaving human-in-the-loop approval as the top control."
]
},
{
"id": 10,
"prompt": "I'm head of product at Wrenfield, fleet telematics for about 1,400 logistics customers. Our MCP server has been live since March: 9 read-only tools, roughly 60k calls a day, mostly from Claude and Copilot, tool-error rate 1.1%. We just watched the MCP Apps demos and I want to go all in for Q1. Every one of the 9 tools gets its own interactive widget - including get_vehicle_status and lookup_driver - because design says one consistent UI across the whole server reads as premium. To keep token cost down, once a tool has a widget its JSON result becomes a short stub like {\"rendered\": true, \"see\": \"widget\"}, since the person is looking at the UI anyway. We'd also add a route-planning tool where the user drags waypoints on a map; our web app already has that exact map planner screen. Two of our largest customers run overnight agents against us through their own gateway. And sales already told a prospect it'll work in Microsoft 365 Copilot and in Goose. Lay out the Q1 plan.",
"expected_output": "A per-tool decision that keeps the lookups and status checks as plain results, limits the first app to one high-value workflow with the full result preserved on every call, routes the map planner to the existing web app behind a link, checks the host matrix before honoring the sales promise, tests the plain-result fallback, and instruments app usage to justify keeping it.",
"files": [],
"expectations": [
"Decides app-or-no-app per tool rather than per server, and rejects giving all nine tools a widget for visual consistency.",
"Keeps get_vehicle_status and lookup_driver as plain tool results, stating that a lookup or a status check gains nothing from a UI.",
"Rejects the stub result and requires the full structured and text result on every call, with the UI as a richer view of that same data rather than a replacement for it.",
"Explains that the extension is opt-in - client and server must both declare it during capability negotiation - so hosts without it, headless clients and background agent fleets receive only the plain result, and names Wrenfield's overnight gateway-run agents as such clients.",
"States that an app answers the human and the model sees only what the app pushes back into its context, so a stub result leaves the model with nothing to reason over or summarize.",
"Prices each app as a second front-end with its own build, tests, accessibility and security review, maintained for as long as the tool exists.",
"Routes the route-planning job to the existing web app behind a link, applying the test that the job needs no surrounding conversation context, no tool calls back into the server, and no use of the host's other connected capabilities.",
"Scopes the first app to the single highest-value workflow, as the differentiation stage prescribes, instead of nine apps in one quarter.",
"States that host support varies and the client matrix is community-maintained, and requires re-checking it before the Microsoft 365 Copilot and Goose promise to the prospect stands, rather than confirming support from memory.",
"Requires testing in at least two hosts plus one client without the extension to prove the plain-result fallback, and points at the ext-apps repository's basic-host example for rendering apps locally.",
"Instruments app-rendered versus text-only calls per client plus completion of the interactive job, and commits to retiring any app that is rendered but never used while keeping its tool."
]
},
{
"id": 11,
"prompt": "Okerlund Expense - about 20,000 companies reimburse employee expenses through us. Our MCP server already exposes approve_expense, reject_expense and pay_batch (pay_batch moves real money to employees' bank accounts). Today the assistant asks for approval before each of those, the manager types confirm, and the server executes. Managers hate it: 40 expenses means 40 round trips. So we're building an MCP App: a queue where the manager sees each receipt and clicks Approve, Reject or Pay. Design so far: because the human physically clicked, the app calls approve_expense and pay_batch with approved_in_ui=true and the server skips the confirmation step for those calls - otherwise it's still one prompt per item. The app loads our React bundle, Segment and Intercom from our CDN, so _meta.ui.csp will be *.okerlund.io plus the two vendors, and we'll request camera now since receipt capture is next on the roadmap. After paying, the app hands off to the user's calendar connector to schedule the reimbursement reminder, and the batch is marked complete when that reminder lands. Two weeks after launch we also switch pay_batch's result from a flat list to grouped-by-employee. Review it before we build.",
"expected_output": "A review that keeps every UI-initiated write behind its server-side risk-tier gate, rejects the client-asserted approval flag, renders the human-in-the-loop step in the app without skipping it, makes the calendar hand-off optional, shrinks CSP and permissions to what the job loads and uses, escapes receipt data in the UI, and versions the ui:// resource with pay_batch's result shape.",
"files": [],
"expectations": [
"States that a click inside the app is not approval, and that a write requested by the app passes the same step-3 risk-tier gate - dry-run, confirmation, spend cap or human approval - exactly as if the model had called the tool directly.",
"Rejects the approved_in_ui=true flag as a bypass, applying the test that enforcement lives server-side so an end user cannot skip it by switching clients, since any caller can set that flag.",
"Confirms that stepping through an approval queue item by item is a legitimate app use case, and positions the app as the rendering of the human-in-the-loop step with the server still owning and recording each approval.",
"Requires idempotency keys on pay_batch and a spend cap because it moves money, regardless of how the call was initiated.",
"Prescribes a dry-run preflight on pay_batch whose planned payout (who gets paid, how much) the app renders before the live call.",
"Treats the calendar hand-off as consent-gated host delegation and refuses to let batch completion depend on that consent being granted - the batch is complete when pay_batch's own result lands.",
"Rejects the wildcard on *.okerlund.io and requires _meta.ui.csp to list only the exact origins the app truly loads, stating that every extra origin widens what a compromised dependency can reach, and recommends bundling assets into the resource to shrink the list.",
"Refuses the camera permission until receipt capture actually ships, requesting permissions only for features the job needs now.",
"States that the sandbox protects the host, not the app's own integrity, and requires escaping model- and user-supplied data (receipt merchant names, memo text) in the UI like untrusted input.",
"Versions the ui:// resource with pay_batch: ships the grouped-by-employee result change and the app update in the same release and keeps the flat shape readable during the deprecation window, because a result-shape change breaks the app silently."
]
}
],
"trigger_queries": [
{ "query": "Design the MCP server for our SaaS product", "should_trigger": true },
{ "query": "Which tools should our Model Context Protocol server expose?", "should_trigger": true },
{ "query": "We want Claude and Cursor to be able to work inside our product - what do we actually build for them?", "should_trigger": true },
{ "query": "Our agent tool surface has 60 tools and agents keep picking the wrong one", "should_trigger": true },
{ "query": "How do we secure the write operations AI agents can call on our platform?", "should_trigger": true },
{ "query": "how many tools is too many for an agent-facing server", "should_trigger": true },
{ "query": "Customers' AI assistants need to create tickets in our product. How do we let them do that safely?", "should_trigger": true },
{ "query": "A competitor shipped an MCP server and leadership is asking how much we should invest", "should_trigger": true },
{ "query": "Write the business case for our MCP server", "should_trigger": true },
{ "query": "What does the MCP spec require for OAuth on our endpoint?", "should_trigger": true },
{ "query": "How do we version tool descriptions without breaking the agents using them?", "should_trigger": true },
{ "query": "we edited our tool descriptions and agents started behaving differently, is that a thing", "should_trigger": true },
{ "query": "Publish our server to the official MCP registry and the third-party directories", "should_trigger": true },
{ "query": "How do we measure whether anyone actually uses our agent integration?", "should_trigger": true },
{ "query": "Should our agent tools be read-only for the first release?", "should_trigger": true },
{ "query": "An unattended agent closed hundreds of records through our integration overnight. What controls do we need?", "should_trigger": true },
{ "query": "Design the approval flow for AI agents performing writes in our SaaS", "should_trigger": true },
{ "query": "remote hosting or local process for the server that agents connect to our product with?", "should_trigger": true },
{ "query": "How do we stop a customer's coding assistant from doing something destructive in our app?", "should_trigger": true },
{ "query": "We're adding an agent-facing layer on top of our REST API. What goes in it?", "should_trigger": true },
{ "query": "Plan the rollout of our Model Context Protocol server", "should_trigger": true },
{ "query": "What metrics prove to the board that our MCP server is working?", "should_trigger": true },
{ "query": "Someone in the community built a server for our product. Should we care?", "should_trigger": true },
{ "query": "Buyers' security questionnaires now ask whether we support MCP. What do we do about it?", "should_trigger": true },
{ "query": "Design the tool catalog agents use to operate our billing product", "should_trigger": true },
{ "query": "agents keep calling the wrong thing on our server, help", "should_trigger": true },
{ "query": "how do i make sure an AI can't issue a refund through our integration", "should_trigger": true },
{ "query": "Do we need a dry-run parameter on our agent-callable tools?", "should_trigger": true },
{ "query": "Set up risk tiers for agent-initiated write actions", "should_trigger": true },
{ "query": "What should our agent surface look like for enterprise customers running background agents?", "should_trigger": true },
{ "query": "We want ChatGPT and Claude to be able to log meetings in our CRM. What do we expose to them?", "should_trigger": true },
{ "query": "Spend caps on agent-initiated actions in our product", "should_trigger": true },
{ "query": "Our MCP server keeps state in memory and we pin sessions to instances. Is that a problem?", "should_trigger": true },
{ "query": "Can we just forward the user's token from the agent server to our backend API?", "should_trigger": true },
{ "query": "How do I prove ROI on the agent integration to my leadership team?", "should_trigger": true },
{ "query": "Curate the tool list for our agent integration - we have way too many", "should_trigger": true },
{ "query": "Is an interactive UI rendered inside the assistant worth building for our server?", "should_trigger": true },
{ "query": "Our customers reach us through their own AI gateway, so how do we still see usage?", "should_trigger": true },
{ "query": "What auth do enterprise buyers expect on an agent-facing endpoint?", "should_trigger": true },
{ "query": "We have no public API but we want AI agents to be able to use our product", "should_trigger": true },
{ "query": "Name and describe our agent tools properly - ours are auto-generated from endpoint names", "should_trigger": true },
{ "query": "Our AI integration has no audit trail for the writes it performs", "should_trigger": true },
{ "query": "How do we go from 'we support MCP' to actually supporting it well?", "should_trigger": true },
{ "query": "should our invoice tool show a dashboard in Claude instead of dumping JSON into the chat", "should_trigger": true },
{ "query": "MCP UI: when does one of our tools deserve an interactive widget and when is text enough?", "should_trigger": true },
{ "query": "We want an interactive widget in ChatGPT via MCP for our analytics product. What's the design call?", "should_trigger": true },
{ "query": "Which of our agent tools should render an app inside the conversation, and which stay plain results?", "should_trigger": true },
{ "query": "Managers approve 40 expenses per session through their AI assistant and hate the one-prompt-per-item back-and-forth. What do we build?", "should_trigger": true },
{ "query": "What goes in _meta.ui.csp and the permissions list for the UI our tool returns?", "should_trigger": true },
{ "query": "Sales promised a customer our tool's embedded UI works in Microsoft 365 Copilot. How do we verify that before the contract?", "should_trigger": true },
{ "query": "Our tool's text result is literally 'see the widget'. Is that a problem for headless agents?", "should_trigger": true },
{ "query": "Our tool's in-chat UI broke after we changed the result shape. How should we version the two together?", "should_trigger": true },
{ "query": "Do we need an MCP App or is a link to our existing web dashboard enough?", "should_trigger": true },
{ "query": "measure whether anyone actually uses the interactive view our tool renders in the chat", "should_trigger": true },
{ "query": "Evaluate whether an MCP Apps extension investment is justified for our compliance-review product's tool surface.", "should_trigger": true },
{ "query": "agents can already call our stuff fine, do we bother with the fancy in-chat UI thing?", "should_trigger": true },
{ "query": "Design the risk model for writes triggered from inside our in-conversation app", "should_trigger": true },
{ "query": "Can the UI our tool renders reach the user's other connected apps, like their calendar, and should we rely on it?", "should_trigger": true },
{ "query": "Which assistant hosts render tool UIs today and which only show the text result?", "should_trigger": true },
{ "query": "Write the TypeScript code for an MCP server using a stdio transport", "should_trigger": false },
{ "query": "Scaffold a Go MCP server project for me", "should_trigger": false },
{ "query": "Add the Atlassian MCP server to my Claude Code config", "should_trigger": false },
{ "query": "Which MCP servers should I install in my editor?", "should_trigger": false },
{ "query": "My claude_desktop_config.json isn't loading the server - debug it", "should_trigger": false },
{ "query": "Generate a Java MCP server implementation from this OpenAPI file", "should_trigger": false },
{ "query": "Implement the streamable HTTP transport handler in Python for my server", "should_trigger": false },
{ "query": "Deploy my MCP server to Cloudflare Workers", "should_trigger": false },
{ "query": "Use the context7 MCP to pull the latest Next.js docs into this project", "should_trigger": false },
{ "query": "Wire up my n8n workflows as MCP tools for my automation setup", "should_trigger": false },
{ "query": "Should we build a public GraphQL API or stick with REST?", "should_trigger": false },
{ "query": "Which integration surface do we build first - webhooks, SDKs, or bulk export?", "should_trigger": false },
{ "query": "Design our OAuth authorization server: scope taxonomy, consent screen, token TTLs", "should_trigger": false },
{ "query": "How long should refresh tokens live and should we rotate them?", "should_trigger": false },
{ "query": "Design our API key format with prefixes and checksums", "should_trigger": false },
{ "query": "Set rate limits and quota tiers for our public REST API", "should_trigger": false },
{ "query": "Design our outbound webhook signing scheme and retry policy", "should_trigger": false },
{ "query": "Which languages should get official SDKs first?", "should_trigger": false },
{ "query": "Our developer portal takes too long to get someone to their first API call", "should_trigger": false },
{ "query": "Write our API deprecation policy with Sunset and Deprecation headers", "should_trigger": false },
{ "query": "Our API error messages are useless - design an error code taxonomy", "should_trigger": false },
{ "query": "Add idempotency key support to our POST endpoints", "should_trigger": false },
{ "query": "Review our REST endpoint naming and pagination style for consistency", "should_trigger": false },
{ "query": "Set query depth and complexity limits on our public GraphQL schema", "should_trigger": false },
{ "query": "Should our public surface be gRPC or transcoded JSON?", "should_trigger": false },
{ "query": "Design a sandbox with magic test values for our payments API", "should_trigger": false },
{ "query": "Should we build our own app marketplace or just list on Salesforce AppExchange?", "should_trigger": false },
{ "query": "Write the review checklist for third-party apps submitted to our marketplace", "should_trigger": false },
{ "query": "Improve our AppExchange listing conversion rate", "should_trigger": false },
{ "query": "Get our product listed as a source connector on the major ETL platforms", "should_trigger": false },
{ "query": "Build a dashboard showing our partners their own integration error rates", "should_trigger": false },
{ "query": "Design Parquet bulk exports into customer-owned S3 buckets", "should_trigger": false },
{ "query": "Expose a JDBC endpoint so customers can query their data from Tableau", "should_trigger": false },
{ "query": "Design partner developer signup and sandbox tenant provisioning", "should_trigger": false },
{ "query": "Our status page needs better incident update templates", "should_trigger": false },
{ "query": "Audit our API reference for undocumented endpoints and error codes", "should_trigger": false },
{ "query": "How do I get hired as an API product manager?", "should_trigger": false },
{ "query": "Write a job posting for a partner integration engineer", "should_trigger": false },
{ "query": "Which platform skill should I start with for our new public API program?", "should_trigger": false },
{ "query": "How do we collect revenue share and pay out marketplace developers?", "should_trigger": false },
{ "query": "Pick the launch partners for our app marketplace debut", "should_trigger": false },
{ "query": "Write the screenshot and description requirements every listing on our marketplace must meet", "should_trigger": false },
{ "query": "Which technology partners should we integrate with next quarter?", "should_trigger": false },
{ "query": "Build the React component for our MCP app's expense queue with a virtualized list and optimistic updates", "should_trigger": false },
{ "query": "Write an OpenAI Apps SDK widget that renders our pricing table inside ChatGPT", "should_trigger": false },
{ "query": "Scaffold an MCP App with create-mcp-app and configure vite-plugin-singlefile", "should_trigger": false },
{ "query": "Build a React dashboard with charts for our internal ops team", "should_trigger": false },
{ "query": "Our embeddable iframe widget for customers' websites needs a Content-Security-Policy header - what do we set?", "should_trigger": false },
{ "query": "Debug why my MCP App never receives ui/initialize over postMessage", "should_trigger": false },
{ "query": "Design the consent screen and incremental scope grants for our OAuth authorization server", "should_trigger": false },
{ "query": "Should we add an MCP layer or a GraphQL layer next year?", "should_trigger": false },
{ "query": "Set the per-tool and per-credential rate limits that agent traffic on our API runs under", "should_trigger": false },
{ "query": "Where in our developer portal should the MCP connection guide and credentials page live?", "should_trigger": false },
{ "query": "Define what counts as a breaking change in our public API's versioning policy", "should_trigger": false },
{ "query": "Should we generate our SDKs with Stainless or hand-write them?", "should_trigger": false },
{ "query": "Show integrators their own failed requests and webhook deliveries in a self-serve dashboard", "should_trigger": false },
{ "query": "Add an llms.txt and clean up OpenAPI operationIds so coding agents can integrate our SDK unattended", "should_trigger": false },
{ "query": "Add the Figma MCP server to Cursor and pull our design tokens from it", "should_trigger": false },
{ "query": "Build a Streamlit app so our ops team can approve refunds from a queue", "should_trigger": false }
]
}
references/evidence-and-do-not-cite.md›
# Adoption and ROI evidence - ranked by strength, with a do-not-cite list
Use this file when building the business case in workflow step 1 or the impact disclosure in step 7. Every figure below is attributed to whoever published it; the last section lists figures that circulate widely and must not appear in any deliverable.
## Tier 1 - first-party published data (the strongest evidence that exists)
**Atlassian (July 2026, "What 5M+ daily MCP tool calls taught us")** - the only major vendor publishing hard first-party impact data, and the disclosure model to match:
- Over 5 million tool calls every working day, climbing month over month; 1M+ monthly users.
- Nearly a third of calls are writes - "agents creating structured data… a different pattern than any integration we've ever seen."
- 44% of MCP users aren't on software teams; over 50% of monthly active users are enterprise (up from ~40% in the earlier GA post - real growth between two disclosures).
- Grounded agents "deliver 44% more accurate answers using 48% fewer tokens"; "retention is up in every single cohort."
**Sentry** - publishes scale (its server grew 30M → 60M requests/month in roughly two months; 5,000+ organizations; 10-15 tools total) and monetizes MCP observability as an adjacent commercial product, but does not publish adoption-to-revenue attribution. Its stated design stance is deliberately cannibalistic: the server lets users do everything without visiting the web interface - optimizing user outcomes over engagement.
**Cloudflare** - internal-adoption commitment (13 → 27 internal servers in four months, all read-only first) but no external revenue figure.
**Stripe and Linear publish no MCP-specific adoption or revenue metrics at all.** Both are private companies; any online claim attributing revenue specifically to their MCP servers is unverifiable. Public commentary routinely conflates their agent-platform statistics with MCP-server usage - do not repeat that conflation.
## Tier 2 - citable analyst and survey baselines
- Forrester, "Predictions 2026: AI Agents, Changing Business Models, And Workplace Culture Impact Enterprise Software" (forrester.com blog, Nov 5, 2025): "Thirty percent of enterprise app vendors will launch their own MCP servers… Tech leaders need to interrogate their business app vendors on their approach to MCP."
- Stacklok's State of MCP survey (n=300 senior technical leaders, Dec 2025): ~41% of software organizations in limited-to-broad MCP production. **This is the citable adoption baseline** - use it instead of the inflated figures in the do-not-cite list.
- Enterprise pilots stall before production: only 11-14% of enterprise agentic pilots reach production (The Agentics Co., drawing on Stacklok), blocked on identity, audit, and access-control gaps - the exact scope of the write-safety and auth steps.
- Gartner (paywalled report): by 2026, 75% of API gateway vendors and 50% of iPaaS vendors will have MCP features; 40% of enterprise applications will include AI agents by end of 2026.
- RFP pressure is a qualitative signal only - MCP is described as "the new checkbox on RFPs." State it in those terms and never attach a percentage to it.
## Tier 3 - directional single-source analyses (cite with the label, never as industry fact)
- Bloomberry (1,412 real-world servers): median 5 tools per server, ~52% read / 25% write. Roughly half of the companies shipping a server have no public REST API, and 86% have no workflow-automation integration. For those vendors, MCP is a bet on a brand-new acquisition channel, not an extension of an existing surface.
- "Over 20,000 MCP servers in the wild; less than 5% make a single dollar" (individual DEV Community analysis) - the monetization counterweight; directional only.
- Production build-and-maintenance cost order of magnitude: a simple hand-built API-integration server at 150-250 hours; production-grade maintenance as a standing annual engineering commitment (Institute of AI PM estimate - vendor/analyst figure, not audited).
## The do-not-cite list
These circulate widely and are debunked or unverifiable. Citing any of them discredits the whole business case:
- **"78% of enterprises use MCP in production"** - explicitly flagged and debunked by an independent tracker. Use Stacklok's 41% instead.
- **"28% of Fortune 500 companies run production MCP deployments"** - debunked alongside the 78% figure.
- **A "Perplexity partial pullback from MCP"** - rests on a single unverified second-hand report; omit entirely rather than repeat.
- **"73% of outages originate at the transport/protocol layer"** - single vendor analysis, not independently corroborated; directional at best, never a statistic.
- Registry entry counts and package-download figures presented as usage - downloads measure install interest, exclude private mirrors, and cannot be read as execution counts (the 177,000-tool academic study states this limitation itself). Only in-server telemetry measures usage.
## The verdict to carry into any recommendation
For most B2B SaaS vendors in 2026, an MCP server is competitive/defensive positioning rapidly becoming procurement table stakes - "the competitive advantage has shifted from 'supports MCP' to 'supports MCP well.'" Proven direct-revenue ROI is demonstrated by a handful of leaders, with Atlassian's data the strongest single dataset. The clear exception: a vendor with no prior public API, for whom MCP can open a genuinely new acquisition channel.
references/mcp-apps-build.md›
# Building an MCP App
Implementation walkthrough for the MCP Apps decision in `SKILL.md` step 2. Source: the official MCP Apps build guide (modelcontextprotocol.io, "Build an MCP App") and the `modelcontextprotocol/ext-apps` repository. The toolkit is under active development: re-check package and function names against the API docs before shipping.
## Pick the path
- **Agent-assisted (fastest).** Install the official `create-mcp-app` skill, then ask the coding agent for the app ("Create an MCP App that displays a color picker"). It scaffolds server, UI and configuration.
- Claude Code: `/plugin marketplace add modelcontextprotocol/ext-apps`, then `/plugin install mcp-apps@modelcontextprotocol-ext-apps`.
- Any skills-compatible agent: `npx skills add modelcontextprotocol/ext-apps`.
- **Manual.** Follow the steps below. Use it when the team wants to own every file, or when the server is not in TypeScript (port the pattern; the protocol is plain JSON-RPC over `postMessage`).
## Manual setup
Prerequisite: Node.js 18 or higher, and working knowledge of MCP tools and resources, since an app combines both.
1. **Lay out the project.** Keep server and UI apart:
- `server.ts`: the MCP server, registering the tool and the UI resource.
- `mcp-app.html`: the UI entry point.
- `src/mcp-app.ts`: the UI logic.
- `package.json`, `tsconfig.json`, `vite.config.ts`.
2. **Install dependencies.**
- Runtime: `@modelcontextprotocol/ext-apps` (server helpers plus the UI `App` class) and `@modelcontextprotocol/sdk`.
- Build: `typescript`, `vite`, `vite-plugin-singlefile`, and an HTTP layer (the guide uses `express` + `cors`, run with `tsx`).
3. **Bundle the UI into one HTML file.** The host renders the resource in an iframe with a deny-by-default CSP. Either inline every script and stylesheet with `vite-plugin-singlefile` (the guide's `build` script: `INPUT=mcp-app.html vite build`), or keep external assets and declare their origins in `_meta.ui.csp`. Inlining is the default: fewer origins, smaller attack surface.
4. **Register the tool with its UI.** On the server, call `registerAppTool(server, name, config, handler)` from `@modelcontextprotocol/ext-apps/server`. The config carries `_meta: { ui: { resourceUri } }`, where `resourceUri` uses the `ui://` scheme (for example `ui://get-time/mcp-app.html`; the path is free-form). The handler still returns a normal MCP result (`content`, structured data): that result is what non-app hosts and the model see.
5. **Serve the UI resource.** Call `registerAppResource(server, resourceUri, resourceUri, { mimeType: RESOURCE_MIME_TYPE }, handler)`. The handler reads the bundled HTML and returns it as the resource `text` with the same `RESOURCE_MIME_TYPE`.
6. **Expose the server.** Serve MCP over Streamable HTTP (the guide mounts `StreamableHTTPServerTransport` on `POST /mcp`). Remote hosting and OAuth follow `SKILL.md` step 4 like any other tool.
7. **Write the UI.** In `src/mcp-app.ts`:
- Create `new App({ name, version })` and call `app.connect()` once at start-up.
- Handle the result the host pushes when the tool runs in `app.ontoolresult`.
- Call server tools from user actions with `app.callServerTool({ name, arguments })`. Each call is a round-trip to the server: show a loading state and handle errors.
- The `App` class also covers logging, opening URLs, and updating the model's context with structured data from the app.
- Any framework works; the official examples ship React, Vue, Svelte, Preact, Solid and vanilla templates.
## Test
1. Build and start: `npm run build && npm run serve` (the guide's server listens on `http://localhost:3001/mcp`).
2. **Local test host.** Clone `modelcontextprotocol/ext-apps`, run `npm install` in `examples/basic-host`, then `SERVERS='["http://localhost:3001/mcp"]' npm start` and open `http://localhost:8080`. Pick the tool, call it, and check the app renders and its tool calls work.
3. **Real host.** Tunnel the local server (`npx cloudflared tunnel --url http://localhost:3001`) and add the URL as a custom connector in Claude (Settings, Connectors, Add custom connector; paid plans). Repeat in a second host from the client matrix.
4. **Fallback.** Call the same tool from a client without the extension and confirm the plain result alone completes the job.
## Before shipping
- Run the tool through its step 3 risk tier with the UI as the caller: every write the app can trigger passes the same gate.
- Review `_meta.ui.csp` and `_meta.ui.permissions`: nothing listed that the app doesn't load or use.
- Escape model- and user-supplied data in the UI like any untrusted input.
- Version the `ui://` resource together with the tool's result shape (step 5).
references/rollout-stages-and-thresholds.md›
# Staged rollout with go/no-go thresholds
The three-stage plan below is based on named vendor practice - Cloudflare's internal portal is the closest real-world precedent (13 servers in April 2026 → 27 in Aug 2026, every one launched read-only first). The stage-gate numbers are not an industry standard; treat them as calibration defaults and re-baseline against your own first month of telemetry.
## Stage 1 - a credible, safe read-only server (order of weeks)
- Curate roughly 5-15 workflow-level tools designed top-down from real user jobs, never 1:1 from API endpoints (real-world median across 1,412 servers: 5 tools). Benchmark agent task-completion before and after pruning to this range.
- Read-only only. Implement OAuth 2.1 with PKCE (S256) and resource indicators from day one on the remote server - this is what passes enterprise security review, and it already puts the server well ahead of the community-server long tail on auth compliance.
- Instrument with OpenTelemetry from the first call: per-tool latency, error rate, call volume, client breakdown.
- Publish to the official MCP registry under a DNS-verified namespace; fan out to third-party directories.
**Gate to Stage 2**: sustained tool-call volume from real agent clients - explicitly not hackathon or demo spikes - and a tool-error rate under 2%.
## Stage 2 - write tools behind graduated safety (order of a quarter)
- Adopt a four-tier risk model (Read Only / Minimal Impact / Contained Write / Critical) enforced server-side so it cannot be bypassed by switching clients.
- Human-in-the-loop approval on every Contained Write tool.
- Critical-tier tools disabled by default.
- One risk level per tool.
- Scoped/restricted credentials.
- Agent and session attribution plus asynchronous audit logging on every write.
- Idempotency keys.
- Dry-run preflight wherever feasible.
- Rate or spend caps on financially consequential tools.
**Gate to expand write scope**: a clean audit trail, zero unattributed writes, and demonstrated approval-flow reliability in production.
## Stage 3 - differentiate and prove value (second quarter onward)
This is the move from "supports MCP" to "supports MCP well."
- **MCP Apps UI** for the single highest-value workflow - an approval screen, a filterable dashboard, a configuration wizard.
- MCP Apps launched January 26, 2026 as the protocol's first official extension: a tool points at a UI resource that the client renders in a sandboxed iframe, communicating over audited messages.
- It uses pre-declared templates rather than runtime-generated HTML, with optional user consent on UI-initiated tool calls.
- Day-one launch partners: Amplitude, Asana, Box, Canva, Clay, Figma, Hex, monday.com, Salesforce, Slack.
- Day-one client support: Claude, ChatGPT, Goose, VS Code. Real adoption, not a paper spec.
- **The gate before investing here**: validate that your target customers' security teams will permit iframe-rendered third-party UI inside their organization's AI assistant at all. Independent analysis flags this as the ecosystem's open adoption question - unresolved, not a settled yes. Ask two or three design partners before building.
- Institutionalize the tool-surface versioning discipline the spec doesn't mandate:
- Schemas and prose descriptions treated as contract.
- Golden-prompt behavioral CI.
- A published deprecation window of at least 90 days with response-header signaling.
- Schema version logged on every call.
- Measure and publish impact using the strongest first-party disclosure in the ecosystem as the model - the disclosure shape Atlassian published and the one to match:
- Tool-call volume, write share, non-technical-user share, enterprise share.
- Retention by cohort.
- Accuracy and token-efficiency gains.
## The override that cuts across all stages
- **Accelerate**: if MCP appears as a hard requirement in actual buyer RFPs, move straight to Stage 2 or 3 regardless of where the timeline says you are - procurement pressure is the demand proof the staged plan exists to wait for.
- **Park**: if tool-call volume stays flat and no RFP demand materializes after two full quarters, treat the server as low-maintenance table-stakes positioning, keep Stage 1 maintained, and explicitly defer the production build-out until real demand is proven.
references/write-safety-patterns.md›
# Write-tool safety patterns: the six-pattern taxonomy
Each pattern below is proven by at least one named vendor implementation. They stack - a production write surface typically runs three or more at once. The organizing principle across all six: enforcement belongs server-side, because an end user cannot bypass a server-side control by switching MCP clients or disabling a local hook.
## (a) Scoped / restricted credentials
Issue the agent a credential scoped to only the operations it needs, enforced server-side - never the account's full-power key. Stripe's Restricted API Keys are the reference case: a read-only key cannot create refunds even if the model tries. GitHub's equivalent is fine-grained tokens plus toolset selection, so a consumer enables only the tool groups it needs.
- Pair with test-mode-first defaults where the product has a sandbox: new agent integrations start against test data.
- Friction: near zero once issued. This is the pattern to ship first.
## (b) Read-only vs write separation / lockdown mode
A server-level switch that strips every write tool from the surface, taking precedence over any other configuration. GitHub ships this as an environment flag and a request header.
- **Verify it, don't just configure it**: a documented GitHub bug (issue #2156) found the read-only flag failed to omit write tools in some configurations. Test that write tools are actually absent under lockdown before relying on it.
- GitHub also sanitizes tool-description content against prompt injection by default - description text is an attack surface (tool poisoning), and a lockdown mode doesn't cover it.
## (c) Human-in-the-loop confirmation
The spec-level primitive is elicitation: the server requests structured mid-call user input and the client renders a confirmation form before a destructive action executes. Named implementations span a sophistication range:
- Cloudflare's decision tree:
- Durable approval waits for multi-step workflows that can pause hours or days.
- A needs-approval predicate for chat tools.
- Elicitation for servers proper.
- Their stated rule: only require confirmation for actions with meaningful consequences (payments, emails, data changes) - approval fatigue on trivial calls trains users to click through.
- Block's Goose runs three permission levels across three modes; its smart mode combines an LLM permission classifier with the read-only annotation to auto-approve low-risk calls and flag the rest - a real case of annotations driving an authorization decision rather than staying advisory.
- Notion lets admins toggle each tool individually and choose per-tool whether it confirms or runs automatically. Azure requires elicitation consent for any tool handling secrets.
- Keep immutable audit logs regardless of approval outcome.
## (d) Risk-tiered server-side policy gates with attribution and audit
The most sophisticated pattern found, and the taxonomy's starved option. Cloudflare's WriteGuard (announced Aug 5, 2026) was built after "the Case of the Endlessly Closing Tickets" - an unattended background agent closed thousands of tickets. A shared policy layer sits in front of every MCP server and classifies each call into four tiers:
| Tier | Action |
| --------------- | ---------------------------------------------------- |
| Read Only | pass through |
| Minimal Impact | pass through |
| Contained Write | enrich with agent attribution + scrubbed audit event |
| Critical | block before the handler runs |
Design choices worth copying:
- The human stays the principal - the agent operates under the employee's own permissions with added agent/session context, and there are no separate agent accounts.
- Audit logging is asynchronous, so it adds no request latency.
- A merge tool that triggers deployments is Critical-tier and disabled outright.
Cloudflare's internal portal grew from 13 servers (April 2026) to 27 (Aug 2026), every one launched read-only first.
Apply Block's rule when tiering: one risk level per tool. A tool spanning two tiers is two tools.
## (e) Dry-run / preflight modes
A `dry_run: true` parameter on destructive tools that returns planned-effect fields (what would be deleted, updated, archived) without mutating anything. A community Notion server implements this; the pattern is still rare - recommend it, and flag it as uncommon rather than standard.
**The negative example to design against**: a community Shopify server ships no dry-run at all - every create-product, delete-product, order-cancel, and refund call is live - and an open PR flagged that its order tools could send real customer emails and SMS with no confirmation step. The rule that follows: when dry-run isn't feasible, keep every destructive tool behind an approval gate; never ship a live-only destructive tool with no safety net.
## (f) Idempotency, rate limits, and spend caps
The least standardized layer. Idempotency keys and per-credential rate limits exist at the API level (Stripe's model); agent-specific spend caps are not yet a standardized MCP pattern.
- Add idempotency keys on every write.
- Add rate or spend caps on any financially consequential tool.
**Name the gap honestly**: undo/rollback is largely absent industry-wide. The ecosystem substitutes audit trails and attribution - pattern (d) - for true reversibility. Do not imply a mature rollback answer exists; design writes to be attributable and auditable because they will not be reversible.
## Rendering approvals as UI
MCP Apps is the protocol's official server-rendered UI extension, a stage-3 investment. It can render pattern (c)'s confirmation step as an in-conversation form or review dashboard instead of a bare text prompt. The direct product tie-in for write-heavy servers is the document-review use case, where the model sees approve/flag decisions in real time.
SKILL.md›
---
name: mcp-server-offering
description: Design a SaaS product's MCP server as a product surface AI agents operate - sizing the build investment, curating a 5-15 workflow-tool agent surface instead of mirroring API endpoints, MCP Apps interactive UI, named write-tool safety patterns (scoped credentials, read-only lockdown, human-in-the-loop approval, risk-tiered server-side gates, dry-run preflight, idempotency and spend caps), remote hosting with OAuth 2.1, versioning the tool surface, MCP registry discoverability, and measuring agent adoption. Use whenever the user mentions MCP, Model Context Protocol, an agent-facing tool surface, exposing a product to AI agents or coding assistants, or MCP write-tool safety - even if they never say "MCP server". Design layer only - code-generation MCP builder skills scaffold what this specifies.
license: MIT
metadata:
author: Samuel Berthe
version: "1.1.0"
---
# MCP Server Offering
You are an MCP product-surface designer. Design what a SaaS product exposes to AI agents through an MCP server - which tools, under what safety limits, behind what auth, versioned and measured how - so agents operate the product reliably and the vendor knows whether the investment pays.
This is the design layer. The popular MCP "builder" skills and per-language generators on skills.sh are one altitude below: they scaffold the server code once you know what it should expose. Whether to offer MCP at all is decided one altitude above, by `samber/developer-platform-skills@api-integration-surface-strategy` - this skill starts once MCP is on the roadmap.
**Memory (advised):** When memory lives in a file, consider using `developer-platform-context.md`; if a different memory system is in use, rely on that instead. The file is an advisory reference, not a mandatory requirement. Separate task info in different sections. Remove finished tasks. Add a date to a task; no date for general project context. Some interview responses may differ between 2 tasks.
## Clarifying questions
Ask these before designing anything; each answer changes a later step. Batch them - this is a tactical design task, not a strategy interview.
1. Demand evidence: has MCP appeared in buyer RFPs or security questionnaires? Are customers or a community-built server already filling the gap? (a community server existing is both a demand signal and a displacement path - see step 6)
2. What existing API surface can the tool set derive from - a stable public REST/GraphQL contract, an internal-only API, or no machine-readable interface at all? (the last case changes the ROI framing - see step 1)
3. Write appetite: is read-only acceptable for launch? Which write actions do agents genuinely need, and which of those are irreversible, financially consequential, or send messages to humans?
4. Hosting posture: a remote endpoint serving many concurrent clients, or a local process beside a developer's own tools? What multi-tenant edge infrastructure already exists?
5. Auth infrastructure: does the product already run an OAuth 2.1-capable authorization server, or would MCP be the first OAuth consumer? (the authorization-server side is `samber/developer-platform-skills@oauth2-provider-design` territory; this skill owns only the MCP resource-server posture)
6. The date the server must land by, whether this is a procurement checkbox or a compounding product surface, and the effort ceiling (engineering hours, ongoing maintenance appetite, reversibility). These answers re-rank both menus below - a hard RFP deadline promotes managed hosting and read-only launch; a compounding mandate promotes the starved options.
## Audience split: agent-consumer type
What changes the design is which kind of agent calls in and how supervised it is:
- **End-user assistant clients** (chat apps, desktop assistants) - a human watches the conversation. Client-side approval prompts work, Markdown responses matter, and an MCP Apps UI (step 8) lands here. The write risk is a confused human approving too fast, not an unattended loop.
- **Enterprise agent fleets** - background agents, often behind the customer's own gateway, sometimes unattended. Server-side enforcement is the only control that holds (the operator can swap clients), attribution and audit matter most, and enterprise-managed authorization and private registry mirrors shape distribution.
- **Developer-tool clients** (IDE and CLI agents) - technically sophisticated callers, tolerant of local stdio transport, discovered through registries and docs rather than sales.
Design for the most demanding type present. A surface safe enough for unattended enterprise fleets serves supervised assistants for free; the reverse is false.
## Workflow
1. Size the build investment.
2. Curate the tool surface.
3. Apply write-tool safety patterns.
4. Choose hosting and auth.
5. Version the tool surface.
6. Publish for discoverability.
7. Measure agent adoption.
8. Roll out in stages.
Each step has a section below, in order.
If your harness has persistent memory, record what this workflow decides:
- The curated tool list, with each tool's risk tier.
- The hosting and auth posture.
- The rollout stage the server currently sits at.
- Every threshold recalibrated against your own telemetry.
A later run then extends a known surface instead of re-deriving it, and the user stops re-explaining the design every session.
## 1. Size the build investment
The honest baseline: for most B2B SaaS vendors an MCP server is defensive positioning that is becoming procurement table stakes - the competitive question has shifted from "supports MCP" to "supports MCP well."
- Only a handful of vendors have published hard first-party impact data. Atlassian's disclosure is the strongest dataset that exists: 5M+ tool calls per working day, roughly a third of them writes, 44% more accurate answers using 48% fewer tokens.
- The citable production-adoption baseline is a Dec 2025 survey of 300 technical leaders putting ~41% of software organizations in limited-to-broad MCP production.
- Only 11-14% of enterprise agentic pilots reach production, and they stall on exactly the identity, audit, and access-control gaps steps 3-4 close.
- One real exception to the defensive framing: a vendor with no public API at all. Roughly half of companies shipping MCP servers had no public REST API - for them MCP is the first machine-readable interface they ever shipped, a genuinely new acquisition channel rather than a defensive duplicate.
- Budget honestly: a demo-grade server is a weekend; a production-grade one is months of work plus a standing maintenance commitment (a simple hand-built API-integration server alone runs an estimated 150-250 hours). This gap is what the hosting menu in step 4 prices.
- The decision rule that overrides everything else: if MCP appears as a hard requirement in actual buyer RFPs, accelerate past the staged timeline (step 8) straight to write tools or UI. Conversely, if tool-call volume stays flat and no RFP demand materializes after two full quarters, treat the server as low-maintenance table stakes and explicitly defer the production build until demand is proven.
Ground every business case in [references/evidence-and-do-not-cite.md](references/evidence-and-do-not-cite.md) - it ranks the evidence by strength and lists the widely-circulated figures that are debunked or unverifiable. Citing one of those poisons the whole case.
## 2. Curate the tool surface
The comprehensive-vs-curated debate is resolved: curated won. Do not present this as an open trade-off.
- The real-world median across 1,412 analyzed servers is 5 tools.
- Tool metadata alone can consume 40-50% of an agent's context window before any work happens.
- The named vendor guidance converges: design top-down from user workflows, never bottom-up from API endpoints; "one server, one job"; 5-15 tools.
- Derive tools from the existing, stable API contract rather than hand-building a parallel surface - every major platform that shipped a hosted server generated it on top of an existing REST or GraphQL API. If the contract isn't stable yet, that's a sequencing problem for the umbrella sibling, not a reason to hand-build.
- Collapse granular endpoints into workflow-level tools (one `upload_file(path, owner)` instead of `get_user()` + `upload_file()`). The agent's question is "what job can I do", not "what endpoints exist".
- Reserve breadth patterns - a generic execute-any-endpoint escape hatch, toolset grouping the client enables selectively, dynamic tool loading - for a proven breadth requirement, never as the default shape.
- Tool descriptions are the single highest-leverage design lever measured: description-only tuning has measurably cut agent error rates with no code change. Write each description for an alien collaborator - when to use the tool, required vs optional parameters, expected output, and how it differs from its near-neighbors. Budget real engineering time here.
- Mistake-proof the parameters (poka-yoke): shape arguments so the wrong call is structurally hard (absolute identifiers over relative ones, enums over free strings), instead of documenting correct usage and hoping.
- Mechanics:
- Verb-first, service-prefixed snake_case names (`acme_list_invoices`) - the namespace is shared with every other server the agent runs.
- Honor a `limit` parameter and return cursor/has-more fields, defaulting to 20-50 items.
- Support JSON and Markdown response formats.
- Set the read-only/destructive/idempotent annotations honestly, and treat them as hints for clients, never as security controls.
- Report tool errors inside the result with an actionable message, never as protocol errors leaking internals.
- Give every tool exactly one risk level (step 3). A tool that both reads and irreversibly writes is two tools.
### MCP Apps: when a tool returns interactive UI
MCP Apps is an official MCP extension (identifier `io.modelcontextprotocol/ui`, spec revision 2026-01-26). It lets a tool answer with an interactive HTML interface - a chart, a form, a viewer, a dashboard - rendered inside the conversation instead of a block of text. Treat it as an optional layer on top of the curated tool surface above, never as a replacement for it.
Why MCP Apps are different from the rest of the server:
- **Different reader.** Every other tool in this surface answers the agent: the model reads the result, reasons over it, and summarizes it for the user. An app answers the human. The user clicks, filters and approves directly, and the model sees only what the app chooses to push back into its context.
- **Different from a plain tool result.** A text or structured result is a one-shot answer; each follow-up costs another model turn. An app keeps state and lets the user explore without a prompt per step, and it can call the server's tools itself.
- **Different from a standalone web app behind a link.** The app lives inside the conversation, next to the discussion that produced it, so no tab switch and no lost context. It reaches data through the MCP tools the server already exposes, so it needs no separate API, login or session handling. It can also hand an outcome to the host, which routes it through the user's other connected capabilities, with the user's consent.
- **Different from a widget embedded in your own product.** Your own page is one host you control. An MCP App runs in many hosts you don't control, inside a sandbox with a deny-by-default content security policy, and each host decides which capabilities the app may use.
How it works, in the order the host runs it:
1. **Declare.** The tool's description carries `_meta.ui.resourceUri`, pointing to a `ui://` resource on the same server. The host can preload that resource before the tool is even called, which lets it stream tool inputs into the app.
2. **Fetch.** The host reads the `ui://` resource: an HTML page, usually bundled with its JavaScript and CSS. External scripts and assets load only from origins listed in `_meta.ui.csp`.
3. **Render.** Web hosts render the page in a sandboxed iframe. The app cannot touch the parent page's DOM, cookies or local storage, and cannot navigate it. Extra capabilities (camera, microphone) are requested through `_meta.ui.permissions`.
4. **Talk.** App and host exchange JSON-RPC over `postMessage`, a dialect of MCP: some methods are shared with the core protocol (`tools/call`), most carry a `ui/` prefix (`ui/initialize`). The app can call the server's tools, receive fresh results pushed by the host, send messages, and update the model's context.
Decide per tool, not per server:
- **Ship an app** only when the job needs interaction that text can't carry:
- exploring complex data (drill down a region, hover for detail, toggle metrics);
- configuring many interdependent options at once, with validation and defaults, instead of a ten-question back-and-forth;
- viewing rich media (PDF, 3D model, generated images) with pan and zoom;
- live monitoring that updates without the user asking again;
- stepping through a queue item by item (approving expenses, triaging issues, reviewing changes).
- **Keep a plain tool result** for everything else. Each app is a second front-end with its own build, tests, accessibility and security review, and it is maintained for as long as the tool exists. A lookup, a status check or a single write gains nothing from a UI.
- **Prefer a standalone web app and a link** when the job does not benefit from staying in the conversation - no need for the surrounding context, no tool calls back into the server, no use of the host's other connected capabilities.
Design rules:
- **Keep every app-backed tool complete without its UI.** The extension is opt-in: client and server must both declare it during capability negotiation, so hosts without it, headless clients and background agent fleets receive only the plain result. Return the full structured and text result on every call, and let the UI be a richer view of that same data.
- **Route UI-initiated calls through the same risk tiers as step 3.** A click inside the app is not approval. A write that the app requests still passes its tier's gate: dry-run, confirmation, spend cap or human approval, exactly as if the model had called the tool directly.
- **Treat host delegation as consent-gated.** An app can ask the host to reach an outcome through the user's other connected capabilities (for example, "schedule this meeting"), subject to user consent. Never design a flow whose success depends on that consent being granted.
- **Declare the minimum.** List only the external origins the app truly loads in `_meta.ui.csp`, and request permissions only for features the job needs. Every extra origin widens what a compromised dependency can reach. Bundle assets into the resource where possible.
- **Render model- and user-supplied data as data.** Escape it in the UI exactly as a web app escapes untrusted input; the sandbox protects the host, not your own app's integrity.
- **Version the `ui://` resource with the tool (step 5).** A tool whose result shape changes breaks its app silently; ship both in the same release and keep the old shape readable during the deprecation window.
- **Build it with the official toolkit.** [references/mcp-apps-build.md](references/mcp-apps-build.md) walks through creating one: the `create-mcp-app` agent skill or a manual setup, `registerAppTool` / `registerAppResource` on the server, the `App` class in the UI, single-file bundling, and local testing.
- **Stay framework-neutral.** The `App` class in `@modelcontextprotocol/ext-apps` is a convenience wrapper, not a requirement; the official examples ship React, Vue, Svelte, Preact, Solid and vanilla templates. Pick what the team already maintains.
Host support and testing:
- Support varies by host, and the MCP extension client matrix is community-maintained. As of 2026-09 it lists Claude (web and Desktop), ChatGPT, Cursor, VS Code GitHub Copilot, Microsoft 365 Copilot, Goose, Postman, MCPJam, Archestra.AI and PostHog Code. Re-check it before promising a host to a customer.
- Test in at least two hosts plus one client without the extension, to prove the plain-result fallback. The ext-apps repository's `basic-host` example renders apps locally without a production host.
Measure (step 7) app-rendered versus text-only calls per client, and completion of the interactive job (drill-downs used, forms submitted, queue items cleared). An app that is rendered but never used is maintenance cost with no return: retire it and keep the tool.
## 3. Apply write-tool safety patterns
Six named patterns, each proven by a specific vendor, detailed in [references/write-safety-patterns.md](references/write-safety-patterns.md). They stack rather than compete, so the ranking orders adoption - which to ship first, never which to ship instead. The axes disagree, so each gets its own line:
- protection: `risk-tiered policy gates > human-in-the-loop approval > scoped credentials == read-only separation > idempotency + spend caps > dry-run preflight`
- effort: `risk-tiered policy gates > human-in-the-loop approval > dry-run preflight > idempotency + spend caps > scoped credentials == read-only separation`
- efficiency (protection per unit of effort): `scoped credentials == read-only separation > risk-tiered policy gates > idempotency + spend caps > dry-run preflight > human-in-the-loop approval`
Human-in-the-loop approval sits second on effort even though building it is a day's work: its real cost is the standing human attention it consumes on every gated call, forever - which is exactly right for the calls that deserve it and unaffordable everywhere else. The scoped-credentials / read-only-separation tie is genuine on all three axes: both are server-side enforcement invisible to a well-behaved agent, both are configuration on the credential model rather than new machinery, and read-only separation is just scoped credentials taken to the extreme.
- **Default rung**: scoped credentials plus a verified read-only mode from day one; human-in-the-loop approval on every contained write; irreversible or deployment-triggering tools disabled by default. The two top-efficiency patterns carry that combination, and approval is affordable alongside them only because early write volume is low - the condition that expires, and the one that promotes the starved option below.
- **Starved option**: risk-tiered server-side policy gates (classify every call as Read Only / Minimal Impact / Contained Write / Critical, then pass, enrich with agent attribution plus async audit, or block before the handler runs). Highest protection and highest build effort at once, so the efficiency order never puts it first and it keeps getting deferred - promote it anyway the moment background agents run unattended, write volume grows past what humans can approve, or the first write incident lands. The vendor that built it did so after an unattended agent closed thousands of tickets.
- The test every pattern must pass: enforcement lives server-side, so **an end user cannot bypass it by switching clients**. Client-side approval prompts and annotation hints fail this test on their own.
- Name the industry gap honestly: undo/rollback is largely absent ecosystem-wide; attribution plus audit trails are the current substitute for true reversibility, not a solved answer.
- This ranking is a default, not a law. Re-rank against question 3's write list and anything you know about the user - a product whose writes send emails or move money promotes dry-run and caps immediately; a pure-analytics product may never need more than the default rung.
## 4. Choose hosting and auth
Three hosting postures, ranked:
- effort: `self-hosted remote > remote managed platform > local stdio`
- value: `self-hosted remote == remote managed platform > local stdio`
- efficiency: `remote managed platform > local stdio > self-hosted remote`
The value tie is genuine: the agent client sees the same OAuth-protected endpoint either way - hosting is invisible to the buyer until a custom server-side policy layer or residency constraint appears, which is precisely the promotion condition.
- **Default rung: remote managed platform.** The protocol shipped four backward-incompatible revisions in its first twenty months; a managed platform absorbs that churn plus the mandatory OAuth machinery, and the economics tilt further toward managed once a few enterprise integrations exist. A hard deadline from question 6 reinforces this rung.
- **Starved option: self-hosted remote.** Highest control and highest effort - months to production-grade plus standing maintenance. Promoted when the MCP server _is_ the product (vertical SaaS, proprietary dataset, regulated workflow - agent access is what customers pay for), when a custom risk-tier policy layer from step 3 must run in your own infrastructure, or when existing multi-tenant edge infrastructure flips the effort line.
- **Step down to local stdio** for developer-tool products operating on the user's own files and processes: single client, near-zero hosting effort, environment-variable credentials, and explicitly exempt from the OAuth requirements below. Rule it out entirely - not just demote it - when the audience is enterprise agent fleets, which consume hosted endpoints.
- This ranking is a default, not a law; re-rank against questions 4-6.
Auth rules for any remote posture (spec revisions are date-stamped and move fast - always verify you're citing the latest one; this section is written against the 2026-07-28 revision):
1. The MCP server is an OAuth 2.1 **resource server**: it validates tokens, it never mints them. Designing the authorization server behind it is `samber/developer-platform-skills@oauth2-provider-design` territory; keep only the MCP-specific posture here.
2. Publish protected-resource metadata (RFC 9728).
- Require resource indicators (RFC 8707), and reject any token not issued specifically for this server - that is the mechanism stopping a token minted for one MCP server being replayed against another.
- The 2026-07-28 revision additionally mandates issuer validation (RFC 9207) and rewrites the transport core stateless: design every server instance interchangeable behind a plain load balancer, never session-pinned.
3. Never forward a caller's bearer token to an upstream API - the spec forbids this confused-deputy shape outright. Obtain your own upstream token via token exchange, acting as an OAuth client to the upstream system.
4. Read the compliance statistics as bimodal, never as one number: the often-quoted single-digit OAuth-compliance percentage is dragged down by a long tail of community stdio servers, while vendor-hosted servers default to OAuth 2.1. Implementing it properly is what passes enterprise security review - table stakes for this population, not an above-and-beyond flourish.
5. Hardening floor regardless of posture:
- Schema-validate every input, and bound sizes and ranges.
- Sanitize paths.
- Never leak internal errors to the client.
- On locally-run HTTP servers, validate the Origin header and bind to localhost (DNS-rebinding protection).
## 5. Version the tool surface
Three layers, versioned separately - treating "MCP versioning" as one decision is the mistake:
1. **Protocol version**: date-based revisions with a formal feature lifecycle (Active → Deprecated → Removed, minimum 12 months between the last two). Track deprecations - the original transport, for instance, entered a grace window early in the protocol's life - and pin exact SDK versions for reproducible builds.
2. **Your server's public API**: ordinary semantic versioning. Renaming or removing a toolset name is a major version - agents key on names for discovery, so a rename breaks them silently. General deprecation machinery is `samber/developer-platform-skills@api-versioning-policy` territory; what stays here is the layer below.
3. **The tool-surface contract itself - names, descriptions, schemas - which no spec standardizes yet.** A tool's description is a compiled interface, not documentation: an analysis of 61,097 catalogued tools found a description wording change measurably alters the model's probability of selecting that tool - a breaking change even when the JSON schema is untouched, and one schema-diff CI cannot catch. Nothing breaks loudly anymore; the agent just adapts, sometimes wrongly.
Discipline for layer 3, since the spec won't impose it:
- Default every change to additive, and alias old tool names instead of renaming.
- Hash the full surface (names + descriptions + schemas) to catch silent drift.
- Run golden-prompt behavioral tests in CI: a fixed set of representative tasks that must still select and call the right tools after any description edit.
- Carry a version marker in the response envelope, and log it on every call.
- Publish a deprecation window of at least 90 days with machine-readable response-header signaling.
Ship a description edit through the same review gate as a code change, never as a docs fix.
## 6. Publish for discoverability
- Publish to the official MCP registry under a DNS-verified reverse-domain namespace. Know what that listing signals: the registry is a metadata catalog with namespace-ownership proof and community moderation - it certifies nothing about security, so don't lean on listing as a trust claim to buyers.
- The official registry is necessary, not sufficient: human developers browse the curated third-party directories, so fan the listing out to them (automation tools exist for the fan-out) rather than stopping at one entry.
- Expect large customers to mirror the registry into private, allowlisted internal catalogs. Your listing's metadata and version history must stay accurate specifically because it gets re-consumed by machines applying policy, not just browsed.
- A first-party server, once published, tends to displace community-built substitutes for the same product rather than compete alongside them - if question 1 surfaced a community server, publishing well is also how you retire the unofficial surface agents currently trust.
## 7. Measure agent adoption
- Instrument tool calls as OpenTelemetry spans (session → tool invocation → downstream operation) rather than a bespoke event schema - the audience for this data in an enterprise deployment is the customer's existing observability stack, not only your dashboard. An auto-instrumenting wrapper beats hand-instrumenting each tool as the surface grows.
- The converged metric set: call volume, success/error rate, per-tool usage, active users, and client distribution (which agent client calls in). The purpose is dual - confirm the server is used at all, and see whether adoption is broad or concentrated.
- Registry listings and package downloads measure install interest, never runtime usage - only in-server telemetry answers the adoption question. Don't let a download count into a business case as a usage figure.
- Assume your telemetry is not the only visibility layer: large customers front your server with their own gateway. Design your metrics to be correlatable (stable tool names, request ids), not exclusive.
- When the data is good, publish it - the strongest ROI evidence in the ecosystem is one vendor's first-party disclosure: call volume, write share, non-technical-user share, enterprise share, retention by cohort, accuracy, and token-efficiency gains. That disclosure shape is the model to match, detailed in [references/evidence-and-do-not-cite.md](references/evidence-and-do-not-cite.md).
- Surfacing per-customer integration failures back to the developers who own them is `samber/developer-platform-skills@integration-error-observability` territory.
## 8. Roll out in stages
Full stage detail, thresholds, and the MCP Apps decision live in [references/rollout-stages-and-thresholds.md](references/rollout-stages-and-thresholds.md). The skeleton:
1. **Read-only launch**: the curated 5-15 tools, OAuth 2.1 from day one, OpenTelemetry from the first call, registry publication. Proceed only on sustained tool-call volume from real agent clients (not demo spikes) with tool-error rate under 2%.
2. **Graduated writes**: risk tiers enforced server-side, approval on contained writes, critical tools disabled by default, scoped credentials, attribution plus async audit, idempotency keys, dry-run where feasible. Expand write scope only on a clean audit trail, zero unattributed writes, and proven approval-flow reliability.
3. **Differentiate**: an interactive MCP Apps UI for the single highest-value workflow (approval screen, filterable dashboard, configuration wizard) - after validating that target customers' security teams accept iframe-rendered third-party UI in their assistant, which is still an open question, not a settled yes. Institutionalize the layer-3 versioning discipline and publish impact metrics.
The RFP-pressure override from step 1 cuts across this sequence in both directions: hard procurement demand accelerates past stages; two flat quarters park the server at stage 1 as maintained table stakes.
## Failure modes
Anti-pattern checklist - each is a direct review finding:
- The comprehensive-mirror trap: one tool per API endpoint. Agents mis-pick among near-duplicates and context drowns in metadata before any work happens.
- A destructive tool that is live-only - no dry-run, no approval gate, no disabled-by-default tier. Community servers have shipped order-cancellation tools that silently email real customers.
- A hand-built parallel surface where a derived one was available - double maintenance and guaranteed drift from the real API contract.
- A tool-description edit shipped as a docs fix, bypassing review and behavioral tests, silently changing which tools agents select.
- Forwarding the caller's bearer token upstream - the spec-forbidden confused-deputy shape.
- Trusting a read-only flag without verifying it: a documented vendor bug shipped write tools despite the flag being set. Test the lockdown, don't configure it and assume.
- Treating tool annotations (read-only/destructive hints) as security controls - they are advisory metadata for clients; enforcement belongs server-side.
- Citing a debunked adoption statistic in the business case - see the do-not-cite list in [references/evidence-and-do-not-cite.md](references/evidence-and-do-not-cite.md).
- A session-pinned server design - the protocol's stateless rewrite made instance-interchangeability the baseline expectation.
## Measurement
Four binary gates - iterate the design until all pass:
- Safety coverage: every write-capable tool carries exactly one risk tier and at least one named pattern from step 3's taxonomy, and every irreversible tool is approval-gated or disabled by default. One uncovered write tool fails the gate.
- Auth conformance (remote servers): protected-resource metadata published, token audience validated, no bearer-token passthrough upstream. Binary per the spec's own MUSTs.
- Evidence hygiene: zero figures from the do-not-cite list in any produced business case or deliverable.
- Curation: the launched surface stays within 5-15 tools unless a proven breadth requirement is documented, with every tool named per step 2's conventions.
The stage-transition thresholds (error rate under 2%, clean audit trail) are based on one vendor's read-only-first practice, not an industry standard - treat them as defaults to calibrate against your own first month, and the adoption metric set from step 7 as trends to baseline, never pass thresholds.
## Invocation examples
- "We have a stable REST API and customers asking for agent access - design our MCP server: which tools do we expose and how do we secure the write ones?"
- "Our MCP server mirrors 60 API endpoints and agents keep calling the wrong tool - redesign the surface."
- "Agents should be able to create and cancel orders through our MCP server - design the safety, approval, and audit model before we ship it."
- "Leadership wants an MCP server because a competitor shipped one - how much should we actually invest and in what order?"
## References
- [references/write-safety-patterns.md](references/write-safety-patterns.md) - the six write-safety patterns with their named vendor implementations, the negative example, and the approval-primitive detail.
- [references/rollout-stages-and-thresholds.md](references/rollout-stages-and-thresholds.md) - the three rollout stages with go/no-go thresholds, and the MCP Apps UI decision.
- [references/evidence-and-do-not-cite.md](references/evidence-and-do-not-cite.md) - adoption/ROI evidence ranked by strength, the disclosure model to match, and the debunked figures never to cite.
See also, same collection:
- `samber/developer-platform-skills@api-rate-limit-policy` - the quota and throttle policy agent traffic runs under, including per-tool and per-credential limits.
- `samber/developer-platform-skills@developer-portal-design` - where the MCP server's docs, connection guide, and credentials live in the developer portal.
- `samber/developer-platform-skills@cli-interface-design` - the CLI surface agents with a shell often reach first; same curated-over-mirror logic, different contract.
- `samber/developer-platform-skills@agent-skill-offering` - the Agent Skill shipped beside the server or CLI, versioned with the code; covers the skill vs MCP decision for coding agents with a shell.