Skip to content

Commit 9972ac7

Browse files
Copilotbaruchiro
andauthored
Add get_document_thumbnail tool for retrieving document previews (#53)
Adds support for retrieving document thumbnail previews from Paperless-NGX's `/api/documents/{id}/thumb/` endpoint. ## Changes - **API Client** (`PaperlessAPI.ts`): Added `getThumbnail(id)` method using axios with `responseType: "arraybuffer"` to fetch WebP thumbnails - **MCP Tool** (`documents.ts`): Added `get_document_thumbnail` tool that returns base64-encoded WebP image as MCP resource (consistent with `download_document` pattern) - **Documentation**: Updated `manifest.json` and `README.md` with new tool - **TypeScript Typing**: Added explicit return type `Promise<AxiosResponse<ArrayBuffer>>` and generic type parameter `axios.get<ArrayBuffer>` to both `getThumbnail` and `downloadDocument` methods for improved type safety - **Changeset**: Created changeset for version management (minor bump) ## Usage ```typescript get_document_thumbnail({ id: 123 }) // Returns: base64-encoded WebP image as MCP resource with mimeType "image/webp" ``` The tool follows MCP conventions by returning the image binary directly as a base64-encoded resource rather than a URL, enabling immediate consumption by AI assistants and client applications. <!-- START COPILOT ORIGINAL PROMPT --> <details> <summary>Original prompt</summary> > > ---- > > *This section details on the original issue you should resolve* > > <issue_title>Feature: Add tool to get document thumbnail (image preview)</issue_title> > <issue_description>- Add a tool to MCP to retrieve a document thumbnail (image preview) > - Use the `/api/documents/{id}/thumb/` endpoint from paperless-ngx, which returns a WebP image > - API should accept a document ID and either: > - Return the image binary as a base64-encoded resource directly (common pattern in MCP tools, like `download_document`) > - Or, optionally, allow returning a link to the image in cases where direct serving isn't possible or secure > - Expected usage: enable chat-based or API client applications to request and display document thumbnails efficiently > - Consider always adding the link to the document response, no harm in adding it. > - Reference: similar implementations for `download_document` return the resource in the MCP response, not just a URL > - MCP documentation and practice: tools for files and images return the binary (as base64-encoded `resource.blob` with `mimeType`), not just a link, for direct consumption > > Acceptance: > - New tool for thumbnail retrieval is listed under Document Operations > - Returns the image as a base64-encoded resource (with proper mime type) > - API docs/README are updated > - Include tests for typical and edge cases > - Ensure permission and error handling are robust</issue_description> > > ## Comments on the Issue (you are @copilot in this section) > > <comments> > </comments> > </details> <!-- START COPILOT CODING AGENT SUFFIX --> - Fixes #52 <!-- START COPILOT CODING AGENT TIPS --> --- ✨ Let Copilot coding agent [set things up for you](https://github.com/baruchiro/paperless-mcp/issues/new?title=✨+Set+up+Copilot+instructions&body=Configure%20instructions%20for%20this%20repository%20as%20documented%20in%20%5BBest%20practices%20for%20Copilot%20coding%20agent%20in%20your%20repository%5D%28https://gh.io/copilot-coding-agent-tips%29%2E%0A%0A%3COnboard%20this%20repo%3E&assignees=copilot) — coding agent works faster and does higher quality work when set up for your repo. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added `get_document_thumbnail` tool to retrieve document preview images by document ID, returning base64-encoded WebP thumbnail images. * Updated API documentation with examples and usage instructions for the new thumbnail retrieval functionality. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: baruchiro <17686879+baruchiro@users.noreply.github.com>
1 parent e2ac0f6 commit 9972ac7

File tree

5 files changed

+64
-3
lines changed

5 files changed

+64
-3
lines changed

.changeset/shy-pianos-ask.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@baruchiro/paperless-mcp": minor
3+
---
4+
5+
Add get_document_thumbnail tool for retrieving document preview images

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,18 @@ download_document({
128128
})
129129
```
130130

131+
#### get_document_thumbnail
132+
Get a document thumbnail (image preview) by ID. Returns the thumbnail as a base64-encoded WebP image resource.
133+
134+
Parameters:
135+
- id: Document ID
136+
137+
```typescript
138+
get_document_thumbnail({
139+
id: 123
140+
})
141+
```
142+
131143
#### bulk_edit_documents
132144
Perform bulk operations on multiple documents.
133145

manifest.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
"name": "download_document",
4141
"description": "Download a document file by ID."
4242
},
43+
{
44+
"name": "get_document_thumbnail",
45+
"description": "Get a document thumbnail (image preview) by ID."
46+
},
4347
{
4448
"name": "bulk_edit_documents",
4549
"description": "Perform bulk operations on multiple documents."

src/api/PaperlessAPI.ts

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import axios from "axios";
1+
import axios, { AxiosResponse } from "axios";
22
import FormData from "form-data";
33
import {
44
BulkEditDocumentsResult,
@@ -162,9 +162,12 @@ export class PaperlessAPI {
162162
return response;
163163
}
164164

165-
async downloadDocument(id: number, asOriginal = false) {
165+
async downloadDocument(
166+
id: number,
167+
asOriginal = false
168+
): Promise<AxiosResponse<ArrayBuffer>> {
166169
const query = asOriginal ? "?original=true" : "";
167-
const response = await axios.get(
170+
const response = await axios.get<ArrayBuffer>(
168171
`${this.baseUrl}/api/documents/${id}/download/${query}`,
169172
{
170173
headers: {
@@ -176,6 +179,19 @@ export class PaperlessAPI {
176179
return response;
177180
}
178181

182+
async getThumbnail(id: number): Promise<AxiosResponse<ArrayBuffer>> {
183+
const response = await axios.get<ArrayBuffer>(
184+
`${this.baseUrl}/api/documents/${id}/thumb/`,
185+
{
186+
headers: {
187+
Authorization: `Token ${this.token}`,
188+
},
189+
responseType: "arraybuffer",
190+
}
191+
);
192+
return response;
193+
}
194+
179195
// Tag operations
180196
async getTags(): Promise<GetTagsResponse> {
181197
return this.request<GetTagsResponse>("/tags/");

src/tools/documents.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,30 @@ export function registerDocumentTools(server: McpServer, api: PaperlessAPI) {
276276
})
277277
);
278278

279+
server.tool(
280+
"get_document_thumbnail",
281+
"Get a document thumbnail (image preview) by ID. Returns the thumbnail as a base64-encoded WebP image resource.",
282+
{
283+
id: z.number(),
284+
},
285+
withErrorHandling(async (args, extra) => {
286+
if (!api) throw new Error("Please configure API connection first");
287+
const response = await api.getThumbnail(args.id);
288+
return {
289+
content: [
290+
{
291+
type: "resource",
292+
resource: {
293+
uri: `document-${args.id}-thumb.webp`,
294+
blob: Buffer.from(response.data).toString("base64"),
295+
mimeType: "image/webp",
296+
},
297+
},
298+
],
299+
};
300+
})
301+
);
302+
279303
server.tool(
280304
"update_document",
281305
"Update a specific document with new values. This tool allows you to modify any document field including title, correspondent, document type, storage path, tags, custom fields, and more. Only the fields you specify will be updated.",

0 commit comments

Comments
 (0)