duck.contrib.mcp.capabilities

Base capability system for MCP views. Lets related JSON-RPC methods be grouped under one namespace and registered as a single pluggable unit instead of being wired into self.handlers one by one.

Submodules

Package Contents

Classes

Capability

Base class for a pluggable MCP capability.

API

class duck.contrib.mcp.capabilities.Capability(view: MCPView)[source]

Base class for a pluggable MCP capability.

A capability owns one namespace of the method space. Registering it with view.register_capability("tools", ToolsCapability(view)) routes every tools/* method here automatically - action is the part of the method after the slash (e.g. “call” for tools/call).

Parameters:

view – The MCPView this capability is attached to.

… rubric:: Example

class ToolsCapability(Capability):
    def setup(self):
        self.handlers = {
            "list": self.list,
            "call": self.call,
        }

    async def list(self, params):
        return {"tools": []}

    async def call(self, params):
        return {"content": [], "isError": False}

view.register_capability("tools", ToolsCapability(view))

Initialization

async after_request(action: str, result: Any) Any[source]

Optional hook run after an action’s handler.

Parameters:
  • action – The part of the method after the slash (e.g. “call”).

  • result – The value returned by the handler.

Returns:

The (possibly modified) result.

async before_request(action: str, params: dict) Optional[Any][source]

Optional hook run before an action’s handler.

Parameters:
  • action – The part of the method after the slash (e.g. “call”).

  • params – The method parameters.

Returns:

Any non-None value short-circuits the handler entirely and is returned as the result instead - useful for things like per-capability rate limiting or caching.

cleanup() None[source]

Called when the capability is removed or the view is torn down.

describe() dict[source]

Build this namespace’s entry in the ‘initialize’ capabilities object.

Returns:

An empty object by default. Override to advertise anything beyond bare namespace presence (e.g. {“listChanged”: True}).

Return type:

dict

async dispatch(action: str, params: dict) Any[source]

Route a namespace-local action to its registered handler, running the before/after hooks around it.

Parameters:
  • action – The part of the method after the slash (e.g. “call”).

  • params – The method parameters.

Raises:

ValueError – If no handler is registered for this action.

setup() None[source]

Called once on registration. Populate self.handlers here.