På denna sida
Den 8 juni 2026 gav Anthropic ägarna till connectors i Claudes katalog en dashboard. Den visar aktiva användare, totalt antal verktygsanrop och placering i katalogen. Den visar ”hälsopoäng, felfrekvenser och latens i en överblick, med fel uppdelade per verktyg så att du kan peka ut vad som fallerar”.
Ett år tidigare hade Alex Volkov på Weights & Biases beskrivit samma problem från andra hållet. När hans agent väl anropade verktyg över MCP ”blev all den observability jag är van vid när min egen kod körs från början till slut lite mörk”. Hans medtalare, Benjamin Eckel på Dylibso, visade varför. En fjärr-MCP-server ”syns för oss i tracen som ett enda service-span” eftersom den körs utanför anroparens kontroll.
Båda vyerna står utanför servern. Klienten ser ett ogenomskinligt span. Katalogen ser totalsiffror. Ingen av dem såg vad servern ombads göra, vad den nekade och vad den rörde. Det gjorde bara servern, så bara servern kan skriva ner det.
Det här är vad Tajos MCP-servrar skriver ner, läst ur koden som kör dem och beskrivet i dokumentationen. Vad en MCP-server är täcker protokollet. Det här täcker raden.
En rad per anrop
En dashboard är hamnkaptenens vy: fartyg in, fartyg ut, vilka som var sena. Förfrågningsloggen är fartygets egen loggbok, skriven ombord när det hände.
Varje tools/call på Tajos arbetsyteserver och på varje connector-server slutar i en rad. Raden skrivs när svaret är byggt, oavsett vad svaret blev. Ett anrop som nekas för att nyckeln inte får skriva, eller för att endpointen är skrivskyddad, får en rad som alla andra. Det gör även ett anrop till ett verktyg som inte finns.
Här är vad raden innehåller, och vad den vägrar innehålla.
| Fält | Sparas | Sparas inte |
|---|---|---|
| Vem | Id:t för API-nyckeln som anropade. En token från en OAuth-inloggning är också en nyckel. | Nyckelns hemlighet eller dess prefix. |
| Var | Arbetsyteservern eller en connector-server, med dess connector och profil. | |
| Verktyg | Namnet, när servern har ett verktyg med det namnet. | Alla andra namn som klienten skickar: de sparas som (unknown). |
| Effekt | read, write, send eller destructive: den tyngsta effekt anropet kunde ha. | |
| Utfall | ok, eller en kort felkod i snake_case som unknown_tool. | Feltext: allt som inte är en kod sparas som tool_error. |
| Varaktighet och storlek | Millisekunder från ankomst till svar, och de byte som anroparen tog emot. | |
| Trace-id | Förfrågans id, från en x-request-id-, x-trace-id- eller W3C traceparent-header, annars ett nytt. | Ett headervärde som inte är hex eller ett UUID. |
| Poster | Upp till 20 id:n för poster som anropet nämnde eller skapade: en kontakt, ett meddelande, ett godkännande. | Själva posterna. |
| Bodies | Argumenten och svaret, rensade, högst 4 KB vardera. | Hemligheter, fritext och de personuppgifter som listas nedan. |
Tre av de vägrarna handlar om klienten, inte om datan. Ett verktygsnamn, en felkod och ett trace-id kommer alla utifrån. Vart och ett sparas bara i en form som servern kan gå i god för. En logg som sparar vad anroparen än skickade kan fyllas med vad som helst, till och med en kunds e-postadress i kolumnen för verktygsnamn.
Benjamin Eckels öppna fråga i slutet av föredraget var hur en collector vet ”att det är ett MCP-verktygsanrop som har ett fel”. På en server är svaret en kolumn. ok är falskt, och koden säger vilket fel.
Argumenten: en regel vi vände på
Invändningen är rimlig, och den är vår egen. Loggar du argumenten har du byggt en andra kopia av dina kunders data, utanför varje begäran om radering. Fram till 18 oktober 2026 var det vår egen regel. Loggen sparade varken argumenten eller svarets body, eftersom båda kan innehålla personuppgifter.
Det var fel avvägning. En förfrågningslogg som inte kan visa vad som skickades och vad som kom tillbaka kan inte besvara den enda fråga den finns till för: varför misslyckades min agents anrop?
Så bodies sparas, och skälet till att de inte gjorde det möts på ett annat sätt. Varje body går igenom en deterministisk genomgång innan den ställs i kö.
- Ingen hemlighet överlever. Ett fält vars namn säger token, password, secret, signature, cookie, session eller ett tjugotal liknande ord behåller bara
[secret]. Detsamma gäller ett värde i en känd form för inloggningsuppgifter, var det än förekommer. Det omfattar bearer-tokens, JWT:er, privata nycklar, URL:er med lösenord och varje ogenomskinlig följd på 40 eller fler nyckeltecken. - Prosa sparas inte alls. Ett fält med namnet
html,text,body,markdownellercontentbehåller bara[redacted]. Prosa innehåller namn och gatuadresser som inget mönster hittar. - Personuppgifter maskeras för gott. Ett fält vars namn markerar personuppgifter, som en e-postadress, ett telefonnummer, ett namn, en adress eller en anteckning, behåller bara
[redacted]. En e-postadress, ett telefonnummer, ett kort eller ett IBAN inuti vilken annan sträng som helst maskeras. - Bodies hålls små. Strängar kapas vid 512 tecken, listor vid 20 objekt, objekt vid 50 nycklar och nästling vid 6 nivåer. Hela bodyn kapas vid 4 KB och markeras som trunkerad.
Två sorters anrop sparar mindre. Kontakter som en persons chatt har hämtat in från en annan app loggas som en markör och ett antal, aldrig som en body. Ett anrop som läser loggen sparar inget svar, eftersom svaret bara skulle vara andra loggrader.
Nu kostnaden. Maskningen är permanent, inte kryptering med en nyckel som någon har. Loggen kan inte visa dig e-postadressen som studsade. Den visar dig kontaktens id, och kontakten, under sina egna regler, är ett anrop bort. Loggen ligger utanför arbetsytans raderingssvep, och därför kan maskningen inte vänta på ett sådant.
Varför loggen inte är granskningsspåret
Tajo har redan en granskningslogg som bara kan läggas till i. Varje rad bär en hash av raden före, så en ändring var som helst bryter kedjan. Varför inte skriva verktygsanrop där?
För att kedjan har ett pris. Varje tillägg tar ett lås per arbetsyta och läser föregående rad för att förlänga kedjan. Att skriva varje läsning genom den skulle ställa en arbetsytas anrop i kö bakom ett enda lås. Det skulle också begrava de tillståndsändringar som granskningsloggen finns för att visa under tusentals läsningar.
Så de två registren delas upp efter fråga. Förfrågningsloggen säger vad en agent bad om och vad som hände, i 30 dagar. Granskningsloggen säger vad som ändrades, vem som tillät det och om någon har ändrat registret sedan dess.
Godkännanden hör till granskningssidan. På Tajos connector-profiler förbereder ett propose-verktyg en deklarerad åtgärd och ett apply-verktyg kör den när den är godkänd. Ingenting når leverantören förrän förslaget är godkänt, av en person eller av en regel som arbetsytan har slagit på. Propose-anropets rad anger godkännandet det skapade bland sina poster. Själva godkännandet är bundet till en SHA-256-digest av exakt den input det gäller. Ett godkännande gäller exakt den input du såg: ändra ett fält så stämmer det inte längre. När skrivningen landar sparar dess granskningsrad input-digesten och en digest av leverantörens svar, aldrig svarets värden.
Vad raden kostar
En rad är en skrivning i databasen, och en skrivning har en commit. Fram till 8 oktober 2026 väntade varje anrop på sin egen commit före svaret, cirka 2,6 ms på vår host. För en klient var det en fjärdedel av ett litet verktygsanrop.
Nu byggs raden när anropet slutar och ställs i kö. En flush skriver kön högst 100 ms senare, en transaktion per arbetsyta, så att många anrop delar en commit. Ingenting i en rad ändras, inte heller dess tidsstämpel. Om 5 000 rader väntar väntar nästa anrop på flushen i stället för att en rad tappas.
Registrering får aldrig ett anrop att misslyckas. En skrivning som misslyckas försöks igen rad för rad, och loggas och tappas sedan. Det som ett hårt kill av processen förlorar är det som låg i kön: högst de sista 100 ms av anrop.
Läsa tillbaka
logs.list returnerar arbetsytans anrop, nyaste först, utan bodies. Den filtrerar på tid, på utfall eller HTTP-status, på källa (MCP eller REST-API:t, som delar tabellen) och på API-nyckel. Den visar 50 per sida som standard, upp till 100. logs.get returnerar ett anrop med nyckelns nuvarande namn, dess status, dess varaktighet, den rensade förfrågan och det rensade svaret samt posterna som anropet rörde.
Båda läser bara anroparens egen arbetsyta. Ett rad-id från en annan arbetsyta hittas inte.
Ett verktygsfel bär förfrågans id. När servern skapade det id:t, eller när det kom som hex eller ett UUID, är det radens trace-id. En agent som fick ett fel kan ge en person det enda värde som namnger anropet.
Vad som är byggt, och vad som inte är det
Byggt, när detta skrivs:
- En rad per
tools/callpå arbetsyteservern och varje connector-server, även nekade och okända anrop. - Nyckel-id, server, connector, profil, verktyg, effekt, utfall, varaktighet, resultatstorlek, trace-id och upp till 20 berörda poster.
- Rensade argument och svar, högst 4 KB vardera.
logs.listochlogs.get, avgränsade till arbetsytan, med 30 dagars lagring.- Godkännanden bundna till en input-digest, och genomförda skrivningar registrerade med input- och output-digests i den hashkedjade granskningsloggen.
Inte byggt, och värt att veta innan du förlitar dig på det:
- Ingen hälsopoäng, inget diagram per verktyg och inget larm vid stigande felfrekvens. En sammanställning per verktyg av anrop, fel och långsammaste varaktigheter finns för Tajos driftpersonal, inte på någon yta du kan öppna.
logs.listkan inte filtrera på verktygsnamn eller trace-id. För att hitta raden bakom ett förfrågnings-id får du avgränsa på tid och nyckel.- Rader exporteras inte till ett tracingsystem som du själv kör. Trace-id:t läses bara från HTTP-headers, inte från MCP-fältet
_metasom föredraget använde för att bära trace-kontext. - Efter 30 dagar raderas en rad. Det finns inget arkiv och ingen export.
- Det som maskerades kan inte återskapas ur loggen.
- Ett hårt kill kan förlora de sista 100 ms av rader.
Föredraget avslutades med att observability i MCP ”inte är jämnt fördelad”. En dashboard längre nedströms kan inte rätta till det, och inte heller en trace som stannar vid serverns dörr. En synkronisering som misslyckas behöver ett eget register; det gör även varje anrop som bad om ett.
Servern såg anropet. Ingen annan gjorde det. Skriv ner det där.
Vanliga Frågor
Vad ska en MCP-server logga för varje verktygsanrop?
En rad per anrop, skriven av servern: vilken API-nyckel som anropade, vilken server och connector, verktygets namn om verktyget finns, dess effektklass, ok eller en kort felkod, varaktigheten, resultatets storlek, förfrågans trace-id, id:na för de poster som anropet nämnde eller skapade, samt argumenten och svaret med hemligheter och personuppgifter bortrensade. Tajos MCP-servrar skriver den raden för varje tools/call, även nekade anrop, och sparar den i 30 dagar.
Ska en MCP-förfrågningslogg spara verktygets argument?
Ja, rensade. En logg utan argumenten kan inte säga varför ett anrop misslyckades. Tajo sparade inga bodies fram till 18 oktober 2026 och sparar nu båda, efter en deterministisk genomgång: hemligheter blir [secret], fritext och personfält blir [redacted], e-postadresser, telefonnummer, kort och IBAN maskeras, och varje body kapas vid 4 KB. Maskningen är permanent, så loggen pekar på posten via id i stället för att kopiera den.
Varför hålla loggen över MCP-verktygsanrop skild från granskningsloggen?
För att de besvarar olika frågor till olika kostnad. Tajos granskningslogg är en hashkedja av tillståndsändringar, och varje tillägg tar ett lås per arbetsyta för att förlänga kedjan. Att skriva varje läsning genom den skulle ställa en arbetsytas anrop i kö bakom det låset och begrava ändringarna bland läsningarna. Verktygsanrop går till en separat tabell utan kedja som sparas i 30 dagar; skrivningar som ett anrop förbereder lämnar fortfarande egna granskningsrader.