Reported issues for transkribus
Pod holds 16 of 17 problems reported by people outside the maintainer team. Issues filed by the project's own owners, members and collaborators are excluded entirely — a maintainer's release checklist is not a warning to a prospective user.
Back to transkribus.
Most discussed
Port the hardened Retry-After parser from lexware #54 + first real interceptor test coverage
Same fleet bug-class lexware fixed in lazyants/lexware-mcp-server#54; sibling issue exists for hetzner. The 429/401 interceptor currently has zero direct test coverage.
Findings
Transkribus 429 backoff has the same bare-parseInt Retry-After bug lexware fixed in #54
transkribus-mcp-server/src/services/transkribus.ts:105 — low bug
Evidence: transkribus.ts:102-107: `const retryAfter = error.response.headers['retry-after']; let delay: number; if (retryAfter) { delay = parseInt(r
Read the thread · 2026-07-03 · open · 2 comments
Port parseRetryAfterMs: 429 Retry-After HTTP-date parses to NaN -> immediate retry
Same bug class as lexware #54 and hetzner #61 — verified still present here.
src/services/transkribus.ts:102:
delay = parseInt(retryAfter, 10) * 1000;
parseInt yields NaN for the RFC 7231 HTTP-date form of Retry-After (only bare delta-seconds parse), so setTimeout(NaN) fires immediately and collapses the 429 backoff into a tight retry loop against an already rate-limited API.
Fix (port the shipped fleet solution)
hetzner-mcp-server fixed this in #61 (PR #65) by port
Read the thread · 2026-07-18 · closed · 1 comment
Accepted #26 redaction residuals (adversarial-only, defense-in-depth)
Tracking, low priority. The #26 fail-closed sanitizer (PR #37) covers all realistic JSON responses. Two residuals remain, each requiring an adversarial / hand-crafted non-JSON server response and documented in code as accepted:
- A bare session token echoed in a non-Set-Cookie custom header with no
sessionid=key prefix and not equal to the module session — not collected, survives on the chained cause. - A token split across non-session-named keys (e.g.
{JSESSION:{ID:x}}) — no
Read the thread · 2026-07-17 · closed · 1 comment
Tighten models.ts type path segment to a verified z.enum
Deferred from #32 (PR #37). The 14 model tools type type as PathSegmentSchema (a string guard + pathSeg encoding). The API documents a closed set (e.g. htr/la/ocr) but the authoritative value list is unverified. A z.enum would make traversal unreachable by construction — stronger than pathSeg.
Blocker: needs the authoritative type value set from the Transkribus API — an incomplete enum would break working calls (a hard regression). Verify against the API, then convert the 14 s
Read the thread · 2026-07-17 · closed · 1 comment
429 backoff mis-parses Retry-After HTTP-date to NaN → immediate retry
Same class as lexware #54 (fixed there with parseRetryAfterMs, shipped in lexware 4.0.0). src/services/transkribus.ts:107 computes the 429 delay with parseInt(retryAfter, 10) * 1000 (header read at :104), which is NaN for an HTTP-date Retry-After; setTimeout(NaN) fires immediately and defeats the backoff.
Fix: port lexware's parseRetryAfterMs (delta-seconds + strict IMF-fixdate validated by an exact Date.UTC round-trip) to :107, and add the accompanying `retry-after.test
Read the thread · 2026-07-17 · closed · 1 comment
Schema consistency: 18 hand-rolled pagination blocks (losing intCoerce), raw ID params in du.ts/kws.ts, hand-rolled userid params
Findings
17 tools hand-roll index/nValues/sortColumn/sortDirection instead of spreading PaginationParams, silently losing intCoerce string coercion
transkribus-mcp-server/src/tools/collections-core.ts:19 — medium duplication
Evidence: collections-core.ts:19-22 index: z.number().int().optional().default(0)... nValues: z.number().int().optional().default(0)... sortColumn... sortDirection... — the same 4-line block is copy-pasted in 17 tools (collections-core ×4, collections-u
Read the thread · 2026-07-03 · open · 1 comment
Add pathSeg(): raw string params interpolated into URL paths (admin tools + 14 model tools); scrub config.params too
The repo has zero encodeURIComponent usage. Hetzner already ships pathSeg() in schemas/common.ts after codex flagged the same class on its DNS PR. The config.params scrub extension complements #26 (which covers bodies).
Findings
Admin tool string params (reportType, reportTime, jobImpl) interpolated raw into URL path without encoding
transkribus-mcp-server/src/tools/admin.ts:103 — low security
Evidence: reportType: z.string() / reportTime: z.string() then: return transkrib
Read the thread · 2026-07-03 · closed · 1 comment
401 re-auth interceptor recurses without bound when /auth/login itself responds 401
Findings
401 interceptor recurses without bound when /auth/login itself responds 401
transkribus-mcp-server/src/services/transkribus.ts:86 — medium bug
Evidence: if (error.response?.status === 401) { ... if (!retried) { (config...).__authRetried = true; sessionId = await login(client); ... } } — login() posts /auth/login through the SAME client, so a 401 from the login endpoint re-enters this handler with a FRESH config (no __authRetried), which calls login() again, recursi
Read the thread · 2026-07-03 · closed · 1 comment
Most recent
Port lexware's OS-keyring credential resolution (env var as fallback)
lexware-mcp-server 4.2.0 moved credential lookup off plain-text env vars and onto the OS keyring, with the env var kept as a fallback (lazyants/lexware-mcp-server#91, commit eb2a89c). This server still reads its credentials only from the environment, so a Claude Desktop / Claude Code config file has to carry the password in clear text.
Current state
src/services/transkribus.ts:9-16 reads TRANSKRIBUS_USER, TRANSKRIBUS_PASSWORD and TRANSKRIBUS_SESSION_ID directly from `process.env
Read the thread · 2026-07-27 · open · 0 comments
ensureSession() has no in-flight login de-duplication
ensureSession() in src/services/transkribus.ts has no promise memo, so N concurrent cold-start tool calls can each fire a /auth/login. Pre-existing; low impact now that #30 (PR #37) removed the recursion, but concurrent first-calls still mean redundant logins.
Fix: memoize the in-flight login promise (store the pending login() promise, await it for concurrent callers, clear on settle). Noted while fixing #30.
Read the thread · 2026-07-17 · open · 0 comments
Feature ideas from audit: job_wait, doc_get_plaintext, export download URL, page images as MCP image content
Curated from the audit's gap analysis. Complements (does not depend on) the deferred Metagrapho work in #22.
Proposals
- transkribus_job_wait — poll a job until FINISHED/FAILED with timeout (small) — Every substantive action (HTR/OCR/LA recognition, training, export, doc duplication, ingest) returns a jobId and completes asynchronously; today an LLM client must call transkribus_job_get in a manual loop, burning turns and context on 'still RUNNING' JSON. A single tool that polls GET /j
Read the thread · 2026-07-03 · open · 0 comments
Cleanup & test hardening: dead src/types/, smoke-test entry lists, redaction-test extension
Findings
src/types/ directory (7 files, 142 lines) is dead code — zero imports anywhere in the repo
transkribus-mcp-server/src/types/common.ts:1 — low refactor
Evidence: export interface TranskribusSession { sessionId: string; userId: number; ... } — grep for types/<name>.js and any ../types/ import across src/ returns nothing outside src/types/ itself. All 7 modules (collections, common, credits, jobs, models, recognition, user) are unreferenced; tools type responses a
Read the thread · 2026-07-03 · open · 0 comments
transkribus_auth_login sends username/password/OTP as URL query parameters
Flagged independently by both the security and the bugs finder: credentials land in server/proxy logs AND the endpoint (JAX-RS @FormParam) won't read them from the query string, so the tool both leaks and fails. The safe form-encoded login() already exists in services/transkribus.ts.
Findings
transkribus_auth_login sends username/password/OTP as URL query params instead of form body
transkribus-mcp-server/src/tools/auth.ts:52 — medium bug
Evidence: Tool: `transkribusReques
Read the thread · 2026-07-03 · closed · 0 comments
Document ingestion is broken end-to-end: 8 tools send JSON where the API expects multipart/XML/CSV/query params
Every ingestion path was verified against the live TrpServer WADL / official Java client: as shipped there is no working way to get a document into Transkribus through this server. The multipart helper transkribusUpload() already exists but is dead code. Decision needed per tool: implement real transport or remove the tool (a tool that can never succeed is worse than a missing one).
Findings
transkribus_upload_page cannot upload a page image — sends JSON to a multipart/form-data e
Read the thread · 2026-07-03 · open · 1 comment
Redact secrets from AxiosError request/response BODIES (config.data password + response.data session echo)
Follow-up to #23 / PR #25. The cookie sanitizer (sanitizeAxiosError) added in #23 strips secrets from the cause-chain structure — request Cookie / response Set-Cookie / authorization / proxy-authorization headers, config.auth / proxy.auth, the raw request._header block, and an object cause. It deliberately does not touch request/response bodies, to preserve request-body debuggability for normal requests. Two distinct body-secret vectors remain:
1. Login passwor
Read the thread · 2026-06-22 · closed · 1 comment
Harden wrapAxiosError: strip request._header + cause; assert depth:null & toJSON leak-free
src/services/transkribus.ts wrapAxiosError chains { cause: err } and is documented as safe for default-depth util.inspect — but it does not actively strip secrets, so it's below the fleet strong-sanitizer bar now set by lexware #51 (sanitizeAxiosError, released v3.2.1) and hetzner #44. The secret here is the session cookie JSESSIONID, not a bearer token: the request interceptor sets config.headers['Cookie'] = 'JSESSIONID=' + sessionId, so on a thrown AxiosError that c
Read the thread · 2026-06-20 · closed · 0 comments
The remaining reports are on the project's issue tracker.