The capabilities object in the initialize response is the contract that tells clients which MCP features to use. Declaring resources with subscribe: true but providing no subscription implementation causes clients to attempt subscriptions that fail silently. Implementing prompts but not declaring prompts in capabilities means clients never discover them — the feature is invisible. These mismatches are a form of contract violation: the server lies about its interface, and clients built against that lie fail in ways that are hard to diagnose.
High because capabilities mismatches cause systematic failures — either clients invoking unimplemented features or silently missing features the server provides — both producing broken integrations.
Audit your capabilities object against your actual handler registrations before every release. Declare exactly what you implement, nothing more.
// src/index.ts — capabilities must match implementation
const server = new Server(
{ name: 'my-server', version: '1.0.0' },
{
capabilities: {
tools: { listChanged: true }, // only if tools are registered
resources: { subscribe: false }, // only if resources are registered
// omit 'prompts' if no prompts are registered
},
}
)
Do not copy a capability template and leave unused fields in — remove subscribe: true if you don't implement the resources/subscribe handler.
ID: mcp-server.security-capabilities.capability-declaration
Severity: high
What to look for: Count all capability declarations in the server config. Enumerate which MCP capabilities are declared (tools, resources, prompts, logging). Compare the capabilities object in the server's initialize response against what the server actually implements. If capabilities.tools is declared, verify the server handles tools/list and tools/call. If capabilities.resources is declared, verify resources/list and resources/read are handled. If capabilities.prompts is declared, verify prompts/list and prompts/get are handled. Check for capabilities that are declared but not implemented (false advertising) or implemented but not declared (hidden features clients can't discover).
Pass criteria: Every capability declared in the initialize response has a corresponding implementation. Every implemented feature is declared in capabilities. No capabilities are advertised but unimplemented, and no features exist but are undeclared. At least 1 capability must be declared, and declared capabilities must match implemented features.
Fail criteria: Capabilities declare tools but tools/list returns empty or errors, or server implements resources/read but doesn't declare resources in capabilities, or capabilities include features with no implementation.
Skip (N/A) when: All checks skip when no MCP server is detected.
Report even on pass: Report the declared capabilities: "Server declares X capabilities: [list]."
Cross-reference: For tool annotations that extend capabilities, see tool-annotations.
Detail on fail: "Capabilities declares 'resources' with 'subscribe: true' but the server has no subscription implementation — clients will attempt to subscribe and get errors" or "Server implements 3 prompts but capabilities object does not declare 'prompts' — clients will never discover them"
Remediation: Keep capabilities in sync with implementation:
// src/index.ts — capability declaration
const server = new Server({ name: "my-server", version: "1.0.0" }, { capabilities: { tools: {}, resources: {}, prompts: {} } })
const server = new McpServer({
name: 'my-server',
version: '1.0.0',
capabilities: {
tools: { listChanged: true }, // only if you register tools
resources: { subscribe: false }, // only if you register resources
// Don't declare prompts if you don't register any
},
})