@@ -67,6 +67,7 @@ function mergeDefinitionsWithStates(
6767 installation_source : state ?. source , // Track how server was installed
6868 env_overrides : state ?. env_overrides ?? { } ,
6969 args_append : state ?. args_append ?? [ ] ,
70+ extra_headers : state ?. extra_headers ?? { } ,
7071 } as ServerViewModel ;
7172 } ) ;
7273}
@@ -100,6 +101,7 @@ function createOfflineServerViewModel(state: InstalledServerState): ServerViewMo
100101 installation_source : state . source ,
101102 env_overrides : state . env_overrides ?? { } ,
102103 args_append : state . args_append ?? [ ] ,
104+ extra_headers : state . extra_headers ?? { } ,
103105 } as ServerViewModel ;
104106 } catch ( e ) {
105107 console . warn ( '[ServersPage] Failed to parse cached_definition, using minimal fallback:' , e ) ;
@@ -135,6 +137,7 @@ function createOfflineServerViewModel(state: InstalledServerState): ServerViewMo
135137 installation_source : state . source ,
136138 env_overrides : state . env_overrides ?? { } ,
137139 args_append : state . args_append ?? [ ] ,
140+ extra_headers : state . extra_headers ?? { } ,
138141 } as ServerViewModel ;
139142}
140143
@@ -149,6 +152,8 @@ interface ConfigModalState {
149152 envOverrides : Record < string , string > ;
150153 /** Additional arguments to append (stdio only) */
151154 argsAppend : string [ ] ;
155+ /** Extra HTTP headers (http only) */
156+ extraHeaders : Record < string , string > ;
152157}
153158
154159export function ServersPage ( ) {
@@ -165,6 +170,7 @@ export function ServersPage() {
165170 inputValues : { } ,
166171 envOverrides : { } ,
167172 argsAppend : [ ] ,
173+ extraHeaders : { } ,
168174 } ) ;
169175
170176 // Features state
@@ -502,6 +508,7 @@ export function ServersPage() {
502508 enableOnSave : true , // This is from Enable flow
503509 envOverrides : { ...( server . env_overrides ?? { } ) } ,
504510 argsAppend : [ ...( server . args_append ?? [ ] ) ] ,
511+ extraHeaders : { ...( server . extra_headers ?? { } ) } ,
505512 } ) ;
506513 return ;
507514 }
@@ -565,6 +572,7 @@ export function ServersPage() {
565572 enableOnSave : false , // Just configure, don't enable
566573 envOverrides : { ...( server . env_overrides ?? { } ) } ,
567574 argsAppend : [ ...( server . args_append ?? [ ] ) ] ,
575+ extraHeaders : { ...( server . extra_headers ?? { } ) } ,
568576 } ) ;
569577 } ;
570578
@@ -579,16 +587,17 @@ export function ServersPage() {
579587 try {
580588 const { saveServerInputs } = await import ( '@/lib/api/registry' ) ;
581589
582- // Save input values with env overrides and args
590+ // Save input values with env overrides, args, and headers
583591 await saveServerInputs (
584592 serverId ,
585593 configModal . inputValues ,
586594 viewSpace ?. id ?? '' ,
587595 Object . keys ( configModal . envOverrides ) . length > 0 ? configModal . envOverrides : undefined ,
588596 configModal . argsAppend . length > 0 ? configModal . argsAppend : undefined ,
597+ Object . keys ( configModal . extraHeaders ) . length > 0 ? configModal . extraHeaders : undefined ,
589598 ) ;
590599
591- setConfigModal ( { open : false , server : null , inputValues : { } , envOverrides : { } , argsAppend : [ ] } ) ;
600+ setConfigModal ( { open : false , server : null , inputValues : { } , envOverrides : { } , argsAppend : [ ] , extraHeaders : { } } ) ;
592601
593602 // Only enable if requested (from Enable flow)
594603 if ( shouldEnable && ! server . enabled ) {
@@ -626,7 +635,7 @@ export function ServersPage() {
626635 // Set the server to pending_config state by enabling but not connecting
627636 // Actually, we just close the modal - the UI already shows Configure button for missing inputs
628637 }
629- setConfigModal ( { open : false , server : null , inputValues : { } , envOverrides : { } , argsAppend : [ ] } ) ;
638+ setConfigModal ( { open : false , server : null , inputValues : { } , envOverrides : { } , argsAppend : [ ] , extraHeaders : { } } ) ;
630639 } ;
631640
632641 // Cancel OAuth flow - uses new ServerManager v2
@@ -1433,6 +1442,72 @@ export function ServersPage() {
14331442 </ div >
14341443 </ div >
14351444
1445+ { /* Extra HTTP Headers (http only) */ }
1446+ { configModal . server . transport . type === 'http' && (
1447+ < div >
1448+ < label className = "block text-sm font-medium text-[rgb(var(--foreground))] mb-1" >
1449+ HTTP Headers
1450+ </ label >
1451+ < p className = "text-xs text-[rgb(var(--muted))] mb-2" >
1452+ Custom HTTP headers sent with each request
1453+ </ p >
1454+ < div className = "space-y-2" >
1455+ { Object . entries ( configModal . extraHeaders ) . map ( ( [ key , value ] , idx ) => (
1456+ < div key = { idx } className = "flex gap-2" >
1457+ < input
1458+ type = "text"
1459+ value = { key }
1460+ onChange = { ( e ) => {
1461+ const entries = Object . entries ( configModal . extraHeaders ) ;
1462+ entries [ idx ] = [ e . target . value , value ] ;
1463+ setConfigModal ( {
1464+ ...configModal ,
1465+ extraHeaders : Object . fromEntries ( entries ) ,
1466+ } ) ;
1467+ } }
1468+ placeholder = "Header-Name"
1469+ className = "input flex-1 font-mono text-sm"
1470+ />
1471+ < input
1472+ type = "text"
1473+ value = { value }
1474+ onChange = { ( e ) => {
1475+ setConfigModal ( {
1476+ ...configModal ,
1477+ extraHeaders : { ...configModal . extraHeaders , [ key ] : e . target . value } ,
1478+ } ) ;
1479+ } }
1480+ placeholder = "value"
1481+ className = "input flex-1 font-mono text-sm"
1482+ />
1483+ < button
1484+ onClick = { ( ) => {
1485+ const { [ key ] : _ , ...rest } = configModal . extraHeaders ;
1486+ setConfigModal ( { ...configModal , extraHeaders : rest } ) ;
1487+ } }
1488+ className = "px-2 py-1 text-sm text-[rgb(var(--muted))] hover:text-[rgb(var(--error))] transition-colors"
1489+ title = "Remove"
1490+ >
1491+ ✕
1492+ </ button >
1493+ </ div >
1494+ ) ) }
1495+ < button
1496+ onClick = { ( ) => {
1497+ setConfigModal ( {
1498+ ...configModal ,
1499+ extraHeaders : { ...configModal . extraHeaders , '' : '' } ,
1500+ } ) ;
1501+ } }
1502+ className = "text-xs text-[rgb(var(--primary))] hover:underline"
1503+ data-testid = "config-add-header"
1504+ >
1505+ + Add header
1506+ </ button >
1507+ </ div >
1508+ </ div >
1509+ ) }
1510+
14361511 < div className = "flex justify-end gap-2 pt-2" >
14371512 < button
14381513 onClick = { handleCancelConfig }
0 commit comments