Introduzione: Server per Database e Testing
In un workflow di sviluppo gestito tramite Model Context Protocol, la comprensione della struttura dati e la qualità del codice sono due pilastri fondamentali. Quando si lavora con un database esistente, serve capire rapidamente quali tabelle esistono, come sono collegate e quali indici mancano. Quando si scrive codice, serve generare test automatici, identificare edge case e misurare le performance.
In questo nono articolo della serie MCP analizziamo quattro server del progetto Tech-MCP che coprono queste due aree critiche: due server dedicati al database (db-schema-explorer e data-mock-generator) e due server dedicati al testing (test-generator e performance-profiler).
Cosa Imparerai in Questo Articolo
- Come esplorare schemi di database SQLite con introspezione PRAGMA
- Generazione automatica di diagrammi ERD in sintassi Mermaid
- Suggerimento automatico di indici per foreign key non indicizzate
- Generazione di dati mock realistici con 16 generatori built-in
- Creazione automatica di skeleton di test unitari da codice sorgente
- Analisi statica delle performance e identificazione di anti-pattern
- Eventi tipizzati:
db:index-suggestion,test:generated,test:coverage-report,perf:bottleneck-found
Server 1: db-schema-explorer
Il server db-schema-explorer consente l'esplorazione interattiva degli schemi di database SQLite. Risolve il problema della comprensione della struttura dati: quando si lavora con un database esistente, e necessario capire rapidamente quali tabelle esistono, come sono collegate, quali indici mancano e come visualizzare le relazioni.
Il server fornisce accesso in sola lettura al database, garantendo che nessuna operazione possa
modificare i dati o lo schema. Utilizza la libreria better-sqlite3 con il flag
readonly: true per un accesso diretto, sincrono e performante.
Architettura del Server
+------------------------------------------------------------+
| db-schema-explorer server |
| |
| +--------------------------------------------------------+ |
| | Tool Layer | |
| | | |
| | explore-schema describe-table | |
| | suggest-indexes generate-erd | |
| +--------------------------------------------------------+ |
| | |
| v |
| +--------------------------------------------------------+ |
| | better-sqlite3 (readonly: true) | |
| | | |
| | PRAGMA table_info PRAGMA index_list | |
| | PRAGMA index_info PRAGMA foreign_key_list | |
| | sqlite_master SELECT COUNT(*) | |
| +--------------------------------------------------------+ |
| | |
| v |
| +--------------------------------------------------------+ |
| | Event Bus: db:index-suggestion | |
| +--------------------------------------------------------+ |
+------------------------------------------------------------+
Tool Disponibili
Tabella dei Tool - db-schema-explorer
| Tool | Descrizione | Parametri |
|---|---|---|
explore-schema |
Esplora lo schema del database, restituendo tutte le tabelle e le loro colonne | dbPath (string) - Percorso al file SQLite |
describe-table |
Dettaglio di una tabella: colonne, indici, foreign key e conteggio righe | dbPath (string); tableName (string) |
suggest-indexes |
Analizza le tabelle e suggerisce indici mancanti per migliori performance | dbPath (string) |
generate-erd |
Genera un diagramma entità-relazione in sintassi Mermaid erDiagram | dbPath (string) |
Tipi di Dato Fondamentali
Il server definisce quattro interfacce TypeScript che strutturano le informazioni restituite dall'introspezione del database:
// TableInfo: informazioni su una tabella
interface TableInfo {
name: string;
columns: ColumnInfo[];
}
// ColumnInfo: dettaglio di una colonna
interface ColumnInfo {
name: string;
type: string; // INTEGER, TEXT, REAL, BLOB, BOOLEAN, DATETIME
nullable: boolean;
primaryKey: boolean;
defaultValue: string | null;
}
// IndexInfo: informazioni su un indice
interface IndexInfo {
name: string;
unique: boolean;
columns: string[];
}
// ForeignKeyInfo: informazioni su una foreign key
interface ForeignKeyInfo {
id: number;
table: string; // tabella referenziata
from: string; // colonna locale
to: string; // colonna referenziata
onUpdate: string;
onDelete: string;
}
Query PRAGMA Utilizzate
Tutta l'analisi si basa su comandi PRAGMA standard di SQLite, che forniscono metadati sulla struttura del database senza modificare alcun dato:
PRAGMA e Informazioni Restituite
| PRAGMA | Uso | Informazioni Restituite |
|---|---|---|
sqlite_master |
Lista tabelle | Nomi tabelle (escluse sqlite_*) |
PRAGMA table_info |
Colonne della tabella | cid, name, type, notnull, dflt_value, pk |
PRAGMA index_list |
Lista indici | seq, name, unique, origin, partial |
PRAGMA index_info |
Colonne dell'indice | seqno, cid, name |
PRAGMA foreign_key_list |
Foreign key | id, seq, table, from, to, on_update, on_delete |
Esempio: Esplorazione Schema
// Richiesta
{
"tool": "explore-schema",
"arguments": {
"dbPath": "/home/user/data/app.sqlite"
}
}
// Risposta
{
"dbPath": "/home/user/data/app.sqlite",
"tableCount": 3,
"tables": [
{
"name": "users",
"columns": [
{ "name": "id", "type": "INTEGER", "nullable": false, "primaryKey": true },
{ "name": "email", "type": "TEXT", "nullable": false, "primaryKey": false },
{ "name": "name", "type": "TEXT", "nullable": true, "primaryKey": false }
]
},
{
"name": "posts",
"columns": [
{ "name": "id", "type": "INTEGER", "nullable": false, "primaryKey": true },
{ "name": "user_id", "type": "INTEGER", "nullable": false, "primaryKey": false },
{ "name": "title", "type": "TEXT", "nullable": false, "primaryKey": false }
]
}
]
}
Esempio: Descrizione Tabella Dettagliata
// Richiesta
{
"tool": "describe-table",
"arguments": {
"dbPath": "/home/user/data/app.sqlite",
"tableName": "posts"
}
}
// Risposta
{
"tableName": "posts",
"rowCount": 1523,
"columns": [
{ "name": "id", "type": "INTEGER", "nullable": false,
"primaryKey": true, "defaultValue": null },
{ "name": "user_id", "type": "INTEGER", "nullable": false,
"primaryKey": false, "defaultValue": null },
{ "name": "title", "type": "TEXT", "nullable": false,
"primaryKey": false, "defaultValue": null }
],
"indexes": [
{ "name": "idx_posts_user_id", "unique": false, "columns": ["user_id"] }
],
"foreignKeys": [
{ "id": 0, "table": "users", "from": "user_id", "to": "id",
"onUpdate": "NO ACTION", "onDelete": "CASCADE" }
]
}
Suggerimento Indici Automatico
Il tool suggest-indexes analizza tutte le tabelle del database e identifica due tipi di
problemi di performance: foreign key senza indice dedicato e tabelle con molte righe prive di indici
user-defined. Per ogni foreign key il cui campo from non e indicizzato, il server genera
automaticamente il comando SQL CREATE INDEX corrispondente.
// Risposta suggest-indexes
{
"tablesAnalyzed": 5,
"suggestionsCount": 2,
"suggestions": [
{
"table": "comments",
"column": "post_id",
"reason": "Foreign key column referencing \"posts\"(\"id\") is not indexed.",
"suggestedSql": "CREATE INDEX idx_comments_post_id ON \"comments\"(\"post_id\");"
}
]
}
Generazione Diagrammi ERD
Il tool generate-erd produce diagrammi entità-relazione in sintassi Mermaid erDiagram,
convertendo automaticamente i tipi SQLite nei tipi Mermaid corrispondenti: INTEGER diventa
int, TEXT/CHAR diventa string, REAL/FLOAT diventa
float, BLOB diventa blob e DATE/TIME diventa
datetime.
erDiagram
users {
int id PK
string email
string name
datetime created_at
}
posts {
int id PK
int user_id
string title
string body
}
users ||--o{ posts : "id -> user_id"
Evento: db:index-suggestion
Ogni volta che suggest-indexes identifica una foreign key non indicizzata, pubblica
l'evento db:index-suggestion sull'Event Bus con il payload:
{
database: string, // percorso al file SQLite
table: string, // nome della tabella
columns: string[], // colonne da indicizzare
reason: string // motivazione del suggerimento
}
Questo evento può essere sottoscritto da server come agile-metrics o
standup-notes per tracciare automaticamente le ottimizzazioni suggerite.
Server 2: data-mock-generator
Il server data-mock-generator genera dati fittizi realistici per testing, sviluppo e prototipazione.
Per testare un'applicazione servono dati che assomiglino a quelli reali, ma crearli manualmente non scala.
Questo server offre 16 tipi di generatore, supporta output in JSON e CSV, e non ha dipendenze
esterne per la generazione dei dati: utilizza esclusivamente Math.random() e
crypto.randomUUID().
Tool Disponibili
Tabella dei Tool - data-mock-generator
| Tool | Descrizione | Parametri |
|---|---|---|
generate-mock-data |
Genera righe di dati basate su uno schema di field/type | schema (array di {field, type}); count (1-10000, default: 10) |
generate-json |
Genera oggetti JSON da un JSON Schema con properties e format hint | jsonSchema (object con properties); count (1-10000, default: 10) |
generate-csv |
Genera dati in formato CSV con header e delimitatore configurabile | columns (array di {name, type}); count (1-10000); delimiter (default: ",") |
list-generators |
Elenca tutti i tipi di generatore disponibili con descrizione | Nessuno |
I 16 Generatori Built-in
Il service layer generators.ts contiene dataset di base (nomi, cognomi, strade, citta, aziende,
parole lorem, domini) e 16 funzioni generatore, ciascuna registrata in un registry
Record<string, GeneratorInfo>:
Generatori Disponibili
| Nome | Tipo Output | Descrizione | Esempio |
|---|---|---|---|
firstName |
string | Nome casuale da pool di 40 | "Jennifer" |
lastName |
string | Cognome casuale da pool di 40 | "Martinez" |
email |
string | Email combinando nome+cognome+dominio | "jennifer_martinez42@example.com" |
phone |
string | Telefono US formato (XXX) XXX-XXXX | "(415) 555-1234" |
address |
string | Indirizzo: numero + via + citta | "4521 Oak Ave, Seattle" |
company |
string | Nome azienda da pool di 20 | "Stark Industries" |
date |
string | Data YYYY-MM-DD tra 2000 e 2025 | "2018-07-23" |
integer |
number | Intero tra 0 e 10000 | 4287 |
float |
number | Decimale con 2 cifre, 0-10000 | 3456.78 |
boolean |
boolean | true o false (50/50) | true |
uuid |
string | UUID v4 via crypto.randomUUID() | "550e8400-e29b-..." |
sentence |
string | Frase lorem ipsum 5-15 parole | "Lorem ipsum dolor sit amet." |
paragraph |
string | Paragrafo di 3-7 frasi lorem | "Lorem ipsum... Dolor sit..." |
url |
string | URL con protocollo, dominio e path | "https://app.demo.io/docs" |
ipv4 |
string | Indirizzo IP v4 valido | "192.168.42.1" |
hexColor |
string | Colore esadecimale con # | "#a3f2c1" |
Esempio: Generazione Dati da Schema
// Richiesta
{
"tool": "generate-mock-data",
"arguments": {
"schema": [
{ "field": "id", "type": "uuid" },
{ "field": "name", "type": "firstName" },
{ "field": "surname", "type": "lastName" },
{ "field": "email", "type": "email" },
{ "field": "active", "type": "boolean" }
],
"count": 3
}
}
// Risposta
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Jennifer",
"surname": "Martinez",
"email": "jennifer.martinez@example.com",
"active": true
},
{
"id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
"name": "Robert",
"surname": "Smith",
"email": "robert_smith42@test.org",
"active": false
}
]
Esempio: Generazione da JSON Schema
Il tool generate-json accetta un JSON Schema con properties e risolve automaticamente
il generatore corretto: prima controlla il campo format (email, uri, uuid, ipv4, date),
poi fa fallback sul type (string diventa sentence, number diventa float, integer diventa integer,
boolean diventa boolean).
// Richiesta
{
"tool": "generate-json",
"arguments": {
"jsonSchema": {
"properties": {
"userId": { "type": "string", "format": "uuid" },
"email": { "type": "string", "format": "email" },
"registeredAt": { "type": "string", "format": "date" },
"score": { "type": "integer" }
}
},
"count": 2
}
}
// Risposta
[
{ "userId": "abc-123-...", "email": "james.lee@mock.dev",
"registeredAt": "2019-03-15", "score": 7842 },
{ "userId": "def-456-...", "email": "mary_white@demo.net",
"registeredAt": "2022-11-08", "score": 1256 }
]
Esempio: Generazione CSV
Il tool generate-csv gestisce correttamente l'escaping del delimitatore, delle virgolette
e dei caratteri newline. Se un valore contiene il delimitatore, virgolette o \n, viene
racchiuso tra virgolette doppie con raddoppio delle virgolette interne.
// Richiesta con delimiter: ";"
Nome;Cognome;IP
James;Smith;192.168.1.42
Linda;Johnson;10.0.0.15
Robert;Williams;172.16.5.200
Integrazione con db-schema-explorer
I due server database sono complementari: lo schema esplorato con db-schema-explorer guida
la definizione dello schema per i mock data. L'AI può esplorare la struttura di un database, estrarre
i tipi delle colonne e passarli direttamente a generate-mock-data per popolare le tabelle
con dati di test realistici.
Server 3: test-generator
Il server test-generator e dedicato alla generazione automatica di test unitari, all'identificazione di edge case e all'analisi della copertura del codice. E il punto di partenza per qualsiasi workflow di testing all'interno della MCP Suite, permettendo di passare da codice sorgente a skeleton di test in pochi secondi.
Il server e completamente stateless: non possiede alcun database ne store interno. Riceve codice sorgente in input, lo analizza tramite parsing delle firme di funzione e restituisce output strutturato senza mantenere stato tra le invocazioni.
Tool Disponibili
Tabella dei Tool - test-generator
| Tool | Descrizione | Parametri |
|---|---|---|
generate-unit-tests |
Genera skeleton di test unitari analizzando le firme delle funzioni | code (string); language (default: typescript); framework (vitest | jest | mocha) |
find-edge-cases |
Analizza il codice e suggerisce edge case classificati per severita | code (string) |
analyze-coverage |
Confronta funzioni nel sorgente con riferimenti nei test e calcola la copertura | sourceCode (string); testCode (string) |
Generazione Automatica di Test
Il tool generate-unit-tests esegue il parsing del codice sorgente cercando due pattern
di dichiarazione: funzioni classiche (export function name(params)) e arrow function
(export const name = (params) =>). Per ogni funzione trovata genera un blocco
describe/it con tre test predefiniti.
// Input: codice sorgente
export function calculateTotal(items: Item[], tax: number): number {
return items.reduce((sum, item) => sum + item.price, 0) * (1 + tax);
}
export const formatCurrency = (amount: number): string => {
return new Intl.NumberFormat('it-IT',
{ style: 'currency', currency: 'EUR' }
).format(amount);
};
// Output generato (framework: vitest)
import { describe, it, expect } from 'vitest';
// import { calculateTotal, formatCurrency } from './source';
describe('calculateTotal', () => {
it('should exist and be callable', () => {
expect(calculateTotal).toBeDefined();
expect(typeof calculateTotal).toBe('function');
});
it('should return expected result with valid input', () => {
const result = calculateTotal(/* items */, /* tax */);
expect(result).toBeDefined();
// TODO: Add specific assertions
});
it('should handle edge cases', () => {
// TODO: Test with null/undefined inputs
// TODO: Test with empty values
// TODO: Test with boundary values
});
});
Identificazione Edge Case
Il tool find-edge-cases esegue un'analisi statica del codice per identificare potenziali
edge case. I controlli sono classificati per severita (high, medium,
low) e coprono numerose categorie:
Categorie di Edge Case Rilevate
| Categoria | Severita | Condizione di Rilevamento |
|---|---|---|
null/undefined |
high | Presenza di parametri nelle funzioni |
empty-string |
high | Uso di .length, .trim(), .split() |
empty-array |
high | Uso di .map(), .filter(), .reduce() |
zero |
high | Uso di parseInt, parseFloat, Math.* |
division-by-zero |
high | Presenza dell'operatore / |
async-rejection |
high | Presenza di async, await, Promise |
error-propagation |
high | Presenza di blocchi try/catch |
file-not-found |
high | Uso di readFile, writeFile, fs.* |
whitespace-string |
medium | Uso di metodi stringa |
negative-numbers |
high | Uso di funzioni numeriche |
nested-null |
medium | Uso di ?., ||, && |
regex-edge-cases |
medium | Uso di RegExp, .match(), .test() |
Analisi della Copertura
Il tool analyze-coverage confronta il codice sorgente con il codice dei test per determinare
quali funzioni hanno copertura. Il processo prevede tre fasi: estrazione dei nomi funzione dal sorgente,
ricerca dei riferimenti nei test (blocchi describe(), blocchi it()/test(),
chiamate dirette) e calcolo della percentuale.
Sorgente Test
+------------------+ +------------------+
| function add() | ------> | describe('add') | COPERTA
| function sub() | ------> | test('sub ...') | COPERTA
| function mul() | --X | | SCOPERTA
| function div() | --X | | SCOPERTA
+------------------+ +------------------+
Coverage: 2/4 = 50%
Eventi del test-generator
Il server pubblica due eventi sull'Event Bus:
-
test:generated: emesso dagenerate-unit-testscon payload{ filePath: string, testCount: number, framework: string } -
test:coverage-report: emesso daanalyze-coveragecon payload{ filePath: string, coverage: number, uncoveredLines: number[] }
Questi eventi possono essere sottoscritti da agile-metrics per includere metriche di copertura
nelle analisi di sprint, o da standup-notes per registrare automaticamente i test generati.
Server 4: performance-profiler
Il server performance-profiler fornisce strumenti di analisi statica delle prestazioni per codice JavaScript e TypeScript. A differenza di un profiler runtime, questo server analizza il codice sorgente senza eseguirlo, identificando anti-pattern di performance noti, dipendenze pesanti e generando template di benchmark eseguibili.
Un principio fondamentale di questo server e la sicurezza by design: non viene mai eseguito
eval() ne codice arbitrario. Il tool benchmark-compare genera un template Node.js
che l'utente può eseguire separatamente nel proprio ambiente.
Tool Disponibili
Tabella dei Tool - performance-profiler
| Tool | Descrizione | Parametri |
|---|---|---|
analyze-bundle |
Analizza file JS/TS per problemi di bundle size e import pesanti | filePath (string) - percorso a file o directory |
find-bottlenecks |
Analisi statica del codice per anti-pattern di performance | code (string); language (typescript | javascript | jsx | tsx) |
benchmark-compare |
Genera un template di benchmark per confrontare due snippet di codice | codeA (string); codeB (string); iterations (default: 1000) |
Analisi del Bundle
Il tool analyze-bundle legge file JavaScript e TypeScript (singoli o intere directory, escludendo
node_modules e dist) e analizza gli import cercando dipendenze pesanti note.
Per ogni pacchetto pesante individuato, il server fornisce la dimensione stimata e un'alternativa
più leggera.
Pacchetti Pesanti Riconosciuti
| Pacchetto | Dimensione Stimata | Alternativa Suggerita |
|---|---|---|
moment |
~300KB con locales | date-fns (~20KB) o dayjs (~2KB) |
lodash |
~70KB minificato | lodash-es con tree shaking |
rxjs |
~50KB+ (import completo) | Import specifici: rxjs/operators |
aws-sdk |
>100MB | @aws-sdk/client-* v3 modulare |
jquery |
~85KB minificato | API DOM native |
three |
~600KB+ | Import da three/examples/jsm/ |
Identificazione Bottleneck
Il tool find-bottlenecks esegue analisi statica riga per riga del codice, rilevando anti-pattern
di performance con severita classificata come critical, warning o
info:
Anti-pattern di Performance Rilevati
| Tipo | Severita | Pattern Rilevato |
|---|---|---|
nested-loop |
critical | Loop for/while annidati (O(n^2)) |
sync-io |
warning | readFileSync, writeFileSync, execSync |
linear-search-in-loop |
warning | .indexOf(), .includes(), .find() dentro un loop |
dom-query-in-loop |
critical | document.querySelector dentro un loop |
sequential-await |
warning | await dentro un loop for/while |
json-in-loop |
warning | JSON.parse/stringify dentro un loop |
missing-pagination |
warning | .findAll(), SELECT * FROM senza LIMIT |
string-concat-in-loop |
info | Concatenazione stringa += dentro un loop |
recursion |
info | Funzione che chiama se stessa senza memoizzazione |
Per ogni bottleneck trovato, l'output include il tipo, la severita, la riga, una descrizione del problema e un suggerimento di fix:
{
"type": "nested-loop",
"severity": "critical",
"line": 42,
"description": "Nested loop detected - potential O(n^2)...",
"suggestion": "Consider using a Map/Set for lookups...",
"pattern": "for (const item of items) {"
}
Generazione Benchmark
Il tool benchmark-compare genera un file Node.js completo per confrontare le performance
di due snippet di codice. Il template include quattro fasi: warmup (10% delle iterazioni), misurazione
con performance.now(), calcolo statistiche (mean, median, min, max, p95, p99, stdDev, ops/sec)
e confronto finale che indica quale snippet e più veloce e di quanto.
// Richiesta
{
"tool": "benchmark-compare",
"arguments": {
"codeA": "const result = arr.filter(x => x > 0).map(x => x * 2);",
"codeB": "const result = []; for (const x of arr) { if (x > 0) result.push(x * 2); }",
"iterations": 5000
}
}
L'output e un template Node.js completo pronto per l'esecuzione con node benchmark.js.
Il server non esegue mai il codice generato: la sicurezza e garantita by design.
Eventi del performance-profiler
Il server pubblica due eventi sull'Event Bus:
-
perf:bottleneck-found: emesso dafind-bottleneckssolo per bottleneck di severitacritical, con payload{ location: string, metric: string, value: number, threshold: number } -
perf:profile-completed: emesso dabenchmark-comparecon payload{ target: string, durationMs: number, results: object }
Interazioni tra i Quattro Server
I quattro server analizzati in questo articolo non operano in isolamento ma si completano a vicenda attraverso flussi di lavoro complementari e attraverso l'Event Bus:
+---------------------+ db:index-suggestion +-------------------+
| db-schema-explorer | ------------------------> | agile-metrics |
| | | standup-notes |
+---------------------+ +-------------------+
^
| (dbPath come input)
|
+---------------------+
| data-mock-generator | genera dati che possono
| | popolare il database
+---------------------+
+-------------------+ test:generated +-------------------+
| test-generator | --------------------------> | standup-notes |
| | test:coverage-report +-------------------+
| | --------------------------> | agile-metrics |
+-------------------+ +-------------------+
+----------------------+ perf:bottleneck-found +-------------------+
| performance-profiler | -----------------------> | standup-notes |
| | perf:profile-completed +-------------------+
| | -----------------------> | agile-metrics |
+----------------------+ +-------------------+
Riepilogo Eventi Pubblicati
| Evento | Server Sorgente | Tool Emittente | Potenziali Sottoscrittori |
|---|---|---|---|
db:index-suggestion |
db-schema-explorer | suggest-indexes | agile-metrics, standup-notes |
test:generated |
test-generator | generate-unit-tests | standup-notes |
test:coverage-report |
test-generator | analyze-coverage | agile-metrics |
perf:bottleneck-found |
performance-profiler | find-bottlenecks | standup-notes, agile-metrics |
perf:profile-completed |
performance-profiler | benchmark-compare | agile-metrics |
Workflow Combinato Tipico
Un flusso di lavoro tipico che combina tutti e quattro i server potrebbe essere:
- Esplorazione schema: l'AI usa
explore-schemaper capire la struttura del database - Suggerimento indici:
suggest-indexesidentifica ottimizzazioni mancanti e pubblicadb:index-suggestion - Generazione dati:
generate-mock-datacrea fixture di test basate sullo schema esplorato - Generazione test:
generate-unit-testscrea skeleton di test per il codice applicativo e pubblicatest:generated - Analisi edge case:
find-edge-casesidentifica i casi limite da coprire nei test - Profiling:
find-bottlenecksanalizza il codice per anti-pattern e pubblicaperf:bottleneck-found - Benchmark:
benchmark-comparegenera template per confrontare implementazioni alternative
Conclusioni
I quattro server analizzati in questo articolo dimostrano come MCP possa coprire due fasi critiche del
ciclo di sviluppo: la comprensione della struttura dati e la garanzia di qualità
del codice. Il server db-schema-explorer offre introspezione completa con PRAGMA,
suggerimento indici e generazione di diagrammi ERD. Il server data-mock-generator fornisce
16 generatori per creare dati realistici in JSON e CSV. Il server test-generator automatizza
la creazione di test unitari con identificazione di edge case. Il server performance-profiler
esegue analisi statica per individuare bottleneck e generare benchmark.
Nel prossimo articolo analizzeremo i Server di Project Management: scrum-board,
agile-metrics, time-tracking, project-economics e
retrospective-manager, cinque server che portano la gestione agile del progetto
direttamente nell'interfaccia AI.
Il codice completo di tutti i server e disponibile nel repository Tech-MCP su GitHub.







