Skip to main content
Glama

Dropbox MCP Server

resource-system.test.ts11.2 kB
import { describe, it, expect, beforeEach, jest, beforeAll, afterAll } from '@jest/globals'; import { setupTestLogger, restoreConsole } from './utils/test-logger.js'; import { testResultsTracker } from './utils/test-results-tracker.js'; import { ResourceHandler } from '../src/resource/resource-handler.js'; import { ResourceResolver } from '../src/resource/resource-resolver.js'; import { ResourcePromptHandler } from '../src/prompt-handlers/resource-prompt-handler.js'; import { fileReviewPrompt, fileDetailPrompt, fileComparePrompt } from '../src/prompt-definitions/file-review-prompt.js'; import { McpError } from '@modelcontextprotocol/sdk/types.js'; // Mock the Dropbox API functions jest.mock('../src/dbx-api.js', () => ({ downloadFile: jest.fn(), listFiles: jest.fn(), getFileMetadata: jest.fn() })); describe('Resource System', () => { const FILE_NAME = 'resource-system.test.ts'; let resourceHandler: ResourceHandler; let resourceResolver: ResourceResolver; let promptHandler: ResourcePromptHandler; beforeAll(() => { // Set up the custom logger to suppress stack traces setupTestLogger(); }); afterAll(() => { // Restore original console methods restoreConsole(); }); beforeEach(() => { resourceHandler = new ResourceHandler(); resourceResolver = new ResourceResolver(); promptHandler = new ResourcePromptHandler(); jest.clearAllMocks(); const testName = expect.getState().currentTestName; if (testName) { testResultsTracker.registerTest(testName, FILE_NAME); } }); afterEach(() => { const testName = expect.getState().currentTestName; if (testName) { const isPassed = !expect.getState().currentTestName?.includes('failed'); if (isPassed) { testResultsTracker.markTestPassed(testName, FILE_NAME); } } }); describe('ResourceResolver', () => { it('should resolve a single file resource', async () => { const mockContent = { content: [{ text: 'file content' }] }; const mockMetadata = { content: [{ text: JSON.stringify({ size: 100, client_modified: '2025-03-04T00:00:00Z' })}]}; require('../src/dbx-api.js').downloadFile.mockResolvedValue(mockContent); require('../src/dbx-api.js').getFileMetadata.mockResolvedValue(mockMetadata); const result = await resourceResolver.resolveResource('dbx://test.txt'); expect(result.content).toBe('file content'); expect(result.mimeType).toBe('text/plain'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { uri: 'dbx://test.txt', mimeType: result.mimeType }); }); it('should handle binary files with base64 encoding', async () => { const mockContent = { content: [{ text: 'base64data', encoding: 'base64' }] }; const mockMetadata = { content: [{ text: JSON.stringify({ size: 100, client_modified: '2025-03-04T00:00:00Z' })}]}; require('../src/dbx-api.js').downloadFile.mockResolvedValue(mockContent); require('../src/dbx-api.js').getFileMetadata.mockResolvedValue(mockMetadata); const result = await resourceResolver.resolveResource('dbx://image.png', { encoding: 'base64' }); expect(result.encoding).toBe('base64'); expect(result.mimeType).toBe('image/png'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { uri: 'dbx://image.png', encoding: result.encoding, mimeType: result.mimeType }); }); it('should resolve a collection of resources', async () => { const mockFiles = { content: [{ text: JSON.stringify([ { '.tag': 'file', name: 'test1.txt', path_display: '/test1.txt' }, { '.tag': 'file', name: 'test2.txt', path_display: '/test2.txt' } ])}]}; require('../src/dbx-api.js').listFiles.mockResolvedValue(mockFiles); const results = await resourceResolver.resolveCollection('dbx://folder'); expect(results).toHaveLength(2); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { uri: 'dbx://folder', resultCount: results.length }); }); it('should handle recursive folder resolution', async () => { const mockFiles = { content: [{ text: JSON.stringify([ { '.tag': 'folder', name: 'subfolder', path_display: '/folder/subfolder' }, { '.tag': 'file', name: 'test.txt', path_display: '/folder/test.txt' } ])}]}; const mockSubfolderFiles = { content: [{ text: JSON.stringify([ { '.tag': 'file', name: 'subtest.txt', path_display: '/folder/subfolder/subtest.txt' } ])}]}; require('../src/dbx-api.js').listFiles .mockResolvedValueOnce(mockFiles) .mockResolvedValueOnce(mockSubfolderFiles); const results = await resourceResolver.resolveCollection('dbx://folder', { recursive: true }); expect(results.some(r => r.uri.includes('subfolder'))).toBe(true); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { uri: 'dbx://folder', recursive: true, resultCount: results.length, hasSubfolderResults: results.some(r => r.uri.includes('subfolder')) }); }); }); describe('ResourceHandler', () => { it('should list resources with proper type', async () => { const mockFiles = { content: [{ text: JSON.stringify([ { '.tag': 'file', name: 'test.txt', path_display: '/test.txt' } ])}]}; require('../src/dbx-api.js').listFiles.mockResolvedValue(mockFiles); const results = await resourceHandler.listResources(''); expect(results[0].type).toBe('inline'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { path: '', resultCount: results.length, resourceType: results[0].type }); }); it('should handle binary resources', async () => { const mockContent = { content: [{ text: 'base64data', encoding: 'base64' }] }; const mockMetadata = { content: [{ text: JSON.stringify({ size: 100, client_modified: '2025-03-04T00:00:00Z' })}]}; require('../src/dbx-api.js').downloadFile.mockResolvedValue(mockContent); require('../src/dbx-api.js').getFileMetadata.mockResolvedValue(mockMetadata); const result = await resourceHandler.readBinaryResource('dbx://image.png'); expect(result.encoding).toBe('base64'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { uri: 'dbx://image.png', encoding: result.encoding }); }); }); describe('ResourcePromptHandler', () => { it('should process prompts with resource references', async () => { const mockContent = { content: [{ text: 'file content' }] }; const mockMetadata = { content: [{ text: JSON.stringify({ size: 100, client_modified: '2025-03-04T00:00:00Z' })}]}; require('../src/dbx-api.js').downloadFile.mockResolvedValue(mockContent); require('../src/dbx-api.js').getFileMetadata.mockResolvedValue(mockMetadata); const result = await promptHandler.processPrompt(fileDetailPrompt, { path: '/test.txt', analysis: 'Test file analysis' }); expect(result.resources?.attachments?.[0].content).toBeDefined(); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { path: '/test.txt', hasAttachments: (result.resources?.attachments?.length ?? 0) > 0 }); }); it('should handle file comparison prompts', async () => { const mockContent1 = { content: [{ text: 'content1' }] }; const mockContent2 = { content: [{ text: 'content2' }] }; const mockMetadata = { content: [{ text: JSON.stringify({ size: 100, client_modified: '2025-03-04T00:00:00Z' })}]}; require('../src/dbx-api.js').downloadFile .mockResolvedValueOnce(mockContent1) .mockResolvedValueOnce(mockContent2); require('../src/dbx-api.js').getFileMetadata.mockResolvedValue(mockMetadata); const result = await promptHandler.processFileComparison('/file1.txt', '/file2.txt'); expect(result.resources?.inline).toHaveLength(2); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { file1: '/file1.txt', file2: '/file2.txt', inlineResourceCount: result.resources?.inline?.length }); }); it('should validate required arguments', async () => { await expect(promptHandler.processPrompt(fileDetailPrompt, {})) .rejects .toThrow('Missing required argument: path'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { validationError: 'Missing required argument: path' }); }); it('should handle folder review with file type filtering', async () => { const mockFiles = { content: [{ text: JSON.stringify([ { '.tag': 'file', name: 'test.ts', path_display: '/test.ts' }, { '.tag': 'file', name: 'test.js', path_display: '/test.js' }, { '.tag': 'file', name: 'test.txt', path_display: '/test.txt' } ])}]}; require('../src/dbx-api.js').listFiles.mockResolvedValue(mockFiles); const result = await promptHandler.processFolderReview('/folder', 'ts,js'); expect(result.resources?.collections).toBeDefined(); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { folder: '/folder', fileTypes: 'ts,js', hasCollections: result.resources?.collections !== undefined }); }); }); describe('Error Handling', () => { it('should handle invalid URI format', async () => { await expect(resourceResolver.resolveResource('invalid://test.txt')) .rejects .toThrow('Invalid URI format'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { invalidUri: 'invalid://test.txt', errorType: 'Invalid URI format' }); }); it('should handle missing resources', async () => { require('../src/dbx-api.js').downloadFile.mockRejectedValue(new Error('path not found')); await expect(resourceResolver.resolveResource('dbx://missing.txt')) .rejects .toThrow('Failed to get file content'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { missingUri: 'dbx://missing.txt', errorType: 'Failed to get file content' }); }); it('should handle API errors gracefully', async () => { require('../src/dbx-api.js').listFiles.mockRejectedValue(new Error('API error')); await expect(resourceHandler.listResources('')) .rejects .toThrow('Failed to list resources'); testResultsTracker.addTestDetails(expect.getState().currentTestName!, FILE_NAME, { path: '', errorType: 'Failed to list resources' }); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Albiemark/dbx-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server