fg-tracker-mcp 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/README.md +14 -1
- package/dist/client.d.ts +3 -1
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/docs.js +2 -0
- package/dist/docs.js.map +1 -1
- package/dist/infra/tools.js +10 -1
- package/dist/infra/tools.js.map +1 -1
- package/dist/loadtest/routes.d.ts +52 -0
- package/dist/loadtest/routes.js +370 -0
- package/dist/loadtest/routes.js.map +1 -0
- package/dist/loadtest/scenario.d.ts +334 -0
- package/dist/loadtest/scenario.js +501 -0
- package/dist/loadtest/scenario.js.map +1 -0
- package/dist/loadtest/tools.d.ts +128 -0
- package/dist/loadtest/tools.js +378 -0
- package/dist/loadtest/tools.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.js +32 -6
- package/dist/server.js.map +1 -1
- package/package.json +4 -3
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { type TrackClient } from '../client.js';
|
|
3
|
+
import { type LoadtestPlan, type ScenarioSummary, type ValidationIssue } from './scenario.js';
|
|
4
|
+
export declare const SCENARIO_EXAMPLE: {
|
|
5
|
+
version: number;
|
|
6
|
+
name: string;
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
defaults: {
|
|
9
|
+
headers: {
|
|
10
|
+
accept: string;
|
|
11
|
+
};
|
|
12
|
+
timeoutMs: number;
|
|
13
|
+
thinkTimeMs: number[];
|
|
14
|
+
};
|
|
15
|
+
variables: {
|
|
16
|
+
locale: string;
|
|
17
|
+
};
|
|
18
|
+
setup: {
|
|
19
|
+
name: string;
|
|
20
|
+
method: string;
|
|
21
|
+
path: string;
|
|
22
|
+
headers: {
|
|
23
|
+
'content-type': string;
|
|
24
|
+
};
|
|
25
|
+
body: {
|
|
26
|
+
email: string;
|
|
27
|
+
password: string;
|
|
28
|
+
};
|
|
29
|
+
extract: {
|
|
30
|
+
var: string;
|
|
31
|
+
from: string;
|
|
32
|
+
path: string;
|
|
33
|
+
}[];
|
|
34
|
+
checks: ({
|
|
35
|
+
type: string;
|
|
36
|
+
in: number[];
|
|
37
|
+
path?: undefined;
|
|
38
|
+
exists?: undefined;
|
|
39
|
+
} | {
|
|
40
|
+
type: string;
|
|
41
|
+
path: string;
|
|
42
|
+
exists: boolean;
|
|
43
|
+
in?: undefined;
|
|
44
|
+
})[];
|
|
45
|
+
}[];
|
|
46
|
+
steps: ({
|
|
47
|
+
name: string;
|
|
48
|
+
method: string;
|
|
49
|
+
path: string;
|
|
50
|
+
headers: {
|
|
51
|
+
authorization: string;
|
|
52
|
+
};
|
|
53
|
+
extract: {
|
|
54
|
+
var: string;
|
|
55
|
+
from: string;
|
|
56
|
+
path: string;
|
|
57
|
+
}[];
|
|
58
|
+
checks: ({
|
|
59
|
+
type: string;
|
|
60
|
+
in: number[];
|
|
61
|
+
value?: undefined;
|
|
62
|
+
} | {
|
|
63
|
+
type: string;
|
|
64
|
+
value: number;
|
|
65
|
+
in?: undefined;
|
|
66
|
+
})[];
|
|
67
|
+
thinkTimeMs: number[];
|
|
68
|
+
} | {
|
|
69
|
+
name: string;
|
|
70
|
+
method: string;
|
|
71
|
+
path: string;
|
|
72
|
+
headers: {
|
|
73
|
+
authorization: string;
|
|
74
|
+
};
|
|
75
|
+
checks: ({
|
|
76
|
+
type: string;
|
|
77
|
+
in: number[];
|
|
78
|
+
value?: undefined;
|
|
79
|
+
} | {
|
|
80
|
+
type: string;
|
|
81
|
+
value: number;
|
|
82
|
+
in?: undefined;
|
|
83
|
+
})[];
|
|
84
|
+
extract?: undefined;
|
|
85
|
+
thinkTimeMs?: undefined;
|
|
86
|
+
})[];
|
|
87
|
+
teardown: never[];
|
|
88
|
+
};
|
|
89
|
+
export declare function formatIssues(issues: ValidationIssue[]): string;
|
|
90
|
+
export declare function formatScenarioSummary(summary: ScenarioSummary): string;
|
|
91
|
+
export interface StartRunInput {
|
|
92
|
+
projectId: string;
|
|
93
|
+
scenarioId: string;
|
|
94
|
+
baseUrl: string;
|
|
95
|
+
connectionId: string;
|
|
96
|
+
plan: unknown;
|
|
97
|
+
credentialId?: string;
|
|
98
|
+
environment?: string;
|
|
99
|
+
confirm?: boolean;
|
|
100
|
+
}
|
|
101
|
+
/** Texto de confirmação que o agente deve mostrar ao usuário antes de iniciar. */
|
|
102
|
+
export declare function runConfirmationText(input: {
|
|
103
|
+
environment?: string;
|
|
104
|
+
baseUrl: string;
|
|
105
|
+
plan: LoadtestPlan;
|
|
106
|
+
scenarioId: string;
|
|
107
|
+
connectionId: string;
|
|
108
|
+
credentialId?: string;
|
|
109
|
+
}): string;
|
|
110
|
+
export type StartRunCheck = {
|
|
111
|
+
ok: true;
|
|
112
|
+
plan: LoadtestPlan;
|
|
113
|
+
body: Record<string, unknown>;
|
|
114
|
+
confirmation: string;
|
|
115
|
+
} | {
|
|
116
|
+
ok: false;
|
|
117
|
+
message: string;
|
|
118
|
+
};
|
|
119
|
+
/** Validação pura de `loadtest_start_run`: recusa sem `confirm === true`, plano inválido ou host local/privado. */
|
|
120
|
+
export declare function checkStartRun(input: StartRunInput): StartRunCheck;
|
|
121
|
+
export declare function formatRun(response: unknown): string;
|
|
122
|
+
export declare function registerLoadtestTools(server: McpServer, client: TrackClient): void;
|
|
123
|
+
export declare function createLoadTestPrompt(args: {
|
|
124
|
+
projectId?: string;
|
|
125
|
+
path?: string;
|
|
126
|
+
baseUrl?: string;
|
|
127
|
+
goal?: string;
|
|
128
|
+
}, endpoint: string): string;
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tools e prompt da Simulação de ambiente (CONTRATO.md §28.8). Criar roteiros e sugerir planos é
|
|
3
|
+
* seguro; iniciar execução só com confirmação explícita do usuário (`confirm: true`).
|
|
4
|
+
*/
|
|
5
|
+
import { stat } from 'node:fs/promises';
|
|
6
|
+
import { resolve } from 'node:path';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { TrackApiError } from '../client.js';
|
|
9
|
+
import { guard, json, text } from '../format.js';
|
|
10
|
+
import { formatRouteScan, scanRoutes } from './routes.js';
|
|
11
|
+
import { PRESETS, describePlan, planWarnings, presetPlan, validatePlan, validateScenario, } from './scenario.js';
|
|
12
|
+
const projectIdSchema = z.string().uuid().describe('ID (uuid) do projeto — veja track_list_projects');
|
|
13
|
+
export const SCENARIO_EXAMPLE = {
|
|
14
|
+
version: 1,
|
|
15
|
+
name: 'Jornada ouvinte',
|
|
16
|
+
baseUrl: 'https://api.exemplo.com',
|
|
17
|
+
defaults: { headers: { accept: 'application/json' }, timeoutMs: 30000, thinkTimeMs: [500, 1500] },
|
|
18
|
+
variables: { locale: 'pt-BR' },
|
|
19
|
+
setup: [
|
|
20
|
+
{
|
|
21
|
+
name: 'Login',
|
|
22
|
+
method: 'POST',
|
|
23
|
+
path: '/v1/auth/login',
|
|
24
|
+
headers: { 'content-type': 'application/json' },
|
|
25
|
+
body: { email: '{{user.username}}', password: '{{user.password}}' },
|
|
26
|
+
extract: [{ var: 'token', from: 'json', path: 'accessToken' }],
|
|
27
|
+
checks: [{ type: 'status', in: [200, 201] }, { type: 'json', path: 'accessToken', exists: true }],
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
steps: [
|
|
31
|
+
{
|
|
32
|
+
name: 'Feed',
|
|
33
|
+
method: 'GET',
|
|
34
|
+
path: '/v1/feed?limit=20',
|
|
35
|
+
headers: { authorization: 'Bearer {{token}}' },
|
|
36
|
+
extract: [{ var: 'itemId', from: 'json', path: 'items[0].id' }],
|
|
37
|
+
checks: [{ type: 'status', in: [200] }, { type: 'maxDurationMs', value: 800 }],
|
|
38
|
+
thinkTimeMs: [300, 800],
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: 'Detalhe',
|
|
42
|
+
method: 'GET',
|
|
43
|
+
path: '/v1/items/{{itemId}}',
|
|
44
|
+
headers: { authorization: 'Bearer {{token}}' },
|
|
45
|
+
checks: [{ type: 'status', in: [200] }, { type: 'maxDurationMs', value: 800 }],
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
teardown: [],
|
|
49
|
+
};
|
|
50
|
+
export function formatIssues(issues) {
|
|
51
|
+
return issues.map((i) => `- ${i.path}: ${i.message}`).join('\n');
|
|
52
|
+
}
|
|
53
|
+
export function formatScenarioSummary(summary) {
|
|
54
|
+
const lines = [`Roteiro "${summary.name}"${summary.baseUrl ? ` · baseUrl ${summary.baseUrl}` : ''}`];
|
|
55
|
+
if (summary.setup.length)
|
|
56
|
+
lines.push(`Setup (1x por VU): ${summary.setup.join(' → ')}`);
|
|
57
|
+
lines.push(`Passos (${summary.steps.length}): ${summary.steps.join(' → ')}`);
|
|
58
|
+
if (summary.teardown.length)
|
|
59
|
+
lines.push(`Teardown: ${summary.teardown.join(' → ')}`);
|
|
60
|
+
lines.push(`Variáveis extraídas: ${summary.extractedVars.join(', ') || '—'}`);
|
|
61
|
+
lines.push(`Checks: ${summary.checks}${summary.checks ? ` (${Object.entries(summary.checkTypes).map(([k, v]) => `${k} ${v}`).join(', ')})` : ''}`);
|
|
62
|
+
lines.push(`Usa credenciais de teste ({{user.*}}): ${summary.usesCredentials ? 'sim' : 'não'}`);
|
|
63
|
+
if (summary.externalEffects.length) {
|
|
64
|
+
lines.push('', '⚠ Possíveis efeitos externos:');
|
|
65
|
+
for (const e of summary.externalEffects)
|
|
66
|
+
lines.push(`- ${e.section} "${e.step}" ${e.method} ${e.path}: ${e.reason}`);
|
|
67
|
+
}
|
|
68
|
+
if (summary.warnings.length)
|
|
69
|
+
lines.push('', 'Avisos:', ...summary.warnings.map((w) => `- ${w}`));
|
|
70
|
+
return lines.join('\n');
|
|
71
|
+
}
|
|
72
|
+
function privateHost(host) {
|
|
73
|
+
const h = host.replace(/^\[|\]$/g, '').toLowerCase();
|
|
74
|
+
if (h === 'localhost' || h.endsWith('.localhost') || h.endsWith('.local') || h.endsWith('.internal'))
|
|
75
|
+
return true;
|
|
76
|
+
if (h === '::1' || h === '0.0.0.0' || /^f[cd][0-9a-f]{2}:/.test(h) || h.startsWith('fe80:'))
|
|
77
|
+
return true;
|
|
78
|
+
const ip = h.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
|
|
79
|
+
if (!ip)
|
|
80
|
+
return false;
|
|
81
|
+
const [a, b] = [Number(ip[1]), Number(ip[2])];
|
|
82
|
+
return a === 10 || a === 127 || a === 0 || (a === 169 && b === 254) || (a === 172 && b >= 16 && b <= 31) || (a === 192 && b === 168) || (a === 100 && b >= 64 && b <= 127);
|
|
83
|
+
}
|
|
84
|
+
/** Texto de confirmação que o agente deve mostrar ao usuário antes de iniciar. */
|
|
85
|
+
export function runConfirmationText(input) {
|
|
86
|
+
const shape = describePlan(input.plan);
|
|
87
|
+
return [
|
|
88
|
+
`- Ambiente: ${input.environment ?? '(não informado — pergunte ao usuário)'}`,
|
|
89
|
+
`- baseUrl: ${input.baseUrl}`,
|
|
90
|
+
`- Roteiro: ${input.scenarioId} · conexão: ${input.connectionId}${input.credentialId ? ` · credenciais: ${input.credentialId}` : ' · sem credenciais (VUs anônimos)'}`,
|
|
91
|
+
`- Executor: ${shape.executor}${input.plan.preset ? ` (preset ${input.plan.preset})` : ''}`,
|
|
92
|
+
`- Pico de VUs: ${shape.peakVus}${shape.peakIterationsPerSecond !== null ? ` · pico de ${shape.peakIterationsPerSecond} iterações/s (RPS ≈ iterações/s × requests por iteração)` : ''}`,
|
|
93
|
+
`- Duração: ${shape.duration}${input.plan.gracefulStop ? ` (+ gracefulStop ${input.plan.gracefulStop})` : ''}`,
|
|
94
|
+
`- Thresholds: ${input.plan.thresholds ? Object.entries(input.plan.thresholds).map(([k, v]) => `${k} ${v.join(', ')}`).join(' · ') : '—'}${input.plan.abortOnFail ? ' · abortOnFail' : ''}`,
|
|
95
|
+
].join('\n');
|
|
96
|
+
}
|
|
97
|
+
/** Validação pura de `loadtest_start_run`: recusa sem `confirm === true`, plano inválido ou host local/privado. */
|
|
98
|
+
export function checkStartRun(input) {
|
|
99
|
+
const planResult = validatePlan(input.plan);
|
|
100
|
+
if (!planResult.ok)
|
|
101
|
+
return { ok: false, message: `Plano inválido — corrija e tente de novo:\n${formatIssues(planResult.issues)}` };
|
|
102
|
+
let url;
|
|
103
|
+
try {
|
|
104
|
+
url = new URL(input.baseUrl);
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return { ok: false, message: `baseUrl inválida: "${input.baseUrl}" (use https://host).` };
|
|
108
|
+
}
|
|
109
|
+
if (!/^https?:$/.test(url.protocol))
|
|
110
|
+
return { ok: false, message: 'baseUrl precisa usar http(s).' };
|
|
111
|
+
if (privateHost(url.hostname))
|
|
112
|
+
return { ok: false, message: `Host ${url.hostname} é local/privado: a simulação só aceita hosts públicos do projeto (CONTRATO §28.6).` };
|
|
113
|
+
const confirmation = runConfirmationText({ ...input, plan: planResult.plan });
|
|
114
|
+
if (input.confirm !== true) {
|
|
115
|
+
return {
|
|
116
|
+
ok: false,
|
|
117
|
+
message: [
|
|
118
|
+
'Recusado: iniciar uma simulação gera carga real no ambiente e exige confirmação explícita do usuário.',
|
|
119
|
+
'Mostre ao usuário exatamente isto e pergunte se deseja iniciar:',
|
|
120
|
+
'',
|
|
121
|
+
confirmation,
|
|
122
|
+
...planWarnings(planResult.plan).map((w) => `- Atenção: ${w}`),
|
|
123
|
+
'',
|
|
124
|
+
'Só chame de novo com `confirm: true` depois de um "sim" explícito nesta conversa. Alternativa recomendada: iniciar pela UI (Infraestrutura → "Simular ambiente"), que também oferece "Avaliar com IA".',
|
|
125
|
+
].join('\n'),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const body = { scenarioId: input.scenarioId, plan: planResult.plan, baseUrl: input.baseUrl, connectionId: input.connectionId };
|
|
129
|
+
if (input.credentialId)
|
|
130
|
+
body.credentialId = input.credentialId;
|
|
131
|
+
if (input.environment)
|
|
132
|
+
body.environment = input.environment;
|
|
133
|
+
return { ok: true, plan: planResult.plan, body, confirmation };
|
|
134
|
+
}
|
|
135
|
+
const n = (v, digits = 0) => (typeof v === 'number' && Number.isFinite(v) ? v.toFixed(digits) : '—');
|
|
136
|
+
const msf = (v) => (typeof v === 'number' && Number.isFinite(v) ? `${Math.round(v)} ms` : '—');
|
|
137
|
+
const pctf = (v) => (typeof v === 'number' && Number.isFinite(v) ? `${(v * 100).toFixed(2)}%` : '—');
|
|
138
|
+
export function formatRun(response) {
|
|
139
|
+
const r = (response?.run ?? response ?? {});
|
|
140
|
+
const lines = [`Run ${r.id ?? '?'} · status ${r.status ?? '?'}${r.environment ? ` · ${r.environment}` : ''}${r.baseUrl ? ` · ${r.baseUrl}` : ''}`];
|
|
141
|
+
if (r.startedAt)
|
|
142
|
+
lines.push(`Início ${r.startedAt}${r.finishedAt ? ` · fim ${r.finishedAt}` : r.endsAt ? ` · término estimado ${r.endsAt}` : ''}`);
|
|
143
|
+
if (r.plan) {
|
|
144
|
+
try {
|
|
145
|
+
const shape = describePlan(r.plan);
|
|
146
|
+
lines.push(`Plano: ${shape.executor}${r.plan.preset ? ` (${r.plan.preset})` : ''} · pico ${shape.peakVus} VUs${shape.peakIterationsPerSecond !== null ? ` / ${shape.peakIterationsPerSecond} it/s` : ''} · ${shape.duration}`);
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
/* plano fora do formato */
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (r.error)
|
|
153
|
+
lines.push(`Erro: ${r.error}`);
|
|
154
|
+
const s = r.summary;
|
|
155
|
+
if (s) {
|
|
156
|
+
const errorRate = s.requests ? (s.failed ?? 0) / s.requests : undefined;
|
|
157
|
+
lines.push('', `Requests ${n(s.requests)} · falhas ${n(s.failed)} (${pctf(errorRate)}) · iterações ${n(s.iterations)} · VUs máx ${n(s.vusMax)}`, `RPS médio ${n(s.rpsAvg, 1)} · máx ${n(s.rpsMax, 1)} · checks ${pctf(s.checksRate)}`, `Latência: p50 ${msf(s.p50)} · p90 ${msf(s.p90)} · p95 ${msf(s.p95)} · p99 ${msf(s.p99)} · média ${msf(s.avg)} · máx ${msf(s.max)}`);
|
|
158
|
+
if (s.thresholds?.length) {
|
|
159
|
+
lines.push('', 'Thresholds:');
|
|
160
|
+
for (const t of s.thresholds)
|
|
161
|
+
lines.push(`- ${t.ok ? '✓' : '✗'} ${t.metric} ${t.expr}${t.value !== undefined && t.value !== null ? ` (valor ${Number(t.value).toFixed(t.metric.includes('duration') ? 0 : 4)})` : ''}`);
|
|
162
|
+
}
|
|
163
|
+
const steps = Object.entries(s.byStep ?? {});
|
|
164
|
+
if (steps.length) {
|
|
165
|
+
lines.push('', 'Por passo:');
|
|
166
|
+
for (const [name, st] of steps.slice(0, 30))
|
|
167
|
+
lines.push(`- ${name}: ${n(st.requests)} req · erro ${pctf(st.failedRate)} · p95 ${msf(st.p95)} · média ${msf(st.avg)}`);
|
|
168
|
+
}
|
|
169
|
+
const statuses = Object.entries(s.byStatus ?? {});
|
|
170
|
+
if (statuses.length)
|
|
171
|
+
lines.push('', `Status: ${statuses.map(([k, v]) => `${k}=${v}`).join(' · ')}`);
|
|
172
|
+
}
|
|
173
|
+
else
|
|
174
|
+
lines.push('', 'Sem resumo ainda (run em fila/iniciando ou sem pontos).');
|
|
175
|
+
const a = r.advice;
|
|
176
|
+
if (a) {
|
|
177
|
+
lines.push('', 'Sugestões da IA:');
|
|
178
|
+
if (a.summary)
|
|
179
|
+
lines.push(a.summary);
|
|
180
|
+
if (a.bottlenecks?.length)
|
|
181
|
+
lines.push('Gargalos:', ...a.bottlenecks.map((b) => `- ${b.title}${b.nodeId ? ` [nó ${b.nodeId}]` : ''}${b.evidence ? ` — ${b.evidence}` : ''}`));
|
|
182
|
+
if (a.actions?.length)
|
|
183
|
+
lines.push('Ações:', ...a.actions.map((x) => `- ${x.title}${x.impact || x.effort ? ` (impacto ${x.impact ?? '?'}, esforço ${x.effort ?? '?'})` : ''}${x.detail ? `: ${x.detail}` : ''}`));
|
|
184
|
+
}
|
|
185
|
+
else if (r.status && ['passed', 'failed', 'aborted', 'error'].includes(r.status)) {
|
|
186
|
+
lines.push('', 'Sem advice: chame de novo com `generateAdvice: true` (IA) ou use "Sugestões da IA" na UI.');
|
|
187
|
+
}
|
|
188
|
+
return lines.join('\n');
|
|
189
|
+
}
|
|
190
|
+
/* ---------------- registro ---------------- */
|
|
191
|
+
async function resolveRoot(path) {
|
|
192
|
+
const root = resolve(process.cwd(), path ?? '.');
|
|
193
|
+
const s = await stat(root).catch(() => null);
|
|
194
|
+
if (!s?.isDirectory())
|
|
195
|
+
throw new Error(`Diretório não encontrado: ${root}. Passe \`path\` com o caminho absoluto do repositório.`);
|
|
196
|
+
return root;
|
|
197
|
+
}
|
|
198
|
+
function asList(value) {
|
|
199
|
+
if (Array.isArray(value))
|
|
200
|
+
return value;
|
|
201
|
+
const items = value?.items;
|
|
202
|
+
return Array.isArray(items) ? items : [];
|
|
203
|
+
}
|
|
204
|
+
export function registerLoadtestTools(server, client) {
|
|
205
|
+
const base = (projectId) => `/v1/projects/${projectId}/loadtest`;
|
|
206
|
+
server.registerTool('loadtest_scan_routes', {
|
|
207
|
+
title: 'Ler rotas HTTP e autenticação do repositório',
|
|
208
|
+
description: 'Varredura local e somente leitura (regex, nada é executado): controllers NestJS (@Controller + @Get/@Post…, DTO de @Body/@Query, @UseGuards/@Public, setGlobalPrefix, APP_GUARD), Express/Fastify (app.get("/x"), router.post, router.route().get()), Next.js (app/**/route.ts e pages/api). Devolve método, caminho, arquivo:linha, controller/handler, DTO (com campos), se é protegida e pistas de auth (login/refresh/cadastro, JWT/cookie/sessão, provedores externos, campos de token). Use para montar jornadas realistas antes de loadtest_create_scenario.',
|
|
209
|
+
inputSchema: {
|
|
210
|
+
path: z.string().optional().describe('Diretório do app/serviço (default: diretório atual)'),
|
|
211
|
+
format: z.enum(['text', 'json']).default('text').describe('text (compacto) ou json (estrutura completa)'),
|
|
212
|
+
},
|
|
213
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
214
|
+
}, async ({ path, format }) => guard(async () => {
|
|
215
|
+
const scan = await scanRoutes(await resolveRoot(path));
|
|
216
|
+
return format === 'json' ? json(scan) : text(formatRouteScan(scan));
|
|
217
|
+
}));
|
|
218
|
+
server.registerTool('loadtest_create_scenario', {
|
|
219
|
+
title: 'Criar roteiro de simulação (jornada)',
|
|
220
|
+
description: [
|
|
221
|
+
'Valida o roteiro (CONTRATO §28.2) e grava no projeto (POST /v1/projects/:id/loadtest/scenarios com token de sessão; com só FG_TRACKER_API_KEY usa POST /v1/loadtest/scenarios). Em erro de validação devolve cada problema com o caminho do campo (ex.: steps[1].checks[0].in) e nada é gravado.',
|
|
222
|
+
'Formato: { version: 1, name, baseUrl?, defaults?: { headers?, timeoutMs?, thinkTimeMs?: n | [min,max] }, variables?, setup?: Step[], steps: Step[] (≥1), teardown?: Step[] }.',
|
|
223
|
+
'Step: { name, method: GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS, path (relativo ao baseUrl, aceita {{var}}), headers?, body?, extract?: [{ var, from: json|header|regex|status, path? }], checks?: [{ type: "status", in: [200] } | { type: "json", path, exists?|equals? } | { type: "bodyContains", value } | { type: "maxDurationMs", value }], thinkTimeMs?, weight?, skipIf? }.',
|
|
224
|
+
'Templates: {{user.username}}, {{user.password}}, {{user.extra.*}} (usuários de teste cifrados no FG Tracker — nunca escreva senhas no roteiro), {{vu}}, {{iteration}}, {{uuid}}, {{randomInt(a,b)}}, variáveis extraídas e variables.',
|
|
225
|
+
`Exemplo: ${JSON.stringify(SCENARIO_EXAMPLE)}`,
|
|
226
|
+
'O resumo aponta passos com possível efeito externo (pagamento, checkout, e-mail, webhook, SMS, convite) — remova-os ou use modo de teste.',
|
|
227
|
+
].join('\n'),
|
|
228
|
+
inputSchema: {
|
|
229
|
+
projectId: projectIdSchema,
|
|
230
|
+
scenario: z.record(z.string(), z.unknown()).describe('Documento do roteiro (§28.2), ver descrição da tool'),
|
|
231
|
+
description: z.string().max(500).optional().describe('Descrição curta da jornada (opcional)'),
|
|
232
|
+
},
|
|
233
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
234
|
+
}, async ({ projectId, scenario, description }) => guard(async () => {
|
|
235
|
+
const result = validateScenario(scenario);
|
|
236
|
+
if (!result.ok) {
|
|
237
|
+
return { ...text(`Roteiro inválido (${result.issues.length} problema(s)) — nada foi gravado:\n${formatIssues(result.issues)}`), isError: true };
|
|
238
|
+
}
|
|
239
|
+
const payload = { name: result.scenario.name, ...(description ? { description } : {}), document: result.scenario, source: 'mcp' };
|
|
240
|
+
let route = `${base(projectId)}/scenarios`;
|
|
241
|
+
let response;
|
|
242
|
+
if (!client.hasToken && client.hasApiKey) {
|
|
243
|
+
route = '/v1/loadtest/scenarios';
|
|
244
|
+
response = await client.post(route, { projectId, ...payload });
|
|
245
|
+
}
|
|
246
|
+
else {
|
|
247
|
+
try {
|
|
248
|
+
response = await client.post(route, payload);
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
if (err instanceof TrackApiError && (err.status === 401 || err.status === 403) && client.hasApiKey) {
|
|
252
|
+
route = '/v1/loadtest/scenarios';
|
|
253
|
+
response = await client.post(route, { projectId, ...payload });
|
|
254
|
+
}
|
|
255
|
+
else
|
|
256
|
+
throw err;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
const saved = (response?.scenario ?? response);
|
|
260
|
+
return text([
|
|
261
|
+
`Roteiro gravado (${route}) · id ${saved?.id ?? '?'}`,
|
|
262
|
+
'',
|
|
263
|
+
formatScenarioSummary(result.summary),
|
|
264
|
+
'',
|
|
265
|
+
'Próximos passos: `loadtest_suggest_plan` para o plano; peça ao usuário para cadastrar usuários de teste (Simular ambiente → Credenciais) e iniciar pela UI.',
|
|
266
|
+
].join('\n'));
|
|
267
|
+
}));
|
|
268
|
+
server.registerTool('loadtest_list_scenarios', {
|
|
269
|
+
title: 'Listar roteiros de simulação',
|
|
270
|
+
description: 'GET /v1/projects/:id/loadtest/scenarios: id, nome, origem (mcp|editor), passos e atualização.',
|
|
271
|
+
inputSchema: { projectId: projectIdSchema },
|
|
272
|
+
annotations: { readOnlyHint: true, openWorldHint: true },
|
|
273
|
+
}, async ({ projectId }) => guard(async () => {
|
|
274
|
+
const list = asList(await client.get(`${base(projectId)}/scenarios`));
|
|
275
|
+
if (list.length === 0)
|
|
276
|
+
return text('Nenhum roteiro. Crie um com o prompt create-load-test ou `loadtest_create_scenario`.');
|
|
277
|
+
const lines = list.map((s) => {
|
|
278
|
+
const doc = s.document;
|
|
279
|
+
return `- ${String(s.name ?? '?')} · id ${String(s.id ?? '?')} · ${String(s.source ?? '?')}${doc?.steps ? ` · ${doc.setup?.length ?? 0} setup + ${doc.steps.length} passos` : ''}${s.updatedAt ? ` · atualizado ${String(s.updatedAt)}` : ''}`;
|
|
280
|
+
});
|
|
281
|
+
return text(`${list.length} roteiro(s):\n${lines.join('\n')}`);
|
|
282
|
+
}));
|
|
283
|
+
server.registerTool('loadtest_suggest_plan', {
|
|
284
|
+
title: 'Sugerir plano de carga (preset k6)',
|
|
285
|
+
description: 'Puro (não chama a API): devolve um plano §28.3 para o preset — smoke (1–5 VUs, 1 min), load (rampa até N e platô), stress (degraus 50%→200% do normal), spike (salto súbito de 10% para 100%), soak (carga média por horas), breakpoint (rampa de arrival-rate até quebrar, abortOnFail). Com targetRps (sem vus) usa executores arrival-rate (targetRps = iterações/s; cada iteração faz vários requests). Mostra pico de VUs, duração e avisos.',
|
|
286
|
+
inputSchema: {
|
|
287
|
+
preset: z.enum(PRESETS).describe('smoke | load | stress | spike | soak | breakpoint'),
|
|
288
|
+
vus: z.number().int().positive().optional().describe('VUs no pico (ou "normal" no stress)'),
|
|
289
|
+
targetRps: z.number().positive().optional().describe('Alvo de iterações por segundo (usa arrival-rate)'),
|
|
290
|
+
duration: z.string().optional().describe('Duração total no formato k6 ("10m", "2h")'),
|
|
291
|
+
},
|
|
292
|
+
annotations: { readOnlyHint: true, openWorldHint: false },
|
|
293
|
+
}, async ({ preset, vus, targetRps, duration }) => guard(async () => {
|
|
294
|
+
const plan = presetPlan(preset, { vus, targetRps, duration });
|
|
295
|
+
const shape = describePlan(plan);
|
|
296
|
+
const warnings = planWarnings(plan);
|
|
297
|
+
return json(plan, [`Plano ${preset}: ${shape.executor} · pico ${shape.peakVus} VUs${shape.peakIterationsPerSecond !== null ? ` / ${shape.peakIterationsPerSecond} it/s` : ''} · ${shape.duration}.`, ...warnings.map((w) => `Atenção: ${w}`), 'Ajuste thresholds ao SLO do produto. Na UI, "Avaliar com IA" confere o plano contra os limites da conta.'].join('\n'));
|
|
298
|
+
}));
|
|
299
|
+
server.registerTool('loadtest_get_run', {
|
|
300
|
+
title: 'Resultado de uma simulação',
|
|
301
|
+
description: 'GET /v1/projects/:id/loadtest/runs/:runId: status, plano, requests/falhas, RPS, p50/p90/p95/p99, checks, thresholds (✓/✗), tabela por passo, status HTTP e "Sugestões da IA" (advice) quando houver. `generateAdvice: true` pede a análise (POST …/advice) se o run terminou sem advice.',
|
|
302
|
+
inputSchema: {
|
|
303
|
+
projectId: projectIdSchema,
|
|
304
|
+
runId: z.string().uuid().describe('ID do run'),
|
|
305
|
+
generateAdvice: z.boolean().default(false).describe('Gerar advice por IA se o run terminou e ainda não tem'),
|
|
306
|
+
},
|
|
307
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: true },
|
|
308
|
+
}, async ({ projectId, runId, generateAdvice }) => guard(async () => {
|
|
309
|
+
const response = (await client.get(`${base(projectId)}/runs/${runId}`));
|
|
310
|
+
const run = (response?.run ?? response);
|
|
311
|
+
if (generateAdvice && !run.advice && run.status && ['passed', 'failed', 'aborted', 'error'].includes(run.status)) {
|
|
312
|
+
run.advice = (await client.post(`${base(projectId)}/runs/${runId}/advice`, {}));
|
|
313
|
+
}
|
|
314
|
+
return text(formatRun(run));
|
|
315
|
+
}));
|
|
316
|
+
server.registerTool('loadtest_start_run', {
|
|
317
|
+
title: 'Iniciar simulação (exige confirmação explícita)',
|
|
318
|
+
description: 'Gera carga REAL no ambiente escolhido. ANTES de chamar com confirm: true, pergunte ao usuário e mostre explicitamente: ambiente, baseUrl, pico de VUs/RPS, duração e thresholds (chamar sem confirm devolve esse texto pronto). Só use confirm: true após um "sim" explícito do usuário nesta conversa — nunca por iniciativa própria. Prefira orientar o usuário a iniciar pela UI (Simular ambiente). POST /v1/projects/:id/loadtest/runs; exige conexão com executor (load_runner_arn) e host do projeto.',
|
|
319
|
+
inputSchema: {
|
|
320
|
+
projectId: projectIdSchema,
|
|
321
|
+
scenarioId: z.string().uuid().describe('ID do roteiro (loadtest_list_scenarios)'),
|
|
322
|
+
baseUrl: z.string().describe('URL base do ambiente-alvo (host verificado do projeto)'),
|
|
323
|
+
connectionId: z.string().uuid().describe('Conexão AWS com o executor de carga'),
|
|
324
|
+
plan: z.record(z.string(), z.unknown()).describe('Plano §28.3 (ex.: saída de loadtest_suggest_plan)'),
|
|
325
|
+
credentialId: z.string().uuid().optional().describe('Conjunto de usuários de teste'),
|
|
326
|
+
environment: z.string().optional().describe('Ambiente (production | staging | development…) para exibir na confirmação'),
|
|
327
|
+
confirm: z.boolean().default(false).describe('true SOMENTE após confirmação explícita do usuário'),
|
|
328
|
+
},
|
|
329
|
+
annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true },
|
|
330
|
+
}, async (input) => guard(async () => {
|
|
331
|
+
const check = checkStartRun(input);
|
|
332
|
+
if (!check.ok)
|
|
333
|
+
return { ...text(check.message), isError: true };
|
|
334
|
+
const response = (await client.post(`${base(input.projectId)}/runs`, check.body));
|
|
335
|
+
const run = (response?.run ?? response);
|
|
336
|
+
return text([`Simulação iniciada · run ${run.id ?? '?'} · status ${run.status ?? '?'}`, check.confirmation, '', `Acompanhe na UI (Simular ambiente) ou com \`loadtest_get_run { projectId: "${input.projectId}", runId: "${run.id ?? '<runId>'}" }\`. Para parar: botão Parar na UI.`].join('\n'));
|
|
337
|
+
}));
|
|
338
|
+
server.registerPrompt('create-load-test', {
|
|
339
|
+
title: 'Criar teste de carga (Simular ambiente)',
|
|
340
|
+
description: 'Roteiro para o agente: ler rotas e autenticação do repositório → escolher 1–3 jornadas realistas → montar setup (login) e passos com extração, checks e think time → evitar efeitos externos → loadtest_create_scenario → loadtest_suggest_plan → orientar usuários de teste e execução pela UI.',
|
|
341
|
+
argsSchema: {
|
|
342
|
+
projectId: z.string().optional().describe('Projeto no FG Tracker (default: da mensagem do usuário ou track_list_projects)'),
|
|
343
|
+
path: z.string().optional().describe('Repositório/app (default: diretório atual)'),
|
|
344
|
+
baseUrl: z.string().optional().describe('URL base do ambiente-alvo'),
|
|
345
|
+
goal: z.string().optional().describe('Objetivo (ex.: "aguentar 500 usuários no lançamento", "achar o ponto de quebra")'),
|
|
346
|
+
},
|
|
347
|
+
}, ({ projectId, path, baseUrl, goal }) => ({
|
|
348
|
+
messages: [{ role: 'user', content: { type: 'text', text: createLoadTestPrompt({ projectId, path, baseUrl, goal }, client.baseUrl) } }],
|
|
349
|
+
}));
|
|
350
|
+
}
|
|
351
|
+
export function createLoadTestPrompt(args, endpoint) {
|
|
352
|
+
const project = args.projectId ? `projectId **${args.projectId}**` : 'o projeto indicado pelo usuário (senão use `track_list_projects` e pergunte)';
|
|
353
|
+
const repo = args.path ? `\`${args.path}\`` : 'o diretório atual';
|
|
354
|
+
const target = args.baseUrl ? `\`${args.baseUrl}\`` : 'a URL do ambiente-alvo (pergunte se não estiver clara; precisa ser um host do projeto — nunca localhost/IP privado)';
|
|
355
|
+
const goal = args.goal ? `Objetivo informado: **${args.goal}**.` : 'Se o usuário não disse o objetivo (validar lançamento, capacidade, ponto de quebra, estabilidade por horas), pergunte em uma frase.';
|
|
356
|
+
return `Você vai criar um teste de carga ("Simulação de ambiente" do FG Tracker em ${endpoint}) para ${project}, a partir do código em ${repo}, mirando ${target}. ${goal}
|
|
357
|
+
|
|
358
|
+
## Regras (obrigatórias)
|
|
359
|
+
- **Nunca invente credenciais reais e nunca coloque senhas, tokens ou chaves no roteiro.** Login usa só \`{{user.username}}\` e \`{{user.password}}\`; o usuário cadastra os usuários de teste (cifrados) no FG Tracker.
|
|
360
|
+
- **Evite efeitos externos**: pagamentos/checkout, e-mails, webhooks, SMS/WhatsApp, convites, push, reset de senha, compras/transferências. Remova esses passos ou use o modo de teste/sandbox do provedor (ex.: chaves de teste do Stripe, domínio de e-mail de teste) e diga isso ao usuário.
|
|
361
|
+
- **Não inicie execuções por conta própria.** A execução é feita pelo usuário na UI (Infraestrutura → "Simular ambiente"). \`loadtest_start_run\` só com confirmação explícita do usuário depois de mostrar ambiente, baseUrl, pico de VUs/RPS e duração.
|
|
362
|
+
- Prefira ambientes de staging; se o alvo for produção, alerte sobre impacto em usuários reais e custo.
|
|
363
|
+
|
|
364
|
+
## Passo a passo
|
|
365
|
+
1. **Rotas e autenticação** — chame \`loadtest_scan_routes { path }\`. Leia os arquivos apontados para confirmar: rota de login (corpo esperado — veja os campos do DTO — e onde vem o token: \`accessToken\` no JSON, header \`set-cookie\`…), refresh, guards, prefixo global e rotas principais de negócio. Se a auth for por provedor externo (Cognito, Clerk, next-auth…), descubra com o usuário como obter token para usuários de teste.
|
|
366
|
+
2. **Jornadas** — escolha **1 a 3 jornadas realistas** do usuário típico, ordenadas por importância, ex.: login → listar → detalhar → ação leve (favoritar, comentar, salvar rascunho). Prefira leituras frequentes; inclua escritas só se forem idempotentes ou fáceis de limpar. Use \`weight\` para refletir a frequência (ex.: listagem 3, detalhe 2, ação 1). Com várias jornadas muito diferentes, crie um roteiro por jornada.
|
|
367
|
+
3. **Setup** — em \`setup\` (1x por VU): login com \`{{user.username}}\`/\`{{user.password}}\` e \`extract\` do token (\`{ "var": "token", "from": "json", "path": "accessToken" }\`) ou do cookie (\`{ "var": "cookie", "from": "header", "path": "set-cookie" }\`); checks \`status\` + \`json exists\` no token.
|
|
368
|
+
4. **Passos** — em \`steps\` (repetidos a cada iteração): headers \`authorization: Bearer {{token}}\` (ou \`cookie: {{cookie}}\`); **extraia ids das listagens** (\`{ "var": "itemId", "from": "json", "path": "items[0].id" }\`) e use-os nos detalhes (\`/v1/items/{{itemId}}\`); corpos válidos segundo os DTOs, com dados variados (\`{{uuid}}\`, \`{{randomInt(1,100)}}\`, \`{{vu}}\`); em cada passo checks \`{ "type": "status", "in": [200] }\` e \`{ "type": "maxDurationMs", "value": <SLO, ex. 800> }\`; think time realista (\`defaults.thinkTimeMs: [500, 1500]\`, maior em telas de leitura). Use \`teardown\` para logout ou limpeza, se existir.
|
|
369
|
+
5. **Validar e gravar** — chame \`loadtest_create_scenario { projectId, scenario }\`. Se voltar com problemas, corrija pelos caminhos indicados e repita. Leia os avisos: variáveis não definidas, passos sem check, **efeitos externos** — resolva antes de seguir.
|
|
370
|
+
6. **Plano** — chame \`loadtest_suggest_plan\` com o preset adequado ao objetivo: \`smoke\` primeiro (sempre), depois \`load\` (carga esperada), \`stress\` (acima do normal), \`spike\` (pico súbito), \`soak\` (horas) ou \`breakpoint\` (achar o limite). Use \`vus\` (usuários simultâneos) ou \`targetRps\` (iterações/s) coerentes com o objetivo e ajuste thresholds ao SLO. Alerte se o plano parecer exagerado para o ambiente.
|
|
371
|
+
7. **Entrega ao usuário** — explique a jornada criada (passos, variáveis, checks) e o plano sugerido, e oriente: (a) criar **usuários de teste** no ambiente-alvo (no mínimo tantos quanto o pico de VUs, ou aceitar reuso) e cadastrá-los em "Simular ambiente → Credenciais" — nunca peça as senhas no chat; (b) garantir que o host está verificado no projeto (nó do diagrama ou TXT \`_fg-tracker.<host>\`); (c) abrir **Infraestrutura → "Simular ambiente"**, escolher o roteiro, o preset/plano e o ambiente, usar "Avaliar com IA" e iniciar; (d) depois, você pode ler o resultado com \`loadtest_get_run\`.
|
|
372
|
+
|
|
373
|
+
Formato do roteiro (referência):
|
|
374
|
+
\`\`\`json
|
|
375
|
+
${JSON.stringify(SCENARIO_EXAMPLE, null, 2)}
|
|
376
|
+
\`\`\``;
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=tools.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/loadtest/tools.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
6
6
|
import { TrackClient } from './client.js';
|
|
7
7
|
import { type ToolText } from './format.js';
|
|
8
8
|
export declare const SERVER_NAME = "fg-tracker";
|
|
9
|
-
export declare const SERVER_VERSION = "0.
|
|
9
|
+
export declare const SERVER_VERSION = "0.9.0";
|
|
10
10
|
export interface CreateServerOptions {
|
|
11
11
|
client?: TrackClient;
|
|
12
12
|
}
|