@@ -37,6 +37,10 @@ interface DotnetCli {
3737 args : Array < string > ;
3838}
3939
40+ const MCP_SERVER_SCHEMA_2025_07_09_GH = "https://modelcontextprotocol.io/schemas/draft/2025-07-09/server.json" ;
41+ const MCP_SERVER_SCHEMA_2025_07_09 = "https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json" ;
42+ const MCP_SERVER_SCHEMA_2025_09_29 = "https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json" ;
43+
4044export class NuGetMcpSetup {
4145 constructor (
4246 public readonly logService : ILogService ,
@@ -136,7 +140,7 @@ export class NuGetMcpSetup {
136140 const localInstallSuccess = await this . installLocalTool ( id , version , cwd ) ;
137141 if ( ! localInstallSuccess ) { return undefined ; }
138142
139- return await this . readServerManifest ( packagesDir , id , version , this . logService ) ;
143+ return await this . readServerManifest ( packagesDir , id , version ) ;
140144 } catch ( e ) {
141145 this . logService . warn ( `
142146Failed to install NuGet package ${ id } @${ version } . Proceeding without server.json.
@@ -268,37 +272,91 @@ stderr: ${installResult.stderr}`);
268272 return true ;
269273 }
270274
271- async readServerManifest ( packagesDir : string , id : string , version : string , logService : ILogService ) : Promise < string | undefined > {
272- const serverJsonPath = path . join ( packagesDir , id . toLowerCase ( ) , version . toLowerCase ( ) , ".mcp" , "server.json" ) ;
273- try {
274- await fs . access ( serverJsonPath , fs . constants . R_OK ) ;
275- } catch {
276- logService . info ( `No server.json found at ${ serverJsonPath } . Proceeding without server.json for ${ id } @${ version } .` ) ;
277- return undefined ;
278- }
279-
280- const json = await fs . readFile ( serverJsonPath , 'utf8' ) ;
281- const manifest = JSON . parse ( json ) ;
282-
275+ prepareServerJson ( manifest : any , id : string , version : string ) : any {
283276 // Force the ID and version of matching NuGet package in the server.json to the one we installed.
284277 // This handles cases where the server.json in the package is stale.
285278 // The ID should match generally, but we'll protect against unexpected package IDs.
279+ // We handle old and new schema formats:
280+ // - https://modelcontextprotocol.io/schemas/draft/2025-07-09/server.json (only hosted in GitHub)
281+ // - https://static.modelcontextprotocol.io/schemas/2025-07-09/server.schema.json (had several breaking changes over time)
282+ // - https://static.modelcontextprotocol.io/schemas/2025-09-29/server.schema.json
286283 if ( manifest ?. packages ) {
287284 for ( const pkg of manifest . packages ) {
288- if ( pkg ?. registry_name === "nuget" ) {
289- if ( pkg . name . toUpperCase ( ) !== id . toUpperCase ( ) ) {
290- logService . warn ( `Package ID mismatch in NuGet.mcp / server.json: expected ${ id } , found ${ pkg . name } .` ) ;
285+ if ( ! pkg ) { continue ; }
286+ const registryType = pkg . registryType ?? pkg . registry_type ?? pkg . registry_name ;
287+ if ( registryType === "nuget" ) {
288+ if ( pkg . name && pkg . name !== id ) {
289+ this . logService . warn ( `Package name mismatch in NuGet.mcp / server.json: expected ${ id } , found ${ pkg . name } .` ) ;
290+ pkg . name = id ;
291291 }
292- if ( pkg . version . toUpperCase ( ) !== version . toUpperCase ( ) ) {
293- logService . warn ( `Package version mismatch in NuGet.mcp / server.json: expected ${ version } , found ${ pkg . version } .` ) ;
292+
293+ if ( pkg . identifier && pkg . identifier !== id ) {
294+ this . logService . warn ( `Package identifier mismatch in NuGet.mcp / server.json: expected ${ id } , found ${ pkg . identifier } .` ) ;
295+ pkg . identifier = id ;
294296 }
295297
296- pkg . name = id ;
297- pkg . version = version ;
298+ if ( pkg . version !== version ) {
299+ this . logService . warn ( `Package version mismatch in NuGet.mcp / server.json: expected ${ version } , found ${ pkg . version } .` ) ;
300+ pkg . version = version ;
301+ }
298302 }
299303 }
300304 }
301305
306+ // the original .NET MCP server project template used a schema URL that is deprecated
307+ if ( manifest [ "$schema" ] === MCP_SERVER_SCHEMA_2025_07_09_GH ) {
308+ manifest [ "$schema" ] = MCP_SERVER_SCHEMA_2025_07_09 ;
309+ }
310+
311+ if ( manifest [ "$schema" ] !== MCP_SERVER_SCHEMA_2025_07_09
312+ && manifest [ "$schema" ] !== MCP_SERVER_SCHEMA_2025_09_29 ) {
313+ this . logService . info ( `NuGet package server.json has unrecognized schema version: '${ manifest [ "$schema" ] } '.` ) ;
314+ }
315+
316+ // provide empty publisher provided metadata to enable VS Code data mapping
317+ if ( ! manifest [ "_meta" ] ) {
318+ manifest [ "_meta" ] = { } ;
319+ }
320+
321+ // starting from 2025-09-29, the server.json schema root was changed to have a "server" property
322+ if ( manifest [ "$schema" ] === MCP_SERVER_SCHEMA_2025_09_29 ) {
323+ manifest = { server : manifest } ;
324+ }
325+
326+ // provide empty registry metadata to enable VS Code data mapping
327+ if ( ! manifest [ "_meta" ] ) {
328+ manifest [ "_meta" ] = { } ;
329+ }
330+
331+ if ( ! manifest [ "_meta" ] [ "io.modelcontextprotocol.registry/official" ] ) {
332+ manifest [ "_meta" ] [ "io.modelcontextprotocol.registry/official" ] = { } ;
333+ }
334+
302335 return manifest ;
303336 }
337+
338+ async readServerManifest ( packagesDir : string , id : string , version : string ) : Promise < string | undefined > {
339+ const serverJsonPath = path . join ( packagesDir , id . toLowerCase ( ) , version . toLowerCase ( ) , ".mcp" , "server.json" ) ;
340+ try {
341+ await fs . access ( serverJsonPath , fs . constants . R_OK ) ;
342+ } catch {
343+ this . logService . info ( `No server.json found at ${ serverJsonPath } . Proceeding without server.json for ${ id } @${ version } .` ) ;
344+ return undefined ;
345+ }
346+
347+ const json = await fs . readFile ( serverJsonPath , 'utf8' ) ;
348+ let manifest ;
349+ try {
350+ manifest = JSON . parse ( json ) ;
351+ } catch {
352+ this . logService . warn ( `Invalid JSON in NuGet package server.json at ${ serverJsonPath } . Proceeding without server.json for ${ id } @${ version } .` ) ;
353+ return undefined ;
354+ }
355+ if ( manifest === null || typeof manifest !== 'object' || Array . isArray ( manifest ) ) {
356+ this . logService . warn ( `Invalid JSON in NuGet package server.json at ${ serverJsonPath } . Proceeding without server.json for ${ id } @${ version } .` ) ;
357+ return undefined ;
358+ }
359+
360+ return this . prepareServerJson ( manifest , id , version ) ;
361+ }
304362}
0 commit comments