bottlenecks-mcp-server
Version:
Model Context Protocol server for Bottlenecks database - enables AI agents like Claude to interact with bottleneck data
391 lines • 17.9 kB
JavaScript
/**
* MCP Schema Tools
* Provides AI agents with data structure and validation information
*/
/**
* Get the complete bottleneck data schema
*/
export function createGetBottleneckSchemaTool(client) {
return {
type: 'call_tool',
name: 'get_bottleneck_schema',
description: 'Get the complete data schema for bottleneck objects, including all fields, types, and validation rules',
inputSchema: {
type: 'object',
properties: {
include_examples: {
type: 'boolean',
description: 'Include example values for each field',
default: true,
},
format: {
type: 'string',
description: 'Response format',
enum: ['json', 'typescript', 'markdown'],
default: 'markdown',
},
},
required: [],
},
handler: async (args) => {
try {
// For now, we'll create the schema based on our database structure
// In the future, this could call /api/mcp/schema endpoint
const schema = {
name: 'Bottleneck',
description: 'A bottleneck represents a constraint, limitation, or inefficiency in a system',
fields: {
id: {
type: 'string',
format: 'uuid',
description: 'Unique identifier for the bottleneck',
required: true,
readonly: true,
example: '123e4567-e89b-12d3-a456-426614174000',
},
title: {
type: 'string',
description: 'Clear, descriptive title of the bottleneck',
required: true,
minLength: 5,
maxLength: 200,
example: 'Database Query Performance Bottleneck',
},
slug: {
type: 'string',
description: 'URL-friendly identifier, auto-generated from title',
required: true,
readonly: true,
pattern: '^[a-z0-9-]+$',
example: 'database-query-performance-bottleneck',
},
description: {
type: 'string',
format: 'mdx',
description: 'Detailed description using MDX format with sections',
required: true,
minLength: 50,
example: 'Use get_bottleneck_template to get the proper MDX format',
},
tags: {
type: 'array',
items: { type: 'string' },
description: 'Categorization tags for the bottleneck',
required: false,
maxItems: 10,
example: ['performance', 'database', 'scalability'],
},
is_public: {
type: 'boolean',
description: 'Whether the bottleneck is publicly visible',
required: true,
default: false,
example: true,
},
author_id: {
type: 'string',
format: 'uuid',
description: 'ID of the user who created this bottleneck',
required: true,
readonly: true,
example: '456e7890-e89b-12d3-a456-426614174001',
},
organization_id: {
type: 'string',
format: 'uuid',
description: 'ID of the organization this bottleneck belongs to',
required: false,
example: '789e0123-e89b-12d3-a456-426614174002',
},
created_at: {
type: 'string',
format: 'date-time',
description: 'When the bottleneck was created',
required: true,
readonly: true,
example: '2024-01-15T10:30:00Z',
},
updated_at: {
type: 'string',
format: 'date-time',
description: 'When the bottleneck was last updated',
required: true,
readonly: true,
example: '2024-01-16T14:22:00Z',
},
file_attachments: {
type: 'array',
items: { $ref: '#/definitions/FileAttachment' },
description: 'Files attached to this bottleneck',
required: false,
readonly: true,
example: [],
},
},
definitions: {
FileAttachment: {
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
filename: { type: 'string' },
original_filename: { type: 'string' },
file_type: { type: 'string' },
file_size: { type: 'number' },
mime_type: { type: 'string' },
upload_type: {
type: 'string',
enum: [
'attachment',
'research_data',
'image',
'reference_doc',
],
},
description: { type: 'string' },
is_public: { type: 'boolean' },
processing_status: {
type: 'string',
enum: ['pending', 'processing', 'completed', 'failed'],
},
created_at: { type: 'string', format: 'date-time' },
},
},
},
validation_rules: {
title: [
'Must be between 5 and 200 characters',
'Should be descriptive and specific',
'Avoid generic terms like "bottleneck" in the title',
],
description: [
'Must be at least 50 characters',
'Should use MDX format with sections',
'Required sections: details',
'Optional sections: impact, efforts, related, forecast, considerations, contributors',
],
tags: [
'Maximum 10 tags per bottleneck',
'Tags should be lowercase, hyphenated',
'Use existing taxonomy when possible',
],
},
};
let content = '';
if (args.format === 'json') {
content = JSON.stringify(schema, null, 2);
}
else if (args.format === 'typescript') {
content = `// Bottleneck TypeScript Interface\n\n`;
content += `interface Bottleneck {\n`;
Object.entries(schema.fields).forEach(([key, field]) => {
const optional = !field.required ? '?' : '';
const readonly = field.readonly ? 'readonly ' : '';
content += ` ${readonly}${key}${optional}: ${field.type};\n`;
});
content += `}\n\n`;
content += `interface FileAttachment {\n`;
Object.entries(schema.definitions.FileAttachment.properties).forEach(([key, field]) => {
content += ` ${key}: ${field.type};\n`;
});
content += `}\n`;
}
else {
// Markdown format (default)
content += `# Bottleneck Data Schema\n\n`;
content += `${schema.description}\n\n`;
content += `## Core Fields\n\n`;
Object.entries(schema.fields).forEach(([key, field]) => {
content += `### ${key}\n`;
content += `- **Type:** ${field.type}${field.format ? ` (${field.format})` : ''}\n`;
content += `- **Required:** ${field.required ? 'Yes' : 'No'}\n`;
if (field.readonly)
content += `- **Read-only:** Yes\n`;
if (field.default !== undefined)
content += `- **Default:** ${field.default}\n`;
content += `- **Description:** ${field.description}\n`;
if (args.include_examples && field.example) {
content += `- **Example:** \`${typeof field.example === 'string' ? field.example : JSON.stringify(field.example)}\`\n`;
}
content += '\n';
});
content += `## Validation Rules\n\n`;
Object.entries(schema.validation_rules).forEach(([field, rules]) => {
content += `### ${field}\n`;
rules.forEach((rule) => {
content += `- ${rule}\n`;
});
content += '\n';
});
content += `## File Attachments\n\n`;
content += `Bottlenecks can have multiple file attachments. Each attachment has:\n\n`;
Object.entries(schema.definitions.FileAttachment.properties).forEach(([key, field]) => {
content += `- **${key}**: ${field.type}`;
if (field.enum)
content += ` (${field.enum.join(', ')})`;
content += '\n';
});
}
return {
content: [
{
type: 'text',
text: content,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error in get_bottleneck_schema: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
};
}
/**
* Get taxonomy information (tags, categories, etc.)
*/
export function createGetTaxonomyTool(client) {
return {
type: 'call_tool',
name: 'get_taxonomy',
description: 'Get the taxonomy system including available tags, categories, and their relationships',
inputSchema: {
type: 'object',
properties: {
category: {
type: 'string',
description: 'Specific category to focus on',
enum: ['all', 'domains', 'types', 'impacts', 'solutions'],
},
include_counts: {
type: 'boolean',
description: 'Include usage counts for each tag',
default: false,
},
},
required: [],
},
handler: async (args) => {
try {
// This would eventually call /api/mcp/taxonomy
// For now, we'll provide a comprehensive taxonomy structure
const taxonomy = {
domains: [
'software-engineering',
'data-science',
'machine-learning',
'devops',
'product-management',
'user-experience',
'business-operations',
'supply-chain',
'manufacturing',
'healthcare',
'finance',
'education',
],
types: [
'performance',
'scalability',
'reliability',
'security',
'usability',
'maintainability',
'cost',
'time',
'resource',
'process',
'communication',
'knowledge',
'skill',
'tool',
'infrastructure',
],
impacts: [
'high-impact',
'medium-impact',
'low-impact',
'critical',
'urgent',
'long-term',
'short-term',
'strategic',
'operational',
'customer-facing',
'internal',
'revenue-affecting',
'cost-affecting',
],
solutions: [
'automation',
'optimization',
'refactoring',
'scaling',
'caching',
'monitoring',
'training',
'documentation',
'tooling',
'process-improvement',
'architecture-change',
'resource-allocation',
],
};
let content = `# Bottlenecks Taxonomy\n\n`;
content += `This taxonomy helps categorize and organize bottlenecks for better discovery and analysis.\n\n`;
const categoriesToShow = args.category === 'all' || !args.category
? Object.keys(taxonomy)
: [args.category].filter((cat) => cat in taxonomy);
categoriesToShow.forEach((category) => {
if (!(category in taxonomy))
return;
content += `## ${category.charAt(0).toUpperCase() + category.slice(1).replace('-', ' ')}\n\n`;
const tags = taxonomy[category];
tags.forEach((tag) => {
content += `- \`${tag}\``;
if (args.include_counts) {
// In a real implementation, this would query the database
const mockCount = Math.floor(Math.random() * 50) + 1;
content += ` (${mockCount} bottlenecks)`;
}
content += '\n';
});
content += '\n';
});
content += `## Usage Guidelines\n\n`;
content += `- Use **domains** to indicate the field or industry\n`;
content += `- Use **types** to categorize the nature of the bottleneck\n`;
content += `- Use **impacts** to indicate severity and scope\n`;
content += `- Use **solutions** to tag potential resolution approaches\n\n`;
content += `**Example:** A bottleneck might be tagged with: \`software-engineering\`, \`performance\`, \`high-impact\`, \`optimization\`\n`;
return {
content: [
{
type: 'text',
text: content,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `Error in get_taxonomy: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
},
};
}
//# sourceMappingURL=schema.js.map