codemesh
Version:
Execute TypeScript code against multiple MCP servers, weaving them together into powerful workflows
92 lines (91 loc) • 3.76 kB
JavaScript
import * as fs from 'node:fs';
import * as path from 'node:path';
import { logger } from './logger.js';
import { createServerObjectName } from './utils.js';
/**
* Parse markdown file and extract tool-specific augmentations
*/
function parseMarkdownAugmentations(markdown, serverObjectName) {
const augmentations = [];
// Split by H1 headers (# serverObject.methodName)
const sections = markdown.split(/^# /m).filter((s) => s.trim());
for (const section of sections) {
const lines = section.split('\n');
const header = lines[0].trim();
// Check if header matches pattern: serverObject.methodName
const match = header.match(/^(\w+)\.(\w+)/);
if (!match) {
logger.warn(`Skipping augmentation section with invalid header: ${header}`);
continue;
}
const [, serverObj, methodName] = match;
// Verify it matches the expected server object name
if (serverObj !== serverObjectName) {
logger.warn(`Skipping augmentation for ${serverObj}.${methodName} - doesn't match server ${serverObjectName}`);
continue;
}
// Get the rest of the markdown (everything after the H1)
const documentation = lines.slice(1).join('\n').trim();
augmentations.push({
toolName: methodName,
serverObjectName,
documentation,
});
logger.log(`Loaded augmentation for ${serverObj}.${methodName}`);
}
return augmentations;
}
/**
* Load tool augmentations from .codemesh directory
*/
/**
* Check if a tool has augmentation documentation
*/
export function hasAugmentation(serverObjectName, toolName, codemeshDir) {
const augmentations = loadAugmentations(codemeshDir);
const key = `${serverObjectName}.${toolName}`;
return augmentations.has(key);
}
export function loadAugmentations(codemeshDir) {
const augmentationMap = new Map();
// Check if .codemesh directory exists
if (!fs.existsSync(codemeshDir)) {
logger.log(`No .codemesh directory found at ${codemeshDir}`);
return augmentationMap;
}
logger.log(`Loading augmentations from ${codemeshDir}...`);
// Read all .md files in the directory
const files = fs.readdirSync(codemeshDir).filter((f) => f.endsWith('.md'));
for (const file of files) {
// Extract server object name from filename (e.g., "filesystem-server.md" -> "filesystemServer")
const serverIdMatch = file.match(/^(.+)\.md$/);
if (!serverIdMatch)
continue;
const serverId = serverIdMatch[1];
// Convert server-id to serverObjectName using utility (e.g., "filesystem-server" -> "filesystemServer")
const serverObjectName = createServerObjectName(serverId);
const filePath = path.join(codemeshDir, file);
logger.log(`Reading augmentation file: ${filePath}`);
try {
const markdown = fs.readFileSync(filePath, 'utf-8');
const augmentations = parseMarkdownAugmentations(markdown, serverObjectName);
for (const aug of augmentations) {
const key = `${aug.serverObjectName}.${aug.toolName}`;
augmentationMap.set(key, aug);
logger.log(`Registered augmentation: ${key}`);
}
}
catch (error) {
logger.error(`Failed to load augmentation file ${filePath}:`, error);
}
}
logger.log(`Loaded ${augmentationMap.size} tool augmentation(s)`);
return augmentationMap;
}
/**
* Get augmentation for a specific tool
*/
export function getAugmentation(augmentations, serverObjectName, toolName) {
const key = `${serverObjectName}.${toolName}`;
return augmentations.get(key);
}