Skip to main content
Glama

Context Pods

by conorluddy
sdk-compatibility.test.tsโ€ข8.71 kB
/** * SDK 1.17.4 Compatibility Tests for MCP Templates * * Validates that all TypeScript templates are compatible with the latest * @modelcontextprotocol/sdk version and use correct import patterns */ import { readFileSync, existsSync, readdirSync } from 'fs'; import { join } from 'path'; import { describe, it, expect } from 'vitest'; import { getAvailableTemplates } from '../src/index.js'; describe('SDK 1.17.4 Compatibility', () => { const typeScriptTemplates = getAvailableTemplates().filter((t) => t.language === 'typescript'); describe('Package.json SDK Dependencies', () => { typeScriptTemplates.forEach((template) => { it(`${template.name} should use SDK version 1.17.4 or higher`, () => { const packageJsonPath = join(template.path, 'package.json'); expect(existsSync(packageJsonPath)).toBe(true); const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8')); const sdkVersion = packageJson.dependencies?.['@modelcontextprotocol/sdk']; expect(sdkVersion).toBeDefined(); expect(sdkVersion).toMatch(/^\^1\.17\.\d+$/); // Extract version number and ensure it's >= 1.17.4 const versionMatch = sdkVersion.match(/\^1\.17\.(\d+)/); if (versionMatch) { const minorVersion = parseInt(versionMatch[1], 10); expect(minorVersion).toBeGreaterThanOrEqual(4); } }); }); }); describe('Import Path Patterns', () => { typeScriptTemplates.forEach((template) => { describe(`${template.name} template imports`, () => { it('should use correct Server import path with .js extension', () => { const sourceFiles = findTypeScriptFiles(template.path); sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); // Only check files that actually import Server from the SDK if (content.includes("from '@modelcontextprotocol/sdk/server")) { expect(content).toMatch( /import\s+.*Server.*\s+from\s+['"]@modelcontextprotocol\/sdk\/server\/index\.js['"]/, ); } }); }); it('should use correct StdioServerTransport import path', () => { const sourceFiles = findTypeScriptFiles(template.path); sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); if (content.includes('StdioServerTransport')) { expect(content).toMatch( /import\s+.*StdioServerTransport.*\s+from\s+['"]@modelcontextprotocol\/sdk\/server\/stdio\.js['"]/, ); } }); }); it('should use correct types import path', () => { const sourceFiles = findTypeScriptFiles(template.path); let hasTypesImport = false; sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); // Check if file imports from SDK types if (content.includes('@modelcontextprotocol/sdk/types')) { hasTypesImport = true; // Verify it has the .js extension expect(content).toMatch(/@modelcontextprotocol\/sdk\/types\.js/); } }); // At least one file should import from types expect(hasTypesImport).toBe(true); }); it('should not import from deprecated SDK paths', () => { const sourceFiles = findTypeScriptFiles(template.path); sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); const importLines = content .split('\n') .filter( (line) => line.includes('import') && line.includes('@modelcontextprotocol/sdk'), ); importLines.forEach((line) => { // Check that we're using proper subpaths expect(line).toMatch(/\/sdk\/(server|types)/); // Check for .js extension expect(line).toMatch(/\.js['"]/); }); }); }); }); }); }); describe('TypeScript Configuration', () => { typeScriptTemplates.forEach((template) => { it(`${template.name} should have proper ESM TypeScript configuration`, () => { const tsconfigPath = join(template.path, 'tsconfig.json'); if (existsSync(tsconfigPath)) { const tsconfig = JSON.parse(readFileSync(tsconfigPath, 'utf-8')); // Check for ESM module settings - Node16 is correct for modern Node.js ESM expect(tsconfig.compilerOptions?.module).toMatch( /^(ES2020|ES2022|ESNext|NodeNext|Node16)$/i, ); expect(tsconfig.compilerOptions?.moduleResolution).toMatch( /^(node|NodeNext|bundler|Node16)$/i, ); // Check for proper target const target = tsconfig.compilerOptions?.target; expect( ['ES2020', 'ES2021', 'ES2022', 'ESNext'].some((t) => target?.toUpperCase() === t), ).toBe(true); } }); }); }); describe('Core MCP Features Usage', () => { typeScriptTemplates.forEach((template) => { describe(`${template.name} template MCP implementation`, () => { it('should properly instantiate Server with correct constructor', () => { const sourceFiles = findTypeScriptFiles(template.path); sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); if (content.includes('new Server')) { // Check for proper Server instantiation pattern expect(content).toMatch(/new Server\s*\(\s*\{[\s\S]*?name:[\s\S]*?version:/); } }); }); it('should use setRequestHandler for protocol handlers', () => { const sourceFiles = findTypeScriptFiles(template.path); sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); if (content.includes('server.')) { // Check for proper handler registration const handlerPatterns = [ 'ListToolsRequestSchema', 'CallToolRequestSchema', 'ListResourcesRequestSchema', 'ReadResourceRequestSchema', ]; handlerPatterns.forEach((pattern) => { if (content.includes(pattern)) { expect(content).toMatch( new RegExp(`server\\.setRequestHandler\\s*\\(\\s*${pattern}`), ); } }); } }); }); it('should properly connect to StdioServerTransport', () => { const sourceFiles = findTypeScriptFiles(template.path); sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); if (content.includes('StdioServerTransport')) { expect(content).toMatch(/new StdioServerTransport\s*\(\s*\)/); expect(content).toMatch(/server\.connect\s*\(\s*transport/); } }); }); }); }); }); describe('No Usage of Deprecated APIs', () => { typeScriptTemplates.forEach((template) => { it(`${template.name} should not use deprecated SDK 0.5.0 patterns`, () => { const sourceFiles = findTypeScriptFiles(template.path); const deprecatedPatterns = [ /McpServer/, // Old class name /createServer.*from.*sdk/, // Old factory pattern /\.handle\(/, // Old handler method /\.onRequest\(/, // Old request handler /import.*\{.*Server.*\}.*from.*['"]@modelcontextprotocol\/sdk['"]/, // Old import ]; sourceFiles.forEach((file) => { const content = readFileSync(file, 'utf-8'); deprecatedPatterns.forEach((pattern) => { expect(content).not.toMatch(pattern); }); }); }); }); }); }); /** * Helper function to find all TypeScript source files in a template */ function findTypeScriptFiles(templatePath: string): string[] { const files: string[] = []; const srcPath = join(templatePath, 'src'); if (!existsSync(srcPath)) { return files; } function scanDirectory(dir: string) { const entries = readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = join(dir, entry.name); if (entry.isDirectory()) { scanDirectory(fullPath); } else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')) { files.push(fullPath); } } } scanDirectory(srcPath); return files; }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/conorluddy/ContextPods'

If you have feedback or need assistance with the MCP directory API, please join our Discord server