fix(mcp): repoint stored-degree tools at programs + auto-refresh JWT#12
Merged
Conversation
Two critical fixes from MCP tester feedback that block the stored-analysis workflow added in v0.5.0. Issue A — search_degrees / get_degree / compare_degrees returned zero rows even though import_degree had written programs. They still queried the legacy `degrees` yaml-blob table (with columns that don't exist on `programs`). Repoint all three reads at `programs`: - search_degrees gains the queryable dimensions degree_type / program_kind / discipline alongside unitid / cip_prefix / catalog_year. - get_degree precedence is now program_key (unique) -> degree_id -> natural key, and returns the lossless unified-JSON `document` for downstream tools. - compare_degrees resolves stored ids against program_key then degree_id. - Legacy `degrees` + shelved `store_degree` left untouched for back-compat. Issue C (+ B) — the MCP server cached one JWT at startup and never refreshed it, so every DB tool (IPEDS included) died ~1h in; a client re-login didn't help. DbClient now holds the full AuthState behind an Arc<RwLock> and calls current_token() before each request: it refreshes proactively when expired (re-reading the on-disk auth file first, so a fresh `db login` is picked up mid-process) and reactively retries once on a 401. The reqwest client also gets explicit request/connect timeouts so a stalled call fails fast instead of hanging to the 4-minute MCP ceiling (Issue B). Verified live: `db status` auto-refreshed a 6h-expired token and read succeeded; MCP search_degrees() returns all 3 imported programs and get_degree(program_key=…) returns the full document. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The client module doc linked to `current_token`, a private method, which trips rustdoc::private_intra_doc_links under the Documentation CI job's RUSTDOCFLAGS=-D warnings. Demote it to a plain code span. Verified with a clean `cargo doc --no-deps --all-features` under RUSTFLAGS/RUSTDOCFLAGS=-D warnings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
First of three phases addressing the MCP tester feedback report. This phase ships the two critical fixes that block the stored-analysis workflow added in v0.5.0.
Issue A —
search_degrees/get_degree/compare_degreesreturned emptyThe tester guessed RLS; the real cause was a table mismatch. These read tools still queried the legacy
degreesyaml-blob table (with columns that don't even exist onprograms), whileimport_degreewrites to the newprogramstable — so they returned 0 rows despite 3 imported programs.programs.search_degreesgains the queryable dimensionsdegree_type/program_kind/disciplinealongsideunitid/cip_prefix/catalog_year.get_degreeprecedence is nowprogram_key(unique) →degree_id→ natural key, and returns the lossless unified-JSONdocument(whatanalyze_degree/cache_yamlaccept).compare_degreesresolves stored ids againstprogram_keythendegree_id.degreestable + shelvedstore_degreeleft untouched for back-compat.Issue C (+ B) — JWT never refreshed; long sessions die at ~1h
The MCP server cached one JWT at startup and discarded the refresh token, so every DB tool (IPEDS included) died ~1h in, and a client re-login didn't help (only a restart did).
DbClientnow holds the fullAuthStatebehind anArc<RwLock>and callscurrent_token()before each request: proactive refresh when expired (re-reading the on-disk auth file first, so a freshdb loginis picked up mid-process) and reactive retry-once on a401.reqwestclient gets explicit request/connect timeouts so a stalled call fails fast instead of hanging to the 4-minute MCP ceiling (Issue B).Verification
programsrow deserialization (locks the column contract).db statusauto-refreshed a 6h-expired token and the read succeeded; MCPsearch_degrees()returns all 3 imported programs, thedegree_type=BSdimension filter works, andget_degree(program_key=…)returns the fulldocument.cargo fmt --check,cargo clippy --all-targets --all-features -D warnings,cargo doc -D warnings, andcargo test --all-featuresall green.Follow-up phases (separate PRs): Fix 3 (
render_plan_graphhang) and Fix 4 (QoL:@-prefix fast-fail, cache lock scope, expired-handle error,recommended_max_plans).🤖 Generated with Claude Code