dbx-mcp-server
Version:
A Model Context Protocol server for Dropbox integration with AI-powered PDF analysis, multi-directory indexing, and parallel processing
129 lines • 4.87 kB
JavaScript
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { ResourceHandler } from '../resource/resource-handler.js';
export class ResourcePromptHandler {
constructor() {
this.resourceHandler = new ResourceHandler();
}
replaceArguments(text, args) {
return text.replace(/\{(\w+)\}/g, (match, key) => {
if (args[key] === undefined) {
throw new McpError(ErrorCode.InvalidParams, `Missing argument: ${key}`);
}
return String(args[key]);
});
}
async resolveResourceUris(resources, args) {
const resolveUris = (refs) => {
if (!refs || !Array.isArray(refs))
return;
for (const ref of refs) {
ref.uri = this.replaceArguments(ref.uri, args);
}
};
if (resources.inline)
resolveUris(resources.inline);
if (resources.attachments)
resolveUris(resources.attachments);
if (resources.collections)
resolveUris(resources.collections);
}
async processPrompt(prompt, args) {
try {
// Validate required arguments
if (prompt.arguments) {
for (const arg of prompt.arguments) {
if (arg.required && args[arg.name] === undefined) {
throw new McpError(ErrorCode.InvalidParams, `Missing required argument: ${arg.name}`);
}
}
}
// Clone the prompt to avoid modifying the original
const processedPrompt = JSON.parse(JSON.stringify(prompt));
// Replace argument placeholders in messages
if (Array.isArray(processedPrompt.messages)) {
processedPrompt.messages = processedPrompt.messages.map(msg => ({
...msg,
content: {
...msg.content,
text: typeof msg.content === 'object' && msg.content && 'text' in msg.content
? this.replaceArguments(msg.content.text, args)
: ''
}
}));
}
// Process resources if present
if (processedPrompt.resources) {
// Replace argument placeholders in resource URIs
await this.resolveResourceUris(processedPrompt.resources, args);
// Process and load resources
await this.resourceHandler.processPromptResources(processedPrompt.resources);
}
return processedPrompt;
}
catch (error) {
throw new McpError(ErrorCode.InternalError, `Failed to process prompt: ${error.message}`);
}
}
// Helper method to process a folder review prompt
async processFolderReview(path, fileTypes) {
const args = {
path,
fileTypes: fileTypes || '*'
};
// If specific file types are provided, update the collection options
if (fileTypes) {
const extensions = fileTypes.split(',').map(ext => ext.trim());
args.fileTypes = extensions.join(', ');
}
return this.processPrompt({
name: 'folder_review',
description: 'Review contents of a folder',
messages: [
{
role: 'assistant',
content: {
type: 'text',
text: 'Analyzing folder: {path}\nFile types: {fileTypes}\n\n',
resources: []
}
}
],
resources: {
collections: [{
type: 'collection',
uri: 'dbx://{path}'
}]
}
}, args);
}
// Helper method to process a file comparison prompt
async processFileComparison(file1, file2) {
return this.processPrompt({
name: 'file_comparison',
description: 'Compare two files',
messages: [
{
role: 'assistant',
content: {
type: 'text',
text: 'Comparing files:\n1. {file1}\n2. {file2}\n\n',
resources: []
}
}
],
resources: {
inline: [
{
type: 'inline',
uri: 'dbx://{file1}'
},
{
type: 'inline',
uri: 'dbx://{file2}'
}
]
}
}, { file1, file2 });
}
}
//# sourceMappingURL=resource-prompt-handler.js.map