Skip to content

Commit c038dff

Browse files
committed
feat: add getPromptContent tool for auto-discovery
- Add MCP tool that dynamically discovers all available prompts - Tool description includes comprehensive list of all prompts with descriptions - Auto-generates enum of available prompts from markdown frontmatter - Enables LLM auto-discovery of TimescaleDB guidance prompts - Updated timescaledb setup prompt description to be more comprehensive Benefits: - LLM can automatically choose appropriate prompts based on user needs - No need for users to explicitly know prompt names - Stays in sync as new .md files are added
1 parent 97e86cd commit c038dff

File tree

3 files changed

+93
-1
lines changed

3 files changed

+93
-1
lines changed

src/apis/getPromptContent.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { z } from 'zod';
2+
import { readdirSync, readFileSync } from 'fs';
3+
import { join, dirname } from 'path';
4+
import { fileURLToPath } from 'url';
5+
import matter from 'gray-matter';
6+
import { ApiFactory } from '../shared/boilerplate/src/types.js';
7+
import { ServerContext } from '../types.js';
8+
import { promptFactories } from '../prompts/index.js';
9+
10+
// Get all available prompt names dynamically from markdown files
11+
const __dirname = dirname(fileURLToPath(import.meta.url));
12+
const markdownPromptsDir = join(__dirname, '../prompts/md');
13+
14+
function getAvailablePrompts() {
15+
const files = readdirSync(markdownPromptsDir).filter(file => file.endsWith('.md'));
16+
const prompts = files.map(file => {
17+
const filePath = join(markdownPromptsDir, file);
18+
const fileContent = readFileSync(filePath, 'utf-8');
19+
const { data } = matter(fileContent);
20+
return {
21+
name: data.name,
22+
title: data.title,
23+
description: data.description,
24+
};
25+
});
26+
return prompts;
27+
}
28+
29+
const availablePrompts = getAvailablePrompts();
30+
const promptNames = availablePrompts.map(p => p.name);
31+
32+
// Create enum schema dynamically
33+
const inputSchema = {
34+
prompt_name: z
35+
.enum(promptNames as [string, ...string[]])
36+
.describe('The name of the prompt to retrieve'),
37+
} as const;
38+
39+
const outputSchema = {
40+
prompt_name: z.string().describe('The name of the requested prompt'),
41+
title: z.string().describe('The display title of the prompt'),
42+
description: z.string().describe('Description of what this prompt does'),
43+
content: z.string().describe('The full prompt content'),
44+
} as const;
45+
46+
export const getPromptContentFactory: ApiFactory<
47+
ServerContext,
48+
typeof inputSchema,
49+
typeof outputSchema
50+
> = ({ pgPool }) => ({
51+
name: 'getPromptContent',
52+
config: {
53+
title: 'Get TimescaleDB Prompt Content',
54+
description: `Retrieve detailed prompt content for TimescaleDB guidance and best practices. This tool provides access to comprehensive guides that help with TimescaleDB implementation.
55+
56+
Available Prompts:
57+
58+
${availablePrompts.map(p => `**${p.name}** - ${p.description}`).join('\n\n')}
59+
`,
60+
inputSchema,
61+
outputSchema,
62+
},
63+
fn: async ({ prompt_name }) => {
64+
// Find the prompt factory by name
65+
const promptFactory = promptFactories.find(factory => {
66+
const prompt = factory({} as ServerContext);
67+
return prompt.name === prompt_name;
68+
});
69+
70+
if (!promptFactory) {
71+
throw new Error(`Prompt '${prompt_name}' not found`);
72+
}
73+
74+
// Create the prompt instance
75+
const prompt = promptFactory({} as ServerContext);
76+
77+
// Execute the prompt to get its content
78+
const result = await prompt.fn({});
79+
80+
// Extract content from the prompt result
81+
const content = result.messages?.[0]?.content?.text || '';
82+
83+
return {
84+
prompt_name: prompt.name,
85+
title: prompt.config.title || prompt.name,
86+
description: prompt.config.description || '',
87+
content: String(content),
88+
};
89+
},
90+
});

src/apis/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { semanticSearchPostgresDocsFactory } from './semanticSearchPostgresDocs.js';
22
import { semanticSearchTimescaleDocsFactory } from './semanticSearchTimescaleDocs.js';
3+
import { getPromptContentFactory } from './getPromptContent.js';
34

45
export const apiFactories = [
56
semanticSearchPostgresDocsFactory,
67
semanticSearchTimescaleDocsFactory,
8+
getPromptContentFactory,
79
] as const;

src/prompts/md/timescaledb_setup_prompt.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
name: timescaledbSetup
33
title: TimescaleDB Complete Setup Guide
4-
description: Step-by-step instructions for setting up TimescaleDB with hypertables, compression, retention policies, and continuous aggregates
4+
description: Step-by-step instructions for designing table schemas and setting up TimescaleDB with hypertables, indexes, compression, retention policies, and continuous aggregates. Instructions for selecting: partition columns, segment_by columns, order_by columns, chunk time interval, real-time aggregation.
55
---
66

77
# TimescaleDB Complete Setup Guide for AI Coding Assistants

0 commit comments

Comments
 (0)