@@ -22,6 +22,21 @@ import type {
2222} from '../../routes/mcp/servers/schemas' ;
2323import { GitHubService } from '../githubService' ;
2424
25+ // =============================================================================
26+ // UTILITY FUNCTIONS
27+ // =============================================================================
28+
29+ /**
30+ * Convert empty strings to undefined for optional fields
31+ * Official registry sometimes returns empty strings instead of omitting fields
32+ *
33+ * @param value - Value to check and convert
34+ * @returns undefined if value is empty string, otherwise the original value
35+ */
36+ function emptyToUndefined ( value : string | undefined ) : string | undefined {
37+ return value === '' ? undefined : value ;
38+ }
39+
2540// =============================================================================
2641// OFFICIAL REGISTRY TYPE DEFINITIONS
2742// =============================================================================
@@ -123,13 +138,16 @@ export interface OfficialServer {
123138 * - "io.github.upstash/context7" → "Context7"
124139 * - "io.github.vfarcic/dot-ai" → "Dot AI"
125140 * - "com.apple-rag/mcp-server" → "Apple RAG"
141+ * - "ai.tickettailor/mcp" → "Tickettailor" (fallback to domain when server part becomes empty)
126142 *
127143 * @param officialName - Official reverse-DNS name
128144 * @returns User-friendly display name
129145 */
130146export function createFriendlyName ( officialName : string ) : string {
131147 // Extract the server part after the last slash
132- const serverPart = officialName . split ( '/' ) . pop ( ) || officialName ;
148+ const parts = officialName . split ( '/' ) ;
149+ const serverPart = parts [ parts . length - 1 ] || officialName ;
150+ const domainPart = parts . length > 1 ? parts [ 0 ] : '' ;
133151
134152 // Remove common prefixes
135153 let friendlyName = serverPart
@@ -138,6 +156,13 @@ export function createFriendlyName(officialName: string): string {
138156 . replace ( / - s e r v e r $ / i, '' )
139157 . replace ( / - m c p $ / i, '' ) ;
140158
159+ // If friendly name is empty after removing prefixes, use domain part
160+ if ( ! friendlyName || friendlyName . trim ( ) === '' ) {
161+ // Extract company/service name from domain (e.g., "ai.tickettailor" → "tickettailor")
162+ const domainParts = domainPart . split ( '.' ) ;
163+ friendlyName = domainParts [ domainParts . length - 1 ] || officialName ;
164+ }
165+
141166 // Convert kebab-case and snake_case to Title Case
142167 friendlyName = friendlyName
143168 . replace ( / [ - _ ] / g, ' ' )
@@ -554,14 +579,14 @@ export async function transformOfficialToDeployStack(
554579 // Version information
555580 version : officialServer . version ,
556581
557- // Repository information
558- repository_url : repository ?. url ,
559- repository_source : repository ?. source ,
560- repository_id : repository ?. id ,
561- repository_subfolder : repository ?. subfolder ,
582+ // Repository information - convert empty strings to undefined
583+ repository_url : emptyToUndefined ( repository ?. url ) ,
584+ repository_source : emptyToUndefined ( repository ?. source ) ,
585+ repository_id : emptyToUndefined ( repository ?. id ) ,
586+ repository_subfolder : emptyToUndefined ( repository ?. subfolder ) ,
562587
563- // Website
564- website_url : officialServer . websiteUrl ,
588+ // Website - convert empty strings to undefined
589+ website_url : emptyToUndefined ( officialServer . websiteUrl ) ,
565590
566591 // Official format storage (will be JSON stringified by create-global.ts)
567592 // Use packagesCopy which now has inferred command/args
@@ -580,7 +605,8 @@ export async function transformOfficialToDeployStack(
580605 } ;
581606
582607 // Optionally enhance with GitHub metadata
583- if ( options ?. fetchGitHubMetadata && options . logger && repository ?. url ) {
608+ // Skip if repository URL is empty or undefined
609+ if ( options ?. fetchGitHubMetadata && options . logger && repository ?. url && repository . url !== '' ) {
584610 try {
585611 const githubData = await enhanceWithGitHubMetadata (
586612 repository . url ,
0 commit comments