Claude API'de Skills, Code Execution ve MCP Connector: Hazır Yetenekleri ve Remote MCP Server'ları Kullanmak
Claude API'de Excel gibi dosyaları üretmek için container.skills ile xlsx skill'ini ve code execution tool'unu birlikte gönderir, $OUTPUT_DIR'dan dönen file_id'leri Files API ile indirirsin; remote MCP server'ı ise mcp_servers ve mcp_toolset ikilisiyle beta header'la API'ye bağlarsın. Sandbox sınırları ve fiyatı, custom SKILL.md yüklemek, pause_turn ve container, allowlist, token kapsamı ve SDK'nın null ve liste davranışı.
Sürüm notu: Bu yazıdaki kodlar .NET 10, Anthropic C# SDK 13.8.0 ve Claude API version 2026-10-21 ile derlenmiş, birim testleri çalıştırılmıştır. Testler SDK'nın gerçek client'ını ağa çıkmayan sahte bir HttpMessageHandler ile kullanıyor; sahte cevapların yapısı Files API, code execution, Skills ve MCP (Model Context Protocol; modele tool ve veri kaynaklarını standart bir yolla bağlayan protokol) connector sayfalarından alınmış, id'ler test için uydurulmuştur. Davranışlar, limitler ve fiyatlar 15 Kasım 2026'da platform.claude.com belgelerinden alınmıştır. Bu yazıda resmî belgelerden yararlanılmıştır.
Önce Tahmin Et
Selin her ayın başında sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) için bir yönetim raporu istiyor: günlük ciro, en çok satan kitaplar, bir grafik ve en çok satanların güncel stoku. Bugün bunu Emre elle, bir Excel dosyasında hazırlıyor. Yeni fikir şu: satış verisini Claude'a ver, Excel'i Claude üretsin, stok bilgisini de Bookstore'un AI Agent'ları ve MCP serisinin onuncu yazısında yazdığımız remote MCP server'dan alsın.
Tahminin ne? Excel dosyasını kim üretir, nerede çalışır ve sana nasıl geri gelir? MCP server'a giden çağrıyı Bookstore.Api mi yapar, yoksa Claude API mi? Ve bu işin bir yerinde müşteri verisi sızma riski var mı? Bu yazıda Claude API'nin kendi tarafında çalışan üç parçasına bakıyoruz: code execution tool'u, Skills API ve MCP connector. Agent pattern'leri ve MCP server yazmak AI Agent'ları ve MCP serisinin konusu; burada o server'ı API'den kullanmayı anlatıyoruz.
Code Execution: Claude'un Sandbox'ı
Code execution tool'u beşinci yazıdaki server tool'lardan biri: tanımı isteğe sen koyuyorsun ama kodu Anthropic'in container'ı çalıştırıyor ve sonuç aynı cevapta geliyor. Belgeye göre tool Claude'a iki alt tool veriyor: shell komutu çalıştıran bash_code_execution ve dosya oluşturup düzenleyen text_editor_code_execution. Üç güncel sürüm var: code_execution_20250825 bash ve dosya işlemlerini, code_execution_20260120 buna ek olarak REPL (komutları tek tek çalıştırıp sonucu hemen gösteren etkileşimli ortam) state'i ve programmatic tool calling'i, code_execution_20260521 ise aynı runtime'ı Python hücrelerindeki 90 saniyelik sınırı modele anlatan bir açıklamayla getiriyor. Hiçbiri beta header istemiyor. Skills sayfasının bütün örnekleri ilk sürümü kullanıyor; biz de onu kullandık.
Sandbox'ın sınırları belgede net: Python 3.11, Linux, x86_64, 5 GiB bellek, 5 GiB disk, 1 CPU. İnternet erişimi tamamen kapalı, çalışma anında paket kurulamıyor; pandas, openpyxl, matplotlib, python-pptx, pypdf gibi kütüphaneler hazır geliyor. Container'lar workspace'e bağlı ve oluşturulduktan 30 gün sonra sona eriyor. Yaklaşık 5 dakika boşta kalan container checkpoint'e alınıyor ve aynı id ile gelen istek onu geri yüklüyor.
Fiyatlandırma iki parçalı. Web search ya da web fetch ile birlikte kullanıldığında code execution için ek ücret yok. Tek başına kullanıldığında çalışma süresi token'lardan ayrı faturalanıyor: en az 5 dakika sayılıyor, organizasyon başına ayda 1.550 saat ücretsiz, sonrası container başına saatte 0,05 USD. İstekte dosya varsa tool hiç çağrılmasa da süre faturalanıyor, çünkü dosyalar container'a önceden yükleniyor.
Skills: Hazır ve Kendi Yeteneklerimiz
Skill, talimatlardan, script'lerden ve kaynak dosyalardan oluşan bir klasör. Skills sayfasına göre Skills API 19 Ağustos 2026'dan beri beta değil. İki kaynak var: Anthropic'in hazır skill'leri (pptx, xlsx, docx, pdf; sürümleri tarih biçiminde ya da latest) ve senin yüklediğin custom skill'ler (skill_... id'li, sürümleri skver_... ya da latest, yalnız kendi workspace'inde görünür). İkisi de aynı yoldan kullanılıyor: isteğin container parametresinde skills listesi ve yanında code execution tool'u. Bir istekte en fazla 20 skill olabiliyor.
Belge yükleme sırasını şöyle anlatıyor: Claude önce her skill'in yalnız adını ve açıklamasını system prompt'ta görüyor, skill dosyaları container'da /skills/{skill-name}/ altına kopyalanıyor ve tam talimatlar yalnız gerektiğinde okunuyor. Bu yüzden açıklama satırı önemli; Claude bir skill'i ne zaman kullanacağına ona bakarak karar veriyor.
Bookstore'un rapor kuralları için küçük bir custom skill yazdık:
---
name: bookstore-report
description: Bookstore's conventions for management reports built from sales data. Use when creating an Excel or PDF report about Bookstore sales, revenue or stock.
---
# Bookstore report conventions
## Workbook layout
- First sheet: `Summary` with the month, total revenue, number of orders and number of books sold.
- Second sheet: `Daily revenue` with one row per day and a line chart of revenue.
- Third sheet: `Top titles` with the ten best-selling titles, sorted by revenue.
- If stock data is available, a fourth sheet: `Stock` with the current stock of the top titles.
## Formatting
- Amounts are in Turkish lira; use the number format `#,##0.00 "TRY"`.
- Dates use `yyyy-mm-dd`.
- Freeze the header row on every sheet.
## Rules
- Use only the data in the uploaded files and the tool results. Never invent numbers.
- Do not add customer names, e-mail addresses or other personal data to any sheet.
- Name the file `sales-report-YYYY-MM.xlsx` and save it to `$OUTPUT_DIR`.
Belgedeki kurallar: SKILL.md yüklemenin kökünde ya da tek bir üst klasörün en üstünde olmalı; name en fazla 64 karakter, yalnız küçük harf, rakam ve tire, içinde anthropic ya da claude geçemez; description en fazla 1.024 karakter; yüklemenin toplamı 30 MB'ın altında. Yükleme kodu dosya adlarını klasörle birlikte gönderiyor:
public static class SkillUploader
{
// Dosya adları klasörü korur ("bookstore-report/SKILL.md"); SKILL.md tek bir üst klasörün en üstünde durur.
public static SkillCreateParams BuildCreateParams(string skillDirectory)
{
string root = Path.GetFullPath(skillDirectory);
string folder = new DirectoryInfo(root).Name;
List<BinaryContent> files = Directory.EnumerateFiles(root, "*", SearchOption.AllDirectories)
.Order(StringComparer.Ordinal)
.Select(path => new BinaryContent
{
Stream = File.OpenRead(path),
FileName = folder + "/" + Path.GetRelativePath(root, path).Replace('\\', '/'),
})
.ToList();
if (!files.Any(f => f.FileName == folder + "/SKILL.md"))
{
throw new InvalidOperationException($"{skillDirectory} has no SKILL.md at its top level.");
}
return new SkillCreateParams { Files = files };
Yükleme bir kez yapılıyor, dönen skill_... id'si yapılandırmaya giriyor. Belge bir uyarıyı ayrıca vurguluyor: skill'ler talimat ve kod taşıdığı için yalnız kendi yazdığın ya da Anthropic'ten gelen skill'leri kullan. Güvenilmeyen bir skill, Claude'u tool'ları ve kodu beklenmedik şekilde kullanmaya yönlendirebilir.
MCP Connector: Remote Server'ı API Çağırsın
MCP connector, Claude API'nin bir remote MCP server'a senin yerine bağlanmasını sağlıyor; Bookstore.Api bir MCP client'ı çalıştırmıyor. Özellik beta ve iki header'ı var: mcp-client-2025-11-20 ve onun her şeyini içeren mcp-client-2026-09-15. Belge yenisini öneriyor; bu sürüm her server'ın döndürdüğü tool listesini kaydedip sabitlemeye de izin veriyor, böylece konuşma ortasında tool'larını değiştiren bir server Claude'un gördüğü listeyi değiştirmiyor. Plan yazılırken eski header vardı; biz yenisini kullanıyoruz.
Kurulum iki parçadan oluşuyor ve ikisi de şart: mcp_servers dizisinde bağlantı bilgisi (type: url, https:// ile başlayan adres, benzersiz bir name, gerekiyorsa authorization_token), tools dizisinde de o server'ı adıyla gösteren bir mcp_toolset. Belgenin doğrulama kurallarına göre her server tam olarak bir toolset tarafından kullanılmalı; yalnız mcp_servers gönderip toolset'i unutmak validation hatası. Sınırlar da önemli: MCP spec'inin yalnız tool çağrıları destekleniyor (prompt ve resource yok) ve server internete HTTP ile açık olmalı; Streamable HTTP ve SSE (Server-Sent Events; sunucudan istemciye tek yönlü olay akışı) kabul ediliyor, yerel stdio server'lar bağlanamıyor. Geliştirme makinendeki localhost server'ına Claude API ulaşamaz.
C# SDK'da MCP connector beta namespace'inde: client.Beta.Messages ve Anthropic.Models.Beta.Messages tipleri. Code execution ve skill'ler beta olmayan client.Messages ile de kullanılabiliyor, ama hepsini tek istekte istediğimiz için raporu beta API ile kuruyoruz.
Bookstore: Aylık Satış Raporu
İsteği kuran method:
public static MessageCreateParams BuildRequest(
IReadOnlyList<BetaMessageParam> messages, string? containerId, SalesReportOptions settings)
{
bool useInventory = !string.IsNullOrWhiteSpace(settings.InventoryMcpUrl);
List<BetaToolUnion> tools = [new BetaCodeExecutionTool20250825()];
if (useInventory)
{
// mcp_servers ve mcp_toolset birlikte gider: her server'ı tam olarak bir toolset kullanmalı.
tools.Add(new BetaMcpToolset
{
McpServerName = InventoryServerName,
// Allowlist: server başka ne sunarsa sunsun yalnız salt okunur stok tool'u.
DefaultConfig = new BetaMcpToolDefaultConfig { Enabled = false },
Configs = new Dictionary<string, BetaMcpToolConfig> { ["get_stock_levels"] = new() { Enabled = true } },
});
}
List<BetaSkillParams> skills = [new() { Type = BetaSkillParamsType.Anthropic, SkillID = "xlsx", Version = "latest" }];
if (!string.IsNullOrWhiteSpace(settings.ConventionsSkillId))
{
skills.Add(new() { Type = BetaSkillParamsType.Custom, SkillID = settings.ConventionsSkillId, Version = "latest" });
}
BetaContainerParams container = new() { Skills = skills };
// SDK bir property'yi set edildiği anda serialize eder: listeleri önce kur, bir kez ata.
MessageCreateParams request = new()
{
Model = settings.Model,
MaxTokens = 8192,
// İlk istekten sonra aynı container bu turun dosyalarını tutar; ID = null "id": null gönderirdi.
Container = containerId is null ? container : container with { ID = containerId },
Messages = messages,
Tools = tools,
};
if (!useInventory)
{
return request;
}
return request with
{
McpServers =
[
new BetaRequestMcpServerUrlDefinition
{
Name = InventoryServerName,
Url = settings.InventoryMcpUrl!,
AuthorizationToken = settings.InventoryMcpToken,
},
],
Betas = [AnthropicBeta.McpClient2026_09_15],
};
}
Üç karar var. Skill listesi sabit sırada; Skills sayfasına göre skill listesini değiştirmek prompt cache'ini bozuyor. Toolset bir allowlist: default_config.enabled = false, yalnız get_stock_levels açık. Server ileride sipariş iptal eden bir tool eklese bile Claude onu görmüyor. Belge de salt okunur asistanlarda yazan tool'ların kapatılmasını öneriyor. Üçüncüsü token: yapılandırmadan geliyor, kodda ya da appsettings.json'da değil:
public sealed class SalesReportOptions
{
public const string SectionName = "SalesReport";
public string Model { get; set; } = "claude-sonnet-5-5";
// Yüklenen bookstore-report skill'inin skill_... id'si (SkillUploader). Boşsa yalnız Anthropic'in xlsx skill'i.
public string? ConventionsSkillId { get; set; }
// Bookstore'un stok tool'larını sunan remote MCP server (AI Agent'ları ve MCP serisi). Boşsa MCP connector yok.
public string? InventoryMcpUrl { get; set; }
// O server için salt okunur bir token; user secrets'tan ya da bir vault'tan, asla appsettings.json'dan değil.
public string? InventoryMcpToken { get; set; }
}
Akışın kendisi:
try
{
List<BetaMessageParam> messages =
[
new BetaUserMessageParam
{
Content = new List<BetaContentBlockParam>
{
new BetaContainerUploadBlockParam { FileID = upload.ID },
new BetaTextBlockParam
{
Text = $"""
The uploaded CSV has Bookstore's book sales for {year}-{month:00}.
Build an Excel management report with the xlsx skill: revenue per day, top titles and a chart.
If the inventory tool is available, add a sheet with the current stock of the top titles.
Save the workbook as sales-report-{year}-{month:00}.xlsx in $OUTPUT_DIR and list the directory.
Then reply with a three-sentence summary.
""",
},
},
},
];
string? containerId = null;
List<string> outputFileIds = [];
BetaMessage response;
int requests = 0;
do
{
response = await claude.Beta.Messages.Create(BuildRequest(messages, containerId, options.Value), cancellationToken);
requests++;
containerId = response.Container?.ID ?? containerId;
outputFileIds.AddRange(OutputFileIds(response));
// pause_turn: Claude devam edebilsin diye turu aynı container'da değiştirmeden geri gönder.
messages.Add(new BetaAssistantMessageParam
{
Content = response.Content.Select(block => new BetaContentBlockParam(block.Json)).ToList(),
});
}
while (response.StopReason?.Value() == BetaStopReason.PauseTurn && requests < MaxRequests);
List<ReportFile> files = [];
foreach (string fileId in outputFileIds.Distinct())
{
files.Add(await DownloadAndDeleteAsync(fileId, cancellationToken));
}
string summary = string.Concat(response.Content.Select(b => b.TryPickText(out BetaTextBlock? t) ? t.Text : string.Empty));
logger.LogInformation("Sales report {Year}-{Month}: stop={StopReason} requests={Requests} files={Files}",
year, month, response.StopReason?.Raw(), requests, files.Count);
return new SalesReport(summary.Trim(), files, requests);
}
finally
{
// CSV yalnız bu çalışma içindi.
await claude.Files.Delete(upload.ID, cancellationToken: CancellationToken.None);
}
CSV (virgülle ayrılmış değerler) dosyası, sekizinci yazıdaki Files API ile yükleniyor ve mesaja container_upload block'uyla giriyor; belgeye göre code execution'a veri dosyası vermenin yolu bu. CSV'de yalnız sipariş numarası, tarih, ISBN (International Standard Book Number; kitaplara verilen uluslararası numara), başlık ve fiyat var, müşteri bilgisi yok. Sandbox'a göndermediğin veri sızamaz.
Uzun bir skill çalışması stop_reason: pause_turn ile durabiliyor. Belgeye göre cevabı olduğu gibi geri gönderirsen Claude turuna devam ediyor; container id'sini de göndermek gerekiyor, aksi hâlde istek yeni bir container'da çalışıyor ve o ana kadar üretilen dosyalar kayboluyor. Döngü bunu en fazla dört istekle yapıyor.
Üretilen dosyalar nasıl geri geliyor? Belgeye göre her bash_code_execution çağrısı boş bir $OUTPUT_DIR klasörü alıyor; komut bitince bu klasörün en üst seviyesindeki dosyalar yakalanıp sonuçta file_id olarak dönüyor. Başka bir yere yazılan dosya container'da kalıyor. Belge bu yüzden Claude'a dosyayı $OUTPUT_DIR'a kopyalamasını ve klasörü listelemesini açıkça söylemeyi öneriyor; prompt'taki "save ... in $OUTPUT_DIR and list the directory" cümlesinin sebebi bu.
// $OUTPUT_DIR'a yazılan dosyalar bash_code_execution sonuçlarında file id olarak döner.
public static IEnumerable<string> OutputFileIds(BetaMessage response) =>
response.Content
.Select(block => block.TryPickBashCodeExecutionToolResult(out BetaBashCodeExecutionToolResultBlock? result) ? result : null)
.Where(result => result is not null)
.SelectMany(result => result!.Content.TryPickBetaBashCodeExecutionResultBlock(out BetaBashCodeExecutionResultBlock? ok)
? ok.Content.Select(output => output.FileID)
: []);
private async Task<ReportFile> DownloadAndDeleteAsync(string fileId, CancellationToken cancellationToken)
{
FileMetadata metadata = await claude.Files.RetrieveMetadata(fileId, cancellationToken: cancellationToken);
using Anthropic.Core.HttpResponse download = await claude.Files.Download(fileId, cancellationToken: cancellationToken);
await using Stream content = await download.ReadAsStream(cancellationToken);
using MemoryStream buffer = new();
await content.CopyToAsync(buffer, cancellationToken);
// Üretilen dosyalar silinene kadar organizasyonun depolama alanından yer kaplar.
await claude.Files.Delete(fileId, cancellationToken: cancellationToken);
return new ReportFile(metadata.Filename, buffer.ToArray());
}
}
Kendi yüklediğin dosyalar indirilemiyordu; skill'lerin ve code execution'ın ürettikleri indirilebiliyor. İndirdikten sonra hem CSV'yi hem üretilen dosyayı siliyoruz; ikisi de silinene kadar organizasyonun depolama alanında duruyor.
SDK'da İki Sürpriz
Testleri yazarken SDK 13.8.0'ın iki davranışıyla karşılaştık; ikisi de istek gövdesini sessizce değiştiriyor.
Birincisi, bir property'ye null atamak alanı göndermemek değil. İlk sürümde ID = containerId yazdık; ilk istekte containerId null olduğu için gövdede "id": null gitti. Yedinci yazıdaki diagnostics alanında da aynı şeyi görmüştük. API'nin bunu nasıl karşıladığını belge söylemiyor, biz alanı yalnız değer varken set ediyoruz.
İkincisi, SDK bir property'yi set edildiği anda serialize ediyor. İlk sürümde Tools = tools atamasından sonra listeye mcp_toolset ekledik; test toolset'in gövdede olmadığını gösterdi. Küçük bir deneme bunu doğruluyor:
List<MessageParam> messages = [new UserMessageParam { Content = "first" }];
MessageCreateParams request = new() { Model = "claude-haiku-5-5", MaxTokens = 10, Messages = messages };
messages.Add(new UserMessageParam { Content = "added later" });
Console.WriteLine(JsonSerializer.Serialize(request.RawBodyData));
{"model":"claude-haiku-5-5","max_tokens":10,"messages":[{"role":"user","content":"first"}]}
Kural basit: listeleri önce tamamen kur, sonra ata. Değiştirmen gerekirse with ile yeni bir istek üret. Döngüde her turda yeni bir MessageCreateParams kurmamız bu yüzden güvenli; önceki istekler eklenen assistant turundan etkilenmiyor.
Testler isteğin JSON'unu, pause_turn sonrası aynı container'ın kullanıldığını, anthropic-beta header'ını ve dosyaların indirilip silindiğini doğruluyor:
Passed! - Failed: 0, Passed: 49, Skipped: 0, Total: 49, Duration: 77 ms - Bookstore.Api.Tests.dll (net10.0)
Güvenlik: Token, Sandbox ve Skill
MCP token'ının kapsamı. Belgeye göre OAuth akışını yürütmek ve token'ı yenilemek API'yi kullananın işi. Bookstore için bu, yalnız stok okuma yetkisi olan, kısa ömürlü bir token demek. Token her istekte Anthropic'e gidiyor ve oradan MCP server'a iletiliyor; LLM Uygulama Güvenliği serisinin dördüncü yazısındaki en az yetki ilkesi burada doğrudan geçerli. Allowlist ikinci bir katman, yetkinin yerine geçmiyor.
Veri saklama. MCP connector, code execution, Files API ve Skills sayfalarının hepsi bu özellikleri ZDR (Zero Data Retention; verinin sağlayıcıda saklanmadığı anlaşma) kapsamı dışında gösteriyor. MCP server'la paylaşılan tool tanımları ve sonuçlar standart saklama politikasına tabi. Kişisel veriyi bu yollara sokmamak bu yüzden tasarım kararı.
Sandbox'ın sınırları. İnternet kapalı olduğu için sandbox'taki kod veriyi dışarı gönderemiyor; ama ürettiği dosya ve cevap metni sana geri geliyor. Excel'i kullanıcılara dağıtmadan önce içeriğine güvenme; LLM Uygulama Güvenliği serisinin beşinci yazısındaki "LLM çıktısı güvenilmeyen input'tur" ilkesi dosyalar için de geçerli.
Alternatif: MCP'yi Kendi Tarafında Bağlamak
MCP connector'ın yetmediği durumlar var: yerel bir stdio server, MCP prompt'ları ya da resource'ları, veya bağlantıyı kendi ağında tutma isteği. Belge bunun için C#'ta ayrı bir Anthropic.Mcp paketi gösteriyor; resmî ModelContextProtocol paketiyle birlikte kullanılıyor ve BetaMcp.ListToolsAsync(mcpClient) gibi yardımcılarla MCP tool'larını SDK'nın tool runner'ına bağlıyor. NuGet'te 15 Kasım 2026 itibarıyla Anthropic.Mcp 1.0.0 ve ModelContextProtocol 2.4.0 var. İkinci yol, on birinci yazıda göreceğimiz AsIChatClient() köprüsü: Claude'u bir IChatClient olarak alıp MCP C# SDK'sının tool'larını Microsoft.Extensions.AI ile bağlamak. Bu yolda tool çağrıları senin process'inden çıkıyor ve token Anthropic'e hiç gitmiyor.
Üretimde Dikkat
Skill sürümünü sabitle. latest geliştirmede rahat, production'da Anthropic skill'leri için tarihli sürüm, kendi skill'lerin için belirli bir skver_ id'si ver. Rapor bir gün farklı görünürse sebebini bilmek istersin.
Çalışma süresini izle. Code execution tek başına kullanıldığında en az 5 dakika faturalanıyor. Ayda bir çalışan bir rapor için önemsiz; her istekte code execution açan bir asistan için ücretsiz saatler çabuk bitebilir. Cevaptaki usage.server_tool_use code execution isteklerinin sayısını veriyor.
Sona eren container'ı yakala. Belgeye göre süresi dolmuş bir container'a istek göndermek hata veriyor; bu durumda container parametresi olmadan yeniden başlamak gerekiyor.
MCP çağrılarını cevaptan izle. Çağrıyı Bookstore.Api değil Claude API yaptığı için Bookstore.Api'nin log'unda o HTTP isteği yok. Ne olduğunu cevaptaki mcp_tool_use ve mcp_tool_result block'larından okuyorsun; sonuç block'unun is_error alanını log'la ve MCP server'ın kendi log'larıyla birlikte izle.
Sık Düşülen Tuzaklar
MCP connector'da yalnız mcp_servers gönderip mcp_toolset'i unutmak. Validation hatası.
localhost'taki MCP server'ı bağlamaya çalışmak. Server internetten HTTPS ile erişilebilir olmalı.
Skill'i code execution tool'u olmadan göndermek. Skill'ler o container'da çalışıyor.
Dosyayı $OUTPUT_DIR dışına yazdırmak. Dosya container'da kalır, cevapta file_id gelmez.
pause_turn'de container id'sini göndermemek. Yeni container, kaybolan dosyalar.
Opsiyonel bir SDK alanına null atamak ya da atadıktan sonra listeyi değiştirmek. İlki null gönderir, ikincisi değişikliği göndermez.
Küçük Bir Deneme
★☆☆ SalesReportOptions'a bir XlsxSkillVersion ekle; boşsa latest, doluysa o tarihli sürüm gitsin. Testte JSON'daki version değerini doğrula.
★★☆ BuildRequest'e mcp_toolset için cache_control ekle ve yedinci yazıdaki gibi otomatik caching'i aç. İki turlu bir testte tools ve container kısmının byte byte aynı kaldığını doğrula.
★★★ Döngüye sona ermiş container durumunu ekle: API hata dönerse container parametresi olmadan bir kez daha başla. Sahte handler'a hata cevabı ekleyip bu yolu test et ve hangi SDK exception'ının geldiğini gör.
Bu yazıda Claude'u tek bir istekte çalışan yeteneklerle genişlettik. Onuncu yazıda bir adım daha ileri gidiyoruz: agent loop'unu, container'ı ve oturum geçmişini Anthropic'in yönettiği Claude Managed Agents. Agent, environment ve session kavramlarına ve onu ne zaman seçmek gerektiğine bakacağız.