WIP: feat(mcp): drive owned test sessions over stdio #56

Draft
mooki wants to merge 16 commits from mooki/Longshot:feat/mcp-server into main
First-time contributor

Why

Draft, stacked on pull request 47 of this forge: review only the commits after 23cc17be6a. It becomes reviewable on its own once 47 is merged. This opens against main because the forge cannot select a fork branch as its base.

This optional stdio adapter lets tools drive owned command-line test sessions without adding another game protocol. It continues Nicholas Gower's https://github.com/NotRexed/Hookshot/issues/1025; no handover agreement is recorded in the retained discussion, and the offer to stop and help his original work after acknowledging his later push stands.

The one dependency question: may this adapter and its SDK-specific tests use the narrowly scoped FastMCP 4.1.3 exception proposed here? Longshot's current CONTRIBUTING guide requires standard-library tests and isolated Python; its existing exceptions cover the build pipeline and the separately scoped button-prompt tools, not MCP. The proposal is not accepted policy. If declined, the MCP adapter should remain outside this repository while the standard-library session client stays here.

What changed

  • 20 typed tools and 3 resource templates wrap the existing session API. Requests are serialized per run; cancellation, coded errors and bounded output are explicit.
  • Images are files first; inline image data is opt-in. Model-selected screenshot/run paths stay under configured roots, and a configured game folder cannot be changed by a tool.
  • The SDK is pinned separately from game requirements. The control client, shared fake bridge and general documentation checks remain SDK-free. No package installs itself; the pin does not lock all transitive dependencies.
  • Nicholas's three original guide/test files from https://github.com/NotRexed/Hookshot/issues/1025 at bce003c7 are retained in the first child commit under his name, changed only by the project's rename. Their rename-equivalent hashes were checked; the original import message and DeepSeek assistance trailers are preserved. Our adaptations follow separately, and his co-author trailer below survives squash merging.
  • The dependency guide explicitly says Forgejo has no CI runner. The retained GitHub workflow's optional install step is not a Forgejo check.
  • The link check added here found a wrong link in pull request 47, fixed there. This child carries no second change to that control-guide line.
  • No native game change, new cheat protocol, build tool or contributor-process mandate. Missing cheats beyond teleport/age, WebGPU captures, run-long physical-input exclusion and save-safe quit remain explicit limits.

This generic adapter has no dependency on the separate workbench project, and nothing here implies maintainer endorsement of that project.

  • Documentation integration: the new main's fictional PR-description sample named a deliberately nonexistent test. The general docs check now excludes only its dedicated tests/pr_description/ data directory; the new tests/test_docs_scope.py proves ordinary and similarly named test guides remain checked, as do missing real links and commands. The stack guide now names the refreshed session prerequisite. These are separate commits, not edits to Nicholas's import.

Flags and settings

Flag What it does Default now Recommendation Helps on Doesn't help on Untested on
HOS_CONTROL Lifecycle changed; native switch existing: Record the chosen endpoint; by default allocate a short private socket Unset outside launch; launch allocates its own endpoint Off by default: local test/control use Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
HOS_HEADLESS Test-profile setting: Suppress the game window 1 in test profile; ordinary profile unchanged Off by default: test profile only Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
HOS_AUDIO Test-profile setting: Mute the test game 0 in test profile; ordinary profile unchanged Off by default: test profile only Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
HOS_ENV_FILE Test-profile setting: Use an owned empty environment file instead of ambient file Owned empty file in test profile; ordinary behavior unchanged Off by default: isolation for tests Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
--run New global selector: Reattach using a retained run manifest No selected run Off by default: explicit owned run Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --run Changed launch output: Choose a new or empty durable run folder Unique folder below root Off by default: unique default avoids overwrite Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --root New: Parent of unique run folders work/control-runs below caller working folder On by default: durable default root Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --profile New: Choose ordinary or isolated test setup default Off by default: test is opt-in Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --ready New: Wait for bridge, present or play readiness bridge Off by default: caller chooses stronger readiness Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --timeout Changed readiness semantics: Bound readiness after admission; observed exits win over timeout 600 seconds On by default: bounded readiness, not a game wall limit Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --exe New: Choose explicit executable instead of Builder/bin discovery Discover native game in bin before root Off by default: development override Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --image New: Pass an explicit positional image path Game folder image Off by default: development override Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --romfs New: Pass explicit game content folder Game folder romfs Off by default: development override Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --user New: Pass explicit user folder; rejected in test profile Existing ordinary location; test profile owns its user folder Off by default: explicit development path Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --cwd New: Choose working/cache folder; requires explicit image Game folder Off by default: explicit isolation choice Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --wrapper New: JSON argv around lifetime supervisor for admission and wall policy None Off by default: machine-specific trusted configuration Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --save Changed test-profile support: Copy source saves to the owned test user folder Fresh test user if omitted Off by default: never select a player save implicitly Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --slot Changed test-profile support: Select the copied save slot All source slots Off by default: caller chooses slot Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --data Changed test-profile restriction: Ordinary data root; test profile refuses redirection Ordinary behavior retained Off by default: test profile owns its location Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --env Changed test-profile precedence: Explicit overrides; profile headless/audio/env-file choices win No extra overrides Off by default: trusted caller values Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
--exclusive Changed input default: Exclude physical input for each test-session request True for test-session inputs; normal behavior otherwise On by default: within each test request only Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
--no-exclusive New negative flag: Allow physical input alongside the request Not selected Off by default: deliberate opt-out Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
sequence --hos Changed conversion: Convert seconds/milliseconds to tested integer game frames Frame units unless selected Off by default: input-format choice Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
stop --timeout New: Wait for original owner to quit/reap game and wrapper 10 seconds On by default: bounded truthful stop Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
stop --terminate New: Authorize owner termination/kill after graceful timeout False Off by default: explicit force only Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
log --lines New: Tail retained run log 100 lines On by default: bounded tail Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
log --since New: Read after a byte cursor No cursor Off by default: explicit incremental reader Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
log --bytes New: Bound read/output bytes 65536; at most 1048576 On by default: bounded output Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
log --expect Wait for new matching text after since cursor No expectation Off by default: explicit witness Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
log --regex New: Treat expectation as regular expression False Off by default: explicit interpretation Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
log --timeout New: Bound the log expectation wait 10 seconds On by default: bounded wait Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
--json Changed session replies: Return manifest/log/status structured values for session commands Plain output without flag Off by default: machine-readable opt-in Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
launch --headless New profile interaction: Existing flag remains valid; test profile is always headless False in ordinary profile; test profile forces headless Off by default: ordinary play choice Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
--sock New session interaction: Existing explicit socket selector; --run selects a retained owned session instead HOS_CONTROL or launch-allocated endpoint Off by default: explicit trusted endpoint Linux fake process tests and Longshot title lifecycle Renderer/gameplay performance Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows)
server --root New in this child: Constrain owned run folders Repository work/control-runs Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --game-dir New in this child: Fix the trusted executable folder; models cannot replace it Unset: tool caller selects it Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --exe New in this child: Explicit executable override None: discover game Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --image New in this child: Explicit positional image None: game layout Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --romfs New in this child: Explicit game content folder None: game layout Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --cwd New in this child: Explicit working/cache folder None: game folder Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --wrapper New in this child: Trusted admission argv; no shell expansion Empty argv Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)
server --env New in this child: Repeatable trusted NAME=VALUE environment entry Empty list Off by default: operator configuration Linux real-SDK offline tests No native-game cost change Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows)

