chore: import upstream snapshot with attribution
Deploy Docs / deploy-docs (push) Failing after 1s
Conformance Tests / client-conformance (push) Failing after 3s
Conformance Tests / server-conformance (push) Failing after 1s
GitHub Actions Security Analysis / zizmor (push) Failing after 1s
CI / checks (push) Failing after 59m20s
CI / all-green (push) Waiting to run

This commit is contained in:
wehub-resource-sync
2026-07-13 12:10:27 +08:00
commit 49b9bb6724
992 changed files with 161690 additions and 0 deletions
+116
View File
@@ -0,0 +1,116 @@
"""`docs/servers/completions.md`: every claim the page makes, proved against the real SDK."""
import pytest
from inline_snapshot import snapshot
from mcp_types import (
Completion,
CompletionContext,
CompletionsCapability,
ErrorData,
PromptReference,
ResourceTemplateReference,
)
from docs_src.completions import tutorial001, tutorial002, tutorial003
from mcp import Client, MCPError
# See test_index.py for why this is a per-module mark and not a conftest hook.
pytestmark = [pytest.mark.anyio, pytest.mark.filterwarnings("error::mcp.MCPDeprecationWarning")]
TEMPLATE_REF = ResourceTemplateReference(uri="github://repos/{owner}/{repo}")
PROMPT_REF = PromptReference(name="review_code")
async def test_a_server_with_no_handler_has_no_completions_capability() -> None:
"""tutorial001: there is something worth completing, but no handler and no advertised capability."""
async with Client(tutorial001.mcp) as client:
(template,) = (await client.list_resource_templates()).resource_templates
assert template.uri_template == "github://repos/{owner}/{repo}"
(prompt,) = (await client.list_prompts()).prompts
assert prompt.name == "review_code"
assert client.server_capabilities.completions is None
async def test_completing_without_a_handler_is_method_not_found() -> None:
"""tutorial001: nothing handles `completion/complete`, so the request is a JSON-RPC error."""
async with Client(tutorial001.mcp) as client:
with pytest.raises(MCPError) as excinfo:
await client.complete(ref=PROMPT_REF, argument={"name": "language", "value": "py"})
assert excinfo.value.error == ErrorData(code=-32601, message="Method not found", data="completion/complete")
async def test_registering_the_handler_advertises_the_capability() -> None:
"""tutorial002: `@mcp.completion()` is the whole declaration; the capability is derived from it."""
async with Client(tutorial002.mcp) as client:
assert client.server_capabilities.completions == CompletionsCapability()
async def test_prompt_argument_completion_filters_on_the_typed_prefix() -> None:
"""tutorial002: the handler returns the languages that start with `argument.value`."""
async with Client(tutorial002.mcp) as client:
result = await client.complete(ref=PROMPT_REF, argument={"name": "language", "value": "py"})
assert result.completion == snapshot(Completion(values=["python"]))
async def test_empty_value_returns_every_suggestion() -> None:
"""tutorial002: an empty prefix matches everything, so the client gets the whole list."""
async with Client(tutorial002.mcp) as client:
result = await client.complete(ref=PROMPT_REF, argument={"name": "language", "value": ""})
assert result.completion.values == ["go", "javascript", "python", "rust", "typescript"]
async def test_returning_none_is_an_empty_list_not_an_error() -> None:
"""tutorial002: an argument the handler does not recognise produces `values=[]`, never a failure."""
async with Client(tutorial002.mcp) as client:
result = await client.complete(ref=PROMPT_REF, argument={"name": "code", "value": "x"})
assert result.completion == snapshot(Completion(values=[]))
result = await client.complete(ref=TEMPLATE_REF, argument={"name": "repo", "value": ""})
assert result.completion.values == []
async def test_context_arguments_resolve_a_dependent_parameter() -> None:
"""tutorial003: the already-resolved `owner` arrives in `context.arguments` and picks the repo list."""
async with Client(tutorial003.mcp) as client:
result = await client.complete(
ref=TEMPLATE_REF,
argument={"name": "repo", "value": ""},
context_arguments={"owner": "modelcontextprotocol"},
)
assert result.completion == snapshot(Completion(values=["python-sdk", "typescript-sdk", "inspector"]))
async def test_the_typed_prefix_still_filters_a_dependent_parameter() -> None:
"""tutorial003: `argument.value` narrows the owner's repos exactly as it narrows a prompt argument."""
async with Client(tutorial003.mcp) as client:
result = await client.complete(
ref=TEMPLATE_REF,
argument={"name": "repo", "value": "py"},
context_arguments={"owner": "modelcontextprotocol"},
)
assert result.completion.values == ["python-sdk"]
def test_context_arguments_is_optional() -> None:
"""tutorial003: `context.arguments` is `dict[str, str] | None`; the handler's `None` guard is required."""
assert CompletionContext.model_fields["arguments"].annotation == (dict[str, str] | None)
assert CompletionContext().arguments is None
async def test_no_context_means_no_suggestions() -> None:
"""tutorial003: without a resolved `owner` (or with an unknown one) the handler has nothing to offer."""
async with Client(tutorial003.mcp) as client:
result = await client.complete(ref=TEMPLATE_REF, argument={"name": "repo", "value": ""})
assert result.completion.values == []
result = await client.complete(
ref=TEMPLATE_REF,
argument={"name": "repo", "value": ""},
context_arguments={"owner": "nobody"},
)
assert result.completion.values == []
async def test_the_prompt_branch_is_untouched_by_the_new_one() -> None:
"""tutorial003: adding the resource-template branch leaves prompt-argument completion as it was."""
async with Client(tutorial003.mcp) as client:
result = await client.complete(ref=PROMPT_REF, argument={"name": "language", "value": "type"})
assert result.completion.values == ["typescript"]