Skip to content

Commit 9907a41

Browse files
committed
Refactor CLI: Improve configuration loading and response handling
1 parent 72f9a8f commit 9907a41

File tree

1 file changed

+70
-56
lines changed

1 file changed

+70
-56
lines changed

src/mcp_client_cli/cli.py

+70-56
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,9 @@ async def run() -> None:
5252
else:
5353
# Use command line args or default query
5454
query = ' '.join(args.query) if args.query else DEFAULT_QUERY
55-
56-
if args.query and args.query[0] == "commit":
57-
query = "check git status and diff. Then commit it with descriptive and concise commit msg"
5855

59-
# Configuration file loading
60-
config_paths = [CONFIG_FILE, CONFIG_DIR / "config.json"]
61-
for path in config_paths:
62-
if os.path.exists(path):
63-
with open(path, 'r') as f:
64-
server_config = json.load(f)
65-
break
66-
else:
67-
raise FileNotFoundError(f"Could not find config file in any of: {', '.join(config_paths)}")
68-
69-
# Server parameters initialization
70-
server_params = [
71-
StdioServerParameters(
72-
command=config["command"],
73-
args=config.get("args", []),
74-
env={**config.get("env", {}), **os.environ}
75-
)
76-
for config in server_config["mcpServers"].values()
77-
if config.get("enabled", True) is not False
78-
]
56+
server_config = load_config()
57+
server_params = load_mcp_server_config(server_config)
7958

8059
# LangChain tools conversion
8160
langchain_tools = await convert_mcp_to_langchain_tools(server_params)
@@ -116,53 +95,88 @@ async def run() -> None:
11695
thread_id = await conversation_manager.get_last_id()
11796
else:
11897
thread_id = uuid.uuid4().hex
98+
11999
input_messages = {
120100
"messages": [HumanMessage(content=query)],
121101
"today_datetime": datetime.now().isoformat(),
122102
}
123-
124103
# Message streaming and tool calls handling
125104
async for chunk in agent_executor.astream(
126105
input_messages,
127106
stream_mode=["messages", "values"],
128107
config={"configurable": {"thread_id": thread_id}}
129108
):
130-
# If this is a message chunk
131-
if isinstance(chunk, tuple) and chunk[0] == "messages":
132-
message_chunk = chunk[1][0] # Get the message content
133-
if isinstance(message_chunk, AIMessageChunk):
134-
content = message_chunk.content
135-
if isinstance(content, str):
136-
print(content, end="", flush=True)
137-
elif isinstance(content, list) and len(content) > 0 and isinstance(content[0], dict) and "text" in content[0]:
138-
print(content[0]["text"], end="", flush=True)
139-
# If this is a final value
140-
elif isinstance(chunk, dict) and "messages" in chunk:
141-
# Print a newline after the complete message
142-
print("\n", flush=True)
143-
elif isinstance(chunk, tuple) and chunk[0] == "values":
144-
message = chunk[1]['messages'][-1]
145-
if isinstance(message, AIMessage) and message.tool_calls:
146-
print("\n\nTool Calls:")
147-
for tc in message.tool_calls:
148-
lines = [
149-
f" {tc.get('name', 'Tool')}",
150-
]
151-
if tc.get("error"):
152-
lines.append(f" Error: {tc.get('error')}")
153-
lines.append(" Args:")
154-
args = tc.get("args")
155-
if isinstance(args, str):
156-
lines.append(f" {args}")
157-
elif isinstance(args, dict):
158-
for arg, value in args.items():
159-
lines.append(f" {arg}: {value}")
160-
print("\n".join(lines))
161-
print()
109+
print_chunk(chunk)
162110

163111
# Saving the last conversation thread ID
164112
await conversation_manager.save_id(thread_id, checkpointer.conn)
165113

114+
def load_config() -> dict:
115+
config_paths = [CONFIG_FILE, CONFIG_DIR / "config.json"]
116+
for path in config_paths:
117+
if os.path.exists(path):
118+
with open(path, 'r') as f:
119+
return json.load(f)
120+
else:
121+
raise FileNotFoundError(f"Could not find config file in any of: {', '.join(config_paths)}")
122+
123+
def load_mcp_server_config(server_config: dict) -> dict:
124+
"""
125+
Load the MCP server configuration from key "mcpServers" in the config file.
126+
"""
127+
server_params = []
128+
for config in server_config["mcpServers"].values():
129+
enabled = config.get("enabled", True)
130+
if not enabled:
131+
continue
132+
133+
server_params.append(
134+
StdioServerParameters(
135+
command=config["command"],
136+
args=config.get("args", []),
137+
env={**config.get("env", {}), **os.environ}
138+
)
139+
)
140+
return server_params
141+
142+
def print_chunk(chunk: any) -> None:
143+
"""
144+
Print the chunk of agent response to the console.
145+
It will stream the response to the console as it is received.
146+
"""
147+
148+
# If this is a message chunk
149+
if isinstance(chunk, tuple) and chunk[0] == "messages":
150+
message_chunk = chunk[1][0] # Get the message content
151+
if isinstance(message_chunk, AIMessageChunk):
152+
content = message_chunk.content
153+
if isinstance(content, str):
154+
print(content, end="", flush=True)
155+
elif isinstance(content, list) and len(content) > 0 and isinstance(content[0], dict) and "text" in content[0]:
156+
print(content[0]["text"], end="", flush=True)
157+
# If this is a final value
158+
elif isinstance(chunk, dict) and "messages" in chunk:
159+
# Print a newline after the complete message
160+
print("\n", flush=True)
161+
elif isinstance(chunk, tuple) and chunk[0] == "values":
162+
message = chunk[1]['messages'][-1]
163+
if isinstance(message, AIMessage) and message.tool_calls:
164+
print("\n\nTool Calls:")
165+
for tc in message.tool_calls:
166+
lines = [
167+
f" {tc.get('name', 'Tool')}",
168+
]
169+
if tc.get("error"):
170+
lines.append(f" Error: {tc.get('error')}")
171+
lines.append(" Args:")
172+
args = tc.get("args")
173+
if isinstance(args, str):
174+
lines.append(f" {args}")
175+
elif isinstance(args, dict):
176+
for arg, value in args.items():
177+
lines.append(f" {arg}: {value}")
178+
print("\n".join(lines))
179+
print()
166180

167181
def main() -> None:
168182
"""Entry point of the script."""

0 commit comments

Comments
 (0)