Measurements

Branch state: on main d725b3631982ed0035ea3ac9cbe1677e9fad260c; head 0ce651b604ef72a514e6f5d42c11c971594f6d97; whole game-free suite on this head: 513 passed, 2 failed, 20 skipped (main d725b3631982ed0035ea3ac9cbe1677e9fad260c: 510 passed, 1 failed, 20 skipped); the commits are unchanged by rebases apart from the results table.

main: d4a69456c9 (2026-11-12)
this PR: feat/mcp-server @ 5502fe20a5

Measurement provenance: main @ d4a69456c9; session prerequisite in forge pull request 47 @ 9f5f6dd292. 5502fe20a5.
Hardware: Core i9-13900K, 96 GB RAM, Arch Linux 7.2.15. No GPU used for the new server checks.
Scene: real SDK catalogue and stdio/in-memory protocol tests against an authored fake game; no new Longshot MCP gameplay run.
Method: whole-suite warm-up, then the same catalogue probe before/after/before/after, fresh HOME each time. Counts and test output, not timing claims. The adapter is a separate process; native game code and ordinary launches are unchanged when it is not used.

How to reproduce: In the optional FastMCP 4.1.3 environment, run python -I -B tests/test_mcp_server.py and the documented catalogue list calls; compare the pinned main source where the adapter is absent, twice in interleaved order. Run tests/run_all.py test_mcp_ test_docs test_longshot_ctl without the SDK to check its isolated absence. Do not treat these fake-game checks as a new Longshot run.

The rebase onto main d725b3631 adds only scripts, docs and tests, with no game-code change; the measured d4a69456 comparisons and pinned game evidence remain valid and were not repeated. Original results below retain their measured commits; the new exact-head suite is recorded separately.

Baseline: main @ d4a69456

main @ d4a69456 this PR @ 5502fe20
Pair 1: complete SDK catalogue Absent (0) 20 tools / 3 resource templates (1)
Pair 2: complete SDK catalogue Absent (0) 20 tools / 3 resource templates (1)
Median complete catalogues 0 1
Whole suite Main: 507 passed / 2 failed / 20 skipped 511 passed / 1 failed / 20 skipped
Before 1: AssertionError: MCP adapter absent on this source
After 1: PASS: real SDK catalogue: 20 tools, 3 resource templates
Before 2: AssertionError: MCP adapter absent on this source
After 2: PASS: real SDK catalogue: 20 tools, 3 resource templates
Real SDK protocol fixture:
Ran 9 tests in 4.679s
OK
Final whole suite:
511 passed, 1 failed, 20 skipped in 154 s (linux, 6 at once)
Selected checks without the SDK:
pass tests/test_docs.py
pass tests/test_mcp_optional.py
pass tests/test_longshot_ctl.py
skip tests/test_mcp_server.py (not found here: fastmcp)
3 passed, 0 failed, 1 skipped in 7 s (linux, 6 at once)

The before probe explicitly tests feature absence, not a failure of main's existing client. The SDK fixture exercises real initialization, tool/resource calls, stdio, error/EOF handling, cancellation, path boundaries, output limits and fake-session lifecycle. The no-SDK check verifies the one-line install refusal, no protocol output and SDK-free ordinary imports.

