Fix post_document: use Buffer instead of browser File API#55
Fix post_document: use Buffer instead of browser File API#55baruchiro merged 7 commits intobaruchiro:mainfrom
Conversation
The form-data npm package doesn't support browser File/Blob objects. postDocument was creating File from Buffer unnecessarily, causing the upload data to be serialized incorrectly. Pass Buffer directly to form-data with filename option, and stringify metadata values for proper multipart form encoding. https://claude.ai/code/session_01SyvNqE1R7m6LmSpkfMUiXz
…x7TEr Claude/fix post document action x7 t er
🦋 Changeset detectedLatest commit: 9fcdb74 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
📝 WalkthroughWalkthroughThe PaperlessAPI.postDocument signature changed from accepting a browser File to accepting a Buffer and a filename (postDocument(document: Buffer, filename: string, ...)). FormData now appends the document with an explicit filename. In the API implementation metadata values are stringified before appending; custom_fields are appended as strings (numbers coerced to strings). The post_document tool now validates base64 input, converts it to a Buffer, constructs metadata excluding undefined fields, passes filename separately, and its schema changes archive_serial_number to number. A changeset records these edits. Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Pull request overview
This pull request fixes the document upload functionality in the Paperless-NGX MCP server by replacing browser-specific File API usage with Node.js Buffer objects, improving server-side compatibility. The changes also add explicit type conversions for metadata fields when constructing FormData requests.
Changes:
- Modified
PaperlessAPI.postDocumentto accept Buffer and explicit filename instead of File object - Added String() conversions for all metadata fields appended to FormData for type consistency
- Updated
post_documenttool to pass raw Buffer and filename directly, removing unnecessary Blob/File intermediary conversions
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/api/PaperlessAPI.ts | Changed postDocument signature from File to Buffer+filename parameters, added explicit String() conversions for all FormData metadata fields |
| src/tools/documents.ts | Simplified document upload by passing Buffer and filename directly to API, removed Blob and File object creation |
| package-lock.json | Version bump from 0.3.0 to 0.4.0 |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/api/PaperlessAPI.ts (1)
129-138:⚠️ Potential issue | 🟠 Major
postDocumentis missing the requiredAccept: application/json; version=5header.The direct
axios.postcall at line 129 only includesAuthorizationand the form-data boundary headers. TheAccept: application/json; version=5header is absent, which violates the project guideline and may cause the Paperless API to respond with an unexpected content type or API version.🔧 Proposed fix
const response = await axios.post<string>( `${this.baseUrl}/api/documents/post_document/`, formData, { headers: { Authorization: `Token ${this.token}`, + Accept: "application/json; version=5", ...formData.getHeaders(), }, } );As per coding guidelines: "Include Accept: application/json; version=5 header in all API requests in src/api/PaperlessAPI.ts".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/api/PaperlessAPI.ts` around lines 129 - 138, The axios.post call inside postDocument is missing the required Accept header; update the request options for the call in method postDocument to include "Accept: application/json; version=5" alongside Authorization and the formData boundary headers (i.e., merge it into the headers object used with axios.post on `${this.baseUrl}/api/documents/post_document/` so the request sends Authorization: `Token ${this.token}`, Accept: application/json; version=5, and ...formData.getHeaders()).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/tools/documents.ts`:
- Around line 136-138: Validate and sanitize the incoming args.file and metadata
before calling api.postDocument: first, guard against invalid base64 by checking
args.file with a strict base64 validation (or attempt a safe decode+re-encode
roundtrip) and throw/return a clear error if it fails instead of calling
Buffer.from blindly (replace the Buffer.from(args.file, "base64") usage in the
post_document handler with this validation step); second, build a metadata
Record explicitly by copying only defined properties from the destructured
metadata (the const { file: _, filename, ...metadata } = args) into a new object
and cast/shape it to Record<string, string | string[] | number | number[]> so
undefined values are excluded before passing to api.postDocument(filename,
document, metadata).
---
Outside diff comments:
In `@src/api/PaperlessAPI.ts`:
- Around line 129-138: The axios.post call inside postDocument is missing the
required Accept header; update the request options for the call in method
postDocument to include "Accept: application/json; version=5" alongside
Authorization and the formData boundary headers (i.e., merge it into the headers
object used with axios.post on `${this.baseUrl}/api/documents/post_document/` so
the request sends Authorization: `Token ${this.token}`, Accept:
application/json; version=5, and ...formData.getHeaders()).
|
@copilot open a new pull request to apply changes based on the comments in this thread |
… input, and sanitize metadata - Change archive_serial_number schema from z.string() to z.number() to match the Paperless-ngx API spec (integer, 0–4294967295) - Add base64 regex validation before decoding the file buffer - Build metadata record explicitly, excluding undefined values - Add patch changeset Tested via `npm run inspect` (MCP Inspector) — worked like a charm. https://claude.ai/code/session_01SyvNqE1R7m6LmSpkfMUiXz
…x7TEr Harden post_document: fix archive_serial_number type, validate base64…
src/api/PaperlessAPI.ts
Outdated
| if (metadata.title) formData.append("title", String(metadata.title)); | ||
| if (metadata.created) formData.append("created", String(metadata.created)); | ||
| if (metadata.correspondent) | ||
| formData.append("correspondent", metadata.correspondent); | ||
| formData.append("correspondent", String(metadata.correspondent)); | ||
| if (metadata.document_type) | ||
| formData.append("document_type", metadata.document_type); | ||
| formData.append("document_type", String(metadata.document_type)); | ||
| if (metadata.storage_path) | ||
| formData.append("storage_path", metadata.storage_path); | ||
| formData.append("storage_path", String(metadata.storage_path)); | ||
| if (metadata.tags) { | ||
| (metadata.tags as string[]).forEach((tag) => | ||
| formData.append("tags", tag) | ||
| (metadata.tags as number[]).forEach((tag) => | ||
| formData.append("tags", String(tag)) |
There was a problem hiding this comment.
Is formData required to be a string value?
Fair enough! Co-authored-by: Baruch Odem (Rothkoff) <baruchiro@gmail.com>
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/api/PaperlessAPI.ts (1)
129-138:⚠️ Potential issue | 🟠 MajorAdd the required
Accept: application/json; version=5header.Every API call in this file must include
Accept: application/json; version=5, butpostDocumentbypasses therequest()wrapper and its directaxios.postonly sendsAuthorization+ form-data headers, omittingAccept.🛠️ Proposed fix
{ headers: { Authorization: `Token ${this.token}`, + Accept: "application/json; version=5", ...formData.getHeaders(), }, }As per coding guidelines: "Include Accept: application/json; version=5 header in all API requests in src/api/PaperlessAPI.ts".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/api/PaperlessAPI.ts` around lines 129 - 138, The postDocument call is missing the required Accept header; update the headers passed to the axios.post in the postDocument (the block constructing response = await axios.post<string>(...)) to include "Accept": "application/json; version=5" alongside Authorization and formData.getHeaders() so the request matches other API calls that use the request() wrapper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/api/PaperlessAPI.ts`:
- Around line 117-122: The current guard in PaperlessAPI (the block that appends
"archive_serial_number" to formData) uses a truthy check on
metadata.archive_serial_number which drops 0; change the conditional to an
explicit nullish check (e.g., check metadata.archive_serial_number !== null &&
metadata.archive_serial_number !== undefined or use
metadata.archive_serial_number ?? undefined) so that numeric zero is preserved
before calling formData.append("archive_serial_number",
String(metadata.archive_serial_number)).
---
Outside diff comments:
In `@src/api/PaperlessAPI.ts`:
- Around line 129-138: The postDocument call is missing the required Accept
header; update the headers passed to the axios.post in the postDocument (the
block constructing response = await axios.post<string>(...)) to include
"Accept": "application/json; version=5" alongside Authorization and
formData.getHeaders() so the request matches other API calls that use the
request() wrapper.
Summary
post_documentaction failing in Node.js environments by replacing the browserFileAPI withBufferforFormDatafile uploadsFormDataDetails
The
post_documenttool was usingnew File()which is a browser-only API not available in Node.js runtimes. This caused the action to fail when called through the MCP server. The fix usesBufferwith a filename option instead, which is compatible with Node.jsFormData.Testing
Tested manually using
npm run inspect(MCP Inspector) — uploaded a document viapost_documentand it worked like a charm.Summary by CodeRabbit
Bug Fixes
Chores