Whatever message this page gives is out now! Go check it out!

Declaring Capabilities

Last update:
May 18, 2026
Capabilities tell clients which MCP features the server actually implements.

Overview

Capabilities tell clients which MCP features the server actually implements. This allows clients to behave correctly without trial-and-error (e.g., only calling tools/list if tools are supported).
The main capability areas are:
  • Tools – for tools/list and tools/call
  • Prompts – for prompts/list and prompts/get
  • Resources – for resources/list and resources/read
  • (Optionally) Logging, sampling, elicitation, etc., depending on your MCP implementation

Basic Capability Declaration

In the CF spec, capabilities are usually declared as a simple struct:

mcpServer = mcpServerBuilder()
    .serverInfo("cf-ops-healthcheck-mcp", "1.0.0")
    .capabilities({
        tools     : true,
        prompts   : false,
        resources : true
    })
    .tools([{ cfc:"mcp.tools.HealthcheckTools" }])
    .resources([
        { uri:"file:///var/log/app.log", name:"App Logs", mimeType:"text/plain" }
    ])
    .build();
      
Interpretation:
  • tools: true – server implements tool methods (tools/list, tools/call).
  • prompts: false – no prompt APIs; a client should not call prompts/list or prompts/get.
  • resources: true – server implements resource methods (resources/list, resources/read).
A well-behaved client:
  • Uses only the supported features.
  • Avoids unnecessary protocol calls that will obviously fail.

Being Precise vs Over-Advertising

Only set a capability to true if:
  • The corresponding MCP methods are implemented.
  • They are stable enough to be used by clients.
  • You intend to support them (even if in “beta”).
Avoid “over-advertising” capabilities:
  • Don’t set prompts: true if you have no prompts yet.
  • Don’t set resources: true if resources/list is a stub or always returns empty and is not meant for use.
This precision:
  • Reduces client confusion and spurious errors.
  • Makes server behavior easier to reason about.
  • Helps agents discover real functionality rather than dead ends.

Capability Granularity and Extensions

Depending on your MCP runtime or future spec versions, capabilities may become more granular. For example:
  • Logging support
  • Streaming vs non-streaming responses
  • Built-in sampling / LLM calling
  • Elicitation (interactive, multi-turn workflows)
Even if the current CF API exposes only a simple struct, it’s wise to think in terms of “what can this server do”:
  • Does it support structured logging callbacks?
  • Can it initiate its own LLM calls (sampling) and expose them as part of tools?
  • Does it support multi-turn interactive flows, or purely atomic tool calls?
If and when those options appear in the API, you can extend your capability declaration:

mcpServer = mcpServerBuilder()
    .serverInfo("cf-analytics-mcp", "2.0.0")
    .capabilities({
        tools      : true,
        prompts    : true,
        resources  : true,
        logging    : true,
        sampling   : false, // hypothetical future fields
        elicitation: false
    })
    ...
    .build();
      

Aligning Capabilities with Implementation

Capabilities are a contract. To keep them honest:
  • Ensure your server initialization always configures tools/prompts/resources in line with the capability flags.
  • Add automated tests for each capability:
    • If tools: true, test tools/list returns expected tools.
    • If prompts: true, test prompts/list and prompts/get for a known prompt.
    • If resources: true, test resources/list and resources/read for at least one resource.
  • If you temporarily disable a feature (e.g., prompts) during a migration:
    • Consider setting the corresponding capability to false for that deployment to avoid confusing clients.
    • When re-enabling, bump the server version (e.g., from 1.3.0 to 1.3.1 or 1.4.0 depending on impact).

Capabilities vs Permissions

Capabilities define what the server can do, not what every caller is allowed to do.
For example:
  • You might advertise tools: true and implement a delete_user tool.
  • Authorization rules might restrict delete_user to only certain authenticated clients.
Think of it as:
  • Capabilities = technical surface
  • Authorization = per-request policy
Capabilities should remain stable and describe the full feature set. Permissions and allow-lists handle who can use what.

Practical Examples

Example 1 — Minimal tool-only server

mcpServer = mcpServerBuilder()
    .serverInfo("cf-healthcheck-mcp", "1.0.0")
    .capabilities({
        tools     : true,
        prompts   : false,
        resources : false
    })
    .tools([{ cfc:"mcp.tools.HealthcheckTools" }])
    .build();
      
This server:
  • Only supports tools/list and tools/call.
  • Has no prompts or resources.
Example 2 — Full featured content server

mcpServer = mcpServerBuilder()
    .serverInfo("cf-content-mcp", "1.2.0")
    .capabilities({
        tools     : true,
        prompts   : true,
        resources : true
    })
    .tools([
        { cfc:"mcp.tools.SearchTools" },
        { cfc:"mcp.tools.SummarizationTools" }
    ])
    .prompts([
        { name:"summarize-article", template:"Summarize this article: {{text}}" },
        { name:"rewrite-for-seo",  template:"Rewrite this for SEO: {{text}}" }
    ])
    .resources([
        { uri:"file:///var/articles/index.json", name:"Article Index", mimeType:"application/json" }
    ])
    .build();
      
Clients can:
  • Discover and call tools.
  • Retrieve prompt templates to drive tasks.
  • Explore and read a known resource.

Share this page

Was this page helpful?
We're glad. Tell us how this page helped.
We're sorry. Can you tell us what didn't work for you?
Thank you for your feedback. Your response will help improve this page.

On this page