@@ -74,6 +74,124 @@ describe('profile-resolver', () => {
7474 await expect ( resolveProfileById ( 'missing' , profilesDir ) ) . rejects . toThrow ( 'openapi_spec_path' ) ;
7575 } ) ;
7676
77+ it ( 'collects env vars from upstream_mcp bearer auth' , async ( ) => {
78+ const root = await createTempDir ( ) ;
79+ const profilesDir = path . join ( root , 'profiles' ) ;
80+
81+ await writeJson ( path . join ( profilesDir , 'proxy-auth.json' ) , {
82+ profile_name : 'proxy-auth-profile' ,
83+ profile_id : 'proxy-auth' ,
84+ tools : [ ] ,
85+ upstream_mcp : [
86+ {
87+ name : 'youtrack' ,
88+ transport : { type : 'http-streamable' , url : 'https://youtrack.example.com/mcp' } ,
89+ auth : { type : 'bearer' , value_from_env : 'YOUTRACK_TOKEN' } ,
90+ } ,
91+ ] ,
92+ } ) ;
93+
94+ const profiles = await listProfilesDetailed ( profilesDir ) ;
95+ expect ( profiles ) . toHaveLength ( 1 ) ;
96+ expect ( profiles [ 0 ] . envVars ) . toEqual ( [ 'YOUTRACK_TOKEN' ] ) ;
97+ expect ( profiles [ 0 ] . authMethods ) . toEqual ( [ ] ) ;
98+ } ) ;
99+
100+ it ( 'collects env vars from multiple upstream_mcp entries with different auth types' , async ( ) => {
101+ const root = await createTempDir ( ) ;
102+ const profilesDir = path . join ( root , 'profiles' ) ;
103+
104+ await writeJson ( path . join ( profilesDir , 'multi-upstream.json' ) , {
105+ profile_name : 'multi-upstream' ,
106+ profile_id : 'multi-upstream' ,
107+ tools : [ ] ,
108+ upstream_mcp : [
109+ {
110+ name : 'svc-a' ,
111+ transport : { type : 'http-streamable' , url : 'https://svc-a.example.com/mcp' } ,
112+ auth : { type : 'bearer' , value_from_env : 'SVC_A_TOKEN' } ,
113+ } ,
114+ {
115+ name : 'svc-b' ,
116+ transport : { type : 'http-streamable' , url : 'https://svc-b.example.com/mcp' } ,
117+ auth : { type : 'custom-header' , header_name : 'X-Api-Key' , value_from_env : 'SVC_B_KEY' } ,
118+ } ,
119+ {
120+ name : 'svc-c' ,
121+ transport : { type : 'http-streamable' , url : 'https://svc-c.example.com/mcp' } ,
122+ } ,
123+ ] ,
124+ } ) ;
125+
126+ const profiles = await listProfilesDetailed ( profilesDir ) ;
127+ expect ( profiles ) . toHaveLength ( 1 ) ;
128+ expect ( profiles [ 0 ] . envVars ) . toEqual ( [ 'SVC_A_TOKEN' , 'SVC_B_KEY' ] ) ;
129+ expect ( profiles [ 0 ] . authMethods ) . toEqual ( [ ] ) ;
130+ } ) ;
131+
132+ it ( 'collects env vars from upstream_mcp session-cookie auth' , async ( ) => {
133+ const root = await createTempDir ( ) ;
134+ const profilesDir = path . join ( root , 'profiles' ) ;
135+
136+ await writeJson ( path . join ( profilesDir , 'upstream-cookie.json' ) , {
137+ profile_name : 'upstream-cookie' ,
138+ profile_id : 'upstream-cookie' ,
139+ tools : [ ] ,
140+ upstream_mcp : [
141+ {
142+ name : 'legacy' ,
143+ transport : { type : 'http-streamable' , url : 'https://legacy.example.com/mcp' } ,
144+ auth : {
145+ type : 'session-cookie' ,
146+ session_cookie_config : {
147+ login_endpoint : '/login' ,
148+ login_method : 'POST' ,
149+ login_content_type : 'application/json' ,
150+ username_field : 'user' ,
151+ username_from_env : 'LEGACY_USER' ,
152+ password_field : 'pass' ,
153+ password_from_env : 'LEGACY_PASS' ,
154+ cookie_names : [ 'sid' ] ,
155+ } ,
156+ } ,
157+ } ,
158+ ] ,
159+ } ) ;
160+
161+ const profiles = await listProfilesDetailed ( profilesDir ) ;
162+ expect ( profiles ) . toHaveLength ( 1 ) ;
163+ expect ( profiles [ 0 ] . envVars ) . toEqual ( [ 'LEGACY_PASS' , 'LEGACY_USER' ] ) ;
164+ expect ( profiles [ 0 ] . authMethods ) . toEqual ( [ ] ) ;
165+ } ) ;
166+
167+ it ( 'merges env vars from both interceptors.auth and upstream_mcp auth without duplication' , async ( ) => {
168+ const root = await createTempDir ( ) ;
169+ const profilesDir = path . join ( root , 'profiles' ) ;
170+
171+ await writeJson ( path . join ( profilesDir , 'combined.json' ) , {
172+ profile_name : 'combined' ,
173+ profile_id : 'combined' ,
174+ tools : [ ] ,
175+ interceptors : {
176+ auth : { type : 'bearer' , value_from_env : 'CLIENT_TOKEN' } ,
177+ } ,
178+ upstream_mcp : [
179+ {
180+ name : 'upstream' ,
181+ transport : { type : 'http-streamable' , url : 'https://upstream.example.com/mcp' } ,
182+ auth : { type : 'bearer' , value_from_env : 'UPSTREAM_TOKEN' } ,
183+ } ,
184+ ] ,
185+ } ) ;
186+
187+ const profiles = await listProfilesDetailed ( profilesDir ) ;
188+ expect ( profiles ) . toHaveLength ( 1 ) ;
189+ expect ( profiles [ 0 ] . envVars ) . toEqual ( [ 'CLIENT_TOKEN' , 'UPSTREAM_TOKEN' ] ) ;
190+ expect ( profiles [ 0 ] . authMethods ) . toEqual ( [
191+ { type : 'bearer' , headerName : undefined , queryParam : undefined , valueFromEnv : 'CLIENT_TOKEN' } ,
192+ ] ) ;
193+ } ) ;
194+
77195 it ( 'returns specPath=undefined for upstream_mcp proxy profile with no openapi_spec_path' , async ( ) => {
78196 const root = await createTempDir ( ) ;
79197 const profilesDir = path . join ( root , 'profiles' ) ;
0 commit comments