diff --git a/README.md b/README.md index 412143a9f..220739930 100644 --- a/README.md +++ b/README.md @@ -1204,13 +1204,13 @@ The MCP protocol defines three core primitives that servers can implement: MCP servers declare capabilities during initialization: -| Capability | Feature Flag | Description | -|-------------|------------------------------|------------------------------------| -| `prompts` | `listChanged` | Prompt template management | -| `resources` | `subscribe`
`listChanged`| Resource exposure and updates | -| `tools` | `listChanged` | Tool discovery and execution | -| `logging` | - | Server logging configuration | -| `completion`| - | Argument completion suggestions | +| Capability | Feature Flag | Description | +|--------------|------------------------------|------------------------------------| +| `prompts` | `listChanged` | Prompt template management | +| `resources` | `subscribe`
`listChanged`| Resource exposure and updates | +| `tools` | `listChanged` | Tool discovery and execution | +| `logging` | - | Server logging configuration | +| `completions`| - | Argument completion suggestions | ## Documentation diff --git a/src/mcp/server/lowlevel/server.py b/src/mcp/server/lowlevel/server.py index faad95aca..562de31b7 100644 --- a/src/mcp/server/lowlevel/server.py +++ b/src/mcp/server/lowlevel/server.py @@ -190,6 +190,7 @@ def get_capabilities( resources_capability = None tools_capability = None logging_capability = None + completions_capability = None # Set prompt capabilities if handler exists if types.ListPromptsRequest in self.request_handlers: @@ -209,12 +210,17 @@ def get_capabilities( if types.SetLevelRequest in self.request_handlers: logging_capability = types.LoggingCapability() + # Set completions capabilities if handler exists + if types.CompleteRequest in self.request_handlers: + completions_capability = types.CompletionsCapability() + return types.ServerCapabilities( prompts=prompts_capability, resources=resources_capability, tools=tools_capability, logging=logging_capability, experimental=experimental_capabilities, + completions=completions_capability, ) @property diff --git a/src/mcp/types.py b/src/mcp/types.py index 4a9c2bf1a..91432d69c 100644 --- a/src/mcp/types.py +++ b/src/mcp/types.py @@ -286,6 +286,12 @@ class LoggingCapability(BaseModel): model_config = ConfigDict(extra="allow") +class CompletionsCapability(BaseModel): + """Capability for completions operations.""" + + model_config = ConfigDict(extra="allow") + + class ServerCapabilities(BaseModel): """Capabilities that a server may support.""" @@ -299,6 +305,8 @@ class ServerCapabilities(BaseModel): """Present if the server offers any resources to read.""" tools: ToolsCapability | None = None """Present if the server offers any tools to call.""" + completions: CompletionsCapability | None = None + """Present if the server offers autocompletion suggestions for prompts and resources.""" model_config = ConfigDict(extra="allow") diff --git a/tests/server/test_session.py b/tests/server/test_session.py index 69321f87c..d00eda875 100644 --- a/tests/server/test_session.py +++ b/tests/server/test_session.py @@ -11,8 +11,13 @@ from mcp.shared.session import RequestResponder from mcp.types import ( ClientNotification, + Completion, + CompletionArgument, + CompletionsCapability, InitializedNotification, + PromptReference, PromptsCapability, + ResourceReference, ResourcesCapability, ServerCapabilities, ) @@ -80,6 +85,7 @@ async def test_server_capabilities(): caps = server.get_capabilities(notification_options, experimental_capabilities) assert caps.prompts is None assert caps.resources is None + assert caps.completions is None # Add a prompts handler @server.list_prompts() @@ -89,6 +95,7 @@ async def list_prompts(): caps = server.get_capabilities(notification_options, experimental_capabilities) assert caps.prompts == PromptsCapability(listChanged=False) assert caps.resources is None + assert caps.completions is None # Add a resources handler @server.list_resources() @@ -98,6 +105,19 @@ async def list_resources(): caps = server.get_capabilities(notification_options, experimental_capabilities) assert caps.prompts == PromptsCapability(listChanged=False) assert caps.resources == ResourcesCapability(subscribe=False, listChanged=False) + assert caps.completions is None + + # Add a complete handler + @server.completion() + async def complete(ref: PromptReference | ResourceReference, argument: CompletionArgument): + return Completion( + values=["completion1", "completion2"], + ) + + caps = server.get_capabilities(notification_options, experimental_capabilities) + assert caps.prompts == PromptsCapability(listChanged=False) + assert caps.resources == ResourcesCapability(subscribe=False, listChanged=False) + assert caps.completions == CompletionsCapability() @pytest.mark.anyio