mcp-use 1.3.8__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/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/client.py CHANGED
@@ -9,7 +9,7 @@ import json
9
9
  import warnings
10
10
  from typing import Any
11
11
 
12
- from mcp.client.session import ElicitationFnT, SamplingFnT
12
+ from mcp.client.session import ElicitationFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
13
13
 
14
14
  from mcp_use.types.sandbox import SandboxOptions
15
15
 
@@ -33,6 +33,8 @@ class MCPClient:
33
33
  sandbox_options: SandboxOptions | None = None,
34
34
  sampling_callback: SamplingFnT | None = None,
35
35
  elicitation_callback: ElicitationFnT | None = None,
36
+ message_handler: MessageHandlerFnT | None = None,
37
+ logging_callback: LoggingFnT | None = None,
36
38
  ) -> None:
37
39
  """Initialize a new MCP client.
38
40
 
@@ -51,6 +53,8 @@ class MCPClient:
51
53
  self.active_sessions: list[str] = []
52
54
  self.sampling_callback = sampling_callback
53
55
  self.elicitation_callback = elicitation_callback
56
+ self.message_handler = message_handler
57
+ self.logging_callback = logging_callback
54
58
  # Load configuration if provided
55
59
  if config is not None:
56
60
  if isinstance(config, str):
@@ -66,6 +70,8 @@ class MCPClient:
66
70
  sandbox_options: SandboxOptions | None = None,
67
71
  sampling_callback: SamplingFnT | None = None,
68
72
  elicitation_callback: ElicitationFnT | None = None,
73
+ message_handler: MessageHandlerFnT | None = None,
74
+ logging_callback: LoggingFnT | None = None,
69
75
  ) -> "MCPClient":
70
76
  """Create a MCPClient from a dictionary.
71
77
 
@@ -82,6 +88,8 @@ class MCPClient:
82
88
  sandbox_options=sandbox_options,
83
89
  sampling_callback=sampling_callback,
84
90
  elicitation_callback=elicitation_callback,
91
+ message_handler=message_handler,
92
+ logging_callback=logging_callback,
85
93
  )
86
94
 
87
95
  @classmethod
@@ -92,6 +100,8 @@ class MCPClient:
92
100
  sandbox_options: SandboxOptions | None = None,
93
101
  sampling_callback: SamplingFnT | None = None,
94
102
  elicitation_callback: ElicitationFnT | None = None,
103
+ message_handler: MessageHandlerFnT | None = None,
104
+ logging_callback: LoggingFnT | None = None,
95
105
  ) -> "MCPClient":
96
106
  """Create a MCPClient from a configuration file.
97
107
 
@@ -108,6 +118,8 @@ class MCPClient:
108
118
  sandbox_options=sandbox_options,
109
119
  sampling_callback=sampling_callback,
110
120
  elicitation_callback=elicitation_callback,
121
+ message_handler=message_handler,
122
+ logging_callback=logging_callback,
111
123
  )
112
124
 
113
125
  def add_server(
@@ -187,6 +199,8 @@ class MCPClient:
187
199
  sandbox_options=self.sandbox_options,
188
200
  sampling_callback=self.sampling_callback,
189
201
  elicitation_callback=self.elicitation_callback,
202
+ message_handler=self.message_handler,
203
+ logging_callback=self.logging_callback,
190
204
  )
191
205
 
192
206
  # Create the session
mcp_use/config.py CHANGED
@@ -7,17 +7,11 @@ This module provides functionality to load MCP configuration from JSON files.
7
7
  import json
8
8
  from typing import Any
9
9
 
10
- from mcp.client.session import ElicitationFnT, SamplingFnT
10
+ from mcp.client.session import ElicitationFnT, LoggingFnT, MessageHandlerFnT, SamplingFnT
11
11
 
12
12
  from mcp_use.types.sandbox import SandboxOptions
13
13
 
14
- from .connectors import (
15
- BaseConnector,
16
- HttpConnector,
17
- SandboxConnector,
18
- StdioConnector,
19
- WebSocketConnector,
20
- )
14
+ from .connectors import BaseConnector, HttpConnector, SandboxConnector, StdioConnector, WebSocketConnector
21
15
  from .connectors.utils import is_stdio_server
22
16
 
23
17
 
@@ -40,6 +34,8 @@ def create_connector_from_config(
40
34
  sandbox_options: SandboxOptions | None = None,
41
35
  sampling_callback: SamplingFnT | None = None,
42
36
  elicitation_callback: ElicitationFnT | None = None,
37
+ message_handler: MessageHandlerFnT | None = None,
38
+ logging_callback: LoggingFnT | None = None,
43
39
  ) -> BaseConnector:
44
40
  """Create a connector based on server configuration.
45
41
  This function can be called with just the server_config parameter:
@@ -61,6 +57,8 @@ def create_connector_from_config(
61
57
  env=server_config.get("env", None),
62
58
  sampling_callback=sampling_callback,
63
59
  elicitation_callback=elicitation_callback,
60
+ message_handler=message_handler,
61
+ logging_callback=logging_callback,
64
62
  )
65
63
 
66
64
  # Sandboxed connector
@@ -72,6 +70,8 @@ def create_connector_from_config(
72
70
  e2b_options=sandbox_options,
73
71
  sampling_callback=sampling_callback,
74
72
  elicitation_callback=elicitation_callback,
73
+ message_handler=message_handler,
74
+ logging_callback=logging_callback,
75
75
  )
76
76
 
77
77
  # HTTP connector
@@ -84,6 +84,8 @@ def create_connector_from_config(
84
84
  sse_read_timeout=server_config.get("sse_read_timeout", 60 * 5),
85
85
  sampling_callback=sampling_callback,
86
86
  elicitation_callback=elicitation_callback,
87
+ message_handler=message_handler,
88
+ logging_callback=logging_callback,
87
89
  )
88
90
 
89
91
  # WebSocket connector