Files
bzuccaro e871e49466 feat: local MCP harness (tools/resources/prompts) + Harness UI page
Streamable-HTTP MCP server on POST /mcp: device.state, attack.deploy/stop/
status/deauth/capture/export_hc22000, loot.handshakes/enterprise_creds,
recon.aps/isearch/devices, pineap.kick_client/set_filter tools; recon DB +
bundled opencode skills resources; attack playbook prompts. Cookie or Bearer
auth. Harness page shows endpoint, token, curl snippet, capability explorer
and a copy-paste pi.dev prompt. scripts/harness_stdio.py for stdio-only
agents.
2026-08-18 20:00:13 -05:00

66 lines
2.2 KiB
Python

#!/usr/bin/env python3
"""stdio bridge to the Mark VIII MCP server.
Agents that only support stdio transport can run:
MCP_URL=http://172.16.52.1:8080/mcp \
MCP_TOKEN=<device session token> \
python3 scripts/harness_stdio.py
JSON-RPC messages are read line-by-line from stdin (one JSON object per
line, no embedded newlines) and forwarded to the Mark VIII Streamable-HTTP
MCP endpoint. Responses are printed back on stdout as single-line JSON.
Get a token from the Mark VIII Harness page, or fetch one:
curl -s -X POST http://172.16.52.1:8080/api/login \
-H 'Content-Type: application/json' \
-d '{"username":"root","password":"<device password>"}' \
-c cookies.txt
"""
import json
import os
import sys
import urllib.request
URL = os.environ.get('MCP_URL', 'http://172.16.52.1:8080/mcp')
TOKEN = os.environ.get('MCP_TOKEN', '')
def forward(msg):
data = json.dumps(msg).encode()
req = urllib.request.Request(URL, data=data, method='POST')
req.add_header('Content-Type', 'application/json')
req.add_header('Accept', 'application/json, text/event-stream')
if TOKEN:
req.add_header('Authorization', 'Bearer ' + TOKEN)
try:
with urllib.request.urlopen(req, timeout=120) as resp:
return resp.read().decode()
except urllib.error.HTTPError as exc:
return json.dumps({'jsonrpc': '2.0', 'id': msg.get('id'),
'error': {'code': exc.code, 'message': exc.read().decode()[:300]}})
except Exception as exc: # noqa: BLE001
return json.dumps({'jsonrpc': '2.0', 'id': msg.get('id'),
'error': {'code': -32000, 'message': str(exc)}})
def main():
if not TOKEN:
print('warning: MCP_TOKEN not set; server will reject calls', file=sys.stderr)
for line in sys.stdin:
line = line.strip()
if not line:
continue
try:
msg = json.loads(line)
except ValueError:
print(json.dumps({'jsonrpc': '2.0', 'id': None,
'error': {'code': -32700, 'message': 'parse error'}}))
continue
print(forward(msg), flush=True)
if __name__ == '__main__':
main()