diff --git a/extensions/general/mcp-server/__tests__/list-inbox-items.test.ts b/extensions/general/mcp-server/__tests__/list-inbox-items.test.ts new file mode 100644 index 00000000..dbebdbd3 --- /dev/null +++ b/extensions/general/mcp-server/__tests__/list-inbox-items.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from 'vitest' +import { createQueuedMockSupabase } from '@/tests/helpers' +import { tools } from '../server' + +const tool = tools.find((candidate) => candidate.name === 'gnubok_list_inbox_items')! + +describe('gnubok_list_inbox_items', () => { + it('advertises file_name in its item output contract', () => { + const schema = tool.outputSchema as { + properties: { + items: { + items: { + properties: Record + required: string[] + } + } + } + } + + expect(schema.properties.items.items.properties.file_name).toEqual({ + type: ['string', 'null'], + description: 'Original document file name, or null when the inbox item has no document', + }) + expect(schema.properties.items.items.required).toContain('file_name') + }) + + it('joins the document and returns its file_name on each list row', async () => { + const { supabase, enqueue, findCall } = createQueuedMockSupabase() + enqueue({ + data: [ + { + id: 'inbox-1', + status: 'received', + source: 'upload', + created_at: '2026-07-31T12:00:00Z', + extracted_data: null, + matched_supplier_id: null, + matched_transaction_id: null, + created_supplier_invoice_id: null, + created_journal_entry_id: null, + email_from: null, + email_subject: null, + error_message: null, + document_attachments: [{ file_name: 'dooer-export-2026-07.pdf' }], + }, + { + id: 'inbox-2', + status: 'received', + source: 'email', + created_at: '2026-07-30T12:00:00Z', + extracted_data: null, + matched_supplier_id: null, + matched_transaction_id: null, + created_supplier_invoice_id: null, + created_journal_entry_id: null, + email_from: null, + email_subject: null, + error_message: null, + document_attachments: [], + }, + ], + error: null, + }) + + const result = (await tool.execute({}, 'company-1', 'user-1', supabase as never)) as { + items: Array<{ file_name: string | null }> + count: number + } + + const select = findCall('invoice_inbox_items', 'select')?.[0] + expect(select).toContain('document_attachments(file_name)') + expect(result.items.map((item) => item.file_name)).toEqual([ + 'dooer-export-2026-07.pdf', + null, + ]) + expect(result.count).toBe(2) + }) +}) diff --git a/extensions/general/mcp-server/server.ts b/extensions/general/mcp-server/server.ts index 9c96e9c0..f0034355 100644 --- a/extensions/general/mcp-server/server.ts +++ b/extensions/general/mcp-server/server.ts @@ -9159,7 +9159,7 @@ export const tools: McpTool[] = [ { name: 'gnubok_list_inbox_items', title: 'List Inbox Items', - description: 'List document inbox items. `processed` covers all terminal links (transaction, supplier invoice, journal entry); booked receipts count as done. unprocessed_only=true returns docs still needing handling.', + description: 'List document inbox items, including each original file_name. `processed` covers all terminal links (transaction, supplier invoice, journal entry); booked receipts count as done. unprocessed_only=true returns docs still needing handling.', inputSchema: { type: 'object', additionalProperties: false, @@ -9173,7 +9173,19 @@ export const tools: McpTool[] = [ type: 'object', additionalProperties: false, properties: { - items: { type: 'array', items: { type: 'object' } }, + items: { + type: 'array', + items: { + type: 'object', + properties: { + file_name: { + type: ['string', 'null'], + description: 'Original document file name, or null when the inbox item has no document', + }, + }, + required: ['file_name'], + }, + }, count: { type: 'number' }, }, required: ['items', 'count'], @@ -9191,7 +9203,11 @@ export const tools: McpTool[] = [ let query = supabase .from('invoice_inbox_items') - .select('id, status, source, created_at, extracted_data, matched_supplier_id, matched_transaction_id, created_supplier_invoice_id, created_journal_entry_id, email_from, email_subject, error_message') + .select(` + id, status, source, created_at, extracted_data, matched_supplier_id, + matched_transaction_id, created_supplier_invoice_id, created_journal_entry_id, + email_from, email_subject, error_message, document_attachments(file_name) + `) .eq('company_id', companyId) .order('created_at', { ascending: false }) // Fetch a wider window when filtering client-side so the limit @@ -9234,6 +9250,7 @@ export const tools: McpTool[] = [ status: item.status, source: item.source, created_at: item.created_at, + file_name: item.document_attachments?.[0]?.file_name ?? null, vendor_name: vendorName, amount, invoice_date: invoiceDate,