@grebyn/toolflow-mcp-server
Version:
MCP server for managing other MCP servers - discover, install, organize into bundles, and automate with workflows. Uses StreamableHTTP transport with dual OAuth/API key authentication.
134 lines (131 loc) • 6.93 kB
JavaScript
/**
* Edit Bundle Tool
* Edit an existing bundle's properties (name, description, config, tags)
*/
import { ApiClient } from '../../utils/api-client.js';
export const editBundleTool = {
name: 'edit_bundle',
description: 'Edit an existing bundle\'s properties like name, description, server configurations, and tags. Only organization members can edit bundles in their organization. Use this to refine bundles after creation, update server configurations, or modify metadata. Supports partial updates - only provide the fields you want to change. The bundle retains all existing data for fields not specified in the update.',
inputSchema: {
type: 'object',
properties: {
bundle_id: {
type: 'string',
description: 'The ID of the bundle to edit. Get this from list_bundles results. Must be a bundle in your organization.'
},
name: {
type: 'string',
description: 'Updated bundle name (2-100 characters). Should be descriptive and unique within your organization. **Use clear, action-oriented names** like: "NextJS Deployment", "Email Toolkit", "Database Management Suite", "AI Development Tools", "Web Scraping Bundle". Avoid generic names like "my-bundle" or "test-1".',
minLength: 2,
maxLength: 100
},
description: {
type: 'string',
description: 'Updated bundle description (5-500 characters). Explain what the bundle does and what MCP servers it contains. This helps others discover and understand your bundle.',
minLength: 5,
maxLength: 500
},
servers: {
type: 'object',
description: 'Updated MCP server configurations in the bundle. Each key is the server name, value is the config with command, args, env, and optional type. This completely replaces the existing server configurations.',
additionalProperties: {
type: 'object',
properties: {
command: { type: 'string' },
args: { type: 'array', items: { type: 'string' } },
env: { type: 'object', additionalProperties: { type: 'string' } },
type: { type: 'string', enum: ['stdio', 'http', 'sse'] }
},
required: ['command', 'args']
}
},
tags: {
type: 'array',
description: 'Updated tags for categorization. Examples: ["web-development", "github", "filesystem"], ["data-analysis", "database", "excel"]. This completely replaces the existing tags.',
items: { type: 'string' }
},
install_commands: {
type: 'array',
description: 'Updated array of shell commands to run before installing the MCP servers. Examples: ["npm install -g @modelcontextprotocol/server-filesystem", "pip install mcp-server-git"]. This completely replaces the existing install commands.',
items: { type: 'string' }
},
},
required: ['bundle_id']
},
async execute(args, context) {
try {
// Validate user has authentication token
if (!context.token) {
throw new Error('User authentication required');
}
// Validate server configurations if provided
if (args.servers !== undefined) {
if (Object.keys(args.servers).length === 0) {
throw new Error('Bundle must contain at least one MCP server configuration');
}
for (const [serverName, serverConfig] of Object.entries(args.servers)) {
if (!serverConfig.command || typeof serverConfig.command !== 'string') {
throw new Error(`Server '${serverName}' must have a valid command`);
}
if (!Array.isArray(serverConfig.args)) {
throw new Error(`Server '${serverName}' must have valid args array`);
}
if (serverConfig.env && typeof serverConfig.env !== 'object') {
throw new Error(`Server '${serverName}' env must be an object`);
}
if (serverConfig.type && !['stdio', 'http', 'sse'].includes(serverConfig.type)) {
throw new Error(`Server '${serverName}' type must be 'stdio', 'http', or 'sse'`);
}
}
}
// Call API to update bundle - API handles authorization and validation
const updatedBundle = await ApiClient.updateBundle(args.bundle_id, {
name: args.name,
description: args.description,
servers: args.servers,
tags: args.tags,
install_commands: args.install_commands
}, context);
if (!updatedBundle) {
throw new Error('Failed to update bundle');
}
const serverCount = updatedBundle.config?.servers ? Object.keys(updatedBundle.config.servers).length : 0;
return {
content: [
{
type: 'text',
text: `✅ Bundle updated successfully!
**Updated Bundle Details:**
- **Name**: ${updatedBundle.name}
- **Description**: ${updatedBundle.description}
- **Servers**: ${serverCount} MCP server${serverCount === 1 ? '' : 's'}
- **Bundle ID**: ${updatedBundle.id}
- **Last Updated**: ${new Date(updatedBundle.updated_at).toLocaleString()}
${updatedBundle.tags && updatedBundle.tags.length > 0 ? `**Tags**: ${updatedBundle.tags.join(', ')}\n` : ''}${serverCount > 0 ? `**Server List**: ${Object.keys(updatedBundle.config.servers).join(', ')}\n` : ''}
**Changes Applied:**
${args.name !== undefined ? '- Name updated' : ''}
${args.description !== undefined ? '- Description updated' : ''}
${args.servers !== undefined ? '- Server configurations updated' : ''}
${args.tags !== undefined ? '- Tags updated' : ''}
${args.install_commands !== undefined ? '- Installation commands updated' : ''}
**Next Steps:**
- Use \`list_bundles\` to view your updated bundle
- Use \`get_bundle_config\` to retrieve the configuration for installation`
}
]
};
}
catch (error) {
console.error('Edit bundle error:', error);
return {
content: [
{
type: 'text',
text: `❌ Failed to edit bundle: ${error.message}`
}
]
};
}
}
};
//# sourceMappingURL=edit-bundle.js.map