Implements MCP server for semantic search across GSD projects: MCP Tools: - gsd_memory_search: Search across all registered projects - gsd_memory_decisions: Find decisions from SUMMARY/PROJECT.md - gsd_memory_patterns: Find patterns from SUMMARY.md - gsd_memory_pitfalls: Find pitfalls from RESEARCH.md - gsd_memory_stack: Find tech stack entries - gsd_memory_register: Register project with memory - gsd_memory_index: Trigger indexing/update - gsd_memory_status: Show system status Architecture: - QMD wrapper with grep fallback when QMD unavailable - YAML frontmatter extractors for GSD document types - Project registry at ~/.gsd/projects.json - Auto-install via bin/install.js for Claude Code Workflow integrations: - new-project: Registers project with memory - plan-phase: Indexes after planning - execute-phase: Indexes after execution - complete-milestone: Indexes milestone completion - Researcher agents query memory before Context7 Tests: 117 passing (66 unit + 51 integration) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
298 lines
9.9 KiB
JavaScript
298 lines
9.9 KiB
JavaScript
#!/usr/bin/env node
|
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
import { search } from './tools/search.js';
|
|
import { findDecisions } from './tools/decisions.js';
|
|
import { findPatterns } from './tools/patterns.js';
|
|
import { findPitfalls } from './tools/pitfalls.js';
|
|
import { findStack } from './tools/stack.js';
|
|
import { register } from './tools/register.js';
|
|
import { index, indexAll } from './tools/index-tool.js';
|
|
import { getStatus } from './tools/status.js';
|
|
// Define available tools
|
|
const tools = [
|
|
{
|
|
name: 'gsd_memory_search',
|
|
description: 'Search across all registered GSD projects for content matching a query. Returns enriched results with project, phase, and document type context.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
query: {
|
|
type: 'string',
|
|
description: 'The search query'
|
|
},
|
|
project: {
|
|
type: 'string',
|
|
description: 'Optional: limit search to a specific project'
|
|
},
|
|
limit: {
|
|
type: 'number',
|
|
description: 'Maximum number of results (default: 20)'
|
|
}
|
|
},
|
|
required: ['query']
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_decisions',
|
|
description: 'Find decisions made across GSD projects. Searches KEY-DECISIONS from SUMMARY.md frontmatter and Key Decisions tables from PROJECT.md.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
query: {
|
|
type: 'string',
|
|
description: 'Optional: filter decisions by keyword'
|
|
},
|
|
project: {
|
|
type: 'string',
|
|
description: 'Optional: limit to a specific project'
|
|
},
|
|
tags: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Optional: filter by tags'
|
|
},
|
|
limit: {
|
|
type: 'number',
|
|
description: 'Maximum number of results (default: 50)'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_patterns',
|
|
description: 'Find patterns established across GSD projects. Extracts PATTERNS-ESTABLISHED from SUMMARY.md frontmatter.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
query: {
|
|
type: 'string',
|
|
description: 'Optional: filter patterns by keyword'
|
|
},
|
|
project: {
|
|
type: 'string',
|
|
description: 'Optional: limit to a specific project'
|
|
},
|
|
tags: {
|
|
type: 'array',
|
|
items: { type: 'string' },
|
|
description: 'Optional: filter by tags'
|
|
},
|
|
limit: {
|
|
type: 'number',
|
|
description: 'Maximum number of results (default: 50)'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_pitfalls',
|
|
description: 'Find documented pitfalls from RESEARCH.md files. Includes what went wrong, causes, and prevention strategies.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
query: {
|
|
type: 'string',
|
|
description: 'Optional: filter pitfalls by keyword'
|
|
},
|
|
project: {
|
|
type: 'string',
|
|
description: 'Optional: limit to a specific project'
|
|
},
|
|
domain: {
|
|
type: 'string',
|
|
description: 'Optional: filter by technology domain'
|
|
},
|
|
limit: {
|
|
type: 'number',
|
|
description: 'Maximum number of results (default: 50)'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_stack',
|
|
description: 'Find tech stack entries across GSD projects. Extracts from SUMMARY.md (tech-stack.added) and RESEARCH.md (standard stack tables).',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
query: {
|
|
type: 'string',
|
|
description: 'Optional: filter by library name or purpose'
|
|
},
|
|
project: {
|
|
type: 'string',
|
|
description: 'Optional: limit to a specific project'
|
|
},
|
|
limit: {
|
|
type: 'number',
|
|
description: 'Maximum number of results (default: 100)'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_register',
|
|
description: 'Register a project with GSD memory. Creates a QMD collection if QMD is available.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
path: {
|
|
type: 'string',
|
|
description: 'Path to the project root (must contain .planning directory)'
|
|
},
|
|
name: {
|
|
type: 'string',
|
|
description: 'Optional: project name (defaults to directory name)'
|
|
}
|
|
},
|
|
required: ['path']
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_index',
|
|
description: 'Trigger indexing/update for a project. Updates QMD collection if available, otherwise marks project as indexed for grep fallback.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
project: {
|
|
type: 'string',
|
|
description: 'Project name to index'
|
|
},
|
|
path: {
|
|
type: 'string',
|
|
description: 'Alternative: project path to index'
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'gsd_memory_status',
|
|
description: 'Show status of GSD memory system: QMD availability, registered projects, document counts.',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {}
|
|
}
|
|
}
|
|
];
|
|
// Create server instance
|
|
const server = new Server({
|
|
name: 'gsd-memory',
|
|
version: '1.0.0'
|
|
}, {
|
|
capabilities: {
|
|
tools: {}
|
|
}
|
|
});
|
|
// Handle list tools request
|
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
tools
|
|
}));
|
|
// Handle tool calls
|
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
const { name, arguments: args } = request.params;
|
|
try {
|
|
let result;
|
|
switch (name) {
|
|
case 'gsd_memory_search':
|
|
result = await search({
|
|
query: args?.query,
|
|
project: args?.project,
|
|
limit: args?.limit
|
|
});
|
|
break;
|
|
case 'gsd_memory_decisions':
|
|
result = await findDecisions({
|
|
query: args?.query,
|
|
project: args?.project,
|
|
tags: args?.tags,
|
|
limit: args?.limit
|
|
});
|
|
break;
|
|
case 'gsd_memory_patterns':
|
|
result = await findPatterns({
|
|
query: args?.query,
|
|
project: args?.project,
|
|
tags: args?.tags,
|
|
limit: args?.limit
|
|
});
|
|
break;
|
|
case 'gsd_memory_pitfalls':
|
|
result = await findPitfalls({
|
|
query: args?.query,
|
|
project: args?.project,
|
|
domain: args?.domain,
|
|
limit: args?.limit
|
|
});
|
|
break;
|
|
case 'gsd_memory_stack':
|
|
result = await findStack({
|
|
query: args?.query,
|
|
project: args?.project,
|
|
limit: args?.limit
|
|
});
|
|
break;
|
|
case 'gsd_memory_register':
|
|
result = await register({
|
|
path: args?.path,
|
|
name: args?.name
|
|
});
|
|
break;
|
|
case 'gsd_memory_index':
|
|
if (args?.project || args?.path) {
|
|
result = await index({
|
|
project: args?.project,
|
|
path: args?.path
|
|
});
|
|
}
|
|
else {
|
|
result = await indexAll();
|
|
}
|
|
break;
|
|
case 'gsd_memory_status':
|
|
result = await getStatus();
|
|
break;
|
|
default:
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: `Unknown tool: ${name}`
|
|
}
|
|
],
|
|
isError: true
|
|
};
|
|
}
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(result, null, 2)
|
|
}
|
|
]
|
|
};
|
|
}
|
|
catch (error) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: `Error: ${error instanceof Error ? error.message : String(error)}`
|
|
}
|
|
],
|
|
isError: true
|
|
};
|
|
}
|
|
});
|
|
// Start the server
|
|
async function main() {
|
|
const transport = new StdioServerTransport();
|
|
await server.connect(transport);
|
|
console.error('GSD Memory MCP server started');
|
|
}
|
|
main().catch((error) => {
|
|
console.error('Fatal error:', error);
|
|
process.exit(1);
|
|
});
|
|
//# sourceMappingURL=index.js.map
|