mcp-use 1.3.9__py3-none-any.whl → 1.3.10__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mcp-use might be problematic. Click here for more details.
- mcp_use/__init__.py +6 -2
- mcp_use/agents/mcpagent.py +101 -17
- mcp_use/agents/remote.py +50 -19
- mcp_use/cli.py +581 -0
- mcp_use/logging.py +27 -12
- mcp_use/managers/base.py +36 -0
- mcp_use/managers/server_manager.py +2 -1
- mcp_use/observability/__init__.py +2 -1
- mcp_use/observability/callbacks_manager.py +162 -0
- mcp_use/observability/laminar.py +24 -3
- mcp_use/observability/langfuse.py +27 -3
- {mcp_use-1.3.9.dist-info → mcp_use-1.3.10.dist-info}/METADATA +15 -14
- {mcp_use-1.3.9.dist-info → mcp_use-1.3.10.dist-info}/RECORD +16 -12
- mcp_use-1.3.10.dist-info/entry_points.txt +2 -0
- {mcp_use-1.3.9.dist-info → mcp_use-1.3.10.dist-info}/WHEEL +0 -0
- {mcp_use-1.3.9.dist-info → mcp_use-1.3.10.dist-info}/licenses/LICENSE +0 -0
mcp_use/cli.py
ADDED
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
"""
|
|
3
|
+
MCP-Use CLI Tool - All-in-one CLI for creating and deploying MCP projects.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
import sys
|
|
8
|
+
import threading
|
|
9
|
+
import time
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from mcp_use import __version__
|
|
13
|
+
|
|
14
|
+
# ============= SPINNER CLASS =============
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Spinner:
|
|
18
|
+
"""Simple loading spinner similar to UV's style."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, message: str = "Loading"):
|
|
21
|
+
self.message = message
|
|
22
|
+
self.running = False
|
|
23
|
+
self.thread = None
|
|
24
|
+
self.frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
|
25
|
+
self.current = 0
|
|
26
|
+
|
|
27
|
+
def start(self):
|
|
28
|
+
"""Start the spinner."""
|
|
29
|
+
self.running = True
|
|
30
|
+
self.thread = threading.Thread(target=self._spin)
|
|
31
|
+
self.thread.daemon = True
|
|
32
|
+
self.thread.start()
|
|
33
|
+
|
|
34
|
+
def _spin(self):
|
|
35
|
+
"""Spin animation loop."""
|
|
36
|
+
while self.running:
|
|
37
|
+
frame = self.frames[self.current % len(self.frames)]
|
|
38
|
+
print(f"\r{frame} {self.message}...", end="", flush=True)
|
|
39
|
+
self.current += 1
|
|
40
|
+
time.sleep(0.1)
|
|
41
|
+
|
|
42
|
+
def stop(self, success_message=None):
|
|
43
|
+
"""Stop the spinner and optionally print success message."""
|
|
44
|
+
self.running = False
|
|
45
|
+
if self.thread:
|
|
46
|
+
self.thread.join()
|
|
47
|
+
if success_message:
|
|
48
|
+
print(f"\r✓ {success_message} ")
|
|
49
|
+
else:
|
|
50
|
+
print("\r" + " " * (len(self.message) + 10), end="\r")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# ============= PROJECT CREATION FUNCTIONS =============
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def print_header():
|
|
57
|
+
"""Print the CLI header."""
|
|
58
|
+
print("\n mcp-use create")
|
|
59
|
+
print("━" * 50)
|
|
60
|
+
print()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_project_name() -> str:
|
|
64
|
+
"""Get project name from user."""
|
|
65
|
+
while True:
|
|
66
|
+
name = input("📝 Project name: ").strip().replace("-", "_")
|
|
67
|
+
if not name:
|
|
68
|
+
print(" ⚠️ Project name cannot be empty")
|
|
69
|
+
continue
|
|
70
|
+
if " " in name:
|
|
71
|
+
print(" ⚠️ Project name cannot contain spaces")
|
|
72
|
+
continue
|
|
73
|
+
if Path(name).exists():
|
|
74
|
+
print(f" ⚠️ Directory '{name}' already exists")
|
|
75
|
+
continue
|
|
76
|
+
return name
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_project_type() -> str:
|
|
80
|
+
"""Get project type from user."""
|
|
81
|
+
print("\n📦 What would you like to create?")
|
|
82
|
+
print(" 1) Server + Agent")
|
|
83
|
+
print(" 2) Server only")
|
|
84
|
+
print(" 3) Agent only")
|
|
85
|
+
|
|
86
|
+
while True:
|
|
87
|
+
choice = input("\n Choice (1-3): ").strip()
|
|
88
|
+
if choice == "1":
|
|
89
|
+
return "server_agent"
|
|
90
|
+
elif choice == "2":
|
|
91
|
+
return "server"
|
|
92
|
+
elif choice == "3":
|
|
93
|
+
return "agent"
|
|
94
|
+
else:
|
|
95
|
+
print(" ⚠️ Please enter 1, 2, or 3")
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def create_server_structure(project_dir: Path, project_name: str):
|
|
99
|
+
"""Create server file in nested project folder."""
|
|
100
|
+
# Create nested project folder
|
|
101
|
+
nested_dir = project_dir / project_name
|
|
102
|
+
nested_dir.mkdir(parents=True)
|
|
103
|
+
|
|
104
|
+
# Create server.py
|
|
105
|
+
server_content = f'''"""
|
|
106
|
+
MCP Server for {project_name}
|
|
107
|
+
"""
|
|
108
|
+
|
|
109
|
+
from mcp.server import FastMCP
|
|
110
|
+
|
|
111
|
+
# Create server instance
|
|
112
|
+
server = FastMCP("{project_name}-server")
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# ============= TOOLS =============
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@server.tool()
|
|
119
|
+
async def add_numbers(a: float, b: float) -> str:
|
|
120
|
+
"""Add two numbers together."""
|
|
121
|
+
result = a + b
|
|
122
|
+
return f"{{result}}"
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
# ============= RESOURCES =============
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@server.resource("config://app")
|
|
129
|
+
async def get_app_config() -> str:
|
|
130
|
+
"""Get the application configuration."""
|
|
131
|
+
return "App: {project_name}, Version: 0.1.0, Status: Active"
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
# ============= PROMPTS =============
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@server.prompt()
|
|
138
|
+
async def assistant_prompt() -> str:
|
|
139
|
+
"""Generate a helpful assistant prompt."""
|
|
140
|
+
return "You are a helpful assistant for {project_name}. Be concise and friendly."
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
# ============= MAIN =============
|
|
144
|
+
|
|
145
|
+
if __name__ == "__main__":
|
|
146
|
+
server.run("stdio")
|
|
147
|
+
'''
|
|
148
|
+
(nested_dir / "server.py").write_text(server_content)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def create_agent_structure(project_dir: Path, project_name: str, project_type: str):
|
|
152
|
+
"""Create agent file in nested project folder."""
|
|
153
|
+
# Create nested project folder if it doesn't exist
|
|
154
|
+
nested_dir = project_dir / project_name
|
|
155
|
+
if not nested_dir.exists():
|
|
156
|
+
nested_dir.mkdir(parents=True)
|
|
157
|
+
|
|
158
|
+
if project_type == "server_agent":
|
|
159
|
+
# For server_agent mode, embed config directly in agent.py
|
|
160
|
+
agent_content = f'''"""
|
|
161
|
+
MCP Agent implementation for {project_name}
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
from langchain_openai import ChatOpenAI
|
|
165
|
+
|
|
166
|
+
from mcp_use import MCPAgent, MCPClient
|
|
167
|
+
|
|
168
|
+
config = {{
|
|
169
|
+
"mcpServers": {{
|
|
170
|
+
"{project_name}": {{
|
|
171
|
+
"command": "python",
|
|
172
|
+
"args": ["{project_name}/server.py"],
|
|
173
|
+
}}
|
|
174
|
+
}}
|
|
175
|
+
}}
|
|
176
|
+
|
|
177
|
+
client = MCPClient(config=config)
|
|
178
|
+
agent = MCPAgent(llm=ChatOpenAI(model="gpt-4o"), client=client, max_steps=10, memory_enabled=True)
|
|
179
|
+
'''
|
|
180
|
+
else:
|
|
181
|
+
# For agent-only mode, use external JSON config file
|
|
182
|
+
agent_content = f'''"""
|
|
183
|
+
MCP Agent implementation for {project_name}
|
|
184
|
+
"""
|
|
185
|
+
|
|
186
|
+
from langchain_openai import ChatOpenAI
|
|
187
|
+
|
|
188
|
+
from mcp_use import MCPAgent, MCPClient
|
|
189
|
+
|
|
190
|
+
client = MCPClient.from_config_file("{project_name}/mcp_servers.json")
|
|
191
|
+
agent = MCPAgent(llm=ChatOpenAI(model="gpt-4o"), client=client, max_steps=10, memory_enabled=True)
|
|
192
|
+
'''
|
|
193
|
+
# Create mcp_servers.json for agent-only mode
|
|
194
|
+
mcp_servers_json = (
|
|
195
|
+
'''{
|
|
196
|
+
"mcpServers": {
|
|
197
|
+
"'''
|
|
198
|
+
+ project_name
|
|
199
|
+
+ """": {
|
|
200
|
+
"command": "npx",
|
|
201
|
+
"args": ["-y", "@modelcontextprotocol/server-everything"]
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}"""
|
|
205
|
+
)
|
|
206
|
+
(nested_dir / "mcp_servers.json").write_text(mcp_servers_json)
|
|
207
|
+
|
|
208
|
+
(nested_dir / "agent.py").write_text(agent_content)
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
def create_common_files(project_dir: Path, project_name: str, project_type: str):
|
|
212
|
+
"""Create common project files."""
|
|
213
|
+
|
|
214
|
+
# pyproject.toml
|
|
215
|
+
pyproject = f"""[project]
|
|
216
|
+
name = "{project_name}"
|
|
217
|
+
version = "0.1.0"
|
|
218
|
+
description = "An MCP project"
|
|
219
|
+
requires-python = ">=3.10"
|
|
220
|
+
dependencies = [
|
|
221
|
+
"mcp>=1.0.0",
|
|
222
|
+
"mcp-use>=0.1.0",
|
|
223
|
+
"langchain-openai>=0.1.0",
|
|
224
|
+
"python-dotenv>=1.0.0",
|
|
225
|
+
]
|
|
226
|
+
"""
|
|
227
|
+
(project_dir / "pyproject.toml").write_text(pyproject)
|
|
228
|
+
|
|
229
|
+
# requirements.txt
|
|
230
|
+
requirements = """mcp>=1.0.0
|
|
231
|
+
mcp-use>=0.1.0
|
|
232
|
+
langchain-openai>=0.1.0
|
|
233
|
+
python-dotenv>=1.0.0
|
|
234
|
+
"""
|
|
235
|
+
(project_dir / "requirements.txt").write_text(requirements)
|
|
236
|
+
|
|
237
|
+
# .gitignore
|
|
238
|
+
gitignore = """__pycache__/
|
|
239
|
+
*.py[cod]
|
|
240
|
+
.env
|
|
241
|
+
venv/
|
|
242
|
+
.venv/
|
|
243
|
+
*.egg-info/
|
|
244
|
+
dist/
|
|
245
|
+
build/
|
|
246
|
+
.pytest_cache/
|
|
247
|
+
.coverage
|
|
248
|
+
"""
|
|
249
|
+
(project_dir / ".gitignore").write_text(gitignore)
|
|
250
|
+
|
|
251
|
+
# README.md
|
|
252
|
+
readme = f"""# {project_name}
|
|
253
|
+
|
|
254
|
+
An MCP project created with mcp-use.
|
|
255
|
+
|
|
256
|
+
## Project Structure
|
|
257
|
+
|
|
258
|
+
```
|
|
259
|
+
{project_name}/
|
|
260
|
+
"""
|
|
261
|
+
|
|
262
|
+
if project_type in ["server_agent", "server"]:
|
|
263
|
+
readme += f"""├── {project_name}/
|
|
264
|
+
│ ├── server.py # MCP server with all components
|
|
265
|
+
"""
|
|
266
|
+
|
|
267
|
+
if project_type in ["server_agent", "agent"]:
|
|
268
|
+
if project_type == "agent":
|
|
269
|
+
readme += f"""├── {project_name}/
|
|
270
|
+
│ ├── agent.py # MCP agent implementation
|
|
271
|
+
│ └── mcp_servers.json # Server configuration
|
|
272
|
+
"""
|
|
273
|
+
else:
|
|
274
|
+
readme += """│ └── agent.py # MCP agent implementation
|
|
275
|
+
"""
|
|
276
|
+
|
|
277
|
+
if project_type in ["server_agent", "agent"]:
|
|
278
|
+
readme += """├── run.py # Simple example
|
|
279
|
+
├── chat.py # Interactive chat
|
|
280
|
+
"""
|
|
281
|
+
|
|
282
|
+
readme += """├── pyproject.toml
|
|
283
|
+
├── requirements.txt
|
|
284
|
+
├── .gitignore
|
|
285
|
+
└── README.md
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
## Setup
|
|
289
|
+
|
|
290
|
+
1. Install dependencies:
|
|
291
|
+
```bash
|
|
292
|
+
pip install -r requirements.txt
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
2. Configure environment:
|
|
296
|
+
```bash
|
|
297
|
+
export OPENAI_API_KEY=your-api-key-here
|
|
298
|
+
```
|
|
299
|
+
"""
|
|
300
|
+
|
|
301
|
+
if project_type in ["server_agent", "server"]:
|
|
302
|
+
readme += f"""
|
|
303
|
+
## Running the Server
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
python {project_name}/server.py
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
The server uses FastMCP and includes:
|
|
310
|
+
- **Tools**: Simple tool functions (e.g., add_numbers)
|
|
311
|
+
- **Resources**: Data resources (e.g., config)
|
|
312
|
+
- **Prompts**: Prompt templates for the LLM
|
|
313
|
+
"""
|
|
314
|
+
|
|
315
|
+
if project_type in ["server_agent", "agent"]:
|
|
316
|
+
readme += f"""
|
|
317
|
+
## Using the Agent
|
|
318
|
+
|
|
319
|
+
```python
|
|
320
|
+
from {project_name}.agent import agent
|
|
321
|
+
|
|
322
|
+
result = await agent.run("Your prompt")
|
|
323
|
+
```
|
|
324
|
+
"""
|
|
325
|
+
|
|
326
|
+
(project_dir / "README.md").write_text(readme)
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def create_example_files(project_dir: Path, project_name: str):
|
|
330
|
+
"""Create example files."""
|
|
331
|
+
|
|
332
|
+
# run.py
|
|
333
|
+
run_content = f'''"""
|
|
334
|
+
Example usage of {project_name}.
|
|
335
|
+
"""
|
|
336
|
+
|
|
337
|
+
import asyncio
|
|
338
|
+
import os
|
|
339
|
+
|
|
340
|
+
from dotenv import load_dotenv
|
|
341
|
+
|
|
342
|
+
from {project_name}.agent import agent
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
async def main():
|
|
346
|
+
load_dotenv()
|
|
347
|
+
|
|
348
|
+
if not os.getenv("OPENAI_API_KEY"):
|
|
349
|
+
print("Error: OPENAI_API_KEY not found")
|
|
350
|
+
return
|
|
351
|
+
|
|
352
|
+
result = await agent.run("What tools are available?")
|
|
353
|
+
print(f"Result: {{result}}")
|
|
354
|
+
|
|
355
|
+
|
|
356
|
+
if __name__ == "__main__":
|
|
357
|
+
asyncio.run(main())
|
|
358
|
+
'''
|
|
359
|
+
(project_dir / "run.py").write_text(run_content)
|
|
360
|
+
|
|
361
|
+
# chat.py
|
|
362
|
+
chat_content = f'''"""
|
|
363
|
+
Interactive chat for {project_name}.
|
|
364
|
+
"""
|
|
365
|
+
|
|
366
|
+
import asyncio
|
|
367
|
+
import os
|
|
368
|
+
|
|
369
|
+
from dotenv import load_dotenv
|
|
370
|
+
|
|
371
|
+
from {project_name}.agent import agent
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
async def chat():
|
|
375
|
+
load_dotenv()
|
|
376
|
+
|
|
377
|
+
if not os.getenv("OPENAI_API_KEY"):
|
|
378
|
+
print("Error: OPENAI_API_KEY not found")
|
|
379
|
+
return
|
|
380
|
+
|
|
381
|
+
print("Chat started (type 'exit' to quit)")
|
|
382
|
+
|
|
383
|
+
while True:
|
|
384
|
+
user_input = input("\\nYou: ")
|
|
385
|
+
if user_input.lower() == "exit":
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
print("Assistant: ", end="", flush=True)
|
|
389
|
+
response = await agent.run(user_input)
|
|
390
|
+
print(response)
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
if __name__ == "__main__":
|
|
394
|
+
asyncio.run(chat())
|
|
395
|
+
'''
|
|
396
|
+
(project_dir / "chat.py").write_text(chat_content)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def create_project(project_name: str, project_type: str) -> bool:
|
|
400
|
+
"""Create the project structure."""
|
|
401
|
+
project_dir = Path.cwd() / project_name
|
|
402
|
+
|
|
403
|
+
try:
|
|
404
|
+
# Create main directory
|
|
405
|
+
spinner = Spinner("Creating project directory")
|
|
406
|
+
spinner.start()
|
|
407
|
+
time.sleep(0.5) # Simulate work
|
|
408
|
+
project_dir.mkdir(parents=True)
|
|
409
|
+
spinner.stop("Created project directory")
|
|
410
|
+
|
|
411
|
+
# Create server if needed
|
|
412
|
+
if project_type in ["server_agent", "server"]:
|
|
413
|
+
spinner = Spinner("Creating server")
|
|
414
|
+
spinner.start()
|
|
415
|
+
time.sleep(0.3)
|
|
416
|
+
create_server_structure(project_dir, project_name)
|
|
417
|
+
spinner.stop("Created server structure")
|
|
418
|
+
|
|
419
|
+
# Create agent if needed
|
|
420
|
+
if project_type in ["server_agent", "agent"]:
|
|
421
|
+
spinner = Spinner("Creating agent")
|
|
422
|
+
spinner.start()
|
|
423
|
+
time.sleep(0.3)
|
|
424
|
+
create_agent_structure(project_dir, project_name, project_type)
|
|
425
|
+
spinner.stop("Created agent structure")
|
|
426
|
+
|
|
427
|
+
# Create common files
|
|
428
|
+
spinner = Spinner("Creating configuration files")
|
|
429
|
+
spinner.start()
|
|
430
|
+
time.sleep(0.3)
|
|
431
|
+
create_common_files(project_dir, project_name, project_type)
|
|
432
|
+
spinner.stop("Created configuration files")
|
|
433
|
+
|
|
434
|
+
# Create examples for server_agent and agent
|
|
435
|
+
if project_type in ["server_agent", "agent"]:
|
|
436
|
+
spinner = Spinner("Creating example files")
|
|
437
|
+
spinner.start()
|
|
438
|
+
time.sleep(0.3)
|
|
439
|
+
create_example_files(project_dir, project_name)
|
|
440
|
+
spinner.stop("Created example files")
|
|
441
|
+
|
|
442
|
+
return True
|
|
443
|
+
|
|
444
|
+
except Exception as e:
|
|
445
|
+
print(f"\n❌ Error: {str(e)}")
|
|
446
|
+
return False
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
# ============= MAIN CLI FUNCTIONS =============
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def show_help():
|
|
453
|
+
"""Show the main help message."""
|
|
454
|
+
help_text = """
|
|
455
|
+
╔══════════════════════════════════════════════════════════════════╗
|
|
456
|
+
║ MCP-Use CLI Tool ║
|
|
457
|
+
║ ║
|
|
458
|
+
║ Create and deploy MCP servers and agents with ease ║
|
|
459
|
+
╚══════════════════════════════════════════════════════════════════╝
|
|
460
|
+
|
|
461
|
+
Usage: uvx mcp-use <command> [options]
|
|
462
|
+
|
|
463
|
+
Available Commands:
|
|
464
|
+
create 🚀 Create a new MCP project (server, agent, or both)
|
|
465
|
+
Interactive wizard to scaffold your MCP project
|
|
466
|
+
|
|
467
|
+
deploy ☁️ Deploy your MCP project to the cloud
|
|
468
|
+
(Coming soon - Cloud deployment from CLI)
|
|
469
|
+
|
|
470
|
+
Examples:
|
|
471
|
+
uvx mcp-use create # Start interactive project creation
|
|
472
|
+
uvx mcp-use deploy # Deploy to cloud (coming soon)
|
|
473
|
+
uvx mcp-use --help # Show this help message
|
|
474
|
+
uvx mcp-use --version # Show version information
|
|
475
|
+
|
|
476
|
+
For more information, visit: https://mcp-use.com
|
|
477
|
+
"""
|
|
478
|
+
print(help_text)
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
def handle_create():
|
|
482
|
+
"""Handle the create command."""
|
|
483
|
+
print_header()
|
|
484
|
+
|
|
485
|
+
# Get project configuration
|
|
486
|
+
project_name = get_project_name()
|
|
487
|
+
project_type = get_project_type()
|
|
488
|
+
|
|
489
|
+
print(f"\n⚙️ Creating {project_type.replace('_', ' + ')} project: {project_name}")
|
|
490
|
+
print()
|
|
491
|
+
|
|
492
|
+
# Create the project
|
|
493
|
+
if create_project(project_name, project_type):
|
|
494
|
+
print(f"\n✨ Successfully created '{project_name}'!")
|
|
495
|
+
print("\n📋 Next steps:")
|
|
496
|
+
print(f" cd {project_name}")
|
|
497
|
+
print(" pip install -r requirements.txt")
|
|
498
|
+
print(" export OPENAI_API_KEY=your-api-key-here")
|
|
499
|
+
|
|
500
|
+
if project_type in ["server_agent", "server"]:
|
|
501
|
+
print("\n # Test the server:")
|
|
502
|
+
print(f" python {project_name}/server.py")
|
|
503
|
+
|
|
504
|
+
if project_type in ["server_agent", "agent"]:
|
|
505
|
+
print("\n # Run examples:")
|
|
506
|
+
print(" python run.py # Simple example")
|
|
507
|
+
print(" python chat.py # Interactive chat")
|
|
508
|
+
|
|
509
|
+
print()
|
|
510
|
+
else:
|
|
511
|
+
sys.exit(1)
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
def handle_deploy():
|
|
515
|
+
"""Handle the deploy command (placeholder for future implementation)."""
|
|
516
|
+
print("\n" + "=" * 60)
|
|
517
|
+
print("🚀 MCP Cloud Deployment")
|
|
518
|
+
print("=" * 60)
|
|
519
|
+
|
|
520
|
+
print("\n📝 Please login to MCP Cloud to continue...")
|
|
521
|
+
print(" Visit: https://cloud.mcp-use.com/login")
|
|
522
|
+
print()
|
|
523
|
+
|
|
524
|
+
# Simulate login prompt
|
|
525
|
+
print("Enter your MCP Cloud credentials:")
|
|
526
|
+
email = input("Email: ")
|
|
527
|
+
|
|
528
|
+
if email:
|
|
529
|
+
print(f"\n✨ Welcome {email}!")
|
|
530
|
+
print()
|
|
531
|
+
print("ℹ️ Deployment from CLI is coming soon!")
|
|
532
|
+
print(" For now, please use the web interface at:")
|
|
533
|
+
print(" https://cloud.mcp-use.com/deploy")
|
|
534
|
+
print()
|
|
535
|
+
print("Stay tuned for updates! 🎉")
|
|
536
|
+
else:
|
|
537
|
+
print("\n❌ Login cancelled")
|
|
538
|
+
|
|
539
|
+
print("=" * 60)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
def main(args=None):
|
|
543
|
+
"""Main entry point for the CLI."""
|
|
544
|
+
parser = argparse.ArgumentParser(
|
|
545
|
+
prog="mcp-use",
|
|
546
|
+
description="MCP-Use CLI Tool - Create and deploy MCP projects",
|
|
547
|
+
add_help=False, # We'll handle help ourselves
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
# Add version argument
|
|
551
|
+
parser.add_argument(
|
|
552
|
+
"--version", "-v", action="version", version=f"mcp-use {__version__}", help="Show version information"
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
# Add help argument
|
|
556
|
+
parser.add_argument("--help", "-h", action="store_true", help="Show help message")
|
|
557
|
+
|
|
558
|
+
# Add subcommand as positional argument
|
|
559
|
+
parser.add_argument("command", nargs="?", choices=["create", "deploy"], help="Command to execute")
|
|
560
|
+
|
|
561
|
+
# Parse arguments
|
|
562
|
+
parsed_args = parser.parse_args(args)
|
|
563
|
+
|
|
564
|
+
# Handle help flag or no command
|
|
565
|
+
if parsed_args.help or not parsed_args.command:
|
|
566
|
+
show_help()
|
|
567
|
+
sys.exit(0)
|
|
568
|
+
|
|
569
|
+
# Handle commands
|
|
570
|
+
if parsed_args.command == "create":
|
|
571
|
+
handle_create()
|
|
572
|
+
elif parsed_args.command == "deploy":
|
|
573
|
+
handle_deploy()
|
|
574
|
+
else:
|
|
575
|
+
print(f"Unknown command: {parsed_args.command}")
|
|
576
|
+
show_help()
|
|
577
|
+
sys.exit(1)
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
if __name__ == "__main__":
|
|
581
|
+
main()
|
mcp_use/logging.py
CHANGED
|
@@ -80,6 +80,9 @@ class Logger:
|
|
|
80
80
|
|
|
81
81
|
root_logger.setLevel(level)
|
|
82
82
|
|
|
83
|
+
# Set propagate to True to ensure child loggers inherit settings
|
|
84
|
+
root_logger.propagate = True
|
|
85
|
+
|
|
83
86
|
# Clear existing handlers
|
|
84
87
|
for handler in root_logger.handlers[:]:
|
|
85
88
|
root_logger.removeHandler(handler)
|
|
@@ -91,6 +94,7 @@ class Logger:
|
|
|
91
94
|
if log_to_console:
|
|
92
95
|
console_handler = logging.StreamHandler(sys.stdout)
|
|
93
96
|
console_handler.setFormatter(formatter)
|
|
97
|
+
console_handler.setLevel(level) # Ensure handler respects the level
|
|
94
98
|
root_logger.addHandler(console_handler)
|
|
95
99
|
|
|
96
100
|
# Add file handler if requested
|
|
@@ -102,6 +106,7 @@ class Logger:
|
|
|
102
106
|
|
|
103
107
|
file_handler = logging.FileHandler(log_to_file)
|
|
104
108
|
file_handler.setFormatter(formatter)
|
|
109
|
+
file_handler.setLevel(level) # Ensure handler respects the level
|
|
105
110
|
root_logger.addHandler(file_handler)
|
|
106
111
|
|
|
107
112
|
@classmethod
|
|
@@ -114,24 +119,34 @@ class Logger:
|
|
|
114
119
|
global MCP_USE_DEBUG
|
|
115
120
|
MCP_USE_DEBUG = debug_level
|
|
116
121
|
|
|
117
|
-
#
|
|
122
|
+
# Determine the target level
|
|
118
123
|
if debug_level == 2:
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
langchain_set_debug(True)
|
|
124
|
+
target_level = logging.DEBUG
|
|
125
|
+
langchain_set_debug(True)
|
|
122
126
|
elif debug_level == 1:
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
langchain_set_debug(False)
|
|
127
|
+
target_level = logging.INFO
|
|
128
|
+
langchain_set_debug(False)
|
|
126
129
|
else:
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
130
|
+
target_level = logging.WARNING
|
|
131
|
+
langchain_set_debug(False)
|
|
132
|
+
|
|
133
|
+
# Update log level for existing loggers in our registry
|
|
134
|
+
for logger in cls._loggers.values():
|
|
135
|
+
logger.setLevel(target_level)
|
|
136
|
+
# Also update handler levels
|
|
137
|
+
for handler in logger.handlers:
|
|
138
|
+
handler.setLevel(target_level)
|
|
139
|
+
|
|
140
|
+
# Also update all mcp_use child loggers that might exist
|
|
141
|
+
# This ensures loggers created with logging.getLogger() are also updated
|
|
142
|
+
base_logger = logging.getLogger("mcp_use")
|
|
143
|
+
base_logger.setLevel(target_level)
|
|
144
|
+
for handler in base_logger.handlers:
|
|
145
|
+
handler.setLevel(target_level)
|
|
131
146
|
|
|
132
147
|
|
|
133
148
|
# Check environment variable for debug flag
|
|
134
|
-
debug_env = os.environ.get("DEBUG", "").lower()
|
|
149
|
+
debug_env = os.environ.get("MCP_USE_DEBUG", "").lower() or os.environ.get("DEBUG", "").lower()
|
|
135
150
|
if debug_env == "2":
|
|
136
151
|
MCP_USE_DEBUG = 2
|
|
137
152
|
elif debug_env == "1":
|
mcp_use/managers/base.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from langchain_core.tools import BaseTool
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BaseServerManager(ABC):
|
|
7
|
+
"""Abstract base class for server managers.
|
|
8
|
+
|
|
9
|
+
This class defines the interface for server managers that can be used with MCPAgent.
|
|
10
|
+
Custom server managers should inherit from this class and implement the required methods.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
@abstractmethod
|
|
14
|
+
async def initialize(self) -> None:
|
|
15
|
+
"""Initialize the server manager."""
|
|
16
|
+
raise NotImplementedError
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
@abstractmethod
|
|
20
|
+
def tools(self) -> list[BaseTool]:
|
|
21
|
+
"""Get all server management tools and tools from the active server.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
list of LangChain tools for server management plus tools from active server
|
|
25
|
+
"""
|
|
26
|
+
raise NotImplementedError
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def has_tool_changes(self, current_tool_names: set[str]) -> bool:
|
|
30
|
+
"""Check if the available tools have changed.
|
|
31
|
+
Args:
|
|
32
|
+
current_tool_names: Set of currently known tool names
|
|
33
|
+
Returns:
|
|
34
|
+
True if tools have changed, False otherwise
|
|
35
|
+
"""
|
|
36
|
+
raise NotImplementedError
|
|
@@ -4,10 +4,11 @@ from mcp_use.client import MCPClient
|
|
|
4
4
|
from mcp_use.logging import logger
|
|
5
5
|
|
|
6
6
|
from ..adapters.base import BaseAdapter
|
|
7
|
+
from .base import BaseServerManager
|
|
7
8
|
from .tools import ConnectServerTool, DisconnectServerTool, GetActiveServerTool, ListServersTool, SearchToolsTool
|
|
8
9
|
|
|
9
10
|
|
|
10
|
-
class ServerManager:
|
|
11
|
+
class ServerManager(BaseServerManager):
|
|
11
12
|
"""Manages MCP servers and provides tools for server selection and management.
|
|
12
13
|
|
|
13
14
|
This class allows an agent to discover and select which MCP server to use,
|