tm-mcp 1.2.0__tar.gz
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.
- tm_mcp-1.2.0/.gitignore +8 -0
- tm_mcp-1.2.0/CHANGELOG.md +454 -0
- tm_mcp-1.2.0/LICENSE +201 -0
- tm_mcp-1.2.0/MCP-USAGE.md +528 -0
- tm_mcp-1.2.0/PKG-INFO +370 -0
- tm_mcp-1.2.0/README.md +342 -0
- tm_mcp-1.2.0/STABILITY.md +181 -0
- tm_mcp-1.2.0/examples/README.md +27 -0
- tm_mcp-1.2.0/pyproject.toml +85 -0
- tm_mcp-1.2.0/tm_mcp/__init__.py +38 -0
- tm_mcp-1.2.0/tm_mcp/auth.py +107 -0
- tm_mcp-1.2.0/tm_mcp/capture_path.py +153 -0
- tm_mcp-1.2.0/tm_mcp/errors.py +142 -0
- tm_mcp-1.2.0/tm_mcp/server.py +3409 -0
tm_mcp-1.2.0/.gitignore
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `tm-mcp`. The format is loosely
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions
|
|
5
|
+
follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## 1.2.0 — 2026-05-19
|
|
8
|
+
|
|
9
|
+
**First PyPI release.** 1.1.0 was never published; this is the
|
|
10
|
+
first version available via `pip install tm-mcp` / `uvx tm-mcp`.
|
|
11
|
+
|
|
12
|
+
### Required env-var change
|
|
13
|
+
|
|
14
|
+
`TM_BASE_URL` is now **required at server startup** alongside
|
|
15
|
+
`TM_API_KEY`. Previously the underlying `trafficmorph` SDK had a
|
|
16
|
+
built-in placeholder default that didn't resolve, so a missing
|
|
17
|
+
`TM_BASE_URL` produced silent DNS failures on every tool call.
|
|
18
|
+
The SDK now refuses to construct without an explicit base URL,
|
|
19
|
+
and the MCP server reads `$TM_BASE_URL` at startup and raises
|
|
20
|
+
`ConfigurationError` if it's missing or blank.
|
|
21
|
+
|
|
22
|
+
If your existing MCP host config already sets `TM_BASE_URL` (as
|
|
23
|
+
the README has recommended since 1.0.0), no action needed. If
|
|
24
|
+
you were relying on the implicit default, add a `TM_BASE_URL`
|
|
25
|
+
entry to the `env` block of your host config — see the Quick
|
|
26
|
+
start section in the README.
|
|
27
|
+
|
|
28
|
+
### Dependency
|
|
29
|
+
|
|
30
|
+
- Pin `trafficmorph` widened to `>= 0.3.2, < 0.4.0` (was
|
|
31
|
+
`>= 0.2.1, < 0.3.0`). The SDK underwent a hardening pass
|
|
32
|
+
between 0.2.x and 0.3.2 (URL validation, header-byte
|
|
33
|
+
validation, structural `%2F` preservation in path
|
|
34
|
+
normalization) — none of those changes affect the
|
|
35
|
+
`trafficmorph.api.*` / `trafficmorph.models` / `trafficmorph.types`
|
|
36
|
+
surfaces `tm-mcp` imports.
|
|
37
|
+
|
|
38
|
+
### Packaging
|
|
39
|
+
|
|
40
|
+
- Licensed under Apache-2.0 (was "Proprietary"). `LICENSE` file
|
|
41
|
+
added; ships in both wheel and sdist.
|
|
42
|
+
- Project URLs now point at the standalone source mirror at
|
|
43
|
+
`github.com/trafficmorph-gif/tm-mcp`.
|
|
44
|
+
- Author contact email added.
|
|
45
|
+
|
|
46
|
+
## 1.1.0 — 2026-05-17
|
|
47
|
+
|
|
48
|
+
**Variables-set tools** — 6 new tools closing the last major
|
|
49
|
+
functional gap in the AI-driven workflow. The catalog grows from
|
|
50
|
+
28 to 34 entries (25 tools + 4 prompts + 5 resources).
|
|
51
|
+
|
|
52
|
+
Variables sets are CSV-style attached data that profiles sample
|
|
53
|
+
per-request to replay traffic with realistic per-request data
|
|
54
|
+
(authenticated tokens, parameterized URLs, distribution-matched
|
|
55
|
+
inputs). The capture-import flow already auto-creates them, but
|
|
56
|
+
until now the AI could only see them indirectly through
|
|
57
|
+
`tm_get_profile`'s attached-set list — couldn't create new ones,
|
|
58
|
+
rename, change mode, or delete from MCP.
|
|
59
|
+
|
|
60
|
+
### Added (6 tools)
|
|
61
|
+
|
|
62
|
+
- `tm_list_variables_sets` — list all variables sets for the
|
|
63
|
+
current user. Plain array of metadata (id, name, mode, macro
|
|
64
|
+
columns, weight column, row count, timestamps).
|
|
65
|
+
- `tm_get_variables_set(variables_set_id)` — single set's
|
|
66
|
+
metadata.
|
|
67
|
+
- `tm_create_variables_set(name, csv_content, mode="ROW")` —
|
|
68
|
+
upload a new set from inline CSV. Three modes accepted: `ROW`
|
|
69
|
+
(default; weighted per-row sampling, requires a `weight`
|
|
70
|
+
column), `COLUMN` (per-column independent sampling; shared
|
|
71
|
+
`weight` and per-column `{col}_weight` are both optional), and
|
|
72
|
+
`SEQUENTIAL` (rows walked in CSV order; weights ignored). CSV
|
|
73
|
+
travels as a string in the JSON body, not multipart.
|
|
74
|
+
- `tm_rename_variables_set(variables_set_id, name)` — change the
|
|
75
|
+
display name only; CSV + mode + attachments preserved.
|
|
76
|
+
- `tm_change_variables_set_mode(variables_set_id, mode)` — switch
|
|
77
|
+
between any of the three modes (ROW / COLUMN / SEQUENTIAL)
|
|
78
|
+
without re-uploading. Server re-parses the stored CSV with the
|
|
79
|
+
new mode and 400s if incompatible (e.g. ROW without a `weight`
|
|
80
|
+
column).
|
|
81
|
+
- `tm_delete_variables_set(variables_set_id)` — remove a set.
|
|
82
|
+
Fails fast with a 400 if the set is still attached to any
|
|
83
|
+
profile; the response names the referencing profile(s) so
|
|
84
|
+
the caller knows which to detach first. There's no auto-
|
|
85
|
+
detach by design — the deliberate choice is to make
|
|
86
|
+
accidental attachment loss visible. Recovery path: detach
|
|
87
|
+
via `tm_update_profile` on each referencing profile, then
|
|
88
|
+
retry the delete.
|
|
89
|
+
|
|
90
|
+
### Server-side changes
|
|
91
|
+
|
|
92
|
+
- New `ApiVariablesSetController` at `/api/v1/variables-sets/*`
|
|
93
|
+
mirroring the in-app UI controller's 6 mutation endpoints. The
|
|
94
|
+
list response drops the UI's quota envelope — public-API
|
|
95
|
+
callers (CLI / MCP / SDKs) get a plain array. CSV download
|
|
96
|
+
omitted from the v1 surface (raw `text/csv` doesn't fit
|
|
97
|
+
cleanly into a uniformly-JSON public API).
|
|
98
|
+
- `ApiVariablesSetControllerTest` — 11 integration tests
|
|
99
|
+
covering list/get/create/rename/change-mode/delete, multi-user
|
|
100
|
+
isolation, ownership 400s, unauthenticated 401, ROW-mode
|
|
101
|
+
weight-column requirement, SEQUENTIAL flips.
|
|
102
|
+
|
|
103
|
+
### Design notes
|
|
104
|
+
|
|
105
|
+
- **Inline CSV upload, not multipart.** Matches the in-app
|
|
106
|
+
controller's pattern. The server's parser size-caps CSVs at
|
|
107
|
+
`MAX_BYTES`; larger sets need pre-downsampling. Simpler client
|
|
108
|
+
surface (the AI can construct a CSV string from analysis
|
|
109
|
+
output without multipart-encoding gymnastics).
|
|
110
|
+
- **Mode validation is client-side string-against-set.** The SDK
|
|
111
|
+
emits per-endpoint mode enums (`CreateVariablesSetRequestMode`,
|
|
112
|
+
`ChangeVariablesSetModeRequestMode`) but they share the same
|
|
113
|
+
three values; expose a single `str` surface to the AI and
|
|
114
|
+
validate against `("ROW", "COLUMN", "SEQUENTIAL")` with a
|
|
115
|
+
usable error message before constructing the typed body.
|
|
116
|
+
Mirrors the server's `VariablesSet.SamplingMode` enum exactly
|
|
117
|
+
— the lockstep file `wire-contracts/sampling-modes.txt` at
|
|
118
|
+
the repo root keeps the three locations (server enum,
|
|
119
|
+
dispatch-agent enum, MCP validator) in sync.
|
|
120
|
+
- **`tm_create_variables_set` is NOT idempotent.** Unlike the
|
|
121
|
+
capture-import path (which auto-suffixes with `(2)`, `(3)`),
|
|
122
|
+
the server enforces strict per-user name uniqueness — a second
|
|
123
|
+
create with an existing name 400s with "A variables set named
|
|
124
|
+
'X' already exists" (see `VariablesSetService.create` L102-104).
|
|
125
|
+
The tool's `idempotentHint=False` reflects this. AI hosts
|
|
126
|
+
should NOT blind-retry on transient failure (the first call
|
|
127
|
+
may have landed; the retry will 400). Recovery: list first,
|
|
128
|
+
then rename / delete / pick a new name as appropriate.
|
|
129
|
+
|
|
130
|
+
- **`trafficmorph` SDK constraint set to `>= 0.2.1, < 0.3.0`**
|
|
131
|
+
in `sdk-mcp/pyproject.toml`.
|
|
132
|
+
|
|
133
|
+
*Lower bound `>= 0.2.1`*: tm-mcp 1.1.0 imports
|
|
134
|
+
`trafficmorph.api.variables_sets.list_variables_sets` and
|
|
135
|
+
`trafficmorph.api.domains.list_domains` — the stable filenames
|
|
136
|
+
produced once the server's explicit operationIds are in place.
|
|
137
|
+
Those names debuted in `trafficmorph 0.2.1`; the transitional
|
|
138
|
+
`0.2.0` had `list_` / `list_1` from the auto-disambiguation
|
|
139
|
+
era. `pip install tm-mcp==1.1.0` against `trafficmorph 0.2.0`
|
|
140
|
+
would crash with ModuleNotFoundError at import.
|
|
141
|
+
|
|
142
|
+
*Upper bound `< 0.3.0`*: no breaking SDK changes are planned,
|
|
143
|
+
but the cap fences off any future major SDK release that
|
|
144
|
+
could rename/reshuffle filenames again. The matching tm-mcp
|
|
145
|
+
release will widen this cap.
|
|
146
|
+
|
|
147
|
+
The SDK was bumped in `sdk-python/pyproject.toml`
|
|
148
|
+
(`0.1.0 → 0.2.0 → 0.2.1`) as part of this release — `0.2.0`
|
|
149
|
+
was the intermediate state added alongside the new
|
|
150
|
+
variables-sets API surface, `0.2.1` is the operationId-stable
|
|
151
|
+
release that tm-mcp 1.1.0 actually depends on. The `0.2.0`
|
|
152
|
+
build is internal-only; only `0.2.1` should be published.
|
|
153
|
+
|
|
154
|
+
### Server-side: explicit operationIds on both list endpoints
|
|
155
|
+
|
|
156
|
+
`ApiDomainController.list` and `ApiVariablesSetController.list`
|
|
157
|
+
now carry explicit `@Operation(operationId = ...)` annotations
|
|
158
|
+
(`"listDomains"` and `"listVariablesSets"` respectively). Without
|
|
159
|
+
explicit IDs, Spring auto-derives bare `list` from the method
|
|
160
|
+
name, both controllers register the same ID, and the OpenAPI
|
|
161
|
+
codegen disambiguates with `list_1` / `list_2` suffixes whose
|
|
162
|
+
assignment depends on iteration order. That made downstream
|
|
163
|
+
client filenames non-deterministic across regens.
|
|
164
|
+
|
|
165
|
+
**Resolved end-to-end in this release.** The regen pass landed
|
|
166
|
+
together with the operationId Java change, so the SDK ships
|
|
167
|
+
with stable filenames from day one:
|
|
168
|
+
|
|
169
|
+
* `trafficmorph.api.domains.list_domains` (was `list_1` in
|
|
170
|
+
the transitional 0.2.0 build)
|
|
171
|
+
* `trafficmorph.api.variables_sets.list_variables_sets` (was
|
|
172
|
+
`list_` in 0.2.0)
|
|
173
|
+
|
|
174
|
+
`tm-mcp 1.1.0`'s imports use the stable names directly. The
|
|
175
|
+
`trafficmorph` SDK was bumped to `0.2.1` to signal the internal
|
|
176
|
+
rename (HTTP wire surface unchanged; pre-existing `0.2.0`
|
|
177
|
+
direct importers of `list_1` / `list_` will see ImportError on
|
|
178
|
+
upgrade — flagged as a known break and documented in the SDK's
|
|
179
|
+
0.2.1 changelog when it ships). tm-mcp's dependency cap is
|
|
180
|
+
tightened to `>= 0.2.1, < 0.3.0` so `pip` keeps the pair
|
|
181
|
+
correctly aligned.
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
## 1.0.0 — 2026-05-17
|
|
186
|
+
|
|
187
|
+
First stable release. The catalog is feature-complete for the v1
|
|
188
|
+
surface: **19 tools + 4 prompts + 5 resources** = 28 entries
|
|
189
|
+
covering reads, writes, run control, profile + domain lifecycle,
|
|
190
|
+
slash-command workflow templates, and URI-addressed reference
|
|
191
|
+
data.
|
|
192
|
+
|
|
193
|
+
See [STABILITY.md](STABILITY.md) for what v1 commits to keeping
|
|
194
|
+
stable across future releases.
|
|
195
|
+
|
|
196
|
+
This release rolls up phases 0.1.0 → 0.6.0 (see history below)
|
|
197
|
+
with no API surface changes from 0.6.0 — the version bump is
|
|
198
|
+
**signal, not contract change**. If you were on 0.6.0, you can
|
|
199
|
+
upgrade to 1.0.0 with no code or config changes.
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## 0.6.0 — 2026-05-17
|
|
204
|
+
|
|
205
|
+
**Phase 0.6.0: URI-addressed resources.**
|
|
206
|
+
|
|
207
|
+
Resources are the third MCP feature class (after tools and
|
|
208
|
+
prompts) — read-only data the AI host pulls into context by URI
|
|
209
|
+
(@-mentions in Claude Code). Each TrafficMorph resource wraps a
|
|
210
|
+
corresponding read tool 1:1 and returns `application/json`
|
|
211
|
+
payloads.
|
|
212
|
+
|
|
213
|
+
### Added (5 resources)
|
|
214
|
+
|
|
215
|
+
- `tm://profiles` (static) — list of all profiles, wraps `tm_list_profiles`.
|
|
216
|
+
- `tm://profiles/{profile_id}` (templated) — single profile detail, wraps `tm_get_profile`.
|
|
217
|
+
- `tm://history/recent` (static) — last 20 runs across all profiles, wraps `tm_list_history` with `size=20, page=0`.
|
|
218
|
+
- `tm://history/{run_id}` (templated) — single run's full metrics, wraps `tm_get_run`.
|
|
219
|
+
- `tm://domains` (static) — registered domains + verification status, wraps `tm_list_domains`.
|
|
220
|
+
|
|
221
|
+
### Design notes
|
|
222
|
+
|
|
223
|
+
- All resources are read-only and side-effect-free.
|
|
224
|
+
- Templated resources coerce path segments (`{profile_id}`,
|
|
225
|
+
`{run_id}`) to `int` and reject non-numeric / zero / negative
|
|
226
|
+
ids client-side with typed `ToolError` — no wasted roundtrips.
|
|
227
|
+
- Static URI `tm://history/recent` reserves the `recent` segment
|
|
228
|
+
against the `tm://history/{run_id}` template; FastMCP's router
|
|
229
|
+
prefers exact-match static URIs. Verified via end-to-end test
|
|
230
|
+
through `mcp.read_resource()`.
|
|
231
|
+
|
|
232
|
+
---
|
|
233
|
+
|
|
234
|
+
## 0.5.0 — 2026-05-17
|
|
235
|
+
|
|
236
|
+
**Phase 0.5.0: Slash-command prompts.**
|
|
237
|
+
|
|
238
|
+
Prompts are user-invoked workflow templates surfaced in Claude
|
|
239
|
+
Code's `/commands` menu. Each prompt returns a templated user
|
|
240
|
+
message instructing the AI to execute a specific tool sequence.
|
|
241
|
+
|
|
242
|
+
### Added (4 prompts)
|
|
243
|
+
|
|
244
|
+
- `/tm_triage <profile_id>` — find most recent FAIL → diff vs
|
|
245
|
+
latest PASS → narrate the regression. Chains 4 tools.
|
|
246
|
+
- `/tm_setup_loadtest <target_url> <rps> <duration_seconds>` —
|
|
247
|
+
domain verification (if needed) + profile creation + optional
|
|
248
|
+
immediate run. Handles the unverified-domain workflow
|
|
249
|
+
gracefully (without this, the AI tends to skip domain checks).
|
|
250
|
+
- `/tm_compare_baseline <profile_id>` — quick regression check:
|
|
251
|
+
most recent run vs most recent PASS.
|
|
252
|
+
- `/tm_import_capture_guided <capture_path>` — split analyse
|
|
253
|
+
(preview) from import (commit) so the user can review groups
|
|
254
|
+
before persisting.
|
|
255
|
+
|
|
256
|
+
### Design notes
|
|
257
|
+
|
|
258
|
+
- Prompts use **Java-parity normalization** for any host-extraction
|
|
259
|
+
guidance (`urllib.parse.urlparse(target_url).hostname` instead
|
|
260
|
+
of substring-between-slashes — robust against ports, query
|
|
261
|
+
strings, mixed case).
|
|
262
|
+
- Prompt text uses the actual Python tool kwargs (`auto_verdict=`
|
|
263
|
+
not `autoVerdict=`) so AI hosts following the template literally
|
|
264
|
+
don't TypeError on the kwarg name mismatch with the response
|
|
265
|
+
field.
|
|
266
|
+
- Prompts describe what `tm_compare_runs` actually returns
|
|
267
|
+
(`verdict_change` + specific `deltas` keys); no fictional
|
|
268
|
+
statistics (Welch's t-test, response-code distribution diffs
|
|
269
|
+
are server-side `RunComparisonService` features and NOT in the
|
|
270
|
+
MCP synthetic compare).
|
|
271
|
+
- Numeric timeouts in prompt text are pre-computed
|
|
272
|
+
(`verdict_timeout_seconds={duration_seconds + 60}`), never
|
|
273
|
+
emitted as arithmetic expressions the AI has to evaluate.
|
|
274
|
+
|
|
275
|
+
---
|
|
276
|
+
|
|
277
|
+
## 0.4.0 — 2026-05-16
|
|
278
|
+
|
|
279
|
+
**Phase 0.4.0: Domain management write tools.**
|
|
280
|
+
|
|
281
|
+
Closes the workflow gap from earlier phases: previously the AI
|
|
282
|
+
could create profiles and start runs, but couldn't onboard a
|
|
283
|
+
fresh target domain (which is a prerequisite). After 0.4.0 the
|
|
284
|
+
AI can drive the full new-target workflow end to end.
|
|
285
|
+
|
|
286
|
+
### Added (4 tools)
|
|
287
|
+
|
|
288
|
+
- `tm_add_domain(domain)` — register a domain; returns the single
|
|
289
|
+
`verificationToken` plus pre-formatted `dnsInstruction` /
|
|
290
|
+
`httpInstruction` strings designed for verbatim user display.
|
|
291
|
+
Idempotent (repeat calls return the same record).
|
|
292
|
+
- `tm_verify_domain_dns(domain_id)` — runs the TXT-lookup check.
|
|
293
|
+
Fail-fast: a miss returns HTTP 400 with the expected TXT
|
|
294
|
+
record + token in the message, NOT a polling-style 200.
|
|
295
|
+
- `tm_verify_domain_http(domain_id)` — same shape, fetches
|
|
296
|
+
`/.well-known/trafficmorph-verify.txt`. Uses the SAME token as
|
|
297
|
+
the DNS path (one `verificationToken` per domain, not separate
|
|
298
|
+
per-method tokens).
|
|
299
|
+
- `tm_delete_domain(domain_id)` — removes a registered domain.
|
|
300
|
+
|
|
301
|
+
### Design notes
|
|
302
|
+
|
|
303
|
+
- Per-endpoint tool surface (separate `_dns` and `_http`) rather
|
|
304
|
+
than a unified `tm_verify_domain(method=...)` — matches the
|
|
305
|
+
established pattern from run control.
|
|
306
|
+
- Verify-miss error messages preserve the server's remediation
|
|
307
|
+
text verbatim through the typed-error mapper so the AI can read
|
|
308
|
+
them back to the user without parsing.
|
|
309
|
+
- `verificationMethod` field uses uppercase tokens (`"DNS"` /
|
|
310
|
+
`"HTTP"` / `"ADMIN"`) — matches the server's
|
|
311
|
+
`DomainVerificationService.markVerified` and the JDBC `LOWER()`
|
|
312
|
+
semantics nothing forces case-folding here.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
## 0.3.0 — 2026-05-16
|
|
317
|
+
|
|
318
|
+
**Phase 0.3.0: Profile lifecycle + capture import.**
|
|
319
|
+
|
|
320
|
+
Adds the write tools for managing profiles + the import-side of
|
|
321
|
+
the capture workflow (analyse from 0.1.0 + import in 0.3.0).
|
|
322
|
+
|
|
323
|
+
### Added (4 tools)
|
|
324
|
+
|
|
325
|
+
- `tm_create_profile(name, target_url, duration_seconds, points, ...)`
|
|
326
|
+
— fails fast on name collision (server's POST is upsert-by-name
|
|
327
|
+
which would silently nullify scripts / callbacks / alerts the
|
|
328
|
+
MCP surface doesn't expose; this guard prevents that).
|
|
329
|
+
- `tm_update_profile(profile_id, ...)` — read-modify-write
|
|
330
|
+
internally so the AI passes only fields to change. Preserves
|
|
331
|
+
all advanced fields (scripts, callback URL, all four auto-alert
|
|
332
|
+
fields) verbatim from the GET response on partial updates.
|
|
333
|
+
Cross-profile rename collision check prevents producing
|
|
334
|
+
duplicate-named pairs.
|
|
335
|
+
- `tm_delete_profile(profile_id)` — removes a profile.
|
|
336
|
+
- `tm_import_capture(capture_path, selections)` — persists
|
|
337
|
+
selected groups from a JSONL capture as profiles. Capture-path
|
|
338
|
+
validation enforces `$TM_MCP_CAPTURE_ROOT` allowlist.
|
|
339
|
+
|
|
340
|
+
### Server-side change
|
|
341
|
+
|
|
342
|
+
- `ApiProfileController.updateProfile` now passes the path id on
|
|
343
|
+
the save request so `TrafficProfileService.save` takes its
|
|
344
|
+
id-based update branch (rather than the name-based upsert
|
|
345
|
+
branch that silently mutated the wrong row when body's name
|
|
346
|
+
matched a different profile). Test:
|
|
347
|
+
`ApiProfileControllerUpdateRoutingTest`.
|
|
348
|
+
|
|
349
|
+
### Design notes
|
|
350
|
+
|
|
351
|
+
- Name normalization on collision checks uses
|
|
352
|
+
`_java_string_trim(...).lower()` to match Java's
|
|
353
|
+
`String.trim()` + JDBC `LOWER()` exactly. Both deliberately
|
|
354
|
+
NOT Python's `str.strip()` + `str.casefold()` (both more
|
|
355
|
+
aggressive — `str.strip()` removes NBSP, `str.casefold()`
|
|
356
|
+
expands ß → ss; either would cause false-positive over-
|
|
357
|
+
rejection).
|
|
358
|
+
- `tm_update_profile` skips the cross-profile collision pre-flight
|
|
359
|
+
when `name` is omitted or unchanged — saves an HTTP roundtrip
|
|
360
|
+
on the common case.
|
|
361
|
+
- Points validation (`@Size(min=2, max=5000)`) mirrors the server
|
|
362
|
+
constraint, with the bound named explicitly in error messages.
|
|
363
|
+
|
|
364
|
+
---
|
|
365
|
+
|
|
366
|
+
## 0.2.0 — 2026-05-16
|
|
367
|
+
|
|
368
|
+
**Phase 0.2.0: Run control.**
|
|
369
|
+
|
|
370
|
+
### Added (4 tools)
|
|
371
|
+
|
|
372
|
+
- `tm_start_run(profile_id, wait=False, fail_on_verdict=..., wait_timeout_seconds=..., verdict_timeout_seconds=...)`
|
|
373
|
+
— with `wait=True`, mirrors the CLI's `tm runs start --wait
|
|
374
|
+
--fail-on-verdict FAIL,WARN` CI-triage shape. Multi-phase
|
|
375
|
+
correlation flow: pre-start history snapshot → poll status
|
|
376
|
+
until terminal → fetch post-run history with exact `runId`
|
|
377
|
+
correlation (falls back to id-anchor + time-drift heuristic
|
|
378
|
+
for legacy rows).
|
|
379
|
+
- `tm_stop_run(profile_id)` — idempotent (no-op when no run is
|
|
380
|
+
active).
|
|
381
|
+
- `tm_pause_run(profile_id)` — idempotent.
|
|
382
|
+
- `tm_resume_run(profile_id)` — NOT idempotent; 400s if no run
|
|
383
|
+
is paused.
|
|
384
|
+
|
|
385
|
+
### Server-side change
|
|
386
|
+
|
|
387
|
+
- `RunHistory.runId` column added (Hibernate auto-migration +
|
|
388
|
+
`SchemaCompatibilityInitializer` ALTER for legacy DBs). Exposed
|
|
389
|
+
via `RunHistorySummary.runId` + populated in
|
|
390
|
+
`RunHistoryService.onRunCompleted`. Enables exact MCP correlation.
|
|
391
|
+
- `RunHistoryRepository.findFiltered` adds `r.id DESC` secondary
|
|
392
|
+
sort to make pagination deterministic under `createdAt` ties
|
|
393
|
+
(microsecond ties happen under concurrent inserts because
|
|
394
|
+
`@PrePersist` sets `createdAt = Instant.now()`). MCP's page-scan
|
|
395
|
+
short-circuit depends on this.
|
|
396
|
+
|
|
397
|
+
### Design notes
|
|
398
|
+
|
|
399
|
+
- All four run-control tools annotated `destructiveHint=True`.
|
|
400
|
+
Idempotent ones (`tm_stop_run`, `tm_pause_run`) also carry
|
|
401
|
+
`idempotentHint=True`.
|
|
402
|
+
- Wait-flow correlation handles multiple race windows: race
|
|
403
|
+
truly fired (mismatched runId), legacy rows (no runId),
|
|
404
|
+
pagination past page 0 (concurrent burst), verdict pending
|
|
405
|
+
(row landed but auto-compare async).
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## 0.1.0 — 2026-05-16
|
|
410
|
+
|
|
411
|
+
**Phase 0.1.0: Read-only MVP.**
|
|
412
|
+
|
|
413
|
+
### Added (7 tools)
|
|
414
|
+
|
|
415
|
+
- `tm_list_profiles` — all profiles owned by the authenticated user.
|
|
416
|
+
- `tm_get_profile(profile_id)` — full config + run status.
|
|
417
|
+
- `tm_list_history(profile_id?, auto_verdict?, region?, ...)` —
|
|
418
|
+
paginated past runs with filters.
|
|
419
|
+
- `tm_get_run(run_id)` — full metric set + verdict.
|
|
420
|
+
- `tm_list_domains` — registered domains + verification status.
|
|
421
|
+
- `tm_compare_runs(run_id, baseline_run_id)` — synthetic
|
|
422
|
+
side-by-side diff; client-side computed from two `tm_get_run`
|
|
423
|
+
calls. Distinct from the server's `RunComparisonService`
|
|
424
|
+
(which adds Welch's t-test + response-code analysis); the MCP
|
|
425
|
+
shape is intentionally leaner.
|
|
426
|
+
- `tm_analyse_capture(capture_path)` — per-endpoint analysis of
|
|
427
|
+
a JSONL capture; read-only (no state persisted; pair with the
|
|
428
|
+
Phase 0.3.0 `tm_import_capture` to commit).
|
|
429
|
+
|
|
430
|
+
### Design notes
|
|
431
|
+
|
|
432
|
+
- Capture-path validation enforces `$TM_MCP_CAPTURE_ROOT` (default
|
|
433
|
+
`~/.trafficmorph/captures/`), symlink-escape defense, `..`
|
|
434
|
+
segment rejection, `.jsonl` extension whitelist.
|
|
435
|
+
- Errors map to typed `ToolError` subclasses: `AuthenticationError`
|
|
436
|
+
(401), `PlanError` (403 with `PLAN_UPGRADE_REQUIRED`),
|
|
437
|
+
`QuotaError` (429), `RateLimitError`, `PayloadTooLargeError`
|
|
438
|
+
(413). Generic 4xx → bare `ToolError` with the server's
|
|
439
|
+
error message preserved verbatim.
|
|
440
|
+
|
|
441
|
+
---
|
|
442
|
+
|
|
443
|
+
## Phase trajectory at a glance
|
|
444
|
+
|
|
445
|
+
| Phase | Tools | Prompts | Resources | Cumulative |
|
|
446
|
+
|---|---|---|---|---|
|
|
447
|
+
| 0.1.0 | 7 | — | — | 7 |
|
|
448
|
+
| 0.2.0 | 4 | — | — | 11 |
|
|
449
|
+
| 0.3.0 | 4 | — | — | 15 |
|
|
450
|
+
| 0.4.0 | 4 | — | — | 19 |
|
|
451
|
+
| 0.5.0 | — | 4 | — | 23 |
|
|
452
|
+
| 0.6.0 | — | — | 5 | 28 |
|
|
453
|
+
| **1.0.0** | **19** | **4** | **5** | **28** |
|
|
454
|
+
| 1.1.0 | +6 (=25) | — | — | 34 |
|
tm_mcp-1.2.0/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for describing the origin of the Work and
|
|
141
|
+
reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may accept and charge a
|
|
167
|
+
fee for accepting support, warranty, indemnity, or other liability
|
|
168
|
+
obligations and/or rights consistent with this License. However, in
|
|
169
|
+
accepting such obligations, You may act only on Your own behalf
|
|
170
|
+
and on Your sole responsibility, not on behalf of any other
|
|
171
|
+
Contributor, and only if You agree to indemnify, defend, and hold
|
|
172
|
+
each Contributor harmless for any liability incurred by, or claims
|
|
173
|
+
asserted against, such Contributor by reason of your accepting any
|
|
174
|
+
such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
200
|
+
implied. See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|