@@ -70,6 +70,99 @@ export interface MCPCConfig {
7070 agents : ComposeDefinition [ ] ;
7171}
7272
73+ /**
74+ * Create proxy configuration from command-line arguments
75+ * This generates an MCPC config that wraps an existing MCP server
76+ */
77+ function createProxyConfig ( args : {
78+ transportType ?: string ;
79+ proxyCommand ?: string [ ] ;
80+ mode ?: string ;
81+ } ) : MCPCConfig {
82+ if ( ! args . proxyCommand || args . proxyCommand . length === 0 ) {
83+ console . error ( "Error: --proxy requires a command after --" ) ;
84+ console . error (
85+ "Example: mcpc --proxy --transport-type stdio -- npx -y @wonderwhy-er/desktop-commander" ,
86+ ) ;
87+ process . exit ( 1 ) ;
88+ }
89+
90+ if ( ! args . transportType ) {
91+ console . error ( "Error: --proxy requires --transport-type to be specified" ) ;
92+ console . error ( "Supported types: stdio, streamable-http, sse" ) ;
93+ console . error (
94+ "Example: mcpc --proxy --transport-type stdio -- npx -y @wonderwhy-er/desktop-commander" ,
95+ ) ;
96+ process . exit ( 1 ) ;
97+ }
98+
99+ const validTransports = [ "stdio" , "streamable-http" , "sse" ] ;
100+ if ( ! validTransports . includes ( args . transportType ) ) {
101+ console . error ( `Error: Invalid transport type '${ args . transportType } '` ) ;
102+ console . error ( `Supported types: ${ validTransports . join ( ", " ) } ` ) ;
103+ process . exit ( 1 ) ;
104+ }
105+
106+ const command = args . proxyCommand [ 0 ] ;
107+ const commandArgs = args . proxyCommand . slice ( 1 ) ;
108+
109+ // Extract server name from command (e.g., "@wonderwhy-er/desktop-commander" -> "desktop-commander")
110+ let serverName = "mcp-server" ;
111+ const npmPackageMatch = command . match ( / @ [ \w - ] + \/ ( [ \w - ] + ) / ) ||
112+ commandArgs . join ( " " ) . match ( / @ [ \w - ] + \/ ( [ \w - ] + ) / ) ;
113+ if ( npmPackageMatch ) {
114+ serverName = npmPackageMatch [ 1 ] ;
115+ } else {
116+ // Try to get name from command itself
117+ const baseName = command . split ( "/" ) . pop ( ) ?. replace ( / \. j s $ / , "" ) ;
118+ if ( baseName && baseName !== "npx" && baseName !== "node" ) {
119+ serverName = baseName ;
120+ }
121+ }
122+
123+ // Create configuration
124+ const config : MCPCConfig = {
125+ name : `${ serverName } -proxy` ,
126+ version : "0.1.0" ,
127+ capabilities : {
128+ tools : { } ,
129+ sampling : { } ,
130+ } ,
131+ agents : [
132+ {
133+ name : serverName ,
134+ description :
135+ `Agentic tool to orchestrate ${ serverName } MCP server tools:
136+ <tool name="${ serverName } .__ALL__"/>` ,
137+ deps : {
138+ mcpServers : {
139+ [ serverName ] : {
140+ command : command ,
141+ args : commandArgs ,
142+ transportType : args . transportType as
143+ | "stdio"
144+ | "streamable-http"
145+ | "sse" ,
146+ } ,
147+ } ,
148+ } ,
149+ options : {
150+ mode : ( args . mode || "agentic" ) as any ,
151+ } ,
152+ } ,
153+ ] ,
154+ } ;
155+
156+ console . error ( `Created proxy configuration for ${ serverName } ` ) ;
157+ console . error ( `Transport: ${ args . transportType } ` ) ;
158+ console . error ( `Command: ${ command } ${ commandArgs . join ( " " ) } ` ) ;
159+ if ( args . mode ) {
160+ console . error ( `Mode: ${ args . mode } ` ) ;
161+ }
162+
163+ return config ;
164+ }
165+
73166/**
74167 * Print help message
75168 */
@@ -78,7 +171,7 @@ function printHelp(): void {
78171MCPC CLI - Model Context Protocol Composer
79172
80173USAGE:
81- npx -y deno run -A jsr:@ mcpc/cli/bin [OPTIONS]
174+ mcpc [OPTIONS]
82175
83176OPTIONS:
84177 --help, -h Show this help message
@@ -89,6 +182,18 @@ OPTIONS:
89182 Add custom HTTP header for URL fetching
90183 Format: "Key: Value" or "Key=Value"
91184 Can be used multiple times
185+ --mode <mode> Set execution mode for all agents
186+ Supported modes:
187+ - agentic: Fully autonomous agent mode (default)
188+ - agentic_workflow: Agent workflow mode with dynamic or predefined steps
189+ - agentic_sampling: Autonomous sampling mode for agentic execution
190+ - agentic_workflow_sampling: Autonomous sampling mode for workflow execution
191+ - code_execution: Code execution mode for most efficient token usage
192+ --proxy Proxy mode: automatically configure MCPC to wrap an MCP server
193+ Use with --transport-type to specify the transport
194+ Example: --proxy --transport-type stdio -- npx -y @wonderwhy-er/desktop-commander
195+ --transport-type <type> Transport type for proxy mode
196+ Supported types: stdio, streamable-http, sse
92197
93198ENVIRONMENT VARIABLES:
94199 MCPC_CONFIG Inline JSON configuration (same as --config)
@@ -97,27 +202,39 @@ ENVIRONMENT VARIABLES:
97202
98203EXAMPLES:
99204 # Show help
100- npx -y deno run -A jsr:@mcpc/cli/bin --help
205+ mcpc --help
206+
207+ # Proxy mode - wrap an existing MCP server (stdio)
208+ mcpc --proxy --transport-type stdio -- npx -y @wonderwhy-er/desktop-commander
209+
210+ # Proxy mode - wrap an MCP server (streamable-http)
211+ mcpc --proxy --transport-type streamable-http -- https://api.example.com/mcp
212+
213+ # Proxy mode - wrap an MCP server (sse)
214+ mcpc --proxy --transport-type sse -- https://api.example.com/sse
101215
102216 # Load from URL
103- npx -y deno run -A jsr:@ mcpc/cli/bin --config-url \\
217+ mcpc --config-url \\
104218 "https://raw.githubusercontent.com/mcpc-tech/mcpc/main/packages/cli/examples/configs/codex-fork.json"
105219
106220 # Load from URL with custom headers
107- npx -y deno run -A jsr:@ mcpc/cli/bin \\
221+ mcpc \\
108222 --config-url "https://api.example.com/config.json" \\
109223 -H "Authorization: Bearer token123" \\
110224 -H "X-Custom-Header: value"
111225
112226 # Load from file
113- npx -y deno run -A jsr:@mcpc/cli/bin --config-file ./my-config.json
227+ mcpc --config-file ./my-config.json
228+
229+ # Override execution mode for all agents
230+ mcpc --config-file ./my-config.json --mode agentic_workflow
114231
115232 # Using environment variable
116233 export MCPC_CONFIG='[{"name":"agent","description":"..."}]'
117- npx -y deno run -A jsr:@ mcpc/cli/bin
234+ mcpc
118235
119236 # Use default configuration (./mcpc.config.json)
120- npx -y deno run -A jsr:@ mcpc/cli/bin
237+ mcpc
121238
122239CONFIGURATION:
123240 Configuration files support environment variable substitution using $VAR_NAME syntax.
@@ -142,6 +259,10 @@ function parseArgs(): {
142259 configFile ?: string ;
143260 requestHeaders ?: Record < string , string > ;
144261 help ?: boolean ;
262+ proxy ?: boolean ;
263+ transportType ?: string ;
264+ proxyCommand ?: string [ ] ;
265+ mode ?: string ;
145266} {
146267 const args = process . argv . slice ( 2 ) ;
147268 const result : {
@@ -150,6 +271,10 @@ function parseArgs(): {
150271 configFile ?: string ;
151272 requestHeaders ?: Record < string , string > ;
152273 help ?: boolean ;
274+ proxy ?: boolean ;
275+ transportType ?: string ;
276+ proxyCommand ?: string [ ] ;
277+ mode ?: string ;
153278 } = { } ;
154279
155280 for ( let i = 0 ; i < args . length ; i ++ ) {
@@ -161,14 +286,15 @@ function parseArgs(): {
161286 } else if ( arg === "--config-file" && i + 1 < args . length ) {
162287 result . configFile = args [ ++ i ] ;
163288 } else if (
164- ( arg === "--request-headers" || arg === "-H" ) && i + 1 < args . length
289+ ( arg === "--request-headers" || arg === "-H" ) &&
290+ i + 1 < args . length
165291 ) {
166292 // Parse header in format "Key: Value" or "Key=Value"
167293 const headerStr = args [ ++ i ] ;
168294 const colonIdx = headerStr . indexOf ( ":" ) ;
169295 const equalIdx = headerStr . indexOf ( "=" ) ;
170296 const separatorIdx = colonIdx !== - 1
171- ? ( equalIdx !== - 1 ? Math . min ( colonIdx , equalIdx ) : colonIdx )
297+ ? equalIdx !== - 1 ? Math . min ( colonIdx , equalIdx ) : colonIdx
172298 : equalIdx ;
173299
174300 if ( separatorIdx !== - 1 ) {
@@ -181,6 +307,16 @@ function parseArgs(): {
181307 }
182308 } else if ( arg === "--help" || arg === "-h" ) {
183309 result . help = true ;
310+ } else if ( arg === "--proxy" ) {
311+ result . proxy = true ;
312+ } else if ( arg === "--transport-type" && i + 1 < args . length ) {
313+ result . transportType = args [ ++ i ] ;
314+ } else if ( arg === "--mode" && i + 1 < args . length ) {
315+ result . mode = args [ ++ i ] ;
316+ } else if ( arg === "--" ) {
317+ // Everything after -- is the proxy command
318+ result . proxyCommand = args . slice ( i + 1 ) ;
319+ break ;
184320 }
185321 }
186322
@@ -200,11 +336,16 @@ export async function loadConfig(): Promise<MCPCConfig | null> {
200336 process . exit ( 0 ) ;
201337 }
202338
339+ // Handle --proxy mode
340+ if ( args . proxy ) {
341+ return createProxyConfig ( args ) ;
342+ }
343+
203344 // Priority 1: --config (inline JSON string)
204345 if ( args . config ) {
205346 try {
206347 const parsed = JSON . parse ( args . config ) ;
207- return normalizeConfig ( parsed ) ;
348+ return applyModeOverride ( normalizeConfig ( parsed ) , args . mode ) ;
208349 } catch ( error ) {
209350 console . error ( "Failed to parse --config argument:" , error ) ;
210351 throw error ;
@@ -215,7 +356,7 @@ export async function loadConfig(): Promise<MCPCConfig | null> {
215356 if ( process . env . MCPC_CONFIG ) {
216357 try {
217358 const parsed = JSON . parse ( process . env . MCPC_CONFIG ) ;
218- return normalizeConfig ( parsed ) ;
359+ return applyModeOverride ( normalizeConfig ( parsed ) , args . mode ) ;
219360 } catch ( error ) {
220361 console . error ( "Failed to parse MCPC_CONFIG environment variable:" , error ) ;
221362 throw error ;
@@ -236,7 +377,7 @@ export async function loadConfig(): Promise<MCPCConfig | null> {
236377 }
237378 const content = await response . text ( ) ;
238379 const parsed = JSON . parse ( content ) ;
239- return normalizeConfig ( parsed ) ;
380+ return applyModeOverride ( normalizeConfig ( parsed ) , args . mode ) ;
240381 } catch ( error ) {
241382 console . error ( `Failed to fetch config from ${ configUrl } :` , error ) ;
242383 throw error ;
@@ -249,7 +390,7 @@ export async function loadConfig(): Promise<MCPCConfig | null> {
249390 try {
250391 const content = await readFile ( configFile , "utf-8" ) ;
251392 const parsed = JSON . parse ( content ) ;
252- return normalizeConfig ( parsed ) ;
393+ return applyModeOverride ( normalizeConfig ( parsed ) , args . mode ) ;
253394 } catch ( error ) {
254395 if ( ( error as NodeJS . ErrnoException ) . code === "ENOENT" ) {
255396 console . error ( `Config file not found: ${ configFile } ` ) ;
@@ -266,16 +407,13 @@ export async function loadConfig(): Promise<MCPCConfig | null> {
266407 try {
267408 const content = await readFile ( defaultConfigPath , "utf-8" ) ;
268409 const parsed = JSON . parse ( content ) ;
269- return normalizeConfig ( parsed ) ;
410+ return applyModeOverride ( normalizeConfig ( parsed ) , args . mode ) ;
270411 } catch ( error ) {
271412 if ( ( error as NodeJS . ErrnoException ) . code === "ENOENT" ) {
272413 // No config file found, this is okay
273414 return null ;
274415 } else {
275- console . error (
276- `Failed to load config from ${ defaultConfigPath } :` ,
277- error ,
278- ) ;
416+ console . error ( `Failed to load config from ${ defaultConfigPath } :` , error ) ;
279417 throw error ;
280418 }
281419 }
@@ -311,6 +449,21 @@ function replaceEnvVarsInConfig(obj: unknown): unknown {
311449 return obj ;
312450}
313451
452+ /**
453+ * Apply mode override to all agents in the configuration
454+ */
455+ function applyModeOverride ( config : MCPCConfig , mode ?: string ) : MCPCConfig {
456+ if ( ! mode ) return config ;
457+
458+ // Apply mode to all agents
459+ config . agents . forEach ( ( agent ) => {
460+ if ( ! agent . options ) agent . options = { } ;
461+ agent . options . mode = mode as any ;
462+ } ) ;
463+
464+ return config ;
465+ }
466+
314467/**
315468 * Normalize configuration to ensure it has the expected structure
316469 * Supports both array format (legacy) and object format (new)
0 commit comments