dbx-mcp-server
Version:
A Model Context Protocol server for Dropbox integration with AI-powered PDF analysis, multi-directory indexing, and parallel processing
223 lines • 8.76 kB
JavaScript
import { getDropboxClient, getDropboxClientForPath, formatDropboxPath } from './client-factory.js';
import { handleDropboxError } from './error-handler.js';
import { getCachedTeamConfig, shouldUseTeamSpace } from './team-config.js';
// File manipulation operations
export async function copyItem(fromPath, toPath) {
try {
// Use team space if either path suggests it
const teamConfig = await getCachedTeamConfig();
const useTeamSpace = shouldUseTeamSpace(fromPath, teamConfig) || shouldUseTeamSpace(toPath, teamConfig);
const client = await getDropboxClient({ useTeamSpace });
await client.filesCopyV2({
from_path: formatDropboxPath(fromPath),
to_path: formatDropboxPath(toPath),
allow_shared_folder: true,
autorename: false,
allow_ownership_transfer: false,
});
return {
content: [{
type: 'text',
text: `Copied from ${fromPath} to ${toPath}`,
}],
};
}
catch (error) {
handleDropboxError(error);
}
}
export async function moveItem(fromPath, toPath) {
try {
// Use team space if either path suggests it
const teamConfig = await getCachedTeamConfig();
const useTeamSpace = shouldUseTeamSpace(fromPath, teamConfig) || shouldUseTeamSpace(toPath, teamConfig);
const client = await getDropboxClient({ useTeamSpace });
await client.filesMoveV2({
from_path: formatDropboxPath(fromPath),
to_path: formatDropboxPath(toPath),
allow_shared_folder: true,
autorename: false,
allow_ownership_transfer: false,
});
return {
content: [{
type: 'text',
text: `Moved from ${fromPath} to ${toPath}`,
}],
};
}
catch (error) {
handleDropboxError(error);
}
}
export async function getSharingLink(path) {
try {
const client = await getDropboxClientForPath(path);
try {
const response = await client.sharingCreateSharedLinkWithSettings({
path: formatDropboxPath(path),
settings: {
requested_visibility: { '.tag': 'public' },
audience: { '.tag': 'public' },
access: { '.tag': 'viewer' },
},
});
return {
content: [{
type: 'text',
text: JSON.stringify({
url: response.result.url,
path: response.result.path_lower,
visibility: response.result.link_permissions?.resolved_visibility?.['.tag'] || 'unknown',
}, null, 2),
}],
};
}
catch (error) {
// If sharing failed, try to get existing links
if (error?.error?.error_summary?.includes('shared_link_already_exists')) {
const linksResponse = await client.sharingListSharedLinks({
path: formatDropboxPath(path),
});
const existingLink = linksResponse.result.links?.[0];
if (existingLink) {
return {
content: [{
type: 'text',
text: JSON.stringify({
url: existingLink.url,
path: existingLink.path_lower,
visibility: existingLink.link_permissions?.resolved_visibility?.['.tag'] || 'unknown',
note: 'Using existing shared link'
}, null, 2),
}],
};
}
}
throw error;
}
}
catch (error) {
handleDropboxError(error);
}
}
// Helper function to categorize files
function categorizeFile(metadata) {
const name = metadata.name?.toLowerCase() || '';
if (metadata['.tag'] === 'folder') {
return 'folder';
}
const imageExtensions = ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.svg', '.webp'];
const documentExtensions = ['.doc', '.docx', '.txt', '.rtf', '.odt'];
const pdfExtensions = ['.pdf'];
const spreadsheetExtensions = ['.xls', '.xlsx', '.csv', '.ods'];
const presentationExtensions = ['.ppt', '.pptx', '.odp'];
const audioExtensions = ['.mp3', '.wav', '.flac', '.aac', '.ogg'];
const videoExtensions = ['.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv'];
if (imageExtensions.some(ext => name.endsWith(ext))) {
return 'image';
}
if (documentExtensions.some(ext => name.endsWith(ext))) {
return 'document';
}
if (pdfExtensions.some(ext => name.endsWith(ext))) {
return 'pdf';
}
if (spreadsheetExtensions.some(ext => name.endsWith(ext))) {
return 'spreadsheet';
}
if (presentationExtensions.some(ext => name.endsWith(ext))) {
return 'presentation';
}
if (audioExtensions.some(ext => name.endsWith(ext))) {
return 'audio';
}
if (videoExtensions.some(ext => name.endsWith(ext))) {
return 'video';
}
return 'other';
}
export async function searchFiles(options) {
try {
const client = await getDropboxClientForPath(options.path || '');
const response = await client.filesSearchV2({
query: options.query,
options: {
path: formatDropboxPath(options.path || ''),
max_results: Math.min(Math.max(1, options.maxResults || 20), 1000),
file_status: { '.tag': 'active' },
filename_only: !options.includeContentMatch,
},
match_field_options: {
include_highlights: true,
},
});
let matches = response.result.matches
.map(match => ({
metadata: match.metadata.metadata,
match_type: match.match_type,
highlights: match.highlight_spans,
}))
.filter(match => {
// Apply filters
const metadata = match.metadata;
// File extension filter
if (options.fileExtensions && options.fileExtensions.length > 0) {
const fileName = metadata.name?.toLowerCase() || '';
const hasMatchingExt = options.fileExtensions.some(ext => fileName.endsWith(ext.toLowerCase()));
if (!hasMatchingExt)
return false;
}
// File category filter
if (options.fileCategories && options.fileCategories.length > 0) {
const category = categorizeFile(metadata);
if (!options.fileCategories.includes(category))
return false;
}
// Date range filter
if (options.dateRange && metadata.server_modified) {
const modifiedDate = new Date(metadata.server_modified);
const startDate = new Date(options.dateRange.start);
const endDate = new Date(options.dateRange.end);
if (modifiedDate < startDate || modifiedDate > endDate) {
return false;
}
}
return true;
});
// Sort results
if (options.sortBy) {
matches.sort((a, b) => {
let aValue, bValue;
switch (options.sortBy) {
case 'last_modified_time':
aValue = new Date(a.metadata.server_modified || 0).getTime();
bValue = new Date(b.metadata.server_modified || 0).getTime();
break;
case 'file_size':
aValue = a.metadata.size || 0;
bValue = b.metadata.size || 0;
break;
default: // relevance
return 0; // Keep original order for relevance
}
return options.order === 'asc' ? aValue - bValue : bValue - aValue;
});
}
const results = {
query: options.query,
total_matches: matches.length,
matches: matches,
};
return {
content: [{
type: 'text',
text: JSON.stringify(results, null, 2),
}],
};
}
catch (error) {
handleDropboxError(error);
}
}
//# sourceMappingURL=advanced-operations.js.map