Ce să înregistrezi pentru fiecare apel de instrument MCP

Un client vede un server MCP la distanță ca un singur span opac, iar panoul de control al directorului vede totaluri. Doar serverul a văzut apelul. Rândul pe care serverele MCP Tajo îl scriu pentru fiecare apel, câmp cu câmp, ce se curăță din el și ce nu este construit.

jurnalizare server MCP

Ce ar trebui să noteze un server MCP pentru fiecare apel de instrument?

Înregistrează un rând per apel de instrument, pe server, pentru că serverul este singurul loc care l-a văzut. Serverele MCP Tajo notează cine a apelat (ID-ul cheii, niciodată secretul ei), ce server și ce conector, instrumentul dacă există, clasa sa de efect, ok sau un cod scurt de eroare, durata, dimensiunea rezultatului, ID-ul de trace, înregistrările atinse de apel și argumentele și răspunsul curățate de secrete și date personale. Rândurile se citesc cu logs.list și logs.get și se șterg după 30 de zile. Ele stau separat de jurnalul de audit înlănțuit prin hash-uri, unde sunt păstrate aprobările și hash-urile intrărilor lor. Neconstruit: un scor de sănătate, o alertă pentru rata de erori, căutare după instrument sau ID de trace și export către propriul tău sistem de tracing.

Află mai mult
Pe această pagină

Pe 8 iunie 2026, Anthropic le-a dat proprietarilor de conectori din directorul Claude un panou de control. Acesta arată utilizatorii activi, numărul total de apeluri de instrumente și poziția în director. Arată „scorul de sănătate, ratele de eroare și latența dintr-o privire, cu defalcări ale erorilor pe instrument ca să identifici exact ce eșuează”.

Cu un an înainte, Alex Volkov de la Weights & Biases descrisese aceeași problemă din celălalt capăt. Odată ce agentul lui a început să apeleze instrumente prin MCP, „toată observabilitatea cu care eram obișnuit când propriul meu cod rula cap-coadă s-a cam stins”. Colegul lui de prezentare, Benjamin Eckel de la Dylibso, a arătat de ce. Un server MCP la distanță „ne apare în trace ca un singur span de serviciu”, pentru că rulează în afara controlului celui care apelează.

Ambele perspective stau în afara serverului. Clientul vede un singur span opac. Directorul vede totaluri. Niciuna nu a văzut ce i s-a cerut serverului, ce a refuzat și ce a atins. Doar serverul a văzut, deci doar serverul poate nota.

Iată ce notează serverele MCP Tajo, citit din codul care le rulează și descris în documentație. Ce este un server MCP explică protocolul. Acest articol explică rândul.

Un rând per apel

Un panou de control este perspectiva căpitanului de port: nave care intră, nave care ies, care au întârziat. Jurnalul de cereri este jurnalul de bord al navei, scris la bord, pe loc.

Fiecare tools/call pe serverul spațiului de lucru Tajo și pe fiecare server de conector se încheie cu un rând. Rândul este scris după ce răspunsul este construit, oricare ar fi fost răspunsul. Un apel refuzat pentru că cheia nu are voie să scrie, sau pentru că endpointul este doar pentru citire, primește un rând ca oricare altul. La fel și un apel către un instrument care nu există.

Iată ce conține rândul și ce refuză să conțină.

CâmpPăstratNepăstrat
CineID-ul cheii API care a apelat. Și un token dintr-o autentificare OAuth este o cheie.Secretul cheii sau prefixul ei.
UndeServerul spațiului de lucru sau un server de conector, cu conectorul și profilul lui.
InstrumentNumele, când serverul are un instrument cu acel nume.Orice alt nume trimis de client: este stocat ca (unknown).
Efectread, write, send sau destructive: cel mai greu efect pe care îl poate avea apelul.
Rezultatok sau un cod scurt de eroare în format snake_case, cum ar fi unknown_tool.Descrierea erorii în text liber: tot ce nu este cod este stocat ca tool_error.
Durată și dimensiuneMilisecundele de la sosire până la răspuns și octeții primiți de apelant.
ID de traceID-ul cererii, dintr-un antet x-request-id, x-trace-id sau W3C traceparent, altfel unul nou.O valoare de antet care nu este hexazecimală sau UUID.
ÎnregistrăriPână la 20 de ID-uri ale înregistrărilor pe care apelul le-a numit sau le-a produs: un contact, un mesaj, o aprobare.Înregistrările în sine.
ConținuturiArgumentele și răspunsul, curățate, cel mult 4 KB fiecare.Secretele, textul liber și datele personale enumerate mai jos.

Trei dintre aceste refuzuri privesc clientul, nu datele. Un nume de instrument, un cod de eroare și un ID de trace vin toate din exterior. Fiecare este păstrat doar într-o formă pentru care serverul poate garanta. Un jurnal care stochează orice a trimis apelantul poate fi umplut cu orice, inclusiv cu adresa de e-mail a unui client în coloana pentru numele instrumentului.

Întrebarea deschisă a lui Benjamin Eckel de la finalul prezentării a fost cum știe un colector „că este un apel de instrument MCP care are o eroare”. Pe un singur server, răspunsul este o coloană. ok este false, iar codul spune ce eroare.