The complete suite used tests/run_all.py --jobs 6 --strict, default compiler, the existing pinned Python with an owned copy of the optional SDK environment. No package was installed. The main suite is the shared baseline run once for this day's moved pull requests at d4a69456. The only final branch failure is main's local tests/test_updater_asset_digest.py: SDK 10.0.113 cannot resolve Microsoft.AspNetCore.App.Ref (= 10.0.13), NU1100. Main additionally failed tests/test_appimage_package_retry.py under heavy load; the requested isolated rerun passed all 9 tests. It fails only under heavy load on this PC; timing-dependent. This branch passed it. The complete suites are not called green.

Retained earlier result: 510 passed / 2 failed / 20 skipped. Its additional test_docs.py failure identified the lowercase README link in the parent. Pull request 47 fixed it; the full suite above was run again after restacking on that parent.

Historical game evidence, Hookshot, 2026-11-12, not a fresh Longshot run: adapter cf2dcf89, game ba005ca4; RTX 4090 / NVIDIA 615.78.08, 1280×720, windowless Kokiri Forest. One 36.3 s ordinary shared run returned 29 matched replies including 26 tool calls, completed sequence frames 1455–1511, produced file/inline images at presents 1572/1575, restored an option and stopped with exit 0. Input save copy unchanged; fatal/device/kernel fault counts 0. No frame-rate or save-draining claim.

Separate historical stack-parent check

Baseline: session-parent @ 596c0a33
This secondary comparison records the prerequisite separately because it is not main. Parent source was carried unchanged apart from its separately checked README link.

session-parent @ 596c0a33 this PR @ 5502fe20
Whole suite 508 passed / 1 failed / 20 skipped 511 passed / 1 failed / 20 skipped

Current validation and retained failures

The exact-head whole-suite result is in branch-state. The local NU1100 reference-pack failure also occurs on main. The other failure was nx2/test_texture_phi_dominance.py: clang++ compiling emit_spirv.cpp was killed with SIGKILL 9, not a failed shader assertion. This is the compiler-killed category reported in other suites today; the signal alone does not establish OOM or another cause.

That compiler fixture passed when run alone. The four SDK-free documentation/scope/optional-package/control-client checks also passed. These successes do not erase the failed full-suite attempt or make it green. The earlier documentation-fixture failure is also preserved in the evidence; the new scope regression and corrected documentation check now pass.

Actual SDK-free test output:

5 checks, 0 skipped, 1 at once (linux)
pass       7.4s  nx2/test_texture_phi_dominance.py
pass       0.1s  tests/test_docs.py
pass       0.1s  tests/test_docs_scope.py
pass       9.1s  tests/test_longshot_ctl.py
pass       0.1s  tests/test_mcp_optional.py
5 passed, 0 failed, 0 skipped in 17 s (linux, 1 at once)

Testing

Tested: Arch Linux 7.2.15, Core i9-13900K, 96 GB: the complete game-free suite with FastMCP 4.1.3 on the exact committed head in branch-state, including the real SDK protocol tests and the new documentation-scope regression. The four SDK-free documentation/scope/optional-package/control-client programs and the isolated compiler fixture also passed, five programs in total. No fresh Longshot game run through this adapter is claimed.

Tested but not measured: the retained historical Hookshot MCP gameplay and current correctness checks; no execution-speed, frame-time or save-drain measurement. The newer main has since added DLSS-settle code and another description-template revision. This branch does not alter that DLSS code; its result-table merge conflict and any later base refresh are left to the maintainer under the frozen-base policy.

Not tested: fresh Longshot execution through this MCP adapter, fresh native Windows execution and other real MCP-host deployments remain outstanding; the local evidence uses Linux and authored fake-game processes. The optional dependency decision remains open. No new GPU code is added, so no separate vendor-specific performance claim or request is proposed; the unchanged renderer's unsupported WebGPU capture, run-long input exclusion and save-draining behavior are not made safe by this adapter.

  • New Longshot game execution through this MCP adapter: deliberately still a draft, also pending the dependency decision. Pull request 47's new Longshot client run is not substituted for an MCP run.
  • Fresh Windows execution, real windows, AMD/Intel/Steam Deck, physical devices, WebGPU screenshots, long sessions, performance or save-safe quit. Historical GitHub Windows/Ubuntu checks are not Forgejo CI. No new C/C++ fixture or host code.
  • Live deployment in a user's MCP host, or an accepted dependency policy. No hardware test request was posted during this move.

Needs other testers:

  • Windows x64: run the optional SDK protocol suite and an owned Longshot stdio lifecycle, including short-path reattachment, screenshots and owner/wrapper shutdown; expect valid replies/files and truthful exit receipts without touching player saves (request to open).
  • A real MCP-host operator on Linux: after the dependency decision, run an owned Longshot launch/state/input/file-and-inline-shot/stop sequence; expect the documented catalogue, confined artifacts and explicit unsupported save draining (request to open).

Screenshots

Nothing on screen changes in this tool; retained historical pictures, if any, are not main/PR rendering comparisons.

No new on-screen change or Longshot MCP picture.

Historical Hookshot ba005ca4 / adapter cf2dcf89, 2026-11-12: inspected file and inline captures of Kokiri Forest, Link and HUD at presents 1572 and 1575. Not new Longshot evidence.

