UNPKG

@the_cfdude/productboard-mcp

Version:

Model Context Protocol server for Productboard REST API with dynamic tool loading

724 lines (695 loc) 19 kB
/** * Plugin integrations management tools */ import { withContext, formatResponse } from '../utils/tool-wrapper.js'; import { isEnterpriseError } from '../utils/parameter-utils.js'; import { ProductboardError } from '../errors/index.js'; import { ErrorCode } from '@modelcontextprotocol/sdk/types.js'; export function setupPluginIntegrationsTools() { return [ { name: 'post_plugin_integration', description: 'Create a new plugin integration', inputSchema: { type: 'object', properties: { body: { type: 'object', description: 'Plugin integration data', properties: { type: { type: 'string', description: 'Type identifier (e.g., "com.mydomain.myservice")', }, name: { type: 'string', description: 'Display name for the integration', }, integrationStatus: { type: 'string', description: 'Status of the integration', enum: ['enabled', 'disabled'], }, initialState: { type: 'object', description: 'Initial button state', properties: { label: { type: 'string', description: 'Button label', }, }, }, action: { type: 'object', description: 'Action configuration', properties: { url: { type: 'string', description: 'URL to call when button is clicked', }, version: { type: 'number', description: 'API version', }, headers: { type: 'object', description: 'HTTP headers to include', }, }, }, }, required: ['type', 'name'], }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['body'], }, }, { name: 'get_plugin_integrations', description: 'List all plugin integrations', inputSchema: { type: 'object', properties: { instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, }, }, { name: 'get_plugin_integration', description: 'Retrieve a specific plugin integration', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id'], }, }, { name: 'patch_plugin_integration', description: 'Update a plugin integration (PATCH)', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, body: { type: 'object', description: 'Plugin integration data to update', properties: { type: { type: 'string', description: 'Type identifier', }, name: { type: 'string', description: 'Display name for the integration', }, integrationStatus: { type: 'string', description: 'Status of the integration', enum: ['enabled', 'disabled'], }, initialState: { type: 'object', description: 'Initial button state', }, action: { type: 'object', description: 'Action configuration', }, }, }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id', 'body'], }, }, { name: 'put_plugin_integration', description: 'Update a plugin integration (PUT - deprecated)', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, body: { type: 'object', description: 'Complete plugin integration data', properties: { type: { type: 'string', description: 'Type identifier', }, name: { type: 'string', description: 'Display name for the integration', }, integrationStatus: { type: 'string', description: 'Status of the integration', enum: ['enabled', 'disabled'], }, initialState: { type: 'object', description: 'Initial button state', }, action: { type: 'object', description: 'Action configuration', }, }, required: ['type', 'name'], }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id', 'body'], }, }, { name: 'delete_plugin_integration', description: 'Delete a plugin integration', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id'], }, }, { name: 'get_plugin_integration_connections', description: 'List plugin integration connections for a specific integration', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id'], }, }, { name: 'get_plugin_integration_connection', description: 'Retrieve a specific plugin integration connection', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, featureId: { type: 'string', description: 'Feature ID', }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id', 'featureId'], }, }, { name: 'put_plugin_integration_connection', description: 'Set the state of a plugin integration connection', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, featureId: { type: 'string', description: 'Feature ID', }, body: { type: 'object', description: 'Connection configuration', properties: { connection: { type: 'object', description: 'Connection state data', properties: { state: { type: 'string', description: 'Connection state', enum: ['initial', 'connected', 'error', 'progress'], }, label: { type: 'string', description: 'Button label', }, hoverLabel: { type: 'string', description: 'Hover text', }, tooltip: { type: 'string', description: 'Tooltip text', }, color: { type: 'string', description: 'Button color', enum: ['blue', 'green', 'orange', 'red', 'gray'], }, targetUrl: { type: 'string', description: 'URL to link to external system', }, }, required: ['state'], }, }, required: ['connection'], }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id', 'featureId', 'body'], }, }, { name: 'delete_plugin_integration_connection', description: 'Delete a plugin integration connection (reset to initial state)', inputSchema: { type: 'object', properties: { id: { type: 'string', description: 'Plugin integration ID', }, featureId: { type: 'string', description: 'Feature ID', }, instance: { type: 'string', description: 'Productboard instance name (optional)', }, workspaceId: { type: 'string', description: 'Workspace ID (optional)', }, }, required: ['id', 'featureId'], }, }, ]; } export async function handlePluginIntegrationsTool(name: string, args: any) { try { switch (name) { case 'post_plugin_integration': return await createPluginIntegration(args); case 'get_plugin_integrations': return await listPluginIntegrations(args); case 'get_plugin_integration': return await getPluginIntegration(args); case 'patch_plugin_integration': return await patchPluginIntegration(args); case 'put_plugin_integration': return await putPluginIntegration(args); case 'delete_plugin_integration': return await deletePluginIntegration(args); case 'get_plugin_integration_connections': return await getPluginIntegrationConnections(args); case 'get_plugin_integration_connection': return await getPluginIntegrationConnection(args); case 'put_plugin_integration_connection': return await putPluginIntegrationConnection(args); case 'delete_plugin_integration_connection': return await deletePluginIntegrationConnection(args); default: throw new Error(`Unknown plugin integrations tool: ${name}`); } } catch (error: any) { const enterpriseInfo = isEnterpriseError(error); if (enterpriseInfo.isEnterpriseFeature) { throw new ProductboardError( ErrorCode.InvalidRequest, enterpriseInfo.message, error ); } throw error; } } // Plugin Integration Management Functions async function createPluginIntegration(args: any) { return await withContext( async context => { // Handle case where body might be passed as a JSON string let body = args.body; if (typeof body === 'string') { try { body = JSON.parse(body); } catch { throw new Error('Invalid JSON in body parameter'); } } const response = await context.axios.post('/plugin-integrations', body, { headers: { 'X-Version': '1', }, }); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function listPluginIntegrations(args: any) { return await withContext( async context => { const response = await context.axios.get('/plugin-integrations', { headers: { 'X-Version': '1', }, }); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function getPluginIntegration(args: any) { return await withContext( async context => { const response = await context.axios.get( `/plugin-integrations/${args.id}`, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function patchPluginIntegration(args: any) { return await withContext( async context => { // Handle case where body might be passed as a JSON string let body = args.body; if (typeof body === 'string') { try { body = JSON.parse(body); } catch { throw new Error('Invalid JSON in body parameter'); } } const response = await context.axios.patch( `/plugin-integrations/${args.id}`, body, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function putPluginIntegration(args: any) { return await withContext( async context => { // Handle case where body might be passed as a JSON string let body = args.body; if (typeof body === 'string') { try { body = JSON.parse(body); } catch { throw new Error('Invalid JSON in body parameter'); } } const response = await context.axios.put( `/plugin-integrations/${args.id}`, body, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function deletePluginIntegration(args: any) { return await withContext( async context => { await context.axios.delete(`/plugin-integrations/${args.id}`, { headers: { 'X-Version': '1', }, }); return { content: [ { type: 'text', text: JSON.stringify({ success: true, message: `Plugin integration ${args.id} deleted successfully`, }), }, ], }; }, args.instance, args.workspaceId ); } // Plugin Integration Connection Functions async function getPluginIntegrationConnections(args: any) { return await withContext( async context => { const response = await context.axios.get( `/plugin-integrations/${args.id}/connections`, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function getPluginIntegrationConnection(args: any) { return await withContext( async context => { const response = await context.axios.get( `/plugin-integrations/${args.id}/connections/${args.featureId}`, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function putPluginIntegrationConnection(args: any) { return await withContext( async context => { // Handle case where body might be passed as a JSON string let body = args.body; if (typeof body === 'string') { try { body = JSON.parse(body); } catch { throw new Error('Invalid JSON in body parameter'); } } const response = await context.axios.put( `/plugin-integrations/${args.id}/connections/${args.featureId}`, body, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: formatResponse(response.data), }, ], }; }, args.instance, args.workspaceId ); } async function deletePluginIntegrationConnection(args: any) { return await withContext( async context => { await context.axios.delete( `/plugin-integrations/${args.id}/connections/${args.featureId}`, { headers: { 'X-Version': '1', }, } ); return { content: [ { type: 'text', text: JSON.stringify({ success: true, message: `Plugin integration connection deleted successfully`, }), }, ], }; }, args.instance, args.workspaceId ); }