Argumentele: o regulă pe care am inversat-o

Obiecția este corectă și este a noastră. Dacă înregistrezi argumentele, ai construit o a doua copie a datelor clienților tăi, în afara oricărei cereri de ștergere. Până pe 18 octombrie 2026, aceasta a fost propria noastră regulă. Jurnalul nu păstra nici argumentele, nici conținutul rezultatului, pentru că ambele pot conține date personale.

A fost un compromis greșit. Un jurnal de cereri care nu poate arăta ce s-a trimis și ce s-a întors nu poate răspunde la singura întrebare pentru care există: de ce a eșuat apelul agentului meu?

Așa că acum conținuturile sunt păstrate, iar motivul pentru care nu erau este tratat altfel. Fiecare conținut trece printr-o singură trecere deterministă înainte să fie pus în coadă.

  • Niciun secret nu supraviețuiește. Un câmp al cărui nume indică token, parolă, secret, semnătură, cookie, sesiune sau în jur de douăzeci de cuvinte similare păstrează doar [secret]. La fel și o valoare cu o formă cunoscută de credențiale, oriunde ar apărea. Asta acoperă tokenurile bearer, JWT-urile, cheile private, URL-urile cu parolă și orice șir opac de 40 sau mai multe caractere de cheie.
  • Textul liber nu este păstrat deloc. Un câmp numit html, text, body, markdown sau content păstrează doar [redacted]. Textul liber conține nume și adrese poștale pe care niciun tipar nu le găsește.
  • Datele personale sunt mascate definitiv. Un câmp al cărui nume indică date personale, cum ar fi un e-mail, un telefon, un nume, o adresă sau o notă, păstrează doar [redacted]. O adresă de e-mail, un număr de telefon, un card sau un IBAN din orice alt șir este mascat.
  • Conținuturile rămân mici. Șirurile sunt tăiate la 512 caractere, listele la 20 de elemente, obiectele la 50 de chei, iar imbricarea la 6 niveluri. Întregul conținut este tăiat la 4 KB și marcat ca trunchiat.

Două tipuri de apeluri păstrează și mai puțin. Contactele aduse de chatul unei persoane dintr-o altă aplicație sunt înregistrate ca un marcaj și un număr, niciodată ca un conținut. Un apel care citește jurnalul nu păstrează niciun răspuns, pentru că răspunsul ar fi doar alte rânduri din jurnal.

Acum costul. Mascarea este permanentă, nu o criptare cu o cheie pe care o deține cineva. Jurnalul nu îți poate arăta adresa de e-mail la care mesajul a ricoșat. Îți arată ID-ul contactului, iar contactul, sub propriile lui reguli, este la un apel distanță. Jurnalul stă în afara ștergerii periodice a datelor spațiului de lucru, motiv pentru care mascarea nu poate aștepta după ea.

De ce jurnalul nu este pista de audit

Tajo are deja un jurnal de audit în care doar se adaugă. Fiecare rând poartă un hash al rândului dinainte, așa că o modificare oriunde rupe lanțul. De ce să nu scriem apelurile de instrumente acolo?

Pentru că lanțul are un preț. Fiecare adăugare ia un lacăt per spațiu de lucru și citește rândul anterior ca să extindă lanțul. Dacă fiecare citire ar trece prin el, apelurile unui spațiu de lucru s-ar alinia în spatele unui singur lacăt. Ar îngropa, de asemenea, schimbările de stare pe care jurnalul de audit există ca să le arate sub mii de citiri.

Așa că cele două evidențe se împart după întrebare. Jurnalul de cereri spune ce a cerut un agent și ce s-a întâmplat, timp de 30 de zile. Jurnalul de audit spune ce s-a schimbat, cine a permis și dacă cineva a modificat evidența de atunci.

Aprobările stau pe partea de audit. Pe profilurile de conector Tajo, un instrument de propunere pregătește o acțiune declarată, iar un instrument de aplicare o rulează după ce este aprobată. Nimic nu ajunge la furnizor până când propunerea nu este aprobată, de o persoană sau de o regulă pe care spațiul de lucru a activat-o. Rândul apelului de propunere numește printre înregistrările sale aprobarea pe care a creat-o. Aprobarea în sine este legată de un hash SHA-256 al intrării exacte. O aprobare acoperă exact intrarea pe care ai văzut-o: schimbi un câmp și nu se mai potrivește. Când scrierea ajunge la destinație, rândul ei de audit păstrează hash-ul intrării și un hash al răspunsului furnizorului, niciodată valorile răspunsului.

Cât costă rândul

Un rând este o scriere în baza de date, iar o scriere are un commit. Până pe 8 octombrie 2026, fiecare apel își aștepta propriul commit înainte de răspuns, aproximativ 2,6 ms pe hostul nostru. Pentru un client, asta însemna un sfert dintr-un apel mic de instrument.

Acum rândul este construit când apelul se termină și este pus în coadă. O golire scrie coada cel mult 100 ms mai târziu, o tranzacție per spațiu de lucru, așa că multe apeluri împart un singur commit. Nimic din rând nu se schimbă, nici măcar marcajul de timp. Dacă așteaptă 5.000 de rânduri, următorul apel așteaptă golirea în loc ca un rând să fie aruncat.

Înregistrarea nu face niciodată un apel să eșueze. O scriere care eșuează este reîncercată rând cu rând, apoi este înregistrată și aruncată. Ce pierde o oprire forțată a procesului este ce stătea în coadă: cel mult ultimele 100 ms de apeluri.

Citirea înapoi

logs.list returnează apelurile spațiului de lucru, cele mai noi primele, fără conținuturi. Filtrează după timp, după rezultat sau status HTTP, după sursă (MCP sau API-ul REST, care folosește același tabel) și după cheia API. Paginează implicit câte 50, până la 100. logs.get returnează un singur apel cu numele actual al cheii, statusul, durata, cererea și răspunsul curățate și înregistrările pe care le-a atins.

Amândouă citesc doar spațiul de lucru al apelantului. Un ID de rând din alt spațiu de lucru nu este găsit.

O eroare de instrument poartă ID-ul cererii. Când serverul a creat acel ID, sau acesta a sosit ca valoare hexazecimală sau UUID, el este ID-ul de trace al rândului. Un agent care a primit o eroare îi poate da unei persoane singura valoare care identifică apelul.

Ce este construit și ce nu

Construit, la momentul scrierii:

Neconstruit, și merită să știi înainte să te bazezi pe el:

  • Niciun scor de sănătate, niciun grafic per instrument și nicio alertă pentru o rată de erori în creștere. Un rezumat per instrument al apelurilor, erorilor și celor mai lente durate există pentru operatorii Tajo, dar nu pe vreo suprafață pe care o poți deschide.
  • logs.list nu poate filtra după numele instrumentului sau după ID-ul de trace. Ca să găsești rândul din spatele unui ID de cerere, restrânge după timp și cheie.
  • Rândurile nu sunt exportate către un sistem de tracing pe care îl rulezi tu. ID-ul de trace este citit doar din antete HTTP, nu din câmpul MCP _meta pe care prezentarea l-a folosit ca să transmită contextul de trace.
  • După 30 de zile, un rând este șters. Nu există arhivă sau export.
  • Ce a fost mascat nu poate fi recuperat din jurnal.
  • O oprire forțată poate pierde ultimele 100 ms de rânduri.

Prezentarea s-a încheiat cu ideea că observabilitatea în MCP „nu este distribuită uniform”. Un panou de control din aval nu poate repara asta, și nici un trace care se oprește la ușa serverului. O sincronizare care eșuează are nevoie de propria evidență; la fel și fiecare apel care a cerut una.

Serverul a văzut apelul. Nimeni altcineva. Notează-l acolo.

Întrebări Frecvente

Ce ar trebui să înregistreze un server MCP pentru fiecare apel de instrument?

Un rând per apel, scris de server: ce cheie API a apelat, ce server și ce conector, numele instrumentului dacă instrumentul există, clasa sa de efect, ok sau un cod scurt de eroare, durata, dimensiunea rezultatului, ID-ul de trace al cererii, ID-urile înregistrărilor pe care apelul le-a numit sau le-a produs și argumentele și răspunsul, cu secretele și datele personale curățate. Serverele MCP Tajo scriu acest rând pentru fiecare tools/call, inclusiv pentru apelurile refuzate, și îl păstrează 30 de zile.

Ar trebui ca un jurnal de cereri MCP să păstreze argumentele instrumentelor?

Da, curățate. Un jurnal fără argumente nu poate spune de ce a eșuat un apel. Tajo nu a păstrat conținuturi până pe 18 octombrie 2026, iar acum le păstrează pe amândouă, după o singură trecere deterministă: secretele devin [secret], textul liber și câmpurile personale devin [redacted], adresele de e-mail, telefoanele, cardurile și IBAN-urile sunt mascate, iar fiecare conținut este tăiat la 4 KB. Mascarea este permanentă, așa că jurnalul indică înregistrarea prin ID în loc să o copieze.

De ce să ții jurnalul apelurilor de instrumente MCP separat de jurnalul de audit?

Pentru că răspund la întrebări diferite, cu costuri diferite. Jurnalul de audit Tajo este un lanț de hash-uri al schimbărilor de stare, iar fiecare adăugare ia un lacăt per spațiu de lucru ca să extindă lanțul. Dacă fiecare citire ar trece prin el, apelurile unui spațiu de lucru ar sta la coadă în spatele acelui lacăt, iar schimbările s-ar pierde printre citiri. Apelurile de instrumente merg într-un tabel separat, fără lanț, păstrat 30 de zile; scrierile pe care un apel le pregătește lasă în continuare propriile rânduri de audit.

Solicită acces anticipat

Introduceți prenumele și adresa de e-mail. Vă vom trimite un link pentru a confirma cererea de acces la Tajo.

Obține Brevo

Această pagină în Markdown: what-to-log-for-every-mcp-tool-call.md

Se încarcă Markdown…
Deschide în Claude Deschide în ChatGPT