@templation/mcp-server
Version:
Enhanced MCP server for Templation - Advanced GitHub repository search, AI-powered template conversion, and comprehensive template management directly in Cursor
756 lines β’ 43.8 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
import fetch from 'node-fetch';
import dotenv from 'dotenv';
dotenv.config();
// Configuration with fallbacks
const API_BASE_URL = process.env.TEMPLATION_API_URL || 'https://templation-api.up.railway.app';
const API_KEY = process.env.TEMPLATION_API_KEY;
if (!API_KEY) {
console.error('β TEMPLATION_API_KEY environment variable is required');
console.error('π Get your API key at: https://templation.up.railway.app/api-keys');
process.exit(1);
}
// Simple in-memory cache for performance
const cache = new Map();
const server = new Server({
name: 'templation',
version: '2.0.0',
}, {
capabilities: {
tools: {},
},
});
// Enhanced cache helper
function getCached(key) {
const cached = cache.get(key);
if (cached && Date.now() - cached.timestamp < cached.ttl) {
return cached.data;
}
cache.delete(key);
return null;
}
function setCache(key, data, ttlMs = 300000) {
cache.set(key, { data, timestamp: Date.now(), ttl: ttlMs });
}
// Enhanced API call helper with retry logic and better error handling
async function apiCall(endpoint, options = {}, retries = 3) {
const url = `${API_BASE_URL}${endpoint}`;
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await fetch(url, {
timeout: 30000, // 30 second timeout
...options,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${API_KEY}`,
'User-Agent': 'Templation-MCP-Server/2.0.0',
...options.headers,
},
});
if (!response.ok) {
const errorText = await response.text();
// Handle specific error cases
if (response.status === 401) {
throw new Error(`Authentication failed. Please check your API key at https://templation.up.railway.app/api-keys`);
}
else if (response.status === 403) {
throw new Error(`Access forbidden. Your API key may not have sufficient permissions.`);
}
else if (response.status === 429) {
if (attempt < retries) {
// Wait before retry on rate limit
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
continue;
}
throw new Error(`Rate limit exceeded. Please try again in a few minutes.`);
}
else if (response.status >= 500) {
if (attempt < retries) {
// Retry on server errors
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
continue;
}
throw new Error(`Server error (${response.status}). Please try again later.`);
}
throw new Error(`API call failed (${response.status}): ${errorText}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
else {
return await response.text();
}
}
catch (error) {
if (attempt === retries) {
if (error instanceof Error) {
throw error;
}
throw new Error(`API call failed: ${String(error)}`);
}
// Wait before retry
await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
}
}
}
// Utility functions for better response formatting
function formatTemplateResult(template, index) {
const tags = Array.isArray(template.tags) ? template.tags.join(', ') :
Array.isArray(template.tech_stack) ? template.tech_stack.join(', ') : 'None';
const createdDate = template.created_at ? new Date(template.created_at).toLocaleDateString() : 'Unknown';
const lastUsed = template.last_used ? new Date(template.last_used).toLocaleDateString() : 'Never';
return `${index + 1}. **${template.name}**\n` +
` π ${template.description || 'No description'}\n` +
` π Source: ${template.source_repo_name || template.source_repo_url || 'Unknown'}\n` +
` π·οΈ Tags: ${tags}\n` +
` π Usage: ${template.usage_count || 0} times\n` +
` π
Created: ${createdDate}${template.last_used ? ` | Last used: ${lastUsed}` : ''}\n` +
` ${template.is_favorite ? 'β Favorite' : ''}`;
}
function formatRepoResult(repo, index) {
const stars = repo.metrics?.stars || 0;
const forks = repo.metrics?.forks || 0;
const techStack = Array.isArray(repo.tech_stack) ? repo.tech_stack.slice(0, 5).join(', ') : 'N/A';
const difficulty = repo.customization_difficulty || 'medium';
const difficultyEmoji = { easy: 'π’', medium: 'π‘', hard: 'π΄' }[difficulty] || 'π‘';
return `${index + 1}. **${repo.name}** β ${stars.toLocaleString()} π΄ ${forks.toLocaleString()}\n` +
` π ${repo.visual_summary || repo.description || 'No description available'}\n` +
` π ${repo.url}\n` +
` π οΈ Tech: ${techStack}\n` +
` ${difficultyEmoji} Difficulty: ${difficulty}\n` +
` ${repo.demo_url ? `π Demo: ${repo.demo_url}\n` : ''}` +
` ${repo.screenshot_url ? `πΈ Preview available\n` : ''}`;
}
// List available tools with enhanced descriptions
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'search_templates',
description: 'Search your saved templates by name, description, or technology. Find templates you\'ve created or converted from GitHub repositories.',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query - can include project names, technologies, or keywords (e.g., "React portfolio", "FastAPI", "e-commerce")',
},
limit: {
type: 'number',
description: 'Maximum number of results to return (1-50, default: 10)',
minimum: 1,
maximum: 50,
default: 10,
},
},
required: ['query'],
},
},
{
name: 'search_exemplar',
description: 'Discover high-quality GitHub repositories for inspiration. Search by project type, technology, or features to find repositories you can use as templates.',
inputSchema: {
type: 'object',
properties: {
description: {
type: 'string',
description: 'Describe what you want to build. Be specific for better results (e.g., "React e-commerce with Stripe payments", "Python FastAPI with authentication", "Vue.js dashboard with charts")',
},
filters: {
type: 'object',
description: 'Optional filters to refine your search results',
properties: {
language: {
type: 'string',
description: 'Programming language filter (e.g., "TypeScript", "Python", "JavaScript", "Go", "Rust")',
},
min_stars: {
type: 'number',
description: 'Minimum number of GitHub stars (helps find popular, well-maintained repositories)',
minimum: 0,
},
max_age_days: {
type: 'number',
description: 'Maximum age in days - only show repositories updated within this timeframe (e.g., 365 for last year)',
minimum: 1,
},
},
},
},
required: ['description'],
},
},
{
name: 'template_converter',
description: 'Convert any GitHub repository into a personalized, step-by-step template with detailed setup instructions and customization guidance.',
inputSchema: {
type: 'object',
properties: {
repo_url: {
type: 'string',
description: 'Full GitHub repository URL (e.g., "https://github.com/vercel/next.js", "https://github.com/fastapi/fastapi")',
pattern: '^https://github\\.com/[^/]+/[^/]+/?$',
},
template_description: {
type: 'string',
description: 'Describe how you want to customize this template and what you\'ll use it for (e.g., "Portfolio website for a data scientist", "E-commerce site for handmade jewelry", "API for a food delivery app")',
},
user_context: {
type: 'object',
description: 'Additional context to personalize the template conversion',
properties: {
project_name: {
type: 'string',
description: 'Your specific project name (e.g., "AcmeCorp Website", "MyFoodApp API")',
},
preferred_style: {
type: 'string',
description: 'Design/coding style preference (e.g., "modern", "minimal", "corporate", "playful")',
},
additional_features: {
type: 'array',
items: { type: 'string' },
description: 'Additional features you want to include (e.g., ["dark mode", "authentication", "payment integration", "analytics"])',
},
target_audience: {
type: 'string',
description: 'Who will use this (e.g., "developers", "small businesses", "students")',
},
deployment_preference: {
type: 'string',
description: 'Preferred deployment platform (e.g., "Vercel", "Netlify", "Railway", "AWS", "self-hosted")',
},
},
},
},
required: ['repo_url', 'template_description'],
},
},
{
name: 'get_user_info',
description: 'Get detailed information about your Templation account, including GitHub connection status and account statistics.',
inputSchema: {
type: 'object',
properties: {
include_stats: {
type: 'boolean',
description: 'Include additional statistics like template count and recent activity',
default: true,
},
},
},
},
{
name: 'get_dashboard_stats',
description: 'Get comprehensive dashboard statistics including template count, repository analysis, recent activity, and usage metrics.',
inputSchema: {
type: 'object',
properties: {
include_recent_activity: {
type: 'boolean',
description: 'Include list of recent templates and activity',
default: false,
},
},
},
},
{
name: 'get_template_details',
description: 'Get detailed information about a specific template, including setup instructions, customization points, and usage history.',
inputSchema: {
type: 'object',
properties: {
template_id: {
type: 'string',
description: 'The unique ID of the template (from search results or dashboard)',
},
include_setup_guide: {
type: 'boolean',
description: 'Include detailed setup and customization instructions',
default: true,
},
},
required: ['template_id'],
},
},
],
};
});
// Handle tool calls with enhanced functionality
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'search_templates': {
const { query, limit = 10 } = args;
// Validate inputs
if (!query.trim()) {
return {
content: [
{
type: 'text',
text: `β Please provide a search query.\n\nπ‘ **Examples:**\nβ’ "React portfolio"\nβ’ "FastAPI authentication"\nβ’ "e-commerce"\nβ’ "dashboard"`,
},
],
};
}
const clampedLimit = Math.max(1, Math.min(50, limit));
const cacheKey = `search_templates:${query}:${clampedLimit}`;
try {
// Check cache first
let templates = getCached(cacheKey);
if (!templates) {
templates = await apiCall(`/api/search/templates?q=${encodeURIComponent(query)}&limit=${clampedLimit}`);
setCache(cacheKey, templates, 180000); // 3 minute cache
}
if (!templates || templates.length === 0) {
return {
content: [
{
type: 'text',
text: `π No templates found for "${query}"\n\nπ‘ **Try:**\nβ’ Different keywords (e.g., "React" instead of "ReactJS")\nβ’ Broader terms (e.g., "web app" instead of "specific framework")\nβ’ Technology names (e.g., "Python", "TypeScript", "Vue")\n\nπ **Create your first template:**\n1. Use \`search_exemplar\` to find a good repository\n2. Use \`template_converter\` to convert it\n3. Or visit https://templation.up.railway.app/templates`,
},
],
};
}
const formattedResults = templates.map((template, index) => formatTemplateResult(template, index)).join('\n\n');
const totalText = templates.length === clampedLimit ? `${templates.length}+ templates` : `${templates.length} template${templates.length === 1 ? '' : 's'}`;
return {
content: [
{
type: 'text',
text: `π― Found ${totalText} for "${query}":\n\n${formattedResults}\n\nπ‘ **Next steps:**\nβ’ Use \`get_template_details\` with a template ID for setup instructions\nβ’ Visit https://templation.up.railway.app/templates to manage templates\nβ’ Use \`template_converter\` to create new templates from GitHub repos`,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `β Error searching templates: ${error instanceof Error ? error.message : 'Unknown error'}\n\nπ§ **Troubleshooting:**\nβ’ Check your API key at https://templation.up.railway.app/api-keys\nβ’ Ensure you have created some templates first\nβ’ Try a simpler search query\nβ’ Check your internet connection`,
},
],
};
}
}
case 'search_exemplar': {
const { description, filters } = args;
// Validate inputs
if (!description.trim()) {
return {
content: [
{
type: 'text',
text: `β Please provide a description of what you want to build.\n\nπ‘ **Good examples:**\nβ’ "React e-commerce website with Stripe payments"\nβ’ "Python FastAPI with JWT authentication"\nβ’ "Vue.js dashboard with real-time charts"\nβ’ "Next.js blog with dark mode"\nβ’ "Express.js REST API with MongoDB"`,
},
],
};
}
const cacheKey = `search_exemplar:${description}:${JSON.stringify(filters || {})}`;
try {
// Check cache first
let searchResult = getCached(cacheKey);
if (!searchResult) {
searchResult = await apiCall('/api/search-exemplar', {
method: 'POST',
body: JSON.stringify({
description,
filters: filters || {},
}),
});
setCache(cacheKey, searchResult, 600000); // 10 minute cache for repo searches
}
if (!searchResult.repos || searchResult.repos.length === 0) {
const filterText = filters ? Object.entries(filters)
.filter(([_, value]) => value !== undefined && value !== null)
.map(([key, value]) => `${key}: ${value}`)
.join(', ') : '';
return {
content: [
{
type: 'text',
text: `π No repositories found for "${description}"${filterText ? ` with filters (${filterText})` : ''}\n\nπ‘ **Try:**\nβ’ Broader search terms (e.g., "React app" instead of "React e-commerce with Stripe and dark mode")\nβ’ Different keywords (e.g., "web scraper" instead of "data extraction tool")\nβ’ Remove or relax filters\nβ’ Popular tech combinations (e.g., "MERN stack", "JAMstack", "MEAN stack")\n\nπ **Popular searches:**\nβ’ "React portfolio website"\nβ’ "Python web scraper"\nβ’ "Node.js REST API"\nβ’ "Vue dashboard"\nβ’ "Flutter mobile app"`,
},
],
};
}
const formattedResults = searchResult.repos.map((repo, index) => formatRepoResult(repo, index)).join('\n\n');
const searchTime = searchResult.search_time_ms ? ` (${searchResult.search_time_ms}ms)` : '';
const filterSummary = filters ? Object.entries(filters)
.filter(([_, value]) => value !== undefined && value !== null)
.map(([key, value]) => {
if (key === 'min_stars')
return `β ${value}+ stars`;
if (key === 'max_age_days')
return `π
Updated within ${value} days`;
if (key === 'language')
return `π» ${value}`;
return `${key}: ${value}`;
}).join(' β’ ') : '';
return {
content: [
{
type: 'text',
text: `π― Found ${searchResult.repos.length} repositories for "${description}"${searchTime}\n${filterSummary ? `π Filters: ${filterSummary}\n` : ''}\n${formattedResults}\n\nπ‘ **Next steps:**\nβ’ Copy a repository URL and use \`template_converter\` to create your personalized template\nβ’ Visit the repository to explore the code and documentation\nβ’ Check demo links to see the project in action\nβ’ Look for repositories with good documentation and recent activity`,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `β Error searching repositories: ${error instanceof Error ? error.message : 'Unknown error'}\n\nπ§ **This might be due to:**\nβ’ GitHub API rate limits (try again in a few minutes)\nβ’ Network connectivity issues\nβ’ Invalid search parameters\nβ’ Temporary service unavailability\n\nπ‘ **Try:**\nβ’ Simpler search terms\nβ’ Removing filters temporarily\nβ’ Waiting a few minutes and trying again`,
},
],
};
}
}
case 'template_converter': {
const { repo_url, template_description, user_context } = args;
// Enhanced validation
if (!repo_url.trim()) {
return {
content: [
{
type: 'text',
text: `β Please provide a GitHub repository URL.\n\nπ‘ **Format:** https://github.com/owner/repository\n**Examples:**\nβ’ https://github.com/vercel/next.js\nβ’ https://github.com/fastapi/fastapi\nβ’ https://github.com/vuejs/vue`,
},
],
};
}
if (!template_description.trim()) {
return {
content: [
{
type: 'text',
text: `β Please provide a description of how you want to customize this template.\n\nπ‘ **Good examples:**\nβ’ "Portfolio website for a data scientist with project showcases"\nβ’ "E-commerce site for handmade jewelry with payment integration"\nβ’ "Task management app for small teams with real-time collaboration"\nβ’ "Blog platform for tech writers with syntax highlighting"`,
},
],
};
}
// Validate GitHub URL format
const githubUrlPattern = /^https:\/\/github\.com\/[^\/]+\/[^\/]+\/?$/;
if (!githubUrlPattern.test(repo_url.trim())) {
return {
content: [
{
type: 'text',
text: `β Invalid GitHub URL format.\n\nβ
**Correct format:** https://github.com/owner/repository\nβ **Your input:** ${repo_url}\n\nπ‘ **Make sure to:**\nβ’ Include the full URL starting with https://github.com/\nβ’ Use the main repository URL (not a specific file or branch)\nβ’ Ensure the repository is publicly accessible`,
},
],
};
}
try {
const startTime = Date.now();
const conversionResult = await apiCall('/api/template-converter', {
method: 'POST',
body: JSON.stringify({
repo_url: repo_url.trim(),
template_description: template_description.trim(),
user_context: user_context || {},
}),
});
const conversionTime = Date.now() - startTime;
// Format the response with enhanced structure
let result = `# π Template Conversion Complete!\n\n`;
result += `**π¦ Repository:** ${repo_url}\n`;
result += `**π― Template Purpose:** ${template_description}\n`;
result += `**β±οΈ Conversion Time:** ${conversionTime}ms\n\n`;
if (user_context?.project_name) {
result += `**π·οΈ Project Name:** ${user_context.project_name}\n`;
}
if (user_context?.preferred_style) {
result += `**π¨ Style Preference:** ${user_context.preferred_style}\n`;
}
if (user_context?.target_audience) {
result += `**π₯ Target Audience:** ${user_context.target_audience}\n`;
}
if (user_context?.deployment_preference) {
result += `**π Deployment:** ${user_context.deployment_preference}\n`;
}
result += `\n`;
if (conversionResult.conversion_steps?.length > 0) {
result += `## π Step-by-Step Conversion Guide\n`;
conversionResult.conversion_steps.forEach((step, index) => {
result += `${index + 1}. ${step}\n`;
});
result += `\n`;
}
if (conversionResult.setup_commands?.length > 0) {
result += `## π Setup Commands\n\`\`\`bash\n`;
conversionResult.setup_commands.forEach((command) => {
result += `${command}\n`;
});
result += `\`\`\`\n\n`;
}
if (conversionResult.files_to_modify?.length > 0) {
result += `## π Files to Customize\n`;
conversionResult.files_to_modify.forEach((file) => {
result += `β’ \`${file}\`\n`;
});
result += `\n`;
}
if (conversionResult.customization_points?.length > 0) {
result += `## π¨ Key Customization Areas\n`;
conversionResult.customization_points.forEach((point) => {
result += `β’ ${point}\n`;
});
result += `\n`;
}
if (user_context?.additional_features?.length && user_context.additional_features.length > 0) {
result += `## β¨ Additional Features to Implement\n`;
user_context.additional_features.forEach((feature) => {
result += `β’ ${feature}\n`;
});
result += `\n`;
}
if (conversionResult.expected_outcome) {
result += `## π― Expected Outcome\n${conversionResult.expected_outcome}\n\n`;
}
if (conversionResult.template_id) {
result += `## πΎ Template Saved Successfully!\n`;
result += `**Template ID:** \`${conversionResult.template_id}\`\n\n`;
result += `π **Access your template:**\n`;
result += `β’ Web Dashboard: https://templation.up.railway.app/templates/${conversionResult.template_id}\n`;
result += `β’ All Templates: https://templation.up.railway.app/templates\n\n`;
result += `π **Find it later:** Use \`search_templates\` with keywords from your description\n`;
result += `π **Get details:** Use \`get_template_details\` with template ID \`${conversionResult.template_id}\``;
}
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
return {
content: [
{
type: 'text',
text: `β Template conversion failed: ${errorMessage}\n\nπ§ **Common issues:**\nβ’ **Invalid URL:** Make sure the GitHub repository URL is correct and publicly accessible\nβ’ **Private repository:** The repository must be public or you need access\nβ’ **Repository not found:** Check if the repository exists and hasn't been renamed\nβ’ **Rate limits:** GitHub API limits may be exceeded, try again in a few minutes\nβ’ **Large repository:** Very large repositories may take longer to process\n\nπ‘ **Tips:**\nβ’ Use popular, well-maintained repositories for better results\nβ’ Ensure the repository has a clear structure and documentation\nβ’ Try repositories with fewer than 10,000 files for faster processing\n\nπ **Get help:** Visit https://templation.up.railway.app/account for support`,
},
],
};
}
}
case 'get_user_info': {
const { include_stats = true } = args;
try {
const userInfo = await apiCall('/api/users/me');
let stats = null;
if (include_stats) {
try {
stats = await apiCall('/api/users/dashboard/stats');
}
catch (e) {
// Stats are optional, continue without them
}
}
let result = `π€ **User Account Information**\n\n`;
result += `**Name:** ${userInfo.name || 'Not provided'}\n`;
result += `**Email:** ${userInfo.email || 'Not provided'}\n`;
result += `**GitHub:** ${userInfo.github_username ? `@${userInfo.github_username} β
` : 'β Not connected'}\n`;
result += `**Account Created:** ${userInfo.created_at ? new Date(userInfo.created_at).toLocaleDateString() : 'Unknown'}\n`;
if (!userInfo.github_connected) {
result += `\nπ **Connect GitHub:** Visit https://templation.up.railway.app/account to connect your GitHub account for better template analysis\n`;
}
if (stats) {
result += `\nπ **Account Statistics:**\n`;
result += `β’ Templates: ${stats.total_templates || 0}\n`;
result += `β’ Repositories Analyzed: ${stats.repositories_analyzed || 0}\n`;
result += `β’ Favorites: ${stats.favorites || 0}\n`;
result += `β’ Recent Activity: ${stats.recent_activity || 0} templates this week\n`;
result += `β’ API Keys: ${stats.active_api_keys || 0} active\n`;
}
result += `\nπ **Quick Links:**\n`;
result += `β’ Dashboard: https://templation.up.railway.app/dashboard\n`;
result += `β’ Templates: https://templation.up.railway.app/templates\n`;
result += `β’ Account Settings: https://templation.up.railway.app/account\n`;
result += `β’ API Keys: https://templation.up.railway.app/api-keys`;
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `β Error getting user info: ${error instanceof Error ? error.message : 'Unknown error'}\n\nπ§ **Troubleshooting:**\nβ’ Check your API key at https://templation.up.railway.app/api-keys\nβ’ Ensure your API key has the correct permissions\nβ’ Try refreshing your API key if it's old\n\nπ‘ **Need help?** Visit https://templation.up.railway.app/account`,
},
],
};
}
}
case 'get_dashboard_stats': {
const { include_recent_activity = false } = args;
try {
const stats = await apiCall('/api/users/dashboard/stats');
let result = `π **Dashboard Statistics**\n\n`;
result += `**π Total Templates:** ${stats.total_templates || 0}\n`;
result += `**π Repositories Analyzed:** ${stats.repositories_analyzed || 0}\n`;
result += `**β Favorite Templates:** ${stats.favorites || 0}\n`;
result += `**π Recent Activity:** ${stats.recent_activity || 0} templates this week\n`;
result += `**π Active API Keys:** ${stats.active_api_keys || 0}\n`;
if (stats.most_used_technologies?.length > 0) {
result += `**π οΈ Top Technologies:** ${stats.most_used_technologies.slice(0, 5).join(', ')}\n`;
}
if (stats.total_templates === 0) {
result += `\nπ‘ **Get started:**\n`;
result += `1. Use \`search_exemplar\` to find interesting repositories\n`;
result += `2. Use \`template_converter\` to create your first template\n`;
result += `3. Visit https://templation.up.railway.app/templates to manage templates\n`;
}
else {
result += `\nπ― **Quick actions:**\n`;
result += `β’ Use \`search_templates\` to find your templates\n`;
result += `β’ Use \`template_converter\` to create more templates\n`;
result += `β’ Visit https://templation.up.railway.app/dashboard for detailed analytics\n`;
}
if (include_recent_activity && stats.recent_templates?.length > 0) {
result += `\nπ **Recent Templates:**\n`;
stats.recent_templates.slice(0, 5).forEach((template, index) => {
result += `${index + 1}. ${template.name} (${new Date(template.created_at).toLocaleDateString()})\n`;
});
}
result += `\nπ **View full dashboard:** https://templation.up.railway.app/dashboard`;
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `β Error getting dashboard stats: ${error instanceof Error ? error.message : 'Unknown error'}\n\nπ§ **This might be due to:**\nβ’ API key authentication issues\nβ’ Temporary service unavailability\nβ’ Network connectivity problems\n\nπ‘ **Try:**\nβ’ Checking your API key at https://templation.up.railway.app/api-keys\nβ’ Waiting a moment and trying again\nβ’ Visiting the web dashboard at https://templation.up.railway.app/dashboard`,
},
],
};
}
}
case 'get_template_details': {
const { template_id, include_setup_guide = true } = args;
if (!template_id?.trim()) {
return {
content: [
{
type: 'text',
text: `β Please provide a template ID.\n\nπ‘ **Get template IDs from:**\nβ’ \`search_templates\` results\nβ’ Template conversion results\nβ’ Web dashboard at https://templation.up.railway.app/templates`,
},
],
};
}
try {
const template = await apiCall(`/api/templates/${template_id}`);
let result = `π **Template Details**\n\n`;
result += `**Name:** ${template.name}\n`;
result += `**Description:** ${template.description || 'No description'}\n`;
result += `**Source Repository:** ${template.source_repo_url}\n`;
result += `**Created:** ${template.created_at ? new Date(template.created_at).toLocaleDateString() : 'Unknown'}\n`;
result += `**Usage Count:** ${template.usage_count || 0} times\n`;
result += `**Last Used:** ${template.last_used ? new Date(template.last_used).toLocaleDateString() : 'Never'}\n`;
result += `**Favorite:** ${template.is_favorite ? 'β Yes' : 'β No'}\n`;
if (template.tech_stack?.length > 0) {
result += `**Technologies:** ${template.tech_stack.join(', ')}\n`;
}
if (include_setup_guide && template.template_data) {
const data = template.template_data;
if (data.conversion_steps?.length > 0) {
result += `\n## π Setup Instructions\n`;
data.conversion_steps.forEach((step, index) => {
result += `${index + 1}. ${step}\n`;
});
}
if (data.setup_commands?.length > 0) {
result += `\n## π Setup Commands\n\`\`\`bash\n`;
data.setup_commands.forEach((command) => {
result += `${command}\n`;
});
result += `\`\`\`\n`;
}
if (data.files_to_modify?.length > 0) {
result += `\n## π Files to Customize\n`;
data.files_to_modify.forEach((file) => {
result += `β’ \`${file}\`\n`;
});
}
if (data.customization_points?.length > 0) {
result += `\n## π¨ Customization Points\n`;
data.customization_points.forEach((point) => {
result += `β’ ${point}\n`;
});
}
if (data.expected_outcome) {
result += `\n## π― Expected Outcome\n${data.expected_outcome}\n`;
}
}
result += `\nπ **Web View:** https://templation.up.railway.app/templates/${template_id}\n`;
result += `π **Source Code:** ${template.source_repo_url}`;
return {
content: [
{
type: 'text',
text: result,
},
],
};
}
catch (error) {
return {
content: [
{
type: 'text',
text: `β Error getting template details: ${error instanceof Error ? error.message : 'Unknown error'}\n\nπ§ **Possible issues:**\nβ’ Template ID not found or invalid\nβ’ Template may have been deleted\nβ’ API key doesn't have access to this template\nβ’ Temporary service issue\n\nπ‘ **Try:**\nβ’ Using \`search_templates\` to find the correct template ID\nβ’ Checking the template exists at https://templation.up.railway.app/templates\nβ’ Verifying your API key permissions`,
},
],
};
}
}
default:
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}. Available tools: search_templates, search_exemplar, template_converter, get_user_info, get_dashboard_stats, get_template_details`);
}
}
catch (error) {
if (error instanceof McpError) {
throw error;
}
// Enhanced error logging for debugging
console.error(`Tool execution failed for ${name}:`, error);
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('π Templation MCP Server v2.0.0 running on stdio');
console.error('π Get your API key: https://templation.up.railway.app/api-keys');
console.error('π Web Dashboard: https://templation.up.railway.app/dashboard');
}
main().catch((error) => {
console.error('π₯ Fatal error in main():', error);
process.exit(1);
});
//# sourceMappingURL=index-backup.js.map