{"record":{"id":"1bda1236129aaefa","repo":"amruthpillai/reactive-resume","slug":"unauthorized","errorCode":null,"errorMessage":"Unauthorized","messagePattern":"Unauthorized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/mcp/src/tools.ts","lineNumber":167,"sourceCode":"\t\tT.getResumeAnalysis,\n\t\tTOOL_META[T.getResumeAnalysis],\n\t\twithErrorHandling(\"getting resume analysis\", async ({ id }: { id: string }) => {\n\t\t\tconst analysis = await client.resume.analysis.getById({ id });\n\n\t\t\tif (!analysis) return text(\"No saved analysis for this resume yet.\");\n\n\t\t\treturn text(JSON.stringify(analysis, null, 2));\n\t\t}),\n\t);\n\n\t// ── Download Resume PDF ────────��──────────────────────────────\n\tserver.registerTool(\n\t\tT.downloadResumePdf,\n\t\tTOOL_META[T.downloadResumePdf],\n\t\twithErrorHandling(\"creating PDF download URL\", async ({ id }: { id: string }) => {\n\t\t\tconst resume = await client.resume.getById({ id });\n\t\t\tconst user = await resolveUserFromRequestHeaders(requestHeaders);\n\t\t\tif (!user) throw new Error(\"Unauthorized\");\n\n\t\t\tconst signedUrl = createResumePdfDownloadUrl({ resumeId: id, userId: user.id });\n\n\t\t\treturn text(\n\t\t\t\tJSON.stringify(\n\t\t\t\t\t{\n\t\t\t\t\t\tresumeId: id,\n\t\t\t\t\t\tname: resume.name,\n\t\t\t\t\t\tdownloadUrl: signedUrl.url,\n\t\t\t\t\t\texpiresAt: signedUrl.expiresAt,\n\t\t\t\t\t\texpiresInSeconds: signedUrl.expiresInSeconds,\n\t\t\t\t\t\tcontentType: \"application/pdf\",\n\t\t\t\t\t},\n\t\t\t\t\tnull,\n\t\t\t\t\t2,\n\t\t\t\t),\n\t\t\t);\n\t\t}),","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/amruthpillai/reactive-resume/blob/3a5b12e2a40374a9571988701fcb75c5a1831c42/packages/mcp/src/tools.ts#L149-L185","documentation":"downloadResumePdf MCP tool resolves the caller from request headers via resolveUserFromRequestHeaders; if that returns null (no/invalid session) it throws a generic Error 'Unauthorized'. The tool does not rely on the transport's auth layer for this check — it explicitly verifies the user before signing the PDF download URL.","triggerScenarios":"Calling the MCP tool without a valid session cookie or Authorization header; an expired session; a transport that strips headers; the MCP server mounted without proxied auth headers.","commonSituations":"An MCP client (Claude/CLI/IDE) that didn't authenticate; a custom integration that forgot to forward credentials; session expired between listing resumes and requesting the download URL.","solutions":["Authenticate the MCP session (sign in via the web app and reuse the session, or pass a valid bearer token) before invoking downloadResumePdf.","Ensure the MCP client forwards Cookie/Authorization headers to the server transport.","On 401/Unauthorized, prompt re-authentication rather than retrying blindly.","Verify the authBaseUrl and cookie domain match between the MCP endpoint and the auth session."],"exampleFix":"// before: no auth header\nawait mcp.tools.call('downloadResumePdf', { id });\n// after: forward session\nawait mcp.tools.call('downloadResumePdf', { id }, { headers: { cookie: sessionCookie } });","handlingStrategy":"try-catch","validationCode":"// ensure the MCP client is authenticated before calling downloadResumePdf\nif (!await hasValidSession()) await promptReauth();","typeGuard":"function isUnauthorized(e: unknown): boolean {\n  return e instanceof Error && /unauthorized/i.test(e.message);\n}","tryCatchPattern":"try { await mcp.tools.call('downloadResumePdf', { id }); }\ncatch (e) {\n  if (isUnauthorized(e)) { await promptReauth(); return; }\n  throw e;\n}","preventionTips":["Forward Cookie/Authorization headers through the MCP transport.","Re-authenticate on session expiry instead of retrying.","Verify authBaseUrl and cookie domain alignment."],"tags":["mcp","auth","authorization","session","pdf"],"backgroundTag":null,"analyzedSha":"3a5b12e2a40374a9571988701fcb75c5a1831c42","analyzedAt":"2026-08-12T22:31:22.666Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}