Skip to content

[codex] Add MCP bridge auth token - #87

Open
CompleteDotTech wants to merge 198 commits into
Gennadiyev:mainfrom
CompleteDotTech:codex/mcp-auth-token-docs
Open

[codex] Add MCP bridge auth token#87
CompleteDotTech wants to merge 198 commits into
Gennadiyev:mainfrom
CompleteDotTech:codex/mcp-auth-token-docs

Conversation

@CompleteDotTech

Copy link
Copy Markdown
Contributor

Summary

Ports the implementation from CompleteDotTech#5 onto Gennadiyev/STS2MCP.

This adds optional bearer-token header support to the Python MCP bridge. It does not change the game/mod HTTP server's authentication behavior.

Dependency Note

The source PR was stacked on the save-snapshots branch, which itself was stacked on the endpoint-audit branch.

This upstream PR is therefore stacked on:

Until those PRs merge, this PR's diff against main includes the endpoint-audit and snapshot foundations. The auth-token implementation itself is the Add MCP bridge auth token commit, followed by this documentation pass.

What Changed

MCP bridge environment loading

The Python MCP bridge now loads settings from:

  1. process environment variables
  2. mcp/.env
  3. current-working-directory .env

Environment variables take precedence over .env values. .env only fills keys that are not already set.

Supported settings:

  • STS2_HOST
  • STS2_PORT
  • STS2_MCP_AUTH_TOKEN

Auth header injection

When STS2_MCP_AUTH_TOKEN is configured, all MCP bridge HTTP requests include:

Authorization: Bearer <token>

This applies to the shared httpx.AsyncClient, so it covers all MCP tool calls that route through the Python bridge.

Important auth boundary

This is client-side header injection only.

The current STS2_MCP game/mod HTTP listener does not require or validate the token by itself. The setting is useful when the Python MCP bridge is pointed at:

  • a local authenticated proxy
  • a tunnel that expects bearer tokens
  • a future authenticated STS2_MCP HTTP listener

It does not make an unauthenticated listener secure on its own.

.env parsing

The .env parser supports:

  • blank lines
  • full-line comments
  • KEY=value
  • export KEY=value
  • single-quoted values
  • double-quoted values
  • inline comments after whitespace

Hashes inside token values are preserved unless the hash begins an inline comment after whitespace.

For example:

STS2_MCP_AUTH_TOKEN=abc#123

keeps abc#123, while:

STS2_MCP_AUTH_TOKEN=abc # local dev token

parses as abc.

Secret hygiene

Adds local .env files to .gitignore:

  • .env
  • mcp/.env

This prevents bridge tokens and machine-specific host/port settings from being committed accidentally.

Documentation

Updates:

  • README.md
  • mcp/README.md
  • docs/endpoint-contracts.md

The docs now cover precedence, .env syntax, auth header behavior, the server-auth limitation, and the intended proxy/tunnel/future-listener use cases.

Validation

Completed locally on this branch:

  • python3 -m py_compile scripts/audit_endpoints.py scripts/test_mcp_server.py mcp/server.py
  • python3 scripts/audit_endpoints.py --skip-live
  • uv run --project mcp python scripts/test_mcp_server.py
  • uv run --directory mcp python server.py --help
  • "/mnt/c/Program Files/dotnet/dotnet.exe" build STS2_MCP.csproj -c Release -o out/STS2_MCP -p:STS2GameDir="C:\Program Files (x86)\Steam\steamapps\common\Slay the Spire 2"

The MCP bridge tests include dotenv precedence and auth header injection coverage. The .NET build completed successfully with 0 warnings and 0 errors.

CompleteDotTech and others added 30 commits March 26, 2026 11:50
The map screen's player summary only included hp, gold, and potion slot
counts. This adds full relic and potion data to BuildMapState so external
tools can display them outside of combat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Map data is now always returned alongside any game state (combat, event,
shop, etc.) so external tools can display the map without caching. Also
adds a version marker for verifying mod DLL is loaded.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Always attach BuildPlayerState output at the top level of every response
so external tools have access to HP, gold, relics, potions, deck piles,
and powers regardless of which screen is active.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exposes player.Deck.Cards in BuildPlayerState so the full deck
composition is available on every screen, not just during combat.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Some screens (e.g. treasure) can cause null reference exceptions
when BuildPlayerState accesses combat-only properties.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When NMapScreen is not open (during combat, events, etc.), compute
next_options from the current map point's children so external tools
always have the available path choices.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GET /api/v1/glossary — returns all categories
GET /api/v1/glossary/cards — all cards with pool grouping
GET /api/v1/glossary/relics — all relics with pool grouping
GET /api/v1/glossary/potions — all potions with pool grouping
GET /api/v1/glossary/keywords — unique keywords from all items

Uses current character's pools during a run, plus colorless/curse.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tries http://+:15526/ first for network access, falls back to
localhost-only if the URL ACL is not configured.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Returns all cards from the current character's card pool during an
active run. Includes id, name, type, cost, description, rarity, pool,
and keywords for each card.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Returns relics from the current character's relic pool. Shared/event
relics not yet accessible — canonical instance lookup returns null
at runtime. Will revisit access pattern later.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Returns potions from the current character's potion pool.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Harvests unique keywords from all cards, relics, and potions in the
current character's pools. Returns name and description for each.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows visible menu buttons as numbered options in player stats widget.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects main menu, singleplayer mode select, and character select screens.
Shows available options with enabled/locked state. Character select includes
HP, gold, energy, starting relics, starting deck, and pool counts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Supports navigating Main Menu, Singleplayer Mode Select, and Character
Select screens. Includes back button, character selection with lock
detection, and embark/confirm to start a run.

Actions: menu_select with options:
- Main menu: singleplayer, multiplayer, settings, quit, etc.
- Mode select: standard, daily, custom, back
- Character select: IRONCLAD, SILENT, etc., confirm, back

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detects NGameOverScreen overlay as state_type: game_over with
continue and main_menu options. Handles via menu_select action.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Exposes player profile data: character stats (wins, losses, ascension,
streaks), card stats (pick/skip/win/loss), encounter and enemy stats,
discovered items, total playtime, score, and floors climbed.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Profile endpoint now includes by_character win/loss for each encounter
and enemy. Widgets show the breakdown under each entry.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds ancient stats with per-character breakdown, epoch milestones,
unlocked achievements, and global stats (wins, losses, runs, best
streak, fastest victory, architect damage).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
GET /api/v1/bestiary returns 126 monsters (HP range, moves) and
95 encounters (type, tier). Widget merges with profile win/loss stats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Encounters now include min/max gold reward and likely_monsters
inferred from encounter name. Widget shows gold and monster columns.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Timeline shows epoch names, descriptions, and unlock requirements.
Multiplayer submenu shows host/join/load options. Settings, compendium,
and timeline screens properly detected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Timeline widget now groups epochs into Completed (green), Locked (yellow
with unlock requirements), and hidden count.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No more flickering from mouse hover. Shows earned epochs from save
data with slot counts for remaining.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant