MCP is easy to demo.
Define a few tools. Give each one a name, a description, and a JSON schema. Wire them to existing functions. The agent can list tools, call tools, and receive a result. The screenshot looks good.
The problem for a deployment product is that once a tool can change state, it is no longer a demo endpoint. It is a product API.
This post follows Skills are not MCP. That post covered the split between the skill and MCP: the skill teaches the agent how to operate, and MCP gives the agent a stable callable surface. This one gets more specific: when an MCP tool can deploy, roll back, configure resources, manage domains, or inspect logs, it has to share the same product semantics as the CLI, HTTP/API, and Web Console.
Otherwise the tool works in the demo, then quietly becomes a second control plane.
Hand-written tool lists drift
The riskiest MCP design is often not obviously wrong. It is convenient.
Imagine a quick_deploy_create tool. It accepts a repository URL, a server id, and a few environment variables, then creates the project, resource, and deployment for the agent. From the agent experience, that feels helpful. From the product boundary, it dodges a long list of questions:
- Which operation key does this action represent?
- Does the CLI or Web Console expose the same action?
- Is the input schema the same as the HTTP/API schema?
- Which tenant, role, entitlement, and capability rules apply?
- Is the mutation idempotent?
- How is the audit event emitted?
- How are secrets, connection strings, and log lines redacted?
- If deployment fails, which readback or recovery command should the user use?
If those questions do not have answers, the MCP tool is not an AI entrypoint. It is a product shortcut.
Shortcuts usually start as demo glue. Then docs mention them. Users remember them. Agent prompts learn them. Later, CLI/API/Web behavior changes while MCP keeps running on the old meaning. The team ends up maintaining a product surface that users cannot inspect, permissions cannot explain, and tests rarely cover well.
Appaloft is trying not to create that shape.
The operation catalog is the contract
Appaloft treats the operation catalog as the shared contract. MCP is not a new business layer.
In public Appaloft, packages/application/src/operation-catalog.ts records product operations: operation key, command/query kind, domain, CLI transport, HTTP/API route, and input schema. MCP descriptors are generated from that catalog. deployments.create becomes deployments_create, deployments.plan becomes deployments_plan, resources.runtime-logs becomes resources_runtime_logs, and system.doctor becomes system_doctor.
That naming is not aesthetic. It lets every entrypoint answer the same question: which product operation am I calling?
If a behavior is not in the operation catalog, Appaloft MCP should not secretly invent a tool for it. The right move is to decide whether the behavior belongs in public Appaloft as a neutral capability. If it does, public core gets the operation, schema, handler, CLI/API surface, tests, and docs first; Cloud then composes private authz, entitlement, audit, policy, or adapters around it. If it is Cloud-only governance, it should still have a clear Cloud route and boundary, not hide inside an agent-only tool.
That slows early development a little. It prevents product semantics from forking.
A tool is transport, not a wrapper
An MCP tool looks like a function call. In a production control plane, it should behave like a transport.
In Appaloft, the tool descriptor exposes the operation to the agent: name, description, input schema, CLI/API metadata, and hints for read-only, destructive, idempotent, or open-world behavior. The actual read or write still returns to the application boundary: CommandBus and QueryBus.
That means deployments_create should not contain MCP-only deployment logic. It should create the same command, run the same application handler, and trigger the same authorization, audit, idempotency, redaction, readback, and error semantics. resources_runtime_logs should not SSH directly to a server and read files; it should use the runtime log query surface that Appaloft already defines.
This boundary matters more with agents. Agents are good at turning “this worked” into “this was safe to do.” The product cannot leave safety to model judgment. Tool schemas should be precise, but real guards belong in the product layer.
Resources and prompts must not become hidden commands
MCP also has resources and prompts. They are useful, and they are easy to misuse.
Resources are a good place for read-only context: an operation catalog snapshot, high-value tools, the Appaloft skill, the deploy protocol, an MCP guide, or agent docs. The agent can read them to decide what to do next. It must not mutate state through a resource.
Prompts are good workflow starters: first deploy, recover a failed deployment, configure a resource, observe runtime, or publish a static artifact. A prompt can remind the agent to inspect, then plan, then execute, then observe. It must not own business state, bypass confirmations, or mutate anything behind the scenes.
The distinction is small in prose and large in production. If a prompt starts creating deployments, it has become a command handler without an operation key. If reading a resource repairs runtime state, it is no longer a resource. When something goes wrong, operators can no longer answer the basic question: which operation changed the system?
So Appaloft keeps the three roles separate:
- tools execute operation-catalog operations;
- resources provide read-only context;
- prompts sequence existing operations.
That sounds plain. Plain is the point here.
Write operations need the same product protections
When an agent calls a write operation, the protection boundary must not become thinner because the entrypoint is MCP.
Deployments, rollbacks, deletes, domains, certificates, dependency resources, storage, organizations, deploy tokens, and system maintenance can all affect a real environment. Some operations create external resources. Some change access paths. Some touch credentials or logs. An MCP tool cannot rely on a description that says “be careful.”
Appaloft wants each write operation to run with product-level context:
- Which actor and tenant context are active.
- Whether the actor has the required capability.
- Whether the operation needs plan-first behavior.
- Whether exact confirmation fields are required.
- Whether input contains secrets or should reference secret refs instead.
- Which output fields must be redacted.
- Whether an audit event is emitted.
- Which structured error and recovery hint should be returned on failure.
Those rules belong to the control plane, not the prompt. The agent can read guidance and follow steps. It cannot become the permission model.
Structured errors beat polished prose
An MCP result should not be only “deployment failed, please try again later.”
The agent needs to distinguish authentication failure, missing permission, missing secret, unprepared server runtime, missing dependency binding, unavailable provider adapter, DNS propagation, health-check timeout, superseded deployment, required confirmation, or unsupported transport.
Those errors help humans too. The CLI can print a better next step. The Web Console can send the user to the right page. The MCP tool can let the agent choose whether to inspect logs or ask for authorization instead of guessing the next command.
That is why the operation catalog cannot stop at tool names. Input, transport, handler, annotations, readback, and error semantics need to return to the same product path. An agent-friendly interface is not one that talks more. It is one that makes the agent guess less.
Auth cannot be an MCP side door
We wrote separately about why AI agents should not log in by copying cookies. The same boundary applies here: a remote MCP gateway should not have MCP-only permissions.
Local stdio MCP can reuse the local Appaloft runtime. Remote MCP needs bearer handoff, profiles, tenant context, and server-side authz. Cloud hosted MCP can add team permissions, entitlement, audit, policy, and rate limits. Enterprise can run a private gateway.
Those differences can exist, but the tool should still return to the same operation. Requests from an agent should not skip the authorization and audit path used by Web or CLI. A hosted gateway should not become a private deploy engine.
MCP is a better calling shape for agents. It is not a looser permission model.
Tests should prove there is no second semantics
If MCP tools are product APIs, tests need to treat them that way.
Public Appaloft has a simple class of MCP tests: every operation catalog entry has one generated tool descriptor; the descriptor preserves operation key, kind, domain, CLI/API transport metadata; high-value deployment and resource tools use operation-key-derived names.
These tests are not flashy. They are valuable. They prove MCP does not have a second hand-written list and that deployments.create has not quietly become a different product action.
Deeper tests need to cover handlers: read-only tools do not mutate, write tools go through the command boundary, destructive operations require confirmation, secrets do not appear in output, and structured results plus text fallbacks work for older clients. Skill evals need to cover real tasks too, so the model does not learn to bypass Resource profile, dependency binding, preview selectors, or auth handoff.
The goal is not “the agent successfully called one tool.” The goal is “the product boundary still held when the agent called the tool.”
The cost we accept
This approach creates work.
When adding an operation, we cannot just add an MCP handler. We have to decide whether it belongs in the operation catalog, then add the schema, CLI/API route, CommandBus/QueryBus handler, permission rules, audit, redaction, readback, docs, skill reference, and tests. In Cloud, the hosted gateway has to prove that it adds governance at the composition layer instead of copying the public MCP server.
We are willing to pay that cost.
The hard part of a deployment control plane is not getting one call to succeed. It is being able to say, six months later: which actor, in which tenant, invoked which operation, with what input, which secrets were referenced but not leaked, whether a plan was reviewed, whether the action was authorized, what state changed, and how the system recovered when it failed.
When AI agents enter production workflows, those questions do not go away. They show up more often.
So Appaloft’s stance on MCP is direct: MCP tools are product APIs. They should be generated, checked, authorized, audited, tested, and routed through the same operation catalog as CLI, HTTP/API, and Web Console. A demo can hand-write tools. A deployment control plane should not keep doing that for long.