@@ -21,6 +21,12 @@ export interface RuntimeDetectionResult {
2121 dependencies ?: Record < string , string > ;
2222 devDependencies ?: Record < string , string > ;
2323 } ;
24+ pyprojectToml ?: { // For Python projects
25+ name ?: string ;
26+ version ?: string ;
27+ description ?: string ;
28+ license ?: string ;
29+ } ;
2430}
2531
2632/**
@@ -109,6 +115,8 @@ export class RuntimeDetector {
109115 ref : string
110116 ) : Promise < RuntimeDetectionResult | null > {
111117 // Try requirements.txt first
118+ let mcpSdkInfo : McpSdkInfo | null = null ;
119+
112120 try {
113121 const { data : file } = await octokit . repos . getContent ( {
114122 owner,
@@ -129,15 +137,14 @@ export class RuntimeDetector {
129137 line . trim ( ) === 'mcp'
130138 ) ;
131139
132- return {
133- runtime : 'python' ,
134- mcp_sdk : {
135- detected : ! ! mcpLine ,
140+ if ( mcpLine ) {
141+ mcpSdkInfo = {
142+ detected : true ,
136143 version : mcpLine ?. split ( / = = | > = / ) [ 1 ] ?. trim ( ) ,
137144 package : 'mcp' ,
138145 runtime : 'python'
139- }
140- } ;
146+ } ;
147+ }
141148 }
142149 } catch {
143150 // Continue to pyproject.toml
@@ -155,26 +162,64 @@ export class RuntimeDetector {
155162 if ( 'content' in file ) {
156163 const content = Buffer . from ( file . content , 'base64' ) . toString ( 'utf8' ) ;
157164
158- // Simple check for "mcp" in dependencies
159- const hasMcp = content . includes ( '"mcp"' ) || content . includes ( "'mcp'" ) ;
165+ // If we haven't found MCP SDK in requirements.txt, check pyproject.toml
166+ if ( ! mcpSdkInfo ) {
167+ // Check for "mcp" in dependencies (handles both "mcp" and "mcp>=1.0.0" formats)
168+ const hasMcp = / [ " ' ] m c p [ " ' ] / . test ( content ) || / [ " ' ] m c p [ > < = ] / . test ( content ) ;
160169
161- // Try to extract version from pyproject.toml if present
162- const versionMatch = content . match ( / m c p \s * = \s * [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / ) ;
170+ // Try to extract version from pyproject.toml if present
171+ // Matches patterns like "mcp>=1.0.0" or "mcp==1.0.0"
172+ const versionMatch = content . match ( / [ " ' ] m c p [ > < = ] = ? \s * ( [ ^ " ' , \] ] + ) [ " ' ] / ) ;
163173
164- return {
165- runtime : 'python' ,
166- mcp_sdk : {
167- detected : hasMcp ,
168- version : versionMatch ?. [ 1 ] ,
169- package : 'mcp' ,
170- runtime : 'python'
174+ if ( hasMcp ) {
175+ mcpSdkInfo = {
176+ detected : true ,
177+ version : versionMatch ?. [ 1 ] ,
178+ package : 'mcp' ,
179+ runtime : 'python'
180+ } ;
171181 }
182+ }
183+
184+ // Extract project metadata from [project] section (always do this)
185+ const nameMatch = content . match ( / ^ \s * n a m e \s * = \s * [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / m) ;
186+ const versionProjMatch = content . match ( / ^ \s * v e r s i o n \s * = \s * [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / m) ;
187+ const descriptionMatch = content . match ( / ^ \s * d e s c r i p t i o n \s * = \s * [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / m) ;
188+
189+ // License can be either a simple string or a table with 'text' field
190+ let licenseValue : string | undefined ;
191+ const licenseSimpleMatch = content . match ( / ^ \s * l i c e n s e \s * = \s * [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / m) ;
192+ const licenseTableMatch = content . match ( / ^ \s * l i c e n s e \s * = \s * \{ \s * t e x t \s * = \s * [ " ' ] ( [ ^ " ' ] + ) [ " ' ] / m) ;
193+ licenseValue = licenseSimpleMatch ?. [ 1 ] || licenseTableMatch ?. [ 1 ] ;
194+
195+ const pyprojectToml = {
196+ name : nameMatch ?. [ 1 ] ,
197+ version : versionProjMatch ?. [ 1 ] ,
198+ description : descriptionMatch ?. [ 1 ] ,
199+ license : licenseValue
172200 } ;
201+
202+ // Return if we found MCP SDK (from either requirements.txt or pyproject.toml)
203+ if ( mcpSdkInfo ) {
204+ return {
205+ runtime : 'python' ,
206+ mcp_sdk : mcpSdkInfo ,
207+ pyprojectToml
208+ } ;
209+ }
173210 }
174211 } catch {
175212 // Continue
176213 }
177214
215+ // If we found MCP SDK in requirements.txt but no pyproject.toml, return without metadata
216+ if ( mcpSdkInfo ) {
217+ return {
218+ runtime : 'python' ,
219+ mcp_sdk : mcpSdkInfo
220+ } ;
221+ }
222+
178223 return null ; // No Python files found
179224 }
180225
0 commit comments