@@ -40,113 +40,6 @@ export interface ApiExtractionResult {
4040 policies : string [ ] ;
4141}
4242
43- function getApiProperties ( apiJson : Record < string , unknown > ) : Record < string , unknown > | undefined {
44- return apiJson . properties as Record < string , unknown > | undefined ;
45- }
46-
47- function hasEmbeddedMcpConfiguration ( apiJson : Record < string , unknown > ) : boolean {
48- const properties = getApiProperties ( apiJson ) ;
49- if ( ! properties ) {
50- return false ;
51- }
52-
53- // Check if mcpTools has actual content (non-empty array), excluding null
54- const mcpTools = properties . mcpTools as unknown [ ] | undefined | null ;
55- if ( Array . isArray ( mcpTools ) && mcpTools . length > 0 ) {
56- return true ;
57- }
58-
59- // Check if mcpProperties exists and is not null or undefined
60- if ( properties . mcpProperties != null ) {
61- return true ;
62- }
63-
64- // MCP APIs created from an existing MCP server are wired purely via
65- // backendId + (optionally absent) mcpProperties. A non-null backendId on a
66- // type='mcp' API is itself an MCP server configuration we must capture.
67- if ( typeof properties . backendId === 'string' && properties . backendId . length > 0 ) {
68- return true ;
69- }
70-
71- return false ;
72- }
73-
74- function buildEmbeddedMcpServerResource (
75- apiJson : Record < string , unknown > ,
76- backendUrl ?: string
77- ) : Record < string , unknown > {
78- const properties = getApiProperties ( apiJson ) ?? { } ;
79- const resourceProperties : Record < string , unknown > = { } ;
80-
81- // Clone mcpProperties so we can augment it with serverUrl without mutating
82- // the caller's apiJson.
83- let mcpProperties : Record < string , unknown > | undefined ;
84- if ( properties . mcpProperties && typeof properties . mcpProperties === 'object' ) {
85- mcpProperties = { ...( properties . mcpProperties as Record < string , unknown > ) } ;
86- } else if ( backendUrl ) {
87- mcpProperties = { } ;
88- }
89-
90- if ( mcpProperties && backendUrl && mcpProperties . serverUrl === undefined ) {
91- mcpProperties . serverUrl = backendUrl ;
92- }
93-
94- if ( mcpProperties !== undefined ) {
95- resourceProperties . mcpProperties = mcpProperties ;
96- }
97- if ( properties . mcpTools !== undefined ) {
98- resourceProperties . mcpTools = properties . mcpTools ;
99- }
100- // Preserve the link to the upstream backend so the MCP server sidecar is
101- // self-describing for MCP-from-existing-MCP-server APIs.
102- if ( typeof properties . backendId === 'string' && properties . backendId . length > 0 ) {
103- resourceProperties . backendId = properties . backendId ;
104- }
105-
106- return {
107- name : 'default' ,
108- properties : resourceProperties ,
109- } ;
110-
111- }
112-
113- /**
114- * For an MCP API wired to a backend via `backendId`, fetch that backend and
115- * return its `properties.url` so the MCP sidecar can carry the actual upstream
116- * server URL. Returns undefined when the API has no backendId, the backend
117- * cannot be fetched, or the backend has no url.
118- */
119- async function resolveLinkedBackendUrl (
120- client : IApimClient ,
121- context : ApimServiceContext ,
122- apiJson : Record < string , unknown > ,
123- workspace ?: string
124- ) : Promise < string | undefined > {
125- const properties = getApiProperties ( apiJson ) ;
126- const backendId = properties ?. backendId ;
127- if ( typeof backendId !== 'string' || backendId . length === 0 ) {
128- return undefined ;
129- }
130-
131- // backendId may be either a bare resource name or a full ARM resource id.
132- // We only consume the trailing name segment for descriptor lookup.
133- const backendName = backendId . includes ( '/' ) ? backendId . split ( '/' ) . pop ( ) ! : backendId ;
134-
135- try {
136- const backendJson = await client . getResource ( context , {
137- type : ResourceType . Backend ,
138- nameParts : [ backendName ] ,
139- workspace,
140- } ) ;
141- const url = ( backendJson ?. properties as Record < string , unknown > | undefined ) ?. url ;
142- return typeof url === 'string' && url . length > 0 ? url : undefined ;
143- } catch ( error ) {
144- const errorMessage = error instanceof Error ? error . message : String ( error ) ;
145- logger . debug ( `Could not resolve backend "${ backendName } " for MCP server URL: ${ errorMessage } ` ) ;
146- return undefined ;
147- }
148- }
149-
15043/**
15144 * Extract all API-specific resources for a single API.
15245 * This includes revisions, specifications, operations, policies, etc.
@@ -259,11 +152,6 @@ export async function extractApiResources(
259152 client , store , context , apiDescriptor , outputDir
260153 ) ;
261154
262- // Extract MCP server configuration (singleton per API; silently skipped when not present)
263- result . mcpServer = await extractApiMcpServer (
264- client , store , context , apiDescriptor , apiJson , outputDir
265- ) ;
266-
267155 // Extract GraphQL resolvers and their policies
268156 const resolverResult = await extractGraphQLResolvers (
269157 client , store , context , apiDescriptor , apiJson , outputDir , filter , workspace
@@ -585,7 +473,7 @@ async function extractGraphQLResolvers(
585473 const policies : string [ ] = [ ] ;
586474
587475 // Only extract resolvers for GraphQL APIs — use the already-fetched apiJson
588- const properties = getApiProperties ( apiJson ) ;
476+ const properties = apiJson . properties as Record < string , unknown > | undefined ;
589477 const apiType = properties ?. type as string | undefined ;
590478 if ( apiType ?. toLowerCase ( ) !== 'graphql' ) {
591479 return { resolvers, resolverPolicies, policies } ;
@@ -629,58 +517,6 @@ async function extractGraphQLResolvers(
629517 return { resolvers, resolverPolicies, policies } ;
630518}
631519
632- /**
633- * Extract MCP (Model Context Protocol) server configuration for an API.
634- *
635- * MCP configuration is embedded directly on the API resource
636- * (`properties.mcpTools`, `properties.mcpProperties`, `properties.backendId`).
637- * There is no separate child resource served by ARM — the
638- * `apis/{id}/mcpServers/default` endpoint returns 404 even on working MCP APIs,
639- * and `apis/{id}/mcpServers` returns 500 (no such collection). All MCP data
640- * therefore comes from the API JSON itself.
641- *
642- * For MCP APIs created from an existing MCP server (the `backendId` pattern),
643- * the upstream URL lives on the linked backend, not on the API. To make the
644- * extracted `mcpServerInformation.json` self-describing, the extractor
645- * resolves that backend and surfaces its URL as `mcpProperties.serverUrl`.
646- */
647- async function extractApiMcpServer (
648- client : IApimClient ,
649- store : IArtifactStore ,
650- context : ApimServiceContext ,
651- apiDescriptor : ResourceDescriptor ,
652- apiJson : Record < string , unknown > ,
653- outputDir : string
654- ) : Promise < boolean > {
655- const apiType = ( getApiProperties ( apiJson ) ?. type as string | undefined ) ?. toLowerCase ( ) ;
656-
657- // Avoid creating MCP artifacts for non-MCP APIs unless they carry meaningful MCP metadata.
658- if ( apiType !== 'mcp' && ! hasEmbeddedMcpConfiguration ( apiJson ) ) {
659- return false ;
660- }
661-
662- if ( ! hasEmbeddedMcpConfiguration ( apiJson ) ) {
663- return false ;
664- }
665-
666- const mcpDescriptor : ResourceDescriptor = {
667- type : ResourceType . McpServer ,
668- nameParts : [ ...apiDescriptor . nameParts ] ,
669- workspace : apiDescriptor . workspace ,
670- } ;
671-
672- // Resolve the upstream backend URL so the MCP sidecar carries the actual
673- // server URL (not just a backendId reference + uri template).
674- const backendUrl = await resolveLinkedBackendUrl ( client , context , apiJson , apiDescriptor . workspace ) ;
675- await store . writeResource (
676- outputDir ,
677- mcpDescriptor ,
678- buildEmbeddedMcpServerResource ( apiJson , backendUrl )
679- ) ;
680- logger . info ( `Extracted ${ buildResourceLabel ( mcpDescriptor ) } from API metadata` ) ;
681- return true ;
682- }
683-
684520/**
685521 * Extract API tag associations in workspace scope using the tag-centric
686522 * `tags/{tag}/apiLinks` endpoint.
0 commit comments