Agent'lara API tasarlamak: retry'a dayanıklı MCP tool contract'larıDesigning agent-facing APIs: MCP tool contracts that survive a retry
MCP'nin 2026-07-28 spec'i, kopan isteklerin yeniden gönderilmesini zorunlu kıldı. İki kez çağrılması güvenli olmayan bir tool artık production tool'u değil — şeması olan bir bug. Idempotency, handle'lar, hata şekilleri, MRTR ve şemanızın token faturası.
MCP's 2026-07-28 spec made re-issuing broken requests mandatory. A tool that is not safe to call twice is no longer a production tool — it is a bug with a schema. Idempotency, handles, error shapes, MRTR, and the token bill your schema runs up.
Naylalabs · MühendislikEngineeringv0.1.0).
Snapshot: Written against the MCP 2026-07-28 specification; last verified August 1, 2026. All schemas, tests and measurements come from the demo repo: agent-native-ops-demo (tag v0.1.0).
On yıllık REST, bize API'yi doküman okuyan, bağlamı kafasında tutan ve POST /orders'ı bir kez çağıran geliştiriciler için tasarlamayı öğretti. Bir MCP tool'unun çağıranı bunların hiçbirini yapmıyor. Açıklamanızı bir context window'dan örnekliyor, iki tur önce ne yaptığını unutuyor ve — 2026-07-28 spec'i itibarıyla — bir response stream'i uçuşta koptuğunda tool'unuzu ikinci kez ateşlemeye mecbur.
Ten years of REST taught us to design APIs for developers who read docs, hold context in their heads, and call POST /orders once. An MCP tool's caller does none of these things. It samples your description through a context window, forgets what it did two turns ago, and — as of the 2026-07-28 spec — is required to fire your tool a second time whenever a response stream breaks mid-flight.
Şu son cümle yavaş okunmayı hak ediyor. Spec, SSE resumability'yi kaldırdı: kopan stream uçuştaki isteği kaybeder ve client bunu yepyeni bir request ID ile tekrar göndermek zorundadır. "Retry" ile "yeni niyet"i protokol seviyesinde ayırt etmenin hiçbir yolu yok. Bunun operasyon tarafını serinin ilk yazısında işlettik ve ölçtük; bu yazı tasarım tarafı: ayakta kalan sözleşmeler.
That last sentence deserves a slow read. The spec removed SSE resumability: a broken stream loses the in-flight request, and the client must re-issue it with a brand-new request ID. There is no protocol-level way to tell "retry" apart from "new intent". We operated and measured the ops side in the first post of this series; this one is the design side: contracts that hold up.
01Tool contract, bir makineye verilmiş sözdürA tool contract is a promise to a machine
Tool contract'ı, bir agent'ın tool'unuzu çağırmadan önce bilebileceği her şeydir: isim, açıklama, inputSchema, outputSchema ve — örtük olarak — işler ters gittiğinde ne olacağı. Bir contract'ı şema dökümünden ayıran dört özellik var:
A tool contract is everything an agent can know about your tool before calling it: the name, the description, inputSchema, outputSchema, and — implicitly — what happens when things go wrong. Four properties separate a contract from a schema dump:
- İki kez çağrılması güvenlidir. Retry'lar artık protokol davranışı, client bug'ı değil.
- It is safe to call twice. Retries are protocol behavior now, not client bugs.
- Hataları bir model tarafından eyleme dönüştürülebilir. Agent destek ticket'ı açamaz; sadece hatanızı okuyup bir sonraki hamlesini seçebilir.
- Its errors are actionable by a model. An agent cannot open a support ticket; it can only read your error and choose its next move.
- State'i explicit'tir. Tool'un çağrılar arasında hatırladığı her şey, şemada bir handle olarak görünür.
- Its state is explicit. Anything the tool remembers across calls is visible in the schema as a handle.
- Fiyatlandırılmıştır. Şemanızın her karakteri, her agent'ın her oturumunda prompt token'ıdır — aşağıda 06'da ölçtük.
- It is priced. Every character of your schema is prompt tokens on every agent, every session — measured in section 06.
Yazının kalanı, en sık yanlış yapıldığını gördüğümüz sırayla bu dört özellik.
The rest of this post is those four properties, in order of how often we have seen them go wrong.
02Retry güvenliği: ilk çağrı için değil, ikinci çağrı için tasarlayınRetry-safety: design for the second call, not the first
Naif tool:
The naive tool:
// Mutlu yolda doğru. Bir stream ilk koptuğunda yanlış.// Correct on the happy path. Wrong the first time a stream breaks. @Tool({ name: 'create_invoice_naive', description: 'Müşteri için fatura oluşturur.''Creates an invoice for a customer.', parameters: z.object({ customerId: z.string(), amountCents: z.number().int().positive(), }), }) async createInvoice(@Payload() input: CreateInvoiceInput) { return this.invoices.create(input); // iki çağrı → iki fatura// two calls → two invoices }
2026-07-28 semantiğinde, iş commit olduktan sonra ama sonuç client'a ulaşmadan kopan bir stream, zorunlu bir retry üretir — ve bir duplicate fatura. Bunu ilk yazının pod-kill deneyinde ölçtük: koşu başına 8 crash ile, naif tool 2.700 niyetin 37'sinde çift fatura kesti (%1,37) — her 73 niyetten biri. Aynı deneyde aşağıdaki key'li tasarım bunu %0,05'e (2.108 niyette 1) indirdi. Çözümün yeri yorum satırı değil, contract'ın kendisi:
Under 2026-07-28 semantics, a stream that breaks after the work commits but before the result reaches the client produces a mandatory retry — and a duplicate invoice. We measured this in the first post's pod-kill experiment: with 8 crashes per run, the naive tool double-billed 37 of 2,700 intents (1.37%) — one in every 73. In the same experiment, the keyed design below cut that to 0.05% (1 in 2,108). The fix belongs in the contract, not in a comment:
// Retry burada baş tacı. Aynı key → aynı fatura, replay edilmiş sonuç.// Retries are welcome here. Same key → same invoice, replayed result. @Tool({ name: 'create_invoice', description: 'Fatura oluşturur. Her iş niyeti için benzersiz bir idempotency_key verin; ''Creates an invoice. Pass an idempotency_key that is unique per business intent; ' + 'aynı key ile gelen retry, yeni fatura oluşturmak yerine ilk faturayı döner.''a retry with the same key returns the first invoice instead of creating a new one.', parameters: z.object({ customerId: z.string(), amountCents: z.number().int().positive(), idempotency_key: z.string().max(64) .describe('Amaçlanan her fatura için benzersiz. SADECE aynı niyeti retry ederken tekrar kullanın.''Unique per intended invoice. Reuse ONLY when retrying the same intent.'), }), }) async createInvoice(@Payload() input: CreateInvoiceInput) { return this.idempotent.execute(input.idempotency_key, () => this.invoices.create(input), ); }
Orada üç tasarım kararı saklı ve her biri tutmanız gereken bir söz:
Three design decisions hide in there, and each one is a promise you must keep:
- Key çağırandan gelir. 2. çağrının retry mı yeni niyet mi olduğunu yalnızca agent bilir. Key'i payload hash'inden türetmeyin — meşru olarak iki özdeş fatura oluşturan bir agent, sessizce tek faturaya dedupe edilir.
- The key comes from the caller. Only the agent knows whether call #2 is a retry or a new intent. Do not derive keys from payload hashes — an agent legitimately creating two identical invoices would be silently deduplicated into one.
- Replay, orijinal sonucu bayt-bayt aynı döner. Replay edilen çağrıya "already exists" hatası dönmek, modele retry'ların tehlikeli olduğunu öğretir; API'nizin etrafından dolanmaya başlar — olasılıksal bir çağırana öğretmek isteyeceğiniz son şey.
- Replay returns the original result, byte-for-byte. A replayed call that returns "already exists" as an error teaches the model that retries are dangerous; it starts improvising around your API — exactly what you do not want a probabilistic caller learning.
- Key'in saklanan bir ömrü vardır.
key → sonuçeşlemesini makul her retry ufkundan uzun bir TTL ile kalıcılaştırın; pencereyi açıklamada belirtin. Ve deneyimizin en öğretici satırı: key'li koşudaki o tek duplicate, crash'in iş commit'i ile idem kaydının arasına denk geldiği andı — read-then-write idempotency atomik değildir. Gerçek exactly-once için iş commit'i ile idem kaydını aynı transaction'a koyun. - The key has a stored lifetime. Persist
key → resultwith a TTL longer than any plausible retry horizon; document the window in the description. And our experiment's most instructive row: the single duplicate in the keyed run was the crash landing between the business commit and the idem record — read-then-write idempotency is not atomic. For true exactly-once, put the commit and the idem record in one transaction.
Bunu açıklamada da söyleyin. Şema biçimi zorlar; modelin muhakemesine ulaşan tek kanal açıklamadır. "SADECE aynı niyeti retry ederken tekrar kullanın" dokümantasyon süsü değil — bir prompt'tur.
Say it in the description, too. The schema enforces shape; the description is the only channel that reaches the model's reasoning. "Reuse ONLY when retrying the same intent" is not documentation fluff — it is a prompt.
03Handle'lar: kendini gösteren stateHandles: state that shows itself
Spec'in çağrılar arası state cevabı, server-minted handle: sunucunun döndüğü, client'ın sıradan bir argüman olarak geri getirdiği opak bir string. Bu, state'i contract'ın içine koyuyor — ve bu bir hediye; sonuna kadar alın:
The spec's answer to cross-call state is the server-minted handle: an opaque string the server returns and the client passes back as an ordinary argument. This puts state inside the contract, and that is a gift — take it fully:
outputSchema: z.object({
results: z.array(SearchResult).max(20),
next_page: z.string().nullable()
.describe('Opak cursor. Devam etmek için search_next aracına verin. ~15 dakikada expire olur.''Opaque cursor. Pass it to search_next to continue. Expires in ~15 minutes.'),
})
- Opak ve versiyonlu. Prefix verin (
h1_…) ki saklanan referansları kırmadan encoding değiştirebilesiniz. Bir agent handle'ınızı decode edebiliyorsa, eninde sonunda bir agent decode edecek — ve handle sentezlemeye başlayacak. - Opaque and versioned. Prefix them (
h1_…) so you can rotate encodings without breaking stored references. If an agent can decode your handle, some agent eventually will — and will start synthesizing them. - Ömür, açıklamada. "~15 dakikada expire olur" model davranışını değiştirir: agent'lar cursor'ları istiflemek yerine vakitlice paginate eder.
- Lifetime in the description. "Expires in ~15 minutes" changes model behavior: agents paginate promptly instead of hoarding cursors.
- Expiry sürpriz değil, tanımlı bir hatadır. Süresi geçen handle, kurtarma ipucu taşıyan makine-okur bir
handle_expireddönmek zorunda ("aramayı yeniden başlat") — çünkü modelin alternatif yorumu, "bu tool bozuk", oturumun kalanını zehirler. - Expiry is a defined error, not a surprise. An expired handle must return a machine-readable
handle_expiredwith a recovery hint ("re-run the search") — because the model's alternative interpretation, "this tool is broken", poisons the rest of the session. - Handle, yetki değildir. Bir cursor'a sahip olmak, çağıranın kimliğinin vermeyeceği erişimi vermemeli. Şema handle'ı taşır; onun neye çözümlenebileceğine platformun kimlik modeli karar verir.
- A handle is not authority. Possessing a cursor must not grant access the caller's identity would not. The schema carries the handle; what it may resolve to is decided by the platform's identity model.
04Hata sözleşmeleri: hatalarınız artık birer promptError contracts: your errors are prompts now
Bir insan hataya çarptığında en kötü ihtimalle okur, iç çeker, başka bir şey dener. Bir agent hataya çarptığında hata metni context window'a girer ve sonraki her kararı şekillendirir. Testi basit: bir dil modeli, yalnızca bu hatayı okuyarak bir sonraki hamlesini doğru seçebilir mi?
When a human hits an error, worst case they read it, sigh, and try something else. When an agent hits an error, the error text enters the context window and shapes every subsequent decision. The test is simple: can a language model, reading only this error, choose its next action correctly?
{
"code": "quota_exceeded", // stabil, snake_case, enumerable
"message": "Bu workspace için aylık fatura kotası doldu.""The monthly invoice quota for this workspace is exhausted.",
"retryable": false, // yükün çoğunu taşıyan tek bit// the single bit doing most of the work
"retry_after_ms": null,
"recovery": "Kullanıcıdan kotayı artırmasını iste veya fatura oluşturmayı ertele.""Ask the user to raise the quota, or defer creating the invoice."
}
- Agent'ların gerçekten kullandığı alan
retryable. Modeller bu alana göre güvenilir dallanır; düzyazıyı güvenilir parse etmezler. retryableis the field agents actually use. Models reliably branch on it; they do not reliably parse prose.recoverymodele, emir kipinde konuşur. Doğaçlama-workaround arıza modunu engellediğiniz yer burası.recoveryspeaks to the model, in imperatives. This is where you prevent the improvised-workaround failure mode.- Kodları stabil ve sıkıcı tutun. Agent system prompt'larında ve eval suite'lerinde biterler; birini yeniden adlandırmak, hiçbir şema değişmese de breaking change'dir. Spec'in şeritlerinde kalın:
-32000–-32019implementasyona ayrılmış alan,-32020ve yukarısı spec'in. - Keep codes stable and boring. They end up in agent system prompts and eval suites; renaming one is a breaking change even though no schema changed. Stay inside the spec's lanes:
-32000–-32019is implementation-defined space,-32020and up belongs to the spec.
Ve bir yasak: başarısızlığı asla özür cümleli başarılı sonuç olarak kodlamayın. "Üzgünüm, bir şeyler ters gitti" mesajlı bir resultType: "complete", sahadaki en yaygın contract bug'ıdır — çağırana tool'unuzun bazen sessizce başarısız olduğunu öğretir, ki bu gürültülü başarısız olmaktan kötüdür.
And one prohibition: never encode failure as a successful result with an apologetic string. A resultType: "complete" carrying "Sorry, something went wrong" is the single most common contract bug in the wild — it teaches the caller that your tool sometimes silently fails, which is worse than failing loudly.
05MRTR: tool'un geriye soru sorması gerektiğindeMRTR: when the tool needs to ask a question back
2026-07-28, sunucu-başlatmalı istekleri (elicitation/create, sampling/createMessage) Multi Round-Trip Request ile değiştirdi: tool, inputRequests taşıyan bir resultType: "input_required" döner; client, orijinal isteği inputResponses ve sizin korelasyon için verdiğiniz requestState ile yeniden gönderir.
2026-07-28 replaced server-initiated requests (elicitation/create, sampling/createMessage) with Multi Round-Trip Requests: the tool returns a resultType: "input_required" carrying inputRequests, and the client retries the original request with inputResponses plus your requestState for correlation.
tools/call (request-id: r1)tools/call (request id r1)resultType: "input_required" · inputRequests ("hangi müşteri?") + requestStateresultType: "input_required" · inputRequests ("which customer?") + requestStateinputResponses + requestState — yeni request-id (r2), herhangi bir replicathe SAME request + inputResponses + requestState — a new request id (r2), any replicaresultType: "complete"requestState'iniz taşır; retry herhangi bir replica'ya düşebileceği için state ya kendi içinde ya da handle store'unuzda yaşamak zorunda.
Figure 1. In MRTR, correlation is carried by your requestState, not the protocol; since the retry can land on any replica, the state must live either inside itself or in your handle store.
- MRTR'ı eksik girdi için kullanın, onay tiyatrosu için değil. "Bu üç müşteriden hangisini kastettin?" iyi bir round trip. Her mutasyonda "Emin misin?" ise agent'lara otomatik onaylamayı öğretir — amacı boşa çıkarır ve her çağrının latency'sini ikiye katlar.
- Use MRTR for missing input, not for confirmation theater. "Which of these three customers did you mean?" is a good round trip. "Are you sure?" on every mutation teaches agents to auto-confirm — defeating the purpose and doubling latency on every call.
requestStatereplica değişimini atlatmak zorunda. Ya kendi içinde taşınır (imzalı, boyutu sınırlı, TTL'li) ya da handle'larınızın store'unda durur. Process belleği seçenek değil.requestStatemust survive a replica change. Either it rides inside itself (signed, size-capped, TTL'd) or it sits in the same store as your handles. Process memory is not an option.- Döngüyü sınırlayın. Çağrı başına en fazla bir-iki round trip ilan edin, ötesinde terminal hata dönün. Bırakırsanız agent'lar sonsuza kadar döner; devre kesicinin yaşadığı yer sizin contract'ınız.
- Bound the loop. Declare at most one or two round trips per call and return a terminal error beyond that. Agents will loop forever if you let them; your contract is where the circuit breaker lives.
06Token bütçesi: şemanız prompt'tur, prompt ise paraToken budgets: your schema is prompt, and prompt is money
Yayınladığınız her tool açıklaması ve şeması, sizi listeleyen her agent'ın context'ine enjekte edilir. Yani tool kataloğu, çağıranlarınızın ödediği tekrarlayan, istek-başına bir maliyettir — ve bir noktadan sonra doğruluk maliyetidir de, çünkü şişmiş kataloglar tool seçimini bozar. Demo repo'nun 6 tool'luk kataloğunu üç yazım stiliyle tokenladık (scripts/schema-tokens.py, o200k_base):
Every tool description and schema you publish is injected into the context of every agent that lists you. A tool catalog is therefore a recurring, per-request cost paid by your callers — and past a point, an accuracy cost too, because bloated catalogs degrade tool selection. We tokenized the demo repo's 6-tool catalog in three writing styles (scripts/schema-tokens.py, o200k_base):
| StilStyle | Token / katalogTokens / catalog | 1M oturumdaPer 1M sessions | OranRatio |
|---|---|---|---|
| (a) Kuru — açıklamasız şema(a) Terse — schema, no descriptions | 652 | 652M | 0.62× |
| (b) İşlenmiş — 1-2 cümle + kritik kurallar(b) Engineered — 1-2 sentences + critical rules | 1 052 | 1.05B | 1.00× |
| (c) Şişkin — her alana paragraf boilerplate(c) Bloated — a boilerplate paragraph per field | 2 516 | 2.52B | 2.39× |
Dolar karşılığını sağlayıcınızın güncel girdi fiyatıyla kendiniz çarpın; oran değişmiyor: şişkin stil, işlenmiş stilin 2,4 katı — ve 1M oturumda aradaki fark 1,5 milyar token. Kuru stil %38 tasarruf ettiriyor ama modelin muhakemesine ulaşan tek kanalı (kural cümlelerini) da atıyor. Tatlı nokta (b): bir cümle ne yaptığı, bir cümle modelin çiğnememesi gereken kurallar (idempotency tekrar kullanımı, handle expiry), başka hiçbir şey.
Multiply into dollars with your provider's current input price; the ratio does not change: the bloated style costs 2.4× the engineered one — and the gap per 1M sessions is 1.5 billion tokens. The terse style saves 38% but throws away the only channel that reaches the model's reasoning (the rule sentences). The sweet spot is (b): one sentence of what, one sentence of rules the model must not break (idempotency reuse, handle expiry), nothing else.
- Spec artık deterministik tool sıralaması öneriyor — stabil katalog, karşı taraftaki LLM için cache'lenebilir bir prompt prefix'i. Tool'larınızı sort'layın; tek satır ve ops tarafındaki
ttlMshikâyesiyle bileşik faiz yapıyor. - The spec now recommends deterministic tool ordering — a stable catalog is a cacheable prompt prefix for the LLM on the other side. Sort your tools; it is one line, and it compounds with the
ttlMsstory on the ops side. - 2026-07-28,
inputSchema'yı$refdahil tam JSON Schema 2020-12'ye açtı. Ortak şekilleri (Money,CustomerRef)$refile tekilleştirin — katalog küçülür, model beş yarım-kopya yerine tek kanonik tanım öğrenir. - 2026-07-28 loosened
inputSchemato full JSON Schema 2020-12 with$ref. Deduplicate shared shapes (Money,CustomerRef) via$ref— smaller catalogs, and one canonical definition for the model to learn instead of five near-duplicates.
07Contract'ı çağıranları şaşırtmadan evriltmekEvolving a contract without gaslighting your callers
Agent'lar kataloğunuzu cache'ler (ttlMs ne kadar süreyle olduğunu söyler) ve modeller oturum boyunca semantiğinizi içselleştirir. Contract değişikliğinin tam olarak üç güvenli çeşidi vardır:
Agents cache your catalog (ttlMs says for how long) and models internalize your semantics across a session. Contract changes come in exactly three safe flavors:
- Ekleyici: yeni opsiyonel alanlar, yeni tool'lar. Güvenli.
- Additive: new optional fields, new tools. Safe.
- Semantik: aynı şekil, farklı davranış. Bunu asla sessizce yapmayın — agent davranışı diff'leyemez, sadece şekli diff'ler.
create_invoiceotomatik e-posta atmaya başladıysa, bu bir patch değil yeni bir tool'dur. - Semantic: same shape, different behavior. Never do this silently — an agent cannot diff behavior, only shape. If
create_invoicestarts auto-sending emails, that is a new tool, not a patch. - Kırıcı: yeni isim (
search_v2); eski tool, modele nereye gideceğini kelimenin tam anlamıyla söyleyen bir açıklamayla deprecation penceresi boyunca yaşar: "Deprecated. Typed sonuç dönen search_v2'yi tercih edin." Açıklama-prompt kanalı migration'ı sizin yerinize yapar — spec'in kendi protokol özellikleri için benimsediği lifecycle politikasının tool ölçeğindeki aynası. - Breaking: a new name (
search_v2); the old tool lives through a deprecation window with a description that literally tells the model where to go: "Deprecated. Prefer search_v2, which returns typed results." The description-as-prompt channel does the migration for you — mirroring, at tool scale, the lifecycle policy the spec adopted for protocol features.
08Implementasyonu değil, contract'ı test edinTest the contract, not the implementation
Demo repo'daki contract testleri bilerek aptal — bir şeyleri yakalamalarının sebebi de bu:
The contract tests in the demo repo are deliberately dumb, which is why they catch things:
// Retry güvenliği için önemli olan yegâne üç test.// The only three tests that matter for retry safety. it('tekrar değil replay: aynı idempotency_key → tek side effect, özdeş sonuç''replays rather than repeats: same idempotency_key → one side effect, identical result', async () => { const key = 'itest-' + randomUUID(); const a = await callTool('create_invoice', { ...input, idempotency_key: key }); const b = await callTool('create_invoice', { ...input, idempotency_key: key }); expect(await countInvoices()).toBe(1); expect(b).toStrictEqual(a); // bayt-bayt replay }); it('süresi geçmiş handle, 500 değil recovery taşıyan handle_expired döner''an expired handle returns handle_expired carrying recovery, not a 500', async () => { /* … */ }); it('katalog deterministik ve token bütçesinin içinde', async () => { const l1 = await listTools(), l2 = await listTools(); expect(l1).toStrictEqual(l2); expect(countTokens(JSON.stringify(l1))).toBeLessThan(BUDGET); });
Kataloğun kendisini CI'da snapshot-test edin: herhangi bir tool açıklamasını değiştiren PR, review'da bir contract diff'i olarak görünür — çünkü tam olarak odur. Bir contract bug'ı production'a sızdığında isteyeceğiniz iz ise girdileri ve retry bağlantısıyla tool-call span'ı — serinin observability yazısının bölgesi.
Snapshot-test the catalog itself in CI: a PR that changes any tool description shows up in review as a contract diff — because that is what it is. And when a contract bug does reach production, the trail you will want is the tool-call span with its inputs and retry linkage — this series' observability post's territory.
09Sık sorulanlarFAQ
Her tool idempotency key almalı mı?
Salt-okur tool'lar almamalı — aramaya takılan gereksiz bir key, şema gürültüsüdür (ve 06'daki tabloya göre token harcamasıdır). Side effect'i olan her tool almalı. Bir tool'un "gerçekten" side effect'i var mı emin değilseniz, vardır.
Should every tool take an idempotency key?
Read-only tools should not — a spurious key on a search is schema noise (and per section 06's table, token spend). Every tool with a side effect should. If you are unsure whether a tool "really" has side effects, it has side effects.
Neden payload hash'iyle dedupe etmek yerine client'ın verdiği key?
Çünkü niyet çağıranda yaşar. İki özdeş payload iki gerçek niyet olabilir ("iki kez aldılar, iki kez tahsil et"); bunu yalnızca agent bilir. Hash-dedup, sunucunun tahmin yürütmesidir — ve yanlış tahmin ettiğinde gerçek işi sessizce yutar.
Why client-supplied keys instead of deduplicating by payload hash?
Because intent lives in the caller. Two identical payloads can be two genuine intents ("charge them twice, they bought twice"); only the agent knows. Hash-dedup is the server guessing — and silently swallowing real work when it guesses wrong.
Mutasyon yapan tool'lara hint koyup dikkatli olmayı client'a bırakamaz mıyım?
Hint'ler client'ın onay isteyip istemeyeceğini şekillendirir; kopan stream sonrası zorunlu yeniden gönderime hiçbir şey yapmaz. Retry güvenliği çağırana devredilemez — çağıran, retry etmeye mecbur.
Can I just add hints to mutating tools and rely on the client to be careful?
Hints shape whether a client asks for confirmation; they do nothing about the mandatory re-issue after a broken stream. Retry-safety cannot be delegated to the caller — the caller is required to retry.
Açıklamalar ne kadar ayrıntılı olmalı?
Bir cümle amaç, bir cümle kural. Ötesi, kendi tool-seçim doğruluğunuzu düşürmek için token ödemektir — 06'daki tablo: boilerplate stil, işlenmiş stilin 2,4 katı.
How verbose should descriptions be?
One sentence of purpose, one sentence of rules. Past that you are paying tokens to lower your own tool-selection accuracy — per the table in section 06, the boilerplate style costs 2.4× the engineered one.
10Changelog
- 1 Ağustos 2026 — İlk yayın; MCP 2026-07-28 ve demo repo
v0.1.0ile doğrulandı. - August 1, 2026 — Initial publication; verified against MCP 2026-07-28 and demo repo
v0.1.0.