import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { WebStandardStreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
import { z } from 'zod';
import { listTemplates } from './tools/list-templates';
import { selectTemplate } from './tools/select-template';
import { generatePrompt } from './tools/generate-prompt';
import { syncTemplates } from './tools/sync-templates';
// Create MCP server
const server = new McpServer({
name: 'prompt-template-selector',
version: '1.0.0',
});
// Define schemas for tool inputs
const ListTemplatesSchema = z.object({
category: z.enum(['agent', 'system', 'tool', 'reminder', 'skill', 'any']).optional(),
include_custom: z.boolean().optional(),
search: z.string().optional(),
});
const SelectTemplateSchema = z.object({
task_description: z.string().min(1, 'Task description is required'),
prompt_type: z.enum(['agent', 'system', 'tool', 'reminder', 'skill', 'any']).optional(),
context: z.string().optional(),
max_results: z.number().min(1).max(10).optional(),
});
const GeneratePromptSchema = z.object({
task_description: z.string().min(1, 'Task description is required'),
prompt_type: z.enum(['agent', 'system', 'tool', 'reminder', 'skill', 'any']).optional(),
target_llm: z.string().optional(),
context: z.string().optional(),
max_results: z.number().min(1).max(10).optional(),
});
const SyncTemplatesSchema = z.object({
force_reindex: z.boolean().optional(),
});
// Register tools
server.tool(
'list_templates',
'List all available prompt templates with optional filtering by category or search query',
ListTemplatesSchema.shape,
async (params) => {
const input = ListTemplatesSchema.parse(params);
const result = await listTemplates(input);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
'select_template',
'Select the most appropriate template(s) for a given task description',
SelectTemplateSchema.shape,
async (params) => {
const input = SelectTemplateSchema.parse(params);
const result = await selectTemplate(input);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
'generate_prompt',
'Generate a customized prompt based on the best matching template(s) for your task',
GeneratePromptSchema.shape,
async (params) => {
const input = GeneratePromptSchema.parse(params);
const result = await generatePrompt(input);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
);
server.tool(
'sync_templates',
'Sync templates from the GitHub repository and update the local index',
SyncTemplatesSchema.shape,
async (params) => {
const input = SyncTemplatesSchema.parse(params);
const result = await syncTemplates(input);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
}
);
// Check transport mode from args or env
const transportMode = process.argv.includes('--http') ? 'http' : 'stdio';
if (transportMode === 'stdio') {
// STDIO transport for local CLI usage (default)
const transport = new StdioServerTransport();
await server.connect(transport);
// Log to stderr so it doesn't interfere with stdio protocol
console.error('MCP Prompt Template Selector running in STDIO mode');
console.error('Available tools: list_templates, select_template, generate_prompt, sync_templates');
} else {
// HTTP transport for server deployment
const transport = new WebStandardStreamableHTTPServerTransport({
sessionIdGenerator: () => crypto.randomUUID(),
enableJsonResponse: true,
});
await server.connect(transport);
const PORT = parseInt(process.env.PORT || '3000', 10);
console.log(`Starting MCP Prompt Template Selector server on port ${PORT}...`);
Bun.serve({
port: PORT,
async fetch(req) {
const url = new URL(req.url);
if (url.pathname === '/health') {
return new Response(JSON.stringify({ status: 'ok', version: '1.0.0' }), {
headers: { 'Content-Type': 'application/json' },
});
}
if (url.pathname === '/mcp' || url.pathname === '/') {
try {
return await transport.handleRequest(req);
} catch (error) {
console.error('MCP error:', error);
return new Response(
JSON.stringify({ error: 'MCP connection error' }),
{
status: 500,
headers: { 'Content-Type': 'application/json' },
}
);
}
}
return new Response(
JSON.stringify({
error: 'Not found',
endpoints: { mcp: '/mcp', health: '/health' },
}),
{
status: 404,
headers: { 'Content-Type': 'application/json' },
}
);
},
});
console.log(`MCP server running at http://localhost:${PORT}`);
console.log('Available tools: list_templates, select_template, generate_prompt, sync_templates');
}