Risk and rollback

The MCP process runs with the operator's authority. A misconfigured game path, wrapper or trusted environment can launch code or expose files; configured roots constrain model-selected paths, not the operator. Stop owned sessions explicitly before stopping the stdio host. Omit the optional server/SDK and use the standard-library client, or revert the child commits; the game has no new native dependency.

Reviewer notes

Review Config, path validation, per-run locks and bounded screenshot/log results in scripts/longshot_mcp.py, then the real-SDK protocol tests. The optional dependency exception remains a maintainer decision and this stays WIP. Original published stack boundary was 9f5f6dd29; the refreshed boundary is 23cc17be6a. Review child commits only after that parent; imported Nicholas files/messages and squash credit remain.

Issues

Original pull request: https://github.com/NotRexed/Hookshot/issues/2921.
Original author/work: https://github.com/NotRexed/Hookshot/issues/1025.
Prerequisite on this forge: #47.
No corresponding forge issue exists in the public issue inventory checked for this move. No old GitHub number is used as a forge closing reference.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main. The frozen base is in branch-state; the maintainer handles the later refresh.
  • python -I -B tests/run_all.py run and passing (any failure that also fails on main is named above). The retained compiler-killed case passed isolated, but the full suite is not called green.
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests).
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README). Relevant command/protocol details are in the topic guide; no unrelated menu default is added.
  • A row in docs/tested-configurations.md for each measured run.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened.
  • Docs updated.

Moved from NotRexed/Hookshot#2921.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra [email protected]
Co-authored-by: Nicholas Gower [email protected]

