diff --git a/mcp_run_python/_cli.py b/mcp_run_python/_cli.py index 69bab42..1c91624 100644 --- a/mcp_run_python/_cli.py +++ b/mcp_run_python/_cli.py @@ -20,7 +20,11 @@ def cli_logic(args_list: Sequence[str] | None = None) -> int: description=f'mcp-run-python CLI v{__version__}\n\nMCP server for running untrusted Python code.\n', formatter_class=argparse.RawTextHelpFormatter, ) - + parser.add_argument( + '--host', + type=str, + help='Host to bind the HTTP server to (default: 127.0.0.1). Use 0.0.0.0 to bind to all interfaces, e.g. when using Docker.', + ) parser.add_argument('--port', type=int, help='Port to run the server on, default 3001.') parser.add_argument('--deps', '--dependencies', help='Comma separated list of dependencies to install') parser.add_argument( @@ -51,6 +55,7 @@ def cli_logic(args_list: Sequence[str] | None = None) -> int: args.mode.replace('-', '_'), allow_networking=not args.disable_networking, http_port=args.port, + http_host=args.host, dependencies=deps, deps_log_handler=deps_log_handler, verbose=bool(args.verbose), diff --git a/mcp_run_python/deno/src/main.ts b/mcp_run_python/deno/src/main.ts index 35920ae..2a1caca 100644 --- a/mcp_run_python/deno/src/main.ts +++ b/mcp_run_python/deno/src/main.ts @@ -20,8 +20,8 @@ const VERSION = '0.0.13' export async function main() { const { args } = Deno const flags = parseArgs(Deno.args, { - string: ['deps', 'return-mode', 'port'], - default: { port: '3001', 'return-mode': 'xml' }, + string: ['deps', 'return-mode', 'port', 'host'], + default: { port: '3001', 'return-mode': 'xml', host: '127.0.0.1' }, }) const deps = flags.deps?.split(',') ?? [] if (args.length >= 1) { @@ -30,11 +30,13 @@ export async function main() { return } else if (args[0] === 'streamable_http') { const port = parseInt(flags.port) - runStreamableHttp(port, deps, flags['return-mode'], false) + const host = flags.host + runStreamableHttp(port, host, deps, flags['return-mode'], false) return } else if (args[0] === 'streamable_http_stateless') { const port = parseInt(flags.port) - runStreamableHttp(port, deps, flags['return-mode'], true) + const host = flags.host + runStreamableHttp(port, host, deps, flags['return-mode'], true) return } else if (args[0] === 'example') { await example(deps) @@ -52,6 +54,7 @@ Usage: deno ... deno/main.ts [stdio|streamable_http|streamable_http_stateless|in options: --port Port to run the HTTP server on (default: 3001) +--host Host to run the HTTP server on (default: 127.0.0.1) --deps Comma separated list of dependencies to install --return-mode Return mode for output data (default: xml)`, ) @@ -171,9 +174,9 @@ function httpSetJsonResponse(res: http.ServerResponse, status: number, text: str /* * Run the MCP server using the Streamable HTTP transport */ -function runStreamableHttp(port: number, deps: string[], returnMode: string, stateless: boolean): void { +function runStreamableHttp(port: number, host:string, deps: string[], returnMode: string, stateless: boolean): void { const server = (stateless ? createStatelessHttpServer : createStatefulHttpServer)(deps, returnMode) - server.listen(port, () => { + server.listen(port, host, () => { console.log(`Listening on port ${port}`) }) } @@ -353,4 +356,4 @@ const LogLevels: LoggingLevel[] = [ 'emergency', ] -await main() +await main() \ No newline at end of file diff --git a/mcp_run_python/main.py b/mcp_run_python/main.py index 413f254..22e5389 100644 --- a/mcp_run_python/main.py +++ b/mcp_run_python/main.py @@ -23,6 +23,7 @@ def run_mcp_server( mode: Mode, *, http_port: int | None = None, + http_host: str | None = None, dependencies: list[str] | None = None, return_mode: Literal['json', 'xml'] = 'xml', deps_log_handler: LogHandler | None = None, @@ -34,6 +35,7 @@ def run_mcp_server( Args: mode: The mode to run the server in. http_port: The port to run the server on if mode is `streamable_http`. + http_host: The host to run the server on if mode is `streamable_http`. dependencies: The dependencies to install. return_mode: The mode to return tool results in. deps_log_handler: Optional function to receive logs emitted while installing dependencies. @@ -49,6 +51,7 @@ def run_mcp_server( mode, dependencies=dependencies, http_port=http_port, + http_host=http_host, return_mode=return_mode, deps_log_handler=deps_log_handler, allow_networking=allow_networking, @@ -78,6 +81,7 @@ def prepare_deno_env( mode: Mode, *, http_port: int | None = None, + http_host: str | None = None, dependencies: list[str] | None = None, return_mode: Literal['json', 'xml'] = 'xml', deps_log_handler: LogHandler | None = None, @@ -92,6 +96,7 @@ def prepare_deno_env( Args: mode: The mode to run the server in. http_port: The port to run the server on if mode is `streamable_http`. + http_host: The host to run the server on if mode is `streamable_http`. dependencies: The dependencies to install. return_mode: The mode to return tool results in. deps_log_handler: Optional function to receive logs emitted while installing dependencies. @@ -126,6 +131,7 @@ def prepare_deno_env( args = _deno_run_args( mode, http_port=http_port, + http_host=http_host, dependencies=dependencies, return_mode=return_mode, allow_networking=allow_networking, @@ -141,6 +147,7 @@ async def async_prepare_deno_env( mode: Mode, *, http_port: int | None = None, + http_host: str | None = None, dependencies: list[str] | None = None, return_mode: Literal['json', 'xml'] = 'xml', deps_log_handler: LogHandler | None = None, @@ -151,6 +158,7 @@ async def async_prepare_deno_env( prepare_deno_env, mode, http_port=http_port, + http_host=http_host, dependencies=dependencies, return_mode=return_mode, deps_log_handler=deps_log_handler, @@ -181,6 +189,7 @@ def _deno_run_args( mode: Mode, *, http_port: int | None = None, + http_host: str | None = None, dependencies: list[str] | None = None, return_mode: Literal['json', 'xml'] = 'xml', allow_networking: bool = True, @@ -197,11 +206,13 @@ def _deno_run_args( ] if dependencies is not None: args.append(f'--deps={",".join(dependencies)}') - if http_port is not None: - if mode in ('streamable_http', 'streamable_http_stateless'): + if mode in ('streamable_http', 'streamable_http_stateless'): + if http_port is not None: args.append(f'--port={http_port}') - else: - raise ValueError('Port is only supported for `streamable_http` modes') + if http_host is not None: + args.append(f'--host={http_host}') + elif http_port is not None or http_host is not None: + raise ValueError('Port and host are only supported for `streamable_http` mode') return args