---
title: "MCP e skills: misurare e ridurre i token senza perdere contesto"
source: "https://www.matteovincenti.com/blog/mcp-skills-ridurre-token-contesto"
language: it
author: "Matteo Vincenti"
published: 2026-10-24
category: "AI"
tags: ["MCP", "Agent Skills", "Token AI", "Context engineering"]
---

# MCP e skills: misurare e ridurre i token senza perdere contesto

Filtri, proiezioni e lettura progressiva delle skills: un laboratorio MCP misura i token locali e verifica che i dati utili restino completi.

![Due schede verdi in un raccoglitore compatto accanto a un archivio più grande di schede color avorio.](https://cdn.sanity.io/images/xrqkwry7/production/994b2956c5581babf83c607ff5eea5946160d36a-1536x1024.png?w=1400&fit=max&auto=format)

Categoria: AI · Tag: MCP, Agent Skills, Token AI, Context engineering

Checkout indica qui il servizio dell'applicazione che gestisce la conclusione di un ordine. Nel laboratorio, P1 identifica gli incidenti che bloccano il suo rilascio. Per decidere se rilasciare quel servizio servono tutti i P1 ancora aperti in produzione, con responsabile e prova da consultare. Se l'integrazione restituisce l'intero registro degli incidenti, il lavoro di selezione finisce nel passaggio successivo. Accorciare le descrizioni dei tool lascia intatto quel volume di dati.

Partirei dal contratto del risultato: quali record servono, quali campi permettono di controllarli e come si riconosce un recupero incompleto. Nel laboratorio di questo articolo il filtro e la proiezione conservano la stessa risposta con meno materiale restituito. Il controllo negativo restituisce anch'esso meno dati, perde un incidente necessario e viene respinto.

MCP e skills intervengono in punti diversi. MCP è il protocollo con cui un client scopre e chiama strumenti esterni; una skill contiene istruzioni e risorse per svolgere un lavoro. Il client decide come presentarli al modello. Questa distinzione permette di scegliere dove intervenire, prima di tagliare testo. La [guida MCP](https://www.matteovincenti.com/blog/mcp-guida-server-tools-skills) approfondisce come si costruisce questo collegamento.

## Catalogo, istruzioni e risultati hanno costi diversi

Un tool espone nome, descrizione e schema degli argomenti. MCP definisce operazioni come `tools/list` e `tools/call`; il caricamento delle definizioni nel contesto del modello appartiene all'host. La [specifica Tools 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/server/tools) prevede anche la paginazione del catalogo. I cursori dei record restituiti da una query applicativa richiedono invece un contratto del tool.

La discovery differita carica le definizioni quando servono. Claude Code la [documenta come comportamento predefinito](https://code.claude.com/docs/en/mcp#scale-with-mcp-tool-search), con condizioni legate a modello, deployment e configurazione. Nel [codice della release Codex 0.164.0](https://github.com/openai/codex/blob/rust-v0.164.0/codex-rs/core/src/mcp_tool_exposure.rs) l'esposizione passa da `Direct` a `Deferred` quando `search_tool_enabled` è attivo. Le opzioni di tool search di una specifica API vanno applicate alla relativa superficie, non copiate nella configurazione di qualunque client.

Una skill segue un'altra sequenza: metadata per riconoscerla, corpo quando viene selezionata, riferimenti quando il lavoro li richiede. La [documentazione Codex](https://learn.chatgpt.com/docs/build-skills) distingue il budget dell'elenco iniziale dalla lettura integrale di `SKILL.md`. Ridurre la descrizione può alleggerire l'elenco, ma rende anche più difficile riconoscere la skill se si eliminano le parole che ne delimitano l'uso.

Infine arrivano i risultati: record, documenti, log. La discovery non riduce un risultato enorme. [Anthropic ha già descritto](https://www.anthropic.com/research/code-execution-with-mcp) come filtrare ed elaborare dati fuori dal contesto del modello. Qui applico quel principio a una query controllabile: prima verifico che il risultato resti sufficiente, poi confronto le quantità.

## La stessa domanda, con un incidente nell'ultima pagina

Il corpus è sintetico: 120 incidenti, con due soli P1 aperti di checkout in produzione. Gli attesi, fissati in `expected.json`, sono `INC-017`, responsabile `payments-oncall`, e `INC-088`, responsabile `checkout-oncall`. Ognuno ha il proprio `evidence_ref`. Ci sono anche incidenti simili ma chiusi, in staging o relativi a un altro servizio.

Il tool `list_incidents` accetta filtri, campi, cursore e limite. Una pagina contiene al massimo 40 record. Le varianti cambiano una scelta alla volta:

- A legge tutte e tre le pagine di record completi, poi filtra nel driver.
- B1 passa il filtro al server, mantenendo i record completi.
- B2 aggiunge la proiezione dei campi necessari: ID, severità, stato, servizio, ambiente, responsabile e riferimento.
- C interrompe A dopo la prima pagina. Serve a verificare che il controllo respinga il risultato incompleto.

Gli argomenti di B2 sono questi; è un estratto della richiesta, mentre il pacchetto contiene il codice completo:

```json
{
  "filters": {
    "severity": "P1",
    "status": "open",
    "service": "checkout",
    "environment": "production"
  },
  "fields": [
    "id", "severity", "status", "service",
    "environment", "owner", "evidence_ref"
  ],
  "limit": 40
}
```

La risposta comprende `records`, `next_cursor`, `total_matching`, `partial` ed `errors`. Il driver valuta l'intera traversata: il cursore finale deve essere nullo, i totali dichiarati nelle diverse pagine devono coincidere con il numero ricevuto, nessuna pagina deve essere parziale e gli errori di ogni pagina devono restare assenti. Una pagina finale pulita non cancella un errore o un risultato parziale precedente. Poi confronta decisione e incidenti normalizzati con gli attesi. Un elenco vuoto e un recupero fallito producono quindi esiti diversi.

La prova usa vere chiamate MCP via stdio con SDK ufficiale client/server 2.3.1. Il driver è deterministico: la scelta delle chiamate non è affidata a un modello. L'ambiente misurato è Linux arm64, Docker 29.9.2, Node 24.21.0 e Python 3.13.17. Tre ripetizioni per variante hanno prodotto tracce identiche byte per byte. La tabella riporta conteggi locali `o200k_base` delle righe JSON-RPC.

_La stessa domanda, con un incidente nell'ultima pagina_

| Variante | Chiamate | Record ricevuti | Token delle risposte tool | Token di tutti i messaggi | Esito |
| --- | --- | --- | --- | --- | --- |
| A — tutte le pagine, filtro nel driver | 3 | 120 | 44626 | 45476 | Accettata |
| B1 — filtro sul server | 1 | 2 | 820 | 1516 | Accettata |
| B2 — filtro e proiezione sul server | 1 | 2 | 274 | 989 | Accettata |
| C — prima pagina di A, poi stop | 1 | 40 | 14872 | 15548 | Respinta: manca INC-088 |

I token della tabella sono conteggi locali `o200k_base`, ottenuti con [tiktoken](https://github.com/openai/tiktoken) 0.14.0. Ogni riga JSON-RPC UTF-8, compreso il newline, viene contata separatamente. La colonna «Token di tutti i messaggi» somma entrambe le direzioni e include inizializzazione, catalogo, richieste e risposte. Il server restituisce il risultato sia in `content` testuale sia in `structuredContent`: il conteggio include entrambe le copie.

B1 elimina record estranei alla domanda; B2 elimina dettagli di indagine che restano recuperabili dalla fonte. C risparmia materiale anche rispetto ad A, ma non vede `INC-088`: non supera il contratto di accettazione.

Il numero di token scende molto perché questa fixture seleziona due record su 120. Per valutare una fattura o una quota servono i contatori del servizio sul task completo, con cache, output, tentativi, correzioni ed eventuali agenti figli. Il lavoro umano va registrato a parte. La quantità contata qui è il materiale scambiato dal laboratorio, non il prompt costruito da Codex o Claude.

## Eseguire il laboratorio senza ricostruire i file

Il pacchetto allegato contiene tutti i 15 file, inclusi Dockerfile, lock delle dipendenze, server, fixture, driver, contatore, attesi e skill. Il README è l'entrypoint. Non occorrono chiavi API o installazioni di pacchetti sul computer.

Scarica: [mcp-token-contract.zip](https://cdn.sanity.io/files/xrqkwry7/production/ef318bec7e82f91a9e555cc378495da9d8d25b3a.zip)

Servono Docker Engine o Docker Desktop con Buildx, Git, una shell e `unzip`. La build usa la rete per scaricare immagini, pacchetti pubblici e vocabolario del tokenizer; il run successivo ha la rete disabilitata. Le immagini base sono fissate per digest e le dipendenze per versione. Crea una directory di lavoro vuota, salvaci `mcp-token-contract.zip` e apri lì il terminale. `git init` prepara il repository locale in cui proverai anche la skill. L'estrazione crea `examples/mcp-token-contract/`.

```bash
git init
unzip mcp-token-contract.zip
mkdir -p .cache/editorial/token-contract-run
docker buildx create --name token-contract-builder --driver docker-container
docker buildx build --builder token-contract-builder --load --progress plain \
  --tag token-contract:lab examples/mcp-token-contract
docker run --rm --name token-contract-run --network none --memory 512m --cpus 1 \
  --mount "type=bind,src=$(pwd)/.cache/editorial/token-contract-run,dst=/out" \
  token-contract:lab
```

Esegui tutto dalla directory che contiene `examples/`; usa una nuova directory di output se hai già una ricevuta da conservare. Il processo termina con successo quando A/B1/B2 coincidono con gli attesi, C perde `INC-088` e viene respinta, e i conteggi sono stabili.

In `.cache/editorial/token-contract-run/` trovi `report.json`, `manifest.json`, gli hash, le risposte normalizzate e le trace `*.wire.jsonl`. Le righe del protocollo sono conservate in base64 per mantenere i byte originali; nel report sono già disponibili i conteggi per messaggio. `B2-1.evidence.json` contiene i dati da usare nel passaggio sulla skill.

## Una skill breve deve conservare le condizioni di lettura

La skill del pacchetto valuta quel rapporto. Le regole necessarie rimangono nel corpo; la gestione delle deroghe è nel riferimento fornito `references/waivers.md`. Il riferimento specifica campi, ambito, scadenza e prova di approvazione richiesti. Una deroga viene descritta separatamente e conserva la decisione sugli incidenti.

Questo è il file `SKILL.md` completo, scritto in inglese per riusarlo nei due client:

```markdown
---
name: release-readiness
description: Assess checkout release readiness from an incident-query report. Use when asked for a release decision based on incident evidence, including a proposed waiver.
---

# Assess the provided incident report

Use the report supplied by the user; do not infer incident state from this skill.
Check that the report covers open P1 incidents for checkout in production.

Keep these rules in every assessment:
- A complete traversal ends with `next_cursor: null`, includes every declared matching record, has `partial: false`, and has no retrieval errors. Otherwise return `INCOMPLETE` and name the missing evidence.
- Every blocker must include its ID, severity, status, service, environment, owner and evidence reference. Missing fields make the assessment incomplete.
- Return `HOLD` when a complete report has at least one matching P1 incident. Return `CLEAR` only when a complete report has none. These labels assess the supplied evidence; they do not execute or authorize a release.
- Preserve all blockers in the output. A proposed waiver cannot silently remove one.

Read [references/waivers.md](references/waivers.md) only when the request proposes a waiver or the report includes one. Apply its checks and report the waiver separately from the incident decision. For a standard assessment with no waiver, use the rules above without loading the reference.

Return the decision, completeness evidence, blocker IDs with owners and references, and any unresolved requirement. If the report is missing, ask for it instead of inventing an assessment.
```

La struttura riprende il caricamento progressivo discusso anche nel video [Sette regole per le skills](https://www.youtube.com/watch?v=ah1dEYkrq3E), confrontato con la documentazione corrente. La scelta importante è la condizione di lettura: senza deroga bastano le regole del corpo; con una proposta di deroga serve anche il riferimento.

I due percorsi testuali predisposti pesano 308 token locali per `SKILL.md` e 490 per `SKILL.md` più riferimento. Una versione monolitica che contiene sempre entrambi pesa gli stessi 490 token. Sono concatenazioni contate, non una misura delle letture effettive del client. Quando il riferimento serve, il suo costo resta.

Per provarla in un repository locale, dalla stessa directory usata per il laboratorio scegli il client. Con Codex CLI/IDE:

```bash
mkdir -p .agents/skills
cp -R examples/mcp-token-contract/skill/release-readiness .agents/skills/
```

Con Claude Code locale:

```bash
mkdir -p .claude/skills
cp -R examples/mcp-token-contract/skill/release-readiness .claude/skills/
```

Copia la cartella solo se non ne esiste già una con lo stesso nome. Avvia il client nel repository. In Codex richiama `$release-readiness`; in Claude Code inizia il messaggio con `/release-readiness`. Le [collocazioni Claude Code](https://code.claude.com/docs/en/skills) distinguono sessioni locali, cloud e plugin.

Un primo prompt può chiedere: «Valuta `.cache/editorial/token-contract-run/B2-1.evidence.json`; non è proposta alcuna deroga». Il secondo aggiunge una proposta per `INC-017` e un tempo di valutazione esplicito: attiva il percorso del riferimento. Se mancano approvatore, scadenza o prova richiesta, la skill deve mantenere quei requisiti irrisolti. Il laboratorio conta i file dei due percorsi; l'esecuzione di questi prompt nel client è una prova ulteriore.

## Dove interverrei in un'integrazione reale

Se il filtro è già noto prima della lettura, lo metterei nel tool. Se il risultato conserva molti campi estranei alla decisione, aggiungerei una proiezione che mantenga identità, classificazione e prove. Per le skills terrei nel corpo le condizioni che devono valere sempre e renderei esplicito quando aprire i dettagli.

Cambierei invece la configurazione di discovery quando il problema osservato sono le definizioni esposte all'inizio. Un catalogo piccolo e usato quasi per intero può giustificare il caricamento immediato: la ricerca aggiunge un passaggio. La documentazione [OpenAI Tool search](https://developers.openai.com/api/docs/guides/tools-tool-search) espone questa alternativa per le API che descrive.

Una CLI che filtra prima di stampare è un'altra possibilità. I manutentori di [Playwright CLI](https://github.com/microsoft/playwright-cli) la propongono per i coding agent, mantenendo MCP per altri loop di interazione. Valuterei l'output e il costo di mantenere l'integrazione: uno script può anche stare dietro un tool MCP.

Il controllo che terrei in ogni variante è quello su `INC-088`: un recupero più corto deve continuare a trovare ciò che cambia la decisione.

Dopo aver conservato i risultati, rimuovi le sole risorse della prova:

```bash
docker buildx rm --force token-contract-builder
docker image rm token-contract:lab
rm -r .cache/editorial/token-contract-run
```

Il container usa `--rm`. Le immagini base possono servire ad altri lavori; la pulizia dell'esempio riguarda il builder dedicato, la sua cache, l'immagine del laboratorio e la directory di output creata.