## Why **Draft, stacked on [pull request 47 of this forge](https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/47): review only the commits after 23cc17be6ac3bf11e5553f0c3008b05325b3249c. It becomes reviewable on its own once 47 is merged.** This opens against main because the forge cannot select a fork branch as its base. This optional stdio adapter lets tools drive owned command-line test sessions without adding another game protocol. It continues Nicholas Gower's https://github.com/NotRexed/Hookshot/issues/1025; no handover agreement is recorded in the retained discussion, and the offer to stop and help his original work after acknowledging his later push stands. **The one dependency question:** may this adapter and its SDK-specific tests use the narrowly scoped **FastMCP 4.1.3** exception proposed here? Longshot's current CONTRIBUTING guide requires standard-library tests and isolated Python; its existing exceptions cover the build pipeline and the separately scoped button-prompt tools, not MCP. The proposal is not accepted policy. If declined, the MCP adapter should remain outside this repository while the standard-library session client stays here. ## What changed - 20 typed tools and 3 resource templates wrap the existing session API. Requests are serialized per run; cancellation, coded errors and bounded output are explicit. - Images are files first; inline image data is opt-in. Model-selected screenshot/run paths stay under configured roots, and a configured game folder cannot be changed by a tool. - The SDK is pinned separately from game requirements. The control client, shared fake bridge and general documentation checks remain SDK-free. No package installs itself; the pin does not lock all transitive dependencies. - Nicholas's three original guide/test files from https://github.com/NotRexed/Hookshot/issues/1025 at bce003c7 are retained in the first child commit under his name, **changed only by the project's rename**. Their rename-equivalent hashes were checked; the original import message and DeepSeek assistance trailers are preserved. Our adaptations follow separately, and his co-author trailer below survives squash merging. - The dependency guide explicitly says Forgejo has no CI runner. The retained GitHub workflow's optional install step is not a Forgejo check. - The link check added here found a wrong link in pull request 47, fixed there. This child carries no second change to that control-guide line. - No native game change, new cheat protocol, build tool or contributor-process mandate. Missing cheats beyond teleport/age, WebGPU captures, run-long physical-input exclusion and save-safe quit remain explicit limits. This generic adapter has no dependency on the separate [workbench project](https://github.com/mooki000/hookshot-workbench), and nothing here implies maintainer endorsement of that project. - Documentation integration: the new main's fictional PR-description sample named a deliberately nonexistent test. The general docs check now excludes only its dedicated `tests/pr_description/` data directory; the new `tests/test_docs_scope.py` proves ordinary and similarly named test guides remain checked, as do missing real links and commands. The stack guide now names the refreshed session prerequisite. These are separate commits, not edits to Nicholas's import. ## Flags and settings | Flag | What it does | Default now | Recommendation | Helps on | Doesn't help on | Untested on | |---|---|---|---|---|---|---| | `HOS_CONTROL` | Lifecycle changed; native switch existing: Record the chosen endpoint; by default allocate a short private socket | Unset outside launch; launch allocates its own endpoint | Off by default: local test/control use | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `HOS_HEADLESS` | Test-profile setting: Suppress the game window | 1 in test profile; ordinary profile unchanged | Off by default: test profile only | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `HOS_AUDIO` | Test-profile setting: Mute the test game | 0 in test profile; ordinary profile unchanged | Off by default: test profile only | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `HOS_ENV_FILE` | Test-profile setting: Use an owned empty environment file instead of ambient file | Owned empty file in test profile; ordinary behavior unchanged | Off by default: isolation for tests | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `--run` | New global selector: Reattach using a retained run manifest | No selected run | Off by default: explicit owned run | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --run` | Changed launch output: Choose a new or empty durable run folder | Unique folder below root | Off by default: unique default avoids overwrite | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --root` | New: Parent of unique run folders | work/control-runs below caller working folder | On by default: durable default root | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --profile` | New: Choose ordinary or isolated test setup | default | Off by default: test is opt-in | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --ready` | New: Wait for bridge, present or play readiness | bridge | Off by default: caller chooses stronger readiness | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --timeout` | Changed readiness semantics: Bound readiness after admission; observed exits win over timeout | 600 seconds | On by default: bounded readiness, not a game wall limit | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --exe` | New: Choose explicit executable instead of Builder/bin discovery | Discover native game in bin before root | Off by default: development override | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --image` | New: Pass an explicit positional image path | Game folder image | Off by default: development override | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --romfs` | New: Pass explicit game content folder | Game folder romfs | Off by default: development override | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --user` | New: Pass explicit user folder; rejected in test profile | Existing ordinary location; test profile owns its user folder | Off by default: explicit development path | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --cwd` | New: Choose working/cache folder; requires explicit image | Game folder | Off by default: explicit isolation choice | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --wrapper` | New: JSON argv around lifetime supervisor for admission and wall policy | None | Off by default: machine-specific trusted configuration | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --save` | Changed test-profile support: Copy source saves to the owned test user folder | Fresh test user if omitted | Off by default: never select a player save implicitly | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --slot` | Changed test-profile support: Select the copied save slot | All source slots | Off by default: caller chooses slot | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --data` | Changed test-profile restriction: Ordinary data root; test profile refuses redirection | Ordinary behavior retained | Off by default: test profile owns its location | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --env` | Changed test-profile precedence: Explicit overrides; profile headless/audio/env-file choices win | No extra overrides | Off by default: trusted caller values | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `--exclusive` | Changed input default: Exclude physical input for each test-session request | True for test-session inputs; normal behavior otherwise | On by default: within each test request only | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `--no-exclusive` | New negative flag: Allow physical input alongside the request | Not selected | Off by default: deliberate opt-out | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `sequence --hos` | Changed conversion: Convert seconds/milliseconds to tested integer game frames | Frame units unless selected | Off by default: input-format choice | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `stop --timeout` | New: Wait for original owner to quit/reap game and wrapper | 10 seconds | On by default: bounded truthful stop | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `stop --terminate` | New: Authorize owner termination/kill after graceful timeout | False | Off by default: explicit force only | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `log --lines` | New: Tail retained run log | 100 lines | On by default: bounded tail | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `log --since` | New: Read after a byte cursor | No cursor | Off by default: explicit incremental reader | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `log --bytes` | New: Bound read/output bytes | 65536; at most 1048576 | On by default: bounded output | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `log --expect` | Wait for new matching text after since cursor | No expectation | Off by default: explicit witness | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `log --regex` | New: Treat expectation as regular expression | False | Off by default: explicit interpretation | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `log --timeout` | New: Bound the log expectation wait | 10 seconds | On by default: bounded wait | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `--json` | Changed session replies: Return manifest/log/status structured values for session commands | Plain output without flag | Off by default: machine-readable opt-in | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `launch --headless` | New profile interaction: Existing flag remains valid; test profile is always headless | False in ordinary profile; test profile forces headless | Off by default: ordinary play choice | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `--sock` | New session interaction: Existing explicit socket selector; --run selects a retained owned session instead | HOS_CONTROL or launch-allocated endpoint | Off by default: explicit trusted endpoint | Linux fake process tests and Longshot title lifecycle | Renderer/gameplay performance | Fresh Windows, other GPUs and long sessions (should help on: Equivalent CLI workflows on Windows) | | `server --root` | New in this child: Constrain owned run folders | Repository work/control-runs | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --game-dir` | New in this child: Fix the trusted executable folder; models cannot replace it | Unset: tool caller selects it | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --exe` | New in this child: Explicit executable override | None: discover game | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --image` | New in this child: Explicit positional image | None: game layout | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --romfs` | New in this child: Explicit game content folder | None: game layout | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --cwd` | New in this child: Explicit working/cache folder | None: game folder | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --wrapper` | New in this child: Trusted admission argv; no shell expansion | Empty argv | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | | `server --env` | New in this child: Repeatable trusted NAME=VALUE environment entry | Empty list | Off by default: operator configuration | Linux real-SDK offline tests | No native-game cost change | Fresh Longshot MCP runtime and Windows (should help on: Equivalent stdio hosts on Windows) | ## Measurements <!-- branch-state --> Branch state: on main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`; head `0ce651b604ef72a514e6f5d42c11c971594f6d97`; whole game-free suite on this head: `513 passed, 2 failed, 20 skipped` (main `d725b3631982ed0035ea3ac9cbe1677e9fad260c`: `510 passed, 1 failed, 20 skipped`); the commits are unchanged by rebases apart from the results table. <!-- /branch-state --> main: d4a69456c9de5131589af1fcf9a09adba4c403d1 (2026-11-12) this PR: feat/mcp-server @ 5502fe20a5aa9b61f7132d3edbb33e16c774946a Measurement provenance: main @ d4a69456c9de5131589af1fcf9a09adba4c403d1; session prerequisite in forge pull request 47 @ 9f5f6dd292efd5727b3dc6503d8c8003acb98333. 5502fe20a5aa9b61f7132d3edbb33e16c774946a. Hardware: Core i9-13900K, 96 GB RAM, Arch Linux 7.2.15. No GPU used for the new server checks. Scene: real SDK catalogue and stdio/in-memory protocol tests against an authored fake game; no new Longshot MCP gameplay run. Method: whole-suite warm-up, then the same catalogue probe before/after/before/after, fresh HOME each time. Counts and test output, not timing claims. The adapter is a separate process; native game code and ordinary launches are unchanged when it is not used. How to reproduce: In the optional FastMCP 4.1.3 environment, run `python -I -B tests/test_mcp_server.py` and the documented catalogue list calls; compare the pinned main source where the adapter is absent, twice in interleaved order. Run `tests/run_all.py test_mcp_ test_docs test_longshot_ctl` without the SDK to check its isolated absence. Do not treat these fake-game checks as a new Longshot run. The rebase onto main d725b3631 adds only scripts, docs and tests, with no game-code change; the measured d4a69456 comparisons and pinned game evidence remain valid and were not repeated. Original results below retain their measured commits; the new exact-head suite is recorded separately. Baseline: main @ d4a69456 | | main @ d4a69456 | this PR @ 5502fe20 | |---|---|---| | Pair 1: complete SDK catalogue | Absent (0) | 20 tools / 3 resource templates (1) | | Pair 2: complete SDK catalogue | Absent (0) | 20 tools / 3 resource templates (1) | | Median complete catalogues | 0 | 1 | | Whole suite | Main: 507 passed / 2 failed / 20 skipped | 511 passed / 1 failed / 20 skipped | ```text Before 1: AssertionError: MCP adapter absent on this source After 1: PASS: real SDK catalogue: 20 tools, 3 resource templates Before 2: AssertionError: MCP adapter absent on this source After 2: PASS: real SDK catalogue: 20 tools, 3 resource templates Real SDK protocol fixture: Ran 9 tests in 4.679s OK Final whole suite: 511 passed, 1 failed, 20 skipped in 154 s (linux, 6 at once) Selected checks without the SDK: pass tests/test_docs.py pass tests/test_mcp_optional.py pass tests/test_longshot_ctl.py skip tests/test_mcp_server.py (not found here: fastmcp) 3 passed, 0 failed, 1 skipped in 7 s (linux, 6 at once) ``` The before probe explicitly tests feature absence, not a failure of main's existing client. The SDK fixture exercises real initialization, tool/resource calls, stdio, error/EOF handling, cancellation, path boundaries, output limits and fake-session lifecycle. The no-SDK check verifies the one-line install refusal, no protocol output and SDK-free ordinary imports. The complete suite used `tests/run_all.py --jobs 6 --strict`, default compiler, the existing pinned Python with an owned copy of the optional SDK environment. No package was installed. The main suite is the shared baseline run once for this day's moved pull requests at d4a69456. The only final branch failure is main's local `tests/test_updater_asset_digest.py`: SDK 10.0.113 cannot resolve `Microsoft.AspNetCore.App.Ref (= 10.0.13)`, `NU1100`. Main additionally failed `tests/test_appimage_package_retry.py` under heavy load; the requested isolated rerun passed all 9 tests. It fails only under heavy load on this PC; timing-dependent. This branch passed it. The complete suites are not called green. Retained earlier result: 510 passed / 2 failed / 20 skipped. Its additional `test_docs.py` failure identified the lowercase README link in the parent. Pull request 47 fixed it; the full suite above was run again after restacking on that parent. Historical game evidence, **Hookshot, 2026-11-12**, not a fresh Longshot run: adapter cf2dcf89, game ba005ca4; RTX 4090 / NVIDIA 615.78.08, 1280×720, windowless Kokiri Forest. One 36.3 s ordinary shared run returned 29 matched replies including 26 tool calls, completed sequence frames 1455–1511, produced file/inline images at presents 1572/1575, restored an option and stopped with exit 0. Input save copy unchanged; fatal/device/kernel fault counts 0. No frame-rate or save-draining claim. ### Separate historical stack-parent check Baseline: session-parent @ 596c0a33 This secondary comparison records the prerequisite separately because it is not main. Parent source was carried unchanged apart from its separately checked README link. | | session-parent @ 596c0a33 | this PR @ 5502fe20 | |---|---|---| | Whole suite | 508 passed / 1 failed / 20 skipped | 511 passed / 1 failed / 20 skipped | ### Current validation and retained failures The exact-head whole-suite result is in branch-state. The local NU1100 reference-pack failure also occurs on main. The other failure was `nx2/test_texture_phi_dominance.py`: clang++ compiling `emit_spirv.cpp` was killed with SIGKILL 9, not a failed shader assertion. This is the compiler-killed category reported in other suites today; the signal alone does not establish OOM or another cause. That compiler fixture passed when run alone. The four SDK-free documentation/scope/optional-package/control-client checks also passed. These successes do not erase the failed full-suite attempt or make it green. The earlier documentation-fixture failure is also preserved in the evidence; the new scope regression and corrected documentation check now pass. Actual SDK-free test output: ```text 5 checks, 0 skipped, 1 at once (linux) pass 7.4s nx2/test_texture_phi_dominance.py pass 0.1s tests/test_docs.py pass 0.1s tests/test_docs_scope.py pass 9.1s tests/test_longshot_ctl.py pass 0.1s tests/test_mcp_optional.py 5 passed, 0 failed, 0 skipped in 17 s (linux, 1 at once) ``` ## Testing **Tested:** Arch Linux 7.2.15, Core i9-13900K, 96 GB: the complete game-free suite with FastMCP 4.1.3 on the exact committed head in branch-state, including the real SDK protocol tests and the new documentation-scope regression. The four SDK-free documentation/scope/optional-package/control-client programs and the isolated compiler fixture also passed, five programs in total. No fresh Longshot game run through this adapter is claimed. Tested but not measured: the retained historical Hookshot MCP gameplay and current correctness checks; no execution-speed, frame-time or save-drain measurement. The newer main has since added DLSS-settle code and another description-template revision. This branch does not alter that DLSS code; its result-table merge conflict and any later base refresh are left to the maintainer under the frozen-base policy. **Not tested:** fresh Longshot execution through this MCP adapter, fresh native Windows execution and other real MCP-host deployments remain outstanding; the local evidence uses Linux and authored fake-game processes. The optional dependency decision remains open. No new GPU code is added, so no separate vendor-specific performance claim or request is proposed; the unchanged renderer's unsupported WebGPU capture, run-long input exclusion and save-draining behavior are not made safe by this adapter. - New Longshot game execution through this MCP adapter: deliberately **still a draft**, also pending the dependency decision. Pull request 47's new Longshot client run is not substituted for an MCP run. - Fresh Windows execution, real windows, AMD/Intel/Steam Deck, physical devices, WebGPU screenshots, long sessions, performance or save-safe quit. Historical GitHub Windows/Ubuntu checks are not Forgejo CI. No new C/C++ fixture or host code. - Live deployment in a user's MCP host, or an accepted dependency policy. No hardware test request was posted during this move. **Needs other testers:** - Windows x64: run the optional SDK protocol suite and an owned Longshot stdio lifecycle, including short-path reattachment, screenshots and owner/wrapper shutdown; expect valid replies/files and truthful exit receipts without touching player saves (request to open). - A real MCP-host operator on Linux: after the dependency decision, run an owned Longshot launch/state/input/file-and-inline-shot/stop sequence; expect the documented catalogue, confined artifacts and explicit unsupported save draining (request to open). ## Screenshots Nothing on screen changes in this tool; retained historical pictures, if any, are not main/PR rendering comparisons. No new on-screen change or Longshot MCP picture. ![Historical Hookshot ba005ca4 / adapter cf2dcf89, 2026-11-12: inspected file and inline captures of Kokiri Forest, Link and HUD at presents 1572 and 1575. Not new Longshot evidence.](https://git.magicbean.dev/attachments/9379a710-a106-4457-a6a9-bf744c20b0db) ## Risk and rollback The MCP process runs with the operator's authority. A misconfigured game path, wrapper or trusted environment can launch code or expose files; configured roots constrain model-selected paths, not the operator. Stop owned sessions explicitly before stopping the stdio host. Omit the optional server/SDK and use the standard-library client, or revert the child commits; the game has no new native dependency. ## Reviewer notes Review Config, path validation, per-run locks and bounded screenshot/log results in scripts/longshot_mcp.py, then the real-SDK protocol tests. The optional dependency exception remains a maintainer decision and this stays WIP. Original published stack boundary was 9f5f6dd29; the refreshed boundary is 23cc17be6ac3bf11e5553f0c3008b05325b3249c. Review child commits only after that parent; imported Nicholas files/messages and squash credit remain. ## Issues Original pull request: https://github.com/NotRexed/Hookshot/issues/2921. Original author/work: https://github.com/NotRexed/Hookshot/issues/1025. Prerequisite on this forge: https://git.magicbean.dev/MagicBeanDev/Longshot/pulls/47. No corresponding forge issue exists in the public issue inventory checked for this move. No old GitHub number is used as a forge closing reference. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [ ] Rebased on current `main`. The frozen base is in branch-state; the maintainer handles the later refresh. - [ ] `python -I -B tests/run_all.py` run and passing (any failure that also fails on `main` is named above). The retained compiler-killed case passed isolated, but the full suite is not called green. - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). Relevant command/protocol details are in the topic guide; no unrelated menu default is added. - [x] A row in `docs/tested-configurations.md` for each measured run. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened. - [x] Docs updated. --- Moved from NotRexed/Hookshot#2921. Assisted-by: GPT-6 Astra Co-Authored-By: GPT-6 Astra <[email protected]> Co-authored-by: Nicholas Gower <[email protected]>
Adapt Nicholas Gower’s bin-first executable lookup and flat/builder layout regression from 7f76855d in #1025 to the command-line client. Refuse an incomplete bin folder instead of starting the root launcher. Expose the runtime’s existing image, romfs and user arguments for development builds.

