Capabilities

Capability Design

How every domain capability in an MCP-first system should be structured, named, and exposed, from the seven building blocks to the action-layer rule.

A capability is the smallest describable ability of a system: typed, permission-checked, auditable, and equally usable by humans and agents alike. MCP-first does not start with screens, but with these capabilities. Only when the capability set is complete do the web app, mobile app, CLI, and agent interfaces emerge as clients on top.

The seven building blocks

MCP-first models every capability with seven structural elements.

Resources

Data and contexts that can be read. Resources provide the agent with prepared context, not raw database tables, but filtered, purpose-bound views of the system state.

Tools

Actions the system can execute. Every tool has a typed input schema, an output schema, an error schema, and an audit schema. A tool is what a button in the web app merely represents.

Prompts / Workflows

Pre-built flows that guide an agent through complex, multi-step processes. Workflows define which tools should be called in which order with what context, and where human input is expected.

Policies

Rules, permissions, protection levels, and approval processes. Policies decide who may see, call, and autonomously execute a capability. They are not a layer added afterward, they are part of the capability definition.

Audit Events

Every action generates an audit entry: who, what, when, with which approval, with what result. Audit events are not an optional operational extension, but a mandatory component of every capability.

Human Confirmation Gates

Mechanisms by which the agent must actively ask the user for confirmation before an action is executed. Confirmation gates are declared in the capability definition, not ad hoc in the UI.

Risk Metadata

Every capability carries a risk level: low, medium, high, critical, or forbidden_for_ai. These metadata control discovery filtering, confirmation requirements, and step-up auth, and are available machine-readably in the tool contract.

What every entity should offer

Regardless of the domain, every entity needs a consistent base set of capabilities.

Base capabilities per entity
  • entity.list Return filtered list
  • entity.search Full-text search with scoping
  • entity.get Single entity with context
  • entity.create Create new entity
  • entity.update Change fields, idempotent
  • entity.archive Deactivate instead of delete
  • entity.audit Retrieve change history
  • entity.permissions Query effective permissions
  • entity.related Load related entities
  • entity.recommended_next_actions Agent-ready action suggestions

Action layer first

Every function is first implemented as an action in the central action layer. Only then does the respective interface adapter emerge.

Action: create_project

Used by:
  Web app
  Mobile app
  MCP Tool
  Worker
  CLI

This means there is no duplicate implementation: when a web app button calls create_project and an agent does the same, both use the same code, the same validations, the same audit events.

Build capabilities once. Expose them everywhere.

Central claim

The MCP server is an adapter

The MCP server contains no business logic. It is a thin adapter between the agent client and the action layer.

Its responsibilities:

  • Discovery, which tools and resources exist in this context?
  • Schema Exposure, typed description of inputs, outputs, and errors
  • Auth Context Mapping, map client token to user and tenant context
  • Policy Checks, may this agent call this tool in this context?
  • Audit Logging, write execution events for every tool call

Typed inputs and outputs

Every tool defines four schemas:

SchemaPurpose
Input SchemaWhat parameters does the tool expect, what types, what required fields?
Output SchemaWhat does the tool return on success?
Error SchemaWhat error codes are possible, permission_denied, confirmation_required, policy_violation?
Audit SchemaWhat is written into the audit event?

No loose JSON structures. Agents, as well as compilers and tests, rely on these schemas. Untyped outputs force guessing logic on the client side.

Idempotency

Many tools should be idempotent: delivering the same result for the same request, without generating unnecessary duplicates.

create_download_link(fileId, expiresAt)

If a valid link for fileId with identical expiresAt already exists, the existing link is returned, no second one is created. This reduces agent errors on retries and makes workflows more robust against network interruptions.