Skip to main content
Glama
mdz-axo

PT-MCP (Paul Test Man Context Protocol)

by mdz-axo
schema-mapper.ts9.09 kB
/** * Schema.org Mapper Service * * Maps codebase entities to Schema.org types and properties. * Based on Ludwig neurosymbolic system with 74+ bidirectional property mappings. */ import { getDatabase } from './database.js'; import type { Entity, SchemaAnnotation } from './schema.js'; import { SchemaOrgType } from './schema.js'; /** * Schema.org property mappings * Based on Ludwig system's 74+ bidirectional mappings */ const PROPERTY_MAPPINGS: Record<string, string> = { // Software properties dependencies: 'softwareRequirements', version: 'softwareVersion', authors: 'author', author: 'author', maintainers: 'maintainer', license: 'license', description: 'description', homepage: 'url', repository: 'codeRepository', bugs: 'discussionUrl', keywords: 'keywords', // Application properties applicationCategory: 'applicationCategory', operatingSystem: 'operatingSystem', permissions: 'permissions', softwareHelp: 'softwareHelp', availableOnDevice: 'availableOnDevice', // API properties documentation: 'documentation', endpointURL: 'url', contentType: 'encodingFormat', httpMethod: 'httpMethod', // Code properties programmingLanguage: 'programmingLanguage', runtimePlatform: 'runtimePlatform', targetProduct: 'targetProduct', codeRepository: 'codeRepository', codeSampleType: 'codeSampleType', // Creative work properties dateCreated: 'dateCreated', dateModified: 'dateModified', datePublished: 'datePublished', creator: 'creator', contributor: 'contributor', publisher: 'publisher', // Additional mappings name: 'name', alternateName: 'alternateName', identifier: 'identifier', sameAs: 'sameAs', isPartOf: 'isPartOf', hasPart: 'hasPart', }; /** * Codebase type to Schema.org type mappings */ const TYPE_MAPPINGS: Record<string, SchemaOrgType | string> = { // Web applications 'web-app': SchemaOrgType.WEB_APPLICATION, 'webapp': SchemaOrgType.WEB_APPLICATION, 'website': SchemaOrgType.WEB_APPLICATION, // API servers 'api': SchemaOrgType.WEB_API, 'rest-api': SchemaOrgType.WEB_API, 'graphql-api': SchemaOrgType.WEB_API, 'api-server': SchemaOrgType.WEB_API, // Mobile apps 'mobile-app': 'MobileApplication', 'ios-app': 'MobileApplication', 'android-app': 'MobileApplication', // Libraries and packages 'library': 'SoftwareLibrary', 'package': 'SoftwareLibrary', 'npm-package': 'SoftwareLibrary', 'module': 'SoftwareLibrary', // Source code 'source': SchemaOrgType.SOFTWARE_SOURCE_CODE, 'repository': SchemaOrgType.SOFTWARE_SOURCE_CODE, 'codebase': SchemaOrgType.SOFTWARE_SOURCE_CODE, // Software applications 'application': SchemaOrgType.SOFTWARE_APPLICATION, 'app': SchemaOrgType.SOFTWARE_APPLICATION, 'software': SchemaOrgType.SOFTWARE_APPLICATION, // Programming languages 'language': SchemaOrgType.COMPUTER_LANGUAGE, 'programming-language': SchemaOrgType.COMPUTER_LANGUAGE, // Documentation 'docs': SchemaOrgType.TECH_ARTICLE, 'documentation': SchemaOrgType.TECH_ARTICLE, 'guide': SchemaOrgType.HOW_TO, 'tutorial': SchemaOrgType.HOW_TO, // API documentation 'api-docs': SchemaOrgType.API_REFERENCE, 'api-reference': SchemaOrgType.API_REFERENCE, }; /** * Schema.org mapper for codebase entities */ export class SchemaMapper { /** * Map codebase entity to Schema.org type */ mapToSchemaType(entityType: string): SchemaOrgType | string { const normalized = entityType.toLowerCase().replace(/_/g, '-'); return TYPE_MAPPINGS[normalized] || SchemaOrgType.SOFTWARE_APPLICATION; } /** * Map codebase properties to Schema.org properties */ mapProperties(properties: Record<string, any>): Record<string, any> { const mapped: Record<string, any> = {}; for (const [key, value] of Object.entries(properties)) { const schemaProperty = PROPERTY_MAPPINGS[key] || key; mapped[schemaProperty] = value; } return mapped; } /** * Create Schema.org annotation for entity */ async annotateEntity(entity: Entity): Promise<SchemaAnnotation> { const schemaType = this.mapToSchemaType(entity.type); const properties = this.mapProperties(entity.metadata || {}); // Add entity name properties.name = entity.name; // Add identifier properties.identifier = entity.name; // Add file reference if available if (entity.source_file) { properties.codeRepository = entity.source_file; } return { entity_id: entity.id!, schema_type: schemaType, properties, context_url: 'https://schema.org', }; } /** * Detect codebase type from analysis results */ detectCodebaseType(analysis: any): SchemaOrgType | string { // Check package.json indicators if (analysis.package?.type === 'module') { return SchemaOrgType.SOFTWARE_SOURCE_CODE; } // Check for web frameworks if (this.hasFramework(analysis, ['react', 'vue', 'angular', 'svelte'])) { return SchemaOrgType.WEB_APPLICATION; } // Check for API frameworks if (this.hasFramework(analysis, ['express', 'fastify', 'koa', 'nestjs'])) { return SchemaOrgType.WEB_API; } // Check for mobile frameworks if (this.hasFramework(analysis, ['react-native', 'flutter', 'ionic'])) { return 'MobileApplication'; } // Check for CLI tools if (analysis.package?.bin) { return 'SoftwareApplication'; } // Default to generic software application return SchemaOrgType.SOFTWARE_APPLICATION; } /** * Extract Schema.org properties from codebase analysis */ extractProperties(analysis: any): Record<string, any> { const properties: Record<string, any> = {}; // Extract from package.json if (analysis.package) { const pkg = analysis.package; if (pkg.name) properties.name = pkg.name; if (pkg.version) properties.softwareVersion = pkg.version; if (pkg.description) properties.description = pkg.description; if (pkg.author) properties.author = this.parseAuthor(pkg.author); if (pkg.license) properties.license = pkg.license; if (pkg.homepage) properties.url = pkg.homepage; if (pkg.repository) properties.codeRepository = this.parseRepository(pkg.repository); if (pkg.keywords) properties.keywords = pkg.keywords; // Dependencies as software requirements if (pkg.dependencies) { properties.softwareRequirements = Object.keys(pkg.dependencies); } } // Extract programming languages if (analysis.languages) { const langs = Object.keys(analysis.languages); if (langs.length > 0) { properties.programmingLanguage = langs; } } // Extract entry points if (analysis.entry_points && analysis.entry_points.length > 0) { properties.hasPart = analysis.entry_points.map((ep: string) => ({ '@type': 'SoftwareSourceCode', name: ep, })); } return properties; } /** * Check if codebase has specific framework */ private hasFramework(analysis: any, frameworks: string[]): boolean { const deps = analysis.package?.dependencies || {}; const devDeps = analysis.package?.devDependencies || {}; const allDeps = { ...deps, ...devDeps }; return frameworks.some((framework) => framework in allDeps); } /** * Parse author field (can be string or object) */ private parseAuthor(author: any): any { if (typeof author === 'string') { return { '@type': 'Person', name: author }; } if (typeof author === 'object') { const parsed: any = { '@type': 'Person' }; if (author.name) parsed.name = author.name; if (author.email) parsed.email = author.email; if (author.url) parsed.url = author.url; return parsed; } return author; } /** * Parse repository field (can be string or object) */ private parseRepository(repo: any): string { if (typeof repo === 'string') { return repo; } if (typeof repo === 'object' && repo.url) { return repo.url; } return ''; } /** * Generate JSON-LD context */ generateJSONLD(annotation: SchemaAnnotation): any { return { '@context': annotation.context_url || 'https://schema.org', '@type': annotation.schema_type, ...annotation.properties, }; } /** * Save annotation to database */ async saveAnnotation(annotation: SchemaAnnotation): Promise<void> { const db = await getDatabase(); await db.upsertSchemaAnnotation(annotation); } /** * Get annotation for entity */ async getAnnotation(entityId: number): Promise<SchemaAnnotation | null> { const db = await getDatabase(); return db.findSchemaAnnotationByEntityId(entityId); } } /** * Singleton instance */ let mapperInstance: SchemaMapper | null = null; /** * Get or create Schema mapper instance */ export function getSchemaMapper(): SchemaMapper { if (!mapperInstance) { mapperInstance = new SchemaMapper(); } return mapperInstance; }

Latest Blog Posts

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/mdz-axo/pt-mcp'

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