İlerleme
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.
Otuz saniye süren ve otuz saniye boyunca hiçbir şey söylemeyen bir araç bozuk görünür.
İlerleme bildirimleri bunu çözer. Araç ne kadar ilerlediğini bildirir; bununla ne çizeceğine istemci karar verir: bir çubuk, dönen bir simge, bir log satırı.
Araçtan bildirme
Bir Context parametresi alın ve report_progress'i çağırın:
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
@mcp.tool()
async def import_catalog(urls: list[str], ctx: Context) -> str:
"""Import book records from a list of catalog URLs."""
for done, url in enumerate(urls, start=1):
await ctx.report_progress(done, total=len(urls), message=f"Imported {url}")
return f"Imported {len(urls)} records."
Üç argüman var ve ne anlama geldiklerine siz karar verirsiniz:
progress: ne kadar ilerlediğiniz. Spesifikasyon bunun her bildirimde artmasını şart koşar; asla bir değeri tekrarlamayın veya geriye gitmeyin.total: biliyorsanız, toplamda ne kadar iş olduğu. İsteğe bağlı.message: bu adım hakkında insanların okuyabileceği tek bir satır. İsteğe bağlı.
ctx tür ipucu sayesinde enjekte edilir ve model onu asla görmez: import_catalog'un girdi şemasında tek bir özellik var, urls. Context nesnesi sayfası baştan sona bu nesneyi anlatır; ilerleme, onun size sunduklarından biridir.
İstemciden dinleme
İstemci, call_tool'a progress_callback= geçirerek çağrı başına dahil olur:
import anyio
from mcp import Client
from server import mcp
async def show(progress: float, total: float | None, message: str | None) -> None:
print(f"{message} ({progress}/{total})")
async def main() -> None:
async with Client(mcp) as client:
result = await client.call_tool(
"import_catalog",
{"urls": ["https://example.com/a.json", "https://example.com/b.json"]},
progress_callback=show,
)
print(result.structured_content)
anyio.run(main)
Callback, sunucunun bildirdiklerini olduğu gibi alan async bir fonksiyondur: progress, total, message.
Info
Client(mcp) doğrudan sunucu nesnesine, bellek içinde bağlanır; Test etme
sayfasının üzerine kurulduğu istemcinin aynısıdır. Client hangi aktarımı kullanırsa kullansın
progress_callback aynı parametredir; birazdan göreceğiniz zamanlama ise bellek içi bağlantıya
özgüdür. Bu bağlantı callback'inizi satır içinde çalıştırır, bu yüzden her bildirim call_tool
dönmeden önce ulaşır. Gerçek bir aktarım üzerinde bildirimler sonuçla yarışır ve yavaş bir callback,
call_tool döndükten sonra hâlâ çalışıyor olabilir.
Deneyin
client.py dosyasını server.py dosyasının yanına koyun ve çalıştırın:
python client.py
Imported https://example.com/a.json (1/2)
Imported https://example.com/b.json (2/2)
{'result': 'Imported 2 records.'}
Sunucudaki her await ctx.report_progress(...), istemcide sırasıyla bir show çağrısına dönüştü ve her iki satır da call_tool dönmeden önce yazdırıldı. İlerleme sonucun içine paketlenmez; araç hâlâ çalışırken akar.
Warning
progress_callback Client'a değil, çağrıya aittir. Bunun için bir kurucu argümanı yoktur,
çünkü farklı çağrılar farklı callback'ler ister: biri bir indirme çubuğunu sürer, sonraki bir
log satırını.
Check
Şimdi progress_callback=show kısmını silin ve yeniden çalıştırın:
{'result': 'Imported 2 records.'}
Hata yok, uyarı yok, sonuç aynı. report_progress, çağıran taraf ilerleme istemediğinde hiçbir
şey yapmaz; bu yüzden koşulsuz bildirirsiniz ve birinin dinleyip dinlemediğini asla merak etmeniz
gerekmez.
Toplamı bilmediğinizde
total, paydayı bildiğiniz durumlar içindir. Çoğu zaman bilmezsiniz: bir akışı boşaltıyor, bir imleç üzerinde ilerliyor ya da uzunluk başlığı olmayan bir şey indiriyorsunuzdur.
Belirtmeyin:
from collections.abc import AsyncIterator
from mcp.server import MCPServer
from mcp.server.mcpserver import Context
mcp = MCPServer("Bookshop")
async def fetch_records(feed_url: str) -> AsyncIterator[str]:
for title in ("Dune", "Neuromancer", "Hyperion"):
yield f"{feed_url}#{title}"
@mcp.tool()
async def import_feed(feed_url: str, ctx: Context) -> str:
"""Import every record a catalog feed yields."""
imported = 0
async for record in fetch_records(feed_url):
imported += 1
await ctx.report_progress(imported, message=f"Imported {record}")
return f"Imported {imported} records."
Callback total=None alır. İstemci yine de etkinlik gösterebilir ("şimdiye kadar 3 tane içe aktarıldı...") ama yüzde gösteremez. Daha güzel bir çubuk için toplam uydurmayın.
Tip
progress'in belirli bir şeyi sayması gerekmez. Bayt, satır, sayfa: kullanıcının tanıyacağı
birimi seçin ve yalnızca tutabileceğiniz bir total sözü verin.
Özet
Contextalan herhangi bir araçtanawait ctx.report_progress(progress, total=None, message=None).- İstemci
call_tool'aprogress_callback=geçirir: çağrı başına, aslaClientüzerinde değil. - Callback
async (progress, total, message) -> Nonebiçimindedir ve araç hâlâ çalışırken tetiklenir. - Çağrıda callback yoksa
report_progresshiçbir şey yapmaz. Koşulsuz bildirin. - Bilmediğinizde
total'ı vermeyin; callbackNonealır.
İlerleme, çalışan bir aracın kullanıcıya gösterdiği şeydir. Sizin için, yani sunucuyu işleten kişi için yazdığı log satırları ise ayrı bir kanaldır: Log tutma.