Co-authored-by: Nicholas Gower <[email protected]>
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Keep a versioned manifest, process birth identity, isolated test profile, bounded readiness and log reads, acknowledged shots and an actual child exit receipt after the launching client exits. A lifetime wrapper supplies admission without machine policy in the client. Re-attached callers ask the original owner to stop; they never signal a pid from disk. Quit has no save-drain guarantee.

Extend the existing socket/named-pipe fake with state, quit refusal and an authored decodable PNG. The tiny authored PNG and fake-process evidence approach adapt Nicholas Gower’s work in #1025; no old live-file protocol or MCP dependency is carried. HOS sequence units become integer frame steps, with half-up and minimum-hold assertions.

Co-authored-by: Nicholas Gower <[email protected]>
Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
The first fork Windows run caught two branch regressions before publication: a plain RUNNER~1 temporary path compared unequal to its resolved spelling, and stop could return while an admission wrapper still held owner.log. Check link/reparse entries directly, compare canonical source/destination identities, record the wrapper birth identity and wait for both owners before stop reports completion. Explicit close_fds preserves only redirected standard handles.

Normalize expected filesystem, JSON and argument errors at the callable session boundary to Failed(code). Regressions cover alternate path spellings, a deliberately held wrapper, closed parent log handles, manifest-reader closure and binary CRLF/UTF-8 log cursors. The capture fake now emits the existing renderer publication line verbatim for the log-expect proof.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Allow ordinary linked parent folders while refusing overlapping resolved save trees and links at the save/UID entries the copier creates. Main did not reject linked destination ancestors. Keep partial trailing UTF-8 bytes behind the returned cursor, including at a live EOF, and only replace an incomplete tail after the run ends. Accept older stop receipts without process_exited.

