@@ -6,6 +6,7 @@ import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/
66import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'
77import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js'
88import { randomUUID } from 'node:crypto'
9+ import { buildPurl } from './lib/purl.ts'
910import { z } from 'zod'
1011import pino from 'pino'
1112import readline from 'readline'
@@ -411,16 +412,14 @@ function createConfiguredServer (): McpServer {
411412 }
412413 }
413414
414- // Build components array for the API request
415+ // Build components array for the API request. Use packageurl-js for correct PURL encoding
416+ // across ecosystems (e.g. @ in npm scoped packages, maven groupId:artifactId).
415417 const components = packages . map ( ( pkg : { ecosystem ?: string ; depname : string ; version ?: string } ) => {
416418 const cleanedVersion = ( pkg . version ?? 'unknown' ) . replace ( / [ \^ ~ ] / g, '' ) // Remove ^ and ~ from version
417419 const ecosystem = pkg . ecosystem ?? 'npm'
418- let purl : string
419- if ( cleanedVersion === '1.0.0' || cleanedVersion === 'unknown' || ! cleanedVersion ) {
420- purl = `pkg:${ ecosystem } /${ pkg . depname } `
421- } else {
420+ const purl = buildPurl ( ecosystem , pkg . depname , cleanedVersion )
421+ if ( cleanedVersion !== '1.0.0' && cleanedVersion !== 'unknown' && cleanedVersion ) {
422422 logger . info ( `Using version ${ cleanedVersion } for ${ pkg . depname } ` )
423- purl = `pkg:${ ecosystem } /${ pkg . depname } @${ cleanedVersion } `
424423 }
425424 return { purl }
426425 } )
@@ -488,7 +487,8 @@ function createConfiguredServer (): McpServer {
488487
489488 // Process each result
490489 for ( const jsonData of jsonLines ) {
491- const purl : string = `pkg:${ jsonData . type || 'unknown' } /${ jsonData . name || 'unknown' } @${ jsonData . version || 'unknown' } `
490+ const ns = jsonData . namespace ? `${ jsonData . namespace } /` : ''
491+ const purl : string = `pkg:${ jsonData . type || 'unknown' } /${ ns } ${ jsonData . name || 'unknown' } @${ jsonData . version || 'unknown' } `
492492 if ( jsonData . score && jsonData . score . overall !== undefined ) {
493493 const scoreEntries = Object . entries ( jsonData . score )
494494 . filter ( ( [ key ] ) => key !== 'overall' && key !== 'uuid' )
@@ -506,7 +506,8 @@ function createConfiguredServer (): McpServer {
506506 }
507507 } else {
508508 const jsonData = JSON . parse ( responseText )
509- const purl : string = `pkg:${ jsonData . type || 'unknown' } /${ jsonData . name || 'unknown' } @${ jsonData . version || 'unknown' } `
509+ const ns = jsonData . namespace ? `${ jsonData . namespace } /` : ''
510+ const purl : string = `pkg:${ jsonData . type || 'unknown' } /${ ns } ${ jsonData . name || 'unknown' } @${ jsonData . version || 'unknown' } `
510511 if ( jsonData . score && jsonData . score . overall !== undefined ) {
511512 const scoreEntries = Object . entries ( jsonData . score )
512513 . filter ( ( [ key ] ) => key !== 'overall' && key !== 'uuid' )
0 commit comments