Repository navigation
MCP endpoint: AI assistants can read the base - #199
Merged
Merged
Conversation
The MCP endpoint coming next must check what the page's routes check, so the logic moves into functions both can call: - commands.request_cancel(): the busy-CPU and same-job checks. The job identity helpers (output_identity, same_output) move with it from tracking, which imports commands, not the other way round. - commands.craft_request_error(): the craft request's input checks. - stock.item_from(), set_alert(), set_target() and rules(): stock rule validation, the craftable check and the rules listing. - planner.rules_for_user(): the stock rules a plan warns about. No change to what the routes accept or answer, except that a craft request's amount can no longer be true (which counted as 1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
/mcp is a Model Context Protocol endpoint, so Claude Code or another MCP client can answer questions about the base. Eleven read-only tools: item search, item details and history, inventory changes, current crafts, a job's held-up steps, craft history and stats, the crafting plan, stock rules and power. - Hand-written JSON-RPC over Streamable HTTP (gcm/mcp/protocol.py): one JSON answer per POST, no sessions. It serves both protocol eras: the 2026-07-28 stateless requests (version in _meta, mirrored headers checked) and initialize-based 2025-03-26..2025-11-25 clients. - Signed in with the user's personal access token as a bearer token (auth.bearer_required), never a session cookie; another site's Origin is refused. - Tools take item keys from search_items, never names, and compact their output for a model's context. - docs: an AI assistants section in using.md, plus README, server.md, how-it-works.md and CONTEXT.md. dev.py prints the MCP address. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Nov 4, 2026
- A tool that raises anything but ToolError answers as a tool error (and is logged) instead of a 500 the client can't read, and a KeyError inside a tool no longer reads as "Unknown tool". - Numbers in arguments must be finite: JSON's 1e400 is infinity to Python, which int() turned into a 500. - inventory_changes builds the snapshot's lookup once instead of scanning it for every changed item. - search_items ranks by the name without Minecraft's colour codes, and tool output drops them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Maselkov
added a commit
that referenced
this pull request
Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #198. Merge #198 first. Until then this diff also shows #198's commit. The base is
mainon purpose, so this can't end up merged into #198's branch.Adds
/mcp, a Model Context Protocol endpoint, so an AI assistant can answer questions about the base, such as "what's draining fastest this week?", "why is M00 slow?" or "what's missing for 64 of these?". Everything is read-only. Signing in from claude.ai (OAuth) and the write tools come in the next PRs.What it adds
gcm/mcp/tools.py:search_items,get_item,item_history,inventory_changes,current_crafts,craft_job,craft_history,craft_stats,plan_craft,stock_rules,power. They call the same code as the page's routes (the planner,stock.rules,inventory.history,bottlenecks.steps…).search_itemsreturns, never a name, so a request can't land on the wrong one of several items with the same name.gcm/mcp/protocol.py): hand-written JSON-RPC over Streamable HTTP. The MCP Python SDK is ASGI and this server is WSGI, and without sessions or streams the protocol is small. Every request gets one JSON answer._metaand theMCP-Protocol-Versionheader must match it,Mcp-Method/Mcp-Nameare checked against the body (-32020 on a mismatch),server/discoveris supported, unsupported versions get -32022. 2025-03-26 to 2025-11-25:initializepicks the version, then each request is served by its header.auth.bearer_requiredpolicy reads the user's personal access token fromAuthorization: Bearer, through the newstore.users.token_user. A session cookie never works on/mcp, and a request from another site'sOrigingets 403. The tools apply the user's role.docs/using.md(setup in Claude Code, a table of the tools), plus README,server.md(the proxy must pass/mcp),how-it-works.mdandCONTEXT.md.dev.pyprints the MCP address.Step 0: what the plan needed checking
initializehandshake and sessions, which is why the endpoint serves both eras.client_id_metadata_document_supportedand thenoneauth method), PKCE S256, and the callbackhttps://claude.ai/api/mcp/auth_callback. Claude Code uses loopback redirects on any port. All of this is for the OAuth PR.Testing
tests/test_mcp.py(35 tests): auth (missing, wrong, revoked or cookie-only credentials; Origin; no-store), both eras' handshakes and errors, header-mismatch cases including base64Mcp-Name, and every tool against the real app.node --test, e2e,node --check, Lua (on 5.4), ruff, luacheck and shellcheck.dev.py: each tool called over HTTP in both eras.claude mcp add --transport http gtnh-dev http://127.0.0.1:8421/mcp --header "Authorization: Bearer <the token dev.py prints>".🤖 Generated with Claude Code