11#!/usr/bin/env node
22import { parseArgs } from "node:util" ;
3+ import * as readline from "node:readline/promises" ;
4+ import { stdin , stdout } from "node:process" ;
35import { z } from "zod" ;
46import { PROVIDERS_OR_POLICIES } from "@huggingface/inference" ;
57import { Agent } from "@huggingface/mcp-client" ;
68import { version as packageVersion } from "../package.json" ;
7- import { ServerConfigSchema } from "./lib/types" ;
8- import { debug , error } from "./lib/utils" ;
9+ import { InputConfigSchema , ServerConfigSchema } from "./lib/types" ;
10+ import { debug , error , ANSI } from "./lib/utils" ;
911import { mainCliLoop } from "./lib/mainCliLoop" ;
1012import { loadConfigFrom } from "./lib/loadConfigFrom" ;
1113
@@ -70,6 +72,7 @@ async function main() {
7072 provider : z . enum ( PROVIDERS_OR_POLICIES ) . optional ( ) ,
7173 endpointUrl : z . string ( ) . optional ( ) ,
7274 apiKey : z . string ( ) . optional ( ) ,
75+ inputs : z . array ( InputConfigSchema ) . optional ( ) ,
7376 servers : z . array ( ServerConfigSchema ) ,
7477 } )
7578 . refine ( ( data ) => data . provider !== undefined || data . endpointUrl !== undefined , {
@@ -85,6 +88,111 @@ async function main() {
8588 process . exit ( 1 ) ;
8689 }
8790
91+ // Handle inputs (i.e. env variables injection)
92+ if ( config . inputs && config . inputs . length > 0 ) {
93+ const rl = readline . createInterface ( { input : stdin , output : stdout } ) ;
94+
95+ stdout . write ( ANSI . BLUE ) ;
96+ stdout . write ( "Some initial inputs are required by the agent. " ) ;
97+ stdout . write ( "Please provide a value or leave empty to load from env." ) ;
98+ stdout . write ( ANSI . RESET ) ;
99+ stdout . write ( "\n" ) ;
100+
101+ for ( const inputItem of config . inputs ) {
102+ const inputId = inputItem . id ;
103+ const description = inputItem . description ;
104+ const envSpecialValue = `\${input:${ inputId } }` ; // Special value to indicate env variable injection
105+
106+ // Check env variables that will use this input
107+ const inputVars = new Set < string > ( ) ;
108+ for ( const server of config . servers ) {
109+ if ( server . type === "stdio" && server . config . env ) {
110+ for ( const [ key , value ] of Object . entries ( server . config . env ) ) {
111+ if ( value === envSpecialValue ) {
112+ inputVars . add ( key ) ;
113+ }
114+ }
115+ }
116+ if ( ( server . type === "http" || server . type === "sse" ) && server . config . options ?. requestInit ?. headers ) {
117+ for ( const [ key , value ] of Object . entries ( server . config . options . requestInit . headers ) ) {
118+ if ( value . includes ( envSpecialValue ) ) {
119+ inputVars . add ( key ) ;
120+ }
121+ }
122+ }
123+ }
124+
125+ if ( inputVars . size === 0 ) {
126+ stdout . write ( ANSI . YELLOW ) ;
127+ stdout . write ( `Input ${ inputId } defined in config but not used by any server.` ) ;
128+ stdout . write ( ANSI . RESET ) ;
129+ stdout . write ( "\n" ) ;
130+ continue ;
131+ }
132+
133+ // Prompt user for input
134+ stdout . write ( ANSI . BLUE ) ;
135+ stdout . write ( ` • ${ inputId } ` ) ;
136+ stdout . write ( ANSI . RESET ) ;
137+ stdout . write ( `: ${ description } . (default: load from ${ Array . from ( inputVars ) . join ( ", " ) } ) ` ) ;
138+
139+ const userInput = ( await rl . question ( "" ) ) . trim ( ) ;
140+
141+ // Inject user input (or env variable) into servers' env
142+ for ( const server of config . servers ) {
143+ if ( server . type === "stdio" && server . config . env ) {
144+ for ( const [ key , value ] of Object . entries ( server . config . env ) ) {
145+ if ( value === envSpecialValue ) {
146+ if ( userInput ) {
147+ server . config . env [ key ] = userInput ;
148+ } else {
149+ const valueFromEnv = process . env [ key ] || "" ;
150+ server . config . env [ key ] = valueFromEnv ;
151+ if ( valueFromEnv ) {
152+ stdout . write ( ANSI . GREEN ) ;
153+ stdout . write ( `Value successfully loaded from '${ key } '` ) ;
154+ stdout . write ( ANSI . RESET ) ;
155+ stdout . write ( "\n" ) ;
156+ } else {
157+ stdout . write ( ANSI . YELLOW ) ;
158+ stdout . write ( `No value found for '${ key } ' in environment variables. Continuing.` ) ;
159+ stdout . write ( ANSI . RESET ) ;
160+ stdout . write ( "\n" ) ;
161+ }
162+ }
163+ }
164+ }
165+ }
166+ if ( ( server . type === "http" || server . type === "sse" ) && server . config . options ?. requestInit ?. headers ) {
167+ for ( const [ key , value ] of Object . entries ( server . config . options . requestInit . headers ) ) {
168+ if ( value . includes ( envSpecialValue ) ) {
169+ if ( userInput ) {
170+ server . config . options . requestInit . headers [ key ] = value . replace ( envSpecialValue , userInput ) ;
171+ } else {
172+ const valueFromEnv = process . env [ key ] || "" ;
173+ server . config . options . requestInit . headers [ key ] = value . replace ( envSpecialValue , valueFromEnv ) ;
174+ if ( valueFromEnv ) {
175+ stdout . write ( ANSI . GREEN ) ;
176+ stdout . write ( `Value successfully loaded from '${ key } '` ) ;
177+ stdout . write ( ANSI . RESET ) ;
178+ stdout . write ( "\n" ) ;
179+ } else {
180+ stdout . write ( ANSI . YELLOW ) ;
181+ stdout . write ( `No value found for '${ key } ' in environment variables. Continuing.` ) ;
182+ stdout . write ( ANSI . RESET ) ;
183+ stdout . write ( "\n" ) ;
184+ }
185+ }
186+ }
187+ }
188+ }
189+ }
190+ }
191+
192+ stdout . write ( "\n" ) ;
193+ rl . close ( ) ;
194+ }
195+
88196 const agent = new Agent (
89197 config . endpointUrl
90198 ? {
0 commit comments