1- """
2- Install command for adding MCP servers to the global configuration
3- """
1+ """Install command for adding MCP servers to the global configuration"""
42
53import json
4+ import logging
65import os
76import re
87from enum import Enum
8+ from typing import Optional
99
1010from prompt_toolkit import PromptSession
1111from prompt_toolkit .formatted_text import HTML
2424from mcpm .utils .rich_click_config import click
2525
2626console = Console ()
27+ logger = logging .getLogger (__name__ )
2728repo_manager = RepositoryManager ()
2829profile_config_manager = ProfileConfigManager ()
2930global_config_manager = GlobalConfigManager ()
3031
31- # Create a prompt session with custom styling
32- prompt_session = PromptSession ()
32+ # Create a prompt session with custom styling (lazy to support headless Windows runs)
33+ prompt_session : Optional [PromptSession ] = None
34+ _prompt_session_error : Optional [Exception ] = None
35+
36+
37+ def _get_prompt_session () -> Optional [PromptSession ]:
38+ """Lazily create a PromptSession, tolerating environments without a console."""
39+
40+ global prompt_session , _prompt_session_error # noqa: PLW0603 - shared module state
41+
42+ if prompt_session is not None :
43+ return prompt_session
44+
45+ if _prompt_session_error is not None :
46+ return None
47+
48+ try :
49+ prompt_session = PromptSession ()
50+ except Exception as exc : # prompt_toolkit raises NoConsoleScreenBufferError on Windows
51+ _prompt_session_error = exc
52+ logger .debug ("Falling back to basic input prompts: %s" , exc )
53+ prompt_session = None
54+
55+ return prompt_session
56+
3357style = Style .from_dict (
3458 {
3559 "prompt" : "ansicyan bold" ,
@@ -88,14 +112,24 @@ def prompt_with_default(prompt_text, default="", hide_input=False, required=Fals
88112 # console.print(f"Default: [yellow]{default}[/]")
89113
90114 # Get user input
115+ session = _get_prompt_session ()
116+
91117 try :
92- result = prompt_session .prompt (
93- message = HTML (f"<prompt>{ prompt_text } </prompt> > " ),
94- style = style ,
95- default = default ,
96- is_password = hide_input ,
97- key_bindings = kb ,
98- )
118+ if session is not None :
119+ result = session .prompt (
120+ message = HTML (f"<prompt>{ prompt_text } </prompt> > " ),
121+ style = style ,
122+ default = default ,
123+ is_password = hide_input ,
124+ key_bindings = kb ,
125+ )
126+ else :
127+ # Basic fallback for environments without an interactive console (e.g., headless Windows)
128+ prompt_parts = [prompt_text ]
129+ if default :
130+ prompt_parts .append (f"[{ default } ]" )
131+ prompt_display = " " .join (prompt_parts ) + " > "
132+ result = input (prompt_display ) # noqa: PLW1513 - suppressed by KeyboardInterrupt handling
99133
100134 # Empty result for non-required field means leave it empty
101135 if not result .strip () and not required :
@@ -111,7 +145,7 @@ def prompt_with_default(prompt_text, default="", hide_input=False, required=Fals
111145 return prompt_with_default (prompt_text , default , hide_input , required )
112146
113147 return result
114- except KeyboardInterrupt :
148+ except ( KeyboardInterrupt , EOFError ) :
115149 raise click .Abort ()
116150
117151
0 commit comments