Game-free tests fail on the previous code and pass with these changes: linked parent success, source-link and save-link refusal, a three-byte character split at the read limit or a live EOF, tail clipping, and a compatible older stop result. The recorded game run remains on 3f1da556; these changes were not rerun in the game.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Record the command-line-only run against the completed main ba005ca4 game build: copied test profile, ready play, frame-acknowledged sequence, inspected bridge shot, live log cursor expectation, second invocation and observed quit exit. No game rebuild, performance or save-drain claim.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Check the child before and after each readiness poll and again at the deadline, before reporting a timeout. Keep bridge I/O within the remaining readiness budget. At stop and termination deadlines, recheck the process before reporting a timeout or escalating; an already-exited child is not forced.

Replace the early-exit test’s race between Python startup and 0.3 seconds with an actual fake child reaped before the first poll. Deterministic clock/process tests cover an exit exactly at the deadline, exit during a transport poll, a still-live timeout, stop-deadline exits and termination escalation. The regressions fail on the open #2904 base; the complete client and real-C bridge checks pass afterward.

Assisted-by: GPT-6 Astra
Co-Authored-By: GPT-6 Astra <[email protected]>
Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
The control guide linked ../readme.md; this repository's file is README.md,
as the other guides link it. Found by the documentation link check carried
in the follow-up branch.

