Travis234 Websec MCP
An optional external HTTP workbench for Travis234 and standard stdio MCP clients. Python 3.13 and macOS or Linux are required. Travis core and its existing MCP adapter supply the host integration; this package owns requests, HTTP execution, sanitization and evidence. KHackBar is a workflow reference and is not a dependency.
This milestone supports individual request experiments. Payload catalogs, generators, batch fuzzing, login/token extraction and browser capture remain future work. The package also includes imported assessment skills, built into Travis and exposed to other clients through MCP resources and prompts. These guides do not install external scanners. See the repository's complete KHackBar feature mapping.
Build, install and activate
For the published package, stop existing Travis sessions, then install or upgrade:
travis234 install 'travis234-websec-mcp==0.1.2'
Start a new Travis process after upgrading. Existing running processes retain their installed descriptor, environment and snapshots until they exit.
Run these commands from the Travis234 repository root:
uv sync --project packages/travis234-websec-mcp --locked --group source-test
websec_dist_dir="$(mktemp -d "${TMPDIR:-/tmp}/websec-dist.XXXXXX")"
uv build --wheel --out-dir "$websec_dist_dir" packages/travis234-mcp-adapter
uv build --wheel --out-dir "$websec_dist_dir" packages/travis234-websec-mcp
export PIP_FIND_LINKS="$websec_dist_dir"
export UV_FIND_LINKS="$websec_dist_dir"
websec_wheel_uri="$(packages/travis234-websec-mcp/.venv/bin/python -c 'from pathlib import Path; import sys; print(next(Path(sys.argv[1]).glob("travis234_websec_mcp-*.whl")).resolve().as_uri())' "$websec_dist_dir")"
travis234 install "travis234-websec-mcp @ $websec_wheel_uri"
travis234 --tools read,bash,websec
Installation registers the package-owned server and one websec facade through
the shared adapter. Discovery and status do not send a testing request. Tool
selection uses the existing --tools allowlist; there is no new Travis flag.
For another MCP client, install the wheel and its dependencies into that client's Python 3.13 environment, then configure this stdio command:
travis234-websec-mcp mcp --transport stdio
The standalone server does not import the Travis extension. It uses the same configuration, request bounds and evidence format.
First setup and profile discovery
Call status first. It returns configuration_path, the exact configured
profile names, authentication readiness and the server-process lifetime of IDs.
Profile names are operator-defined; default becomes available only if you
create a profile with that name.
When configuration is missing, status.data.setup.command contains an executable
argument list for the installed server's Python interpreter. Replace its example
origin with your exact authorized origin and run it in the server's environment.
This also works when Travis has installed the package in a private environment
and its console command is not on your shell's PATH. With the console command
available, the equivalent is:
travis234-websec-mcp init --profile default --origin https://api.example
Repeat --origin to authorize additional exact origins. Init validates all inputs
before creating state, creates a mode-0600 config, and refuses to overwrite an
existing file or follow a symlinked Websec directory. It creates a profile like:
{
"version": 1,
"profiles": {
"default": {
"origins": ["https://api.example"],
"headers": {"User-Agent": "travis234-websec-mcp/0.1.2"},
"deadline_seconds": 10
}
}
}
This profile needs no environment variables. Restart Travis after setup, call
status, and use the returned name exactly in prepare. Status and discovery
remain read-only and never create a profile or authorize an origin automatically.
For an existing config, edit the file reported by configuration_path. An
invalid_config diagnostic identifies its profile, field, reason and corrective
hint without returning header values or malformed JSON content. JSON syntax
errors include line and column. A missing config means no profiles exist yet;
guessing a profile name cannot create one.
Headers and the launch environment
Profile header values accept printable ASCII literal strings, ${NAME}
interpolation, and exact $env:NAME references. For example, a literal
"User-Agent": "my-retest/1.0" is valid without exporting USER_AGENT.
Credentials should use references such as "Authorization": "Bearer ${WEBSEC_TOKEN}".
Available configured header values remain subject to existing redaction rules.
Referenced variables must be set in the environment that launches Travis.
Exporting them in a later tool shell, or editing ~/.zshenv, cannot change an
already-running parent's environment. Reconnecting MCP starts a child of that
same parent; restart the entire Travis process with the variables available.
The native Python CLI does not load .env for this package. The npm sandbox
launcher can receive an explicitly selected file through its existing
--dotenv /path/to/.env option; see the root README for that launch boundary.
Status reports missing or invalid reference names under each profile's
authentication object. Send returns the same names in error.details before
opening a connection; values are never included. Configuration and environment
are captured at server startup.
Prepare responses are sanitized previews. Password/token fields and known
credentials can appear as [REDACTED] while the private immutable request retains
the original bytes for sending. Keep credentials out of tool arguments: the host
records inputs before the plugin can sanitize them.
Imported assessment skills
The source index is htooayelwinict/awesome-ai-offensive-security. That repository contains links; the actual skills are imported from these linked MIT-licensed projects at fixed revisions:
| Source | Included skills |
|---|---|
| SnailSploit/Claude-Red | offensive-api-security, offensive-jwt, offensive-idor, offensive-ssrf, offensive-ssti, offensive-ai-security, offensive-reporting |
| transilienceai/communitytools | web-app-logic, client-side, authentication, injection, server-side, reconnaissance, including their reference and scenario files |
All thirteen skills ship as read-only built-ins in Travis's Python and npm
distributions, using its existing lazy loader, precedence and trust rules.
Installing this optional package adds the Websec tools. When the user asks to
use Websec MCP, its facade instructs the agent to try loading the original eight
SKILL.md guides before its first Websec call, like Evidence MCP's research
skill. This guidance also accompanies authorized delegation. User overrides
and --no-skills remain effective; unavailable guides are reported. These eight
guides cover API, JWT, IDOR, SSRF, SSTI, AI security, reporting and business logic.
The five added guides cover client-side behavior, authentication, injection,
server-side behavior and reconnaissance. The system prompt routes to them by
task and loads their references progressively. The package does not register duplicate
skill directories. A standalone installation exposes the same documents
through MCP resources and prompts. No skill is copied into the user's Codex installation.
Each imported skill has a TRAVIS234.md guide describing the supported tools
and request workflow. Local changes add compatible YAML metadata and a link to
that guide. The five new entrypoints retain their original guides as UPSTREAM.md.
Upstream methodology and references are retained; executable helpers are not
installed and their source paths are recorded in the manifest. Each skill keeps
its upstream license; SOURCES.json
records repository revisions, source paths, original hashes and shipped hashes.
Imports are bundled: startup, discovery and reads do not fetch updates or run
upstream code.
For a standard MCP client:
resources/listenumerates skill documents in pages of eight. Pass itsnextCursorback ascursoruntil it is absent.- Read
websec://skills/indexfor the skill index, then a skill'swebsec://skills/<name>/TRAVIS234.mdandwebsec://skills/<name>/SKILL.md. - A document larger than 4 KiB returns an ordered part index. Read the listed
?part=1,?part=2, … URIs in order. All bytes are retained, with UTF-8 characters kept intact. Relative references resolve within the skill's URI directory. Each part is at most 4 KiB before protocol encoding. When literal code examples cannot pass the existing text classifier unchanged, the read uses a standard MCP blob with the same MIME type: Base64-decode it as UTF-8 to recover the exact text. prompts/listexposes thirteen entry prompts, namedwebsec-<skill-name>.prompts/gettakes that name and no arguments; it directs the client to the integration guide and relevant upstream resources.
Resource reads accept only bundled catalog URIs. Unknown URIs, prompts and cursors return fixed errors. The original document is checked before any part is returned, and the existing final MCP frame checks still apply. When a known credential overlaps a document, its read fails without returning that document.
The existing seven request operations retain their contracts; inspect adds
offline HTML-resource observations. Browser sessions,
raw protocol experiments, parallel probes and external tools mentioned in a
guide require those capabilities separately. Imported methodology does not
enable them in the Websec executor.
Try the actual acceptance fixture
In one terminal, start the bundled fixture. It prints its actual loopback origin:
packages/travis234-websec-mcp/.venv/bin/python packages/travis234-websec-mcp/tests/http_fixture.py
Keep it running. In a second terminal, copy that origin into
WEBSEC_FIXTURE_ORIGIN, then create an isolated lab configuration:
export WEBSEC_FIXTURE_ORIGIN='http://127.0.0.1:<printed-port>'
export WEBSEC_LAB_TOKEN='synthetic-lab-token'
websec_lab_dir="$(mktemp -d "${TMPDIR:-/tmp}/websec-lab.XXXXXX")"
export TRAVIS234_CODING_AGENT_DIR="$websec_lab_dir/agent"
packages/travis234-websec-mcp/.venv/bin/python - <<'PY'
import json
import os
from pathlib import Path
from urllib.parse import urlsplit
origin = os.environ['WEBSEC_FIXTURE_ORIGIN']
assert urlsplit(origin).hostname == '127.0.0.1' and urlsplit(origin).port
path = Path(os.environ['TRAVIS234_CODING_AGENT_DIR']) / 'websec' / 'config.json'
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps({'version': 1, 'profiles': {'lab': {
'origins': [origin],
'headers': {'Authorization': 'Bearer ${WEBSEC_LAB_TOKEN}'},
'deadline_seconds': 10,
}}}))
PY
Run installation and activation in that same terminal so Travis inherits the
directory override and credential reference. Stop the fixture with Ctrl-C.
Normal operator configuration lives at ~/.travis234/agent/websec/config.json;
the existing TRAVIS234_CODING_AGENT_DIR override changes the agent directory.
The package never loads .env files. Headers accept literal strings, exact $env:NAME
references or ${NAME} interpolation. Missing or empty references leave offline operations
available and make send return authentication_unavailable before connecting.
Request workflow
Call websec with the following operation arguments. Replace the fixture origin
with its printed value and copy each returned ID exactly:
| Operation | Arguments and result |
|---|---|
status |
{} or {"operation":"status"} returns configuration, profiles and limits. |
prepare |
{"operation":"prepare","profile":"lab","request":{"url":"<fixture-origin>/query-echo?q=original&q=untouched"}} creates an immutable request ID. Optional request fields are method, header pairs and a UTF-8 body. |
mutate |
{"operation":"mutate","request_id":"<original-id>","location":"query","index":0,"value":"changed"} creates a new ID. Header mutation is also indexed; body mutation replaces the whole body. |
transform |
{"operation":"transform","value":"a b","codec":"url","direction":"encode"} returns a%20b. Codecs are url, base64, hex, double_url, html, unicode and reverse; both directions are supported. |
send |
{"operation":"send","request_id":"<request-id>"} executes that snapshot once. Send the original and changed IDs separately. |
inspect |
{"operation":"inspect","response_id":"<response-id>"} observes external script and stylesheet attributes in retained HTML without another HTTP exchange. |
compare |
{"operation":"compare","left_response_id":"<original-response-id>","right_response_id":"<changed-response-id>"} returns measured differences, completeness and an optional sanitized diff. |
export |
The same response pair with "operation":"export" writes a new evidence file and returns its basename, ID and byte count. |
The fixture receives original, then changed, with the second query entry
unchanged. Its UTF-8 response bodies have 8 and 7 bytes respectively. Reusing the
original ID sends the original value again. prepare also accepts strict raw
HTTP/1.1 text using raw_request and an explicit origin, instead of request.
Ambiguous framing, invalid fields and unavailable IDs return specific bounded
errors. Comparisons report observations rather than vulnerability verdicts.
Additional text codecs
| Codec | Defined behavior |
|---|---|
double_url |
Apply the existing UTF-8 URL conversion exactly twice. Decoding rejects malformed percent escapes or invalid UTF-8 at either step. A literal + stays +. |
html |
Encode the five HTML special characters; the apostrophe becomes '. Decode named/numeric entities once using HTML5 rules. Markup stays text: decoding <b>é</b> returns <b>é</b>. |
unicode |
Encode each UTF-16 unit as a lowercase \uXXXX escape, including valid pairs for supplementary characters. Decode those escapes once, combine valid surrogate pairs and reject malformed or unpaired units. Other backslash sequences and percent escapes stay literal. |
reverse |
Reverse Unicode code points. Both directions perform the same operation; A😀é becomes é😀A. Combining marks reverse individually. |
These operations retain the 16 KiB input and 64 KiB output limits. The aggregate
MCP frame limit also applies, so a valid engine result can return output_limit
at the public boundary. Errors never return a successful partial transformation.
Known credentials are checked in both the source value and the derived result.
Bounds, credentials and lifetime
Origins are exact normalized scheme/host/port allowlists. Every send checks its
final target. The client performs one exchange, follows no redirects, retries
nothing, carries no cookie jar, verifies TLS and ignores proxy environment
variables. Status advertises max_concurrent_sends: 1. Send sequentially and
wait for the active exchange; an overlapping send returns busy with a hint.
Cancellation and shutdown close and join owned HTTP work.
| Resource | Limit |
|---|---|
| URL / request body / raw import | 8 / 64 / 128 KiB |
| Wire headers, including authentication and framing | 100 entries / 32 KiB |
| Transform input / output | 16 / 64 KiB |
| Deadline | Default 10 seconds; profile integer 1–30. A caller may only lower it with timeout_seconds. |
| Retained response / text preview | 1 MiB / 8 KiB |
| Static HTML inspection | 10,000 start/end elements; up to 32 resources, 2 KiB per attribute and 8 KiB of resource entries |
| Requests / responses in memory | 32 / 16; unpinned oldest entries are evicted. |
| Complete outgoing MCP frame / exported JSON | 32 KiB / 4 MiB |
Compressed responses are reported as unsupported_encoding and are not decoded.
Binary and incomplete responses preserve honest byte measurements; comparison
does not infer complete text equality or an exact complete-body length from them.
Incomplete or oversized presentation values are withheld in full, with explicit
omission flags. Complete bounded JSON can retain unrelated public fields.
Body diagnostics and multiple HTML resources
Read body_text_omitted_reason alongside complete, observed_body_bytes,
retained_body_bytes and body_text_clipped:
| Reason | Meaning |
|---|---|
redacted |
The privacy filter withheld the text value. |
analysis_limit |
Bounded filtering could not approve the text; this does not establish a credential match. |
incomplete |
The response capture is partial, including a response-size cutoff or interrupted exchange. |
output_limit |
Safe text exceeds the preview allowance. |
binary |
No supported UTF-8 text view is available. |
null |
No whole-text omission; individual JSON fields can still be sanitized. |
[REDACTED] alone does not distinguish those cases. Byte measurements describe
the captured body, even when its public preview is withheld.
Use inspect on a retained HTML response for content or SRI review. Each
external script or stylesheet has an index, element type, line/column, URL,
integrity, crossorigin, type and duplicate-attribute flag. Assess each
resource separately; those indices are unrelated to query/header mutation
indices. Inline script contents and input values are excluded, and embedded
resource URLs such as data: are withheld. Attributes remain sanitized.
Check capture_complete, inspection_complete and limitations before making
absence claims. Static attributes do not validate SRI hashes, JavaScript
execution, browser policy or security impact. Use an available browser when
needed. Returned URLs do not expand authorized origins or authorize fetching
every resource. HTML exports include the same sanitized observations and body
diagnostics; exports do not reveal raw withheld bodies.
Keep credentials in the operator environment and profile references. Never paste them into tool arguments: the host records those inputs before the plugin sees them. Available referenced values and bounded URL/Base64/hex forms are sanitized from returned results and exports. Authentication values go only to an allowed origin's request.
Request and response IDs belong to one server process. Shutdown, reload or
eviction can invalidate them. Exports persist under
<agent-directory>/websec/evidence/ as new atomic mode-0600 JSON files; the tool
does not accept arbitrary export paths or overwrite prior evidence.
Restart the entire Travis process after changing profile configuration, credential references/environment or the installed package. Registrations are process-local; an existing host does not replace a different descriptor in place. Stop Travis before removing the package, then start a new process to confirm the facade is absent. Removing the package preserves exported evidence.
Qualification
PYTHONDONTWRITEBYTECODE=1 packages/travis234-websec-mcp/.venv/bin/python -m pytest -q -p no:cacheprovider packages/travis234-websec-mcp/tests
The acceptance test builds actual wheels, installs through Travis's package manager in a fresh interpreter outside the checkout, binds a real session, uses a deterministic model stream and real HTTP/MCP transports, scans persisted session JSONL, and checks A1–A13. Container qualification uses the same driver with offline wheels, a nonroot user and Docker networking disabled. A build or unit-test pass alone does not establish installed acceptance or deployment.
Metadata
Release files for travis234-websec-mcp 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| travis234_websec_mcp-0.1.2.tar.gz | 718.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| travis234_websec_mcp-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.6 MB
Release files / travis234_websec_mcp-0.1.2.tar.gz
| Download URL | travis234_websec_mcp-0.1.2.tar.gz |
|---|---|
| Size | 718.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6f1c20ec4e23c097a5cbc50ef376ed17eb431be4a89c1f237df3c7a86f17c670
|
|
BLAKE2b-256 checksum How to use checksums |
acb12c5d35163719edf81d2431d9dd72967f3280dd3b42ab81c61db27141e7c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|
Release files / travis234_websec_mcp-0.1.2-py3-none-any.whl
| Download URL | travis234_websec_mcp-0.1.2-py3-none-any.whl |
|---|---|
| Size | 884.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
40351204774b19807f8bd5e281877b28291c2e0bc72e1369cc0708bb70f3628d
|
|
BLAKE2b-256 checksum How to use checksums |
b11c4c09eb5831944755c57882569c5d271cd077a6f25b382c12885b66a0266f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.13
|