Ana içeriğe geç

Tamamlamalar

Makine çevirisi

Bu sayfa İngilizce dokümantasyondan otomatik olarak çevrildi; esas alınması gereken sürüm İngilizce sayfadır. Yanlış görünen bir şey varsa, nasıl bildireceğinizi Çeviriler sayfası açıklar.

Sunucunuzun üzerine bir arayüz kuran bir istemci, kullanıcı yazdıkça argüman değerlerini otomatik tamamlamak ister: dil adları, depo adları, dosya yolları.

Tamamlamalar, sunucunuzun bu önerileri sağlama yoludur.

Tamamlamaya değer bir şey

Tamamlamalar tam olarak iki şeye uygulanır: bir prompt'un argümanlarına ve bir kaynak şablonunun parametrelerine. O halde her birinden birer tane içeren bir sunucuyla başlayın:

server.py
from mcp.server import MCPServer

mcp = MCPServer("GitHub Explorer")


@mcp.resource("github://repos/{owner}/{repo}")
def github_repo(owner: str, repo: str) -> str:
    """A GitHub repository."""
    return f"Repository: {owner}/{repo}"


@mcp.prompt()
def review_code(language: str, code: str) -> str:
    """Review a snippet of code."""
    return f"Review this {language} code:\n{code}"

Burada henüz tamamlamalarla ilgili hiçbir şey yok.

  • review_code bir language alır. Kullanıcı hangi yazımları kabul ettiğinizi tahmin etmek zorunda kalmamalı.
  • github_repo bir owner ve bir repo alır. İkisi için de serbest metin kutuları kötü bir form olur.

Tamamlama işleyicisi

@mcp.completion() ile dekore edilmiş tek bir fonksiyon ekleyin:

server.py
from mcp.server import MCPServer
from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference

mcp = MCPServer("GitHub Explorer")

LANGUAGES = ["go", "javascript", "python", "rust", "typescript"]


@mcp.resource("github://repos/{owner}/{repo}")
def github_repo(owner: str, repo: str) -> str:
    """A GitHub repository."""
    return f"Repository: {owner}/{repo}"


@mcp.prompt()
def review_code(language: str, code: str) -> str:
    """Review a snippet of code."""
    return f"Review this {language} code:\n{code}"


@mcp.completion()
async def handle_completion(
    ref: PromptReference | ResourceTemplateReference,
    argument: CompletionArgument,
    context: CompletionContext | None,
) -> Completion | None:
    if isinstance(ref, PromptReference) and argument.name == "language":
        return Completion(values=[lang for lang in LANGUAGES if lang.startswith(argument.value)])
    return None
  • Sunucu başına tek bir işleyici vardır. Her tamamlama isteği buraya düşer; neyin tamamlandığına göre siz dallanırsınız.
  • async def olmak zorundadır: SDK onu await eder.
  • Üç argüman alır:
  • ref: hangi prompt veya kaynak şablonu olduğu; bir PromptReference ya da ResourceTemplateReference olarak gelir. İkisini isinstance ile ayırt edersiniz.
  • argument: argument.name tamamlanmakta olan argüman, argument.value ise kullanıcının şu ana kadar yazdığıdır.
  • context: hâlihazırda çözümlenmiş argümanlar. Şimdilik görmezden gelin.
  • Bir Completion(values=[...]) döndürürsünüz; sunacak bir şeyiniz yoksa None.

Tip

argument.value, kullanıcının yazdığı ön ektir. SDK sizin yerinize filtreleme yapmaz: values içine ne koyarsanız arayüz onu gösterir. startswith'i yazmak size düşer.

Deneyin

Test etme sayfasındaki bellek içi Client ile çalıştırın. client.complete()'i ref=PromptReference(name="review_code") ve argument={"name": "language", "value": "py"} ile çağırın:

result.completion.values  # ['python']
  • ref, işleyicinizin aldığı referans türünün aynısıdır.
  • argument, tam olarak iki anahtarı (name ve value) olan düz bir dict'tir.

Boş bir value gönderin, listenin tamamı geri döner. lang.startswith("") her dil için doğrudur:

result.completion.values  # ['go', 'javascript', 'python', 'rust', 'typescript']

code hakkında sorun (işleyicinizin tanımadığı bir argüman); None döndürür, SDK da bunu boş bir listeye çevirir:

result.completion.values  # []

None "öneri yok" demektir, asla bir hata değildir. Arayüz düz bir metin kutusuna geri döner.

Hiç bildirmediğiniz bir yetenek

İşleyiciyi kaydetmek bildirimin ta kendisidir. Bir istemci bağlayın ve bakın:

client.server_capabilities.completions  # CompletionsCapability()

completions'ı hiçbir yerde listelemediniz. SDK işleyiciyi gördü ve yeteneği sizin yerinize bildirdi. İsteğe bağlı her yetenek böyle çalışır: işleyici bildirimin kendisidir. (Üç temel yapı isteğe bağlı değildir: MCPServer işleyici olsun olmasın bunları her zaman bildirir.)

Check

İlk server.py dosyasına (işleyicisi olmayana) dönün ve yine de sorun. Çağrı bir JSON-RPC hatasıyla başarısız olur:

Method not found

Ve client.server_capabilities.completions None olur. Yeteneğin anlamı budur: düzgün davranan bir istemci bunu kontrol eder ve yanıtlayamayacağınız isteği hiç göndermez.

Bağımlı argümanlar

github://repos/{owner}/{repo} kaynağının iki parametresi var ve repo için işe yarar değerler önce hangi owner'ın seçildiğine bağlı.

context tam da bunun için var. Kullanıcının hâlihazırda çözümlediği argümanları taşır:

server.py
from mcp.server import MCPServer
from mcp.types import Completion, CompletionArgument, CompletionContext, PromptReference, ResourceTemplateReference

mcp = MCPServer("GitHub Explorer")

LANGUAGES = ["go", "javascript", "python", "rust", "typescript"]

REPOS_BY_OWNER = {
    "modelcontextprotocol": ["python-sdk", "typescript-sdk", "inspector"],
    "pydantic": ["pydantic", "pydantic-ai", "logfire"],
}


@mcp.resource("github://repos/{owner}/{repo}")
def github_repo(owner: str, repo: str) -> str:
    """A GitHub repository."""
    return f"Repository: {owner}/{repo}"


@mcp.prompt()
def review_code(language: str, code: str) -> str:
    """Review a snippet of code."""
    return f"Review this {language} code:\n{code}"


@mcp.completion()
async def handle_completion(
    ref: PromptReference | ResourceTemplateReference,
    argument: CompletionArgument,
    context: CompletionContext | None,
) -> Completion | None:
    if isinstance(ref, PromptReference) and argument.name == "language":
        return Completion(values=[lang for lang in LANGUAGES if lang.startswith(argument.value)])
    if isinstance(ref, ResourceTemplateReference) and argument.name == "repo":
        if context is None or context.arguments is None:
            return None
        repos = REPOS_BY_OWNER.get(context.arguments.get("owner", ""), [])
        return Completion(values=[repo for repo in repos if repo.startswith(argument.value)])
    return None
  • Yeni dal, şablonun repo parametresi için devreye girer.
  • context.arguments, şu ana kadar seçilen değerlerin (burada owner) bir dict[str, str] | None'ıdır.
  • Henüz owner yoksa mantıklı öneri de yoktur; bu yüzden işleyici None döndürür.

İstemci bu çözümlenmiş değerleri context_arguments= ile gönderir. Bu kez ref bir ResourceTemplateReference(uri="github://repos/{owner}/{repo}") olur. Boş bir value ile repo'yu isteyin ve context_arguments={"owner": "modelcontextprotocol"} geçirin:

result.completion.values  # ['python-sdk', 'typescript-sdk', 'inspector']

context_arguments='ı kaldırın, aynı çağrı [] döndürür. İşleyici, sahibi bilmeden hangi depoları önereceğini bilemez.

Info

Completion ayrıca total= ve has_more= de alır. values daha uzun bir listenin bir dilimi olduğunda bunları ayarlayın; böylece arayüz "ve 200 tane daha" gösterebilir. Çoğu işleyicinin bunlara hiç ihtiyacı olmaz.

Özet

  • Tamamlamalar, prompt argümanları ve kaynak şablonu parametreleri için önerilerdir. Başka bir şey değil.
  • @mcp.completion() tek işleyiciyi kaydeder. İmzası async def (ref, argument, context) -> Completion | None'dır.
  • isinstance(ref, ...) ve argument.name üzerinden dallanın. argument.value'ya göre filtrelemeyi kendiniz yapın.
  • None boş bir listeye dönüşür. Asla bir hata değildir.
  • context.arguments hâlihazırda çözümlenmiş değerleri tutar; istemci bunları context_arguments= olarak sağlar.
  • completions yeteneği, işleyiciyi kaydettiğiniz anda ortaya çıkar. O olmadan istek Method not found olur.

Öneriler, kullanıcı bir prompt'u veya şablonu hâlâ doldururken işe yarar; bir araç çağrısının ortasında kullanıcıya soru sormak için Elicitation gerekir. Bir aracın metin dışında döndürebileceği her şey ise Görseller, ses ve simgeler sayfasında.