Assisted-by: Claude Fable 5.2
Co-Authored-By: Claude Fable 5.2 <[email protected]>
Imported from NotRexed/Hookshot#1025 at bce003c7fc45521100891b3eaa1b657510922333

Assisted-by: DeepSeek V4.1 Flash

Co-Authored-By: DeepSeek V4.1 Flash <[email protected]>
Adapt the original guide and protocol checks to the existing bridge. Keep the game, client and general checks independent of the optional SDK.

Co-authored-by: Nicholas Gower <[email protected]>

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Bind a configured game folder, reject screenshot traversal and links out, and keep run folders under the configured root. Save sources remain read-only copies. Keep one save catalogue tool with slot metadata.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Resolve the shared temporary fixture root and both sides of path identity assertions so Windows short-name aliases do not fail equivalent paths. Keep manifest equality checks strict.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
The docs check exposed the carried control guide link to lowercase readme.md; Longshot names it README.md. Preserve the original import and adaptation commits unchanged.

Assisted-by: GPT-6 Astra

Co-Authored-By: GPT-6 Astra <[email protected]>
Author
First-time contributor

The description now follows the latest template, with the complete Testing section and checklist, one branch-state block, and the original measurement labels and uploaded picture preserved. Two follow-up commits name the refreshed session prerequisite and exclude only fictional PR-description fixtures from the documentation check, with regressions protecting real guides. The exact-head whole suite retains the local .NET prerequisite failure and a compiler-killed texture-phi case; that compiler fixture and all four SDK-free checks passed when selected separately, without erasing the failed whole-suite attempt. This remains WIP pending the optional-dependency decision, fresh Longshot use through the adapter, and the listed test requests.

The description now follows the latest template, with the complete Testing section and checklist, one branch-state block, and the original measurement labels and uploaded picture preserved. Two follow-up commits name the refreshed session prerequisite and exclude only fictional PR-description fixtures from the documentation check, with regressions protecting real guides. The exact-head whole suite retains the local .NET prerequisite failure and a compiler-killed texture-phi case; that compiler fixture and all four SDK-free checks passed when selected separately, without erasing the failed whole-suite attempt. This remains WIP pending the optional-dependency decision, fresh Longshot use through the adapter, and the listed test requests.
mooki force-pushed feat/mcp-server from 5502fe20a5 to 0ce651b604
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 2s
2026-11-13 02:10:00 +00:00
Compare
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 2s
This pull request has changes conflicting with the target branch.
  • docs/tested-configurations.md
View command line instructions

Manual merge helper

Use this merge commit message when completing the merge manually.

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'feat/mcp-server:mooki-feat/mcp-server'
git switch 'mooki-feat/mcp-server'
Sign in to join this conversation.
No description provided.