Coverage for src/quickmcp/quick.py: 86%
44 statements
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-20 20:56 +0200
« prev ^ index » next coverage.py v7.10.4, created at 2025-08-20 20:56 +0200
1"""
2QuickMCP - Super Simple API
3The easiest way to create MCP servers.
4"""
6from typing import Optional, Any, Callable
7from pathlib import Path
9from .server import QuickMCPServer
10from .factory import create_mcp_from_module as _create_from_module
11from .factory import MCPFactory, FactoryConfig
14def server(name: str = "quickmcp-server") -> QuickMCPServer:
15 """
16 Create a new MCP server with zero configuration.
18 Example:
19 from quickmcp.quick import server
21 app = server("my-app")
23 @app.tool()
24 def hello(name: str) -> str:
25 return f"Hello, {name}!"
27 app.run()
28 """
29 return QuickMCPServer(name)
32def from_file(
33 file_path: str,
34 name: Optional[str] = None,
35 include_private: bool = False
36) -> QuickMCPServer:
37 """
38 Create an MCP server from any Python file instantly.
40 Example:
41 from quickmcp.quick import from_file
43 # Turn any Python file into an MCP server
44 app = from_file("my_utils.py")
45 app.run()
47 Args:
48 file_path: Path to Python file
49 name: Optional server name (defaults to filename)
50 include_private: Include functions starting with underscore
52 Returns:
53 Ready-to-run MCP server
54 """
55 # Use sensible defaults - no configuration needed
56 config = FactoryConfig(
57 check_dependencies=False, # Don't fail on missing optional deps
58 warn_on_code_execution=False, # Don't warn, just work
59 strict_type_conversion=False, # Be flexible
60 cache_dependency_analysis=True, # Fast
61 cache_type_hints=True, # Fast
62 )
64 if name is None:
65 name = Path(file_path).stem.replace("_", "-") + "-mcp"
67 return _create_from_module(
68 file_path,
69 server_name=name,
70 include_private=include_private,
71 auto_run=False,
72 config=config
73 )
76def from_object(obj: Any, name: Optional[str] = None) -> QuickMCPServer:
77 """
78 Create an MCP server from any Python object (module, class, or dict).
80 Example:
81 from quickmcp.quick import from_object
82 import math
84 # From a module
85 app = from_object(math)
87 # From a class
88 class MyTools:
89 def add(self, a: int, b: int) -> int:
90 return a + b
92 app = from_object(MyTools)
94 # From a dict of functions
95 app = from_object({
96 "greet": lambda name: f"Hello, {name}!",
97 "add": lambda a, b: a + b
98 })
100 app.run()
101 """
102 from .factory import create_mcp_from_object as _create_from_object
104 # Use sensible defaults
105 config = FactoryConfig(
106 check_dependencies=False,
107 warn_on_code_execution=False,
108 strict_type_conversion=False,
109 cache_dependency_analysis=True,
110 cache_type_hints=True,
111 )
113 return _create_from_object(obj, server_name=name, config=config)
116def run(
117 func_or_file: Optional[Any] = None,
118 name: str = "quickmcp-server",
119 **kwargs
120):
121 """
122 The simplest way to run an MCP server.
124 Example:
125 from quickmcp.quick import run
127 # Run current file as server
128 run(__file__)
130 # Run with a function dict
131 run({
132 "hello": lambda name: f"Hello, {name}!",
133 "add": lambda a, b: a + b
134 })
136 # Run with decorators in current file
137 from quickmcp.quick import run, tool
139 @tool
140 def greet(name: str) -> str:
141 return f"Hello, {name}!"
143 run() # Automatically finds decorated functions
144 """
145 import sys
146 import inspect
148 # If no argument, try to find decorated functions in caller's module
149 if func_or_file is None:
150 # Get the calling module
151 frame = inspect.currentframe()
152 if frame and frame.f_back:
153 caller_module = inspect.getmodule(frame.f_back)
154 if caller_module and hasattr(caller_module, '__file__'):
155 func_or_file = caller_module.__file__
157 # Determine what we're working with
158 if func_or_file is None:
159 # Create empty server
160 app = server(name)
161 elif isinstance(func_or_file, str):
162 # It's a file path
163 app = from_file(func_or_file, name=name)
164 elif isinstance(func_or_file, dict):
165 # It's a dictionary of functions
166 app = from_object(func_or_file, name=name)
167 elif callable(func_or_file):
168 # It's a single function
169 app = from_object({func_or_file.__name__: func_or_file}, name=name)
170 elif hasattr(func_or_file, '__class__'):
171 # It's an object/class
172 app = from_object(func_or_file, name=name)
173 else:
174 # Create empty server
175 app = server(name)
177 # Run the server
178 transport = kwargs.get('transport', 'stdio')
179 host = kwargs.get('host', 'localhost')
180 port = kwargs.get('port', 8000)
182 app.run(transport=transport, host=host, port=port)
185# Simple decorator for marking functions as tools
186def tool(func: Optional[Callable] = None, *, name: Optional[str] = None, description: Optional[str] = None):
187 """
188 Simple decorator to mark a function as an MCP tool.
190 Example:
191 from quickmcp.quick import tool, run
193 @tool
194 def hello(name: str) -> str:
195 return f"Hello, {name}!"
197 @tool(description="Add two numbers")
198 def add(a: int, b: int) -> int:
199 return a + b
201 run() # Automatically creates server with these tools
202 """
203 from .factory import mcp_tool
204 return mcp_tool(func, name=name, description=description)
207# Export the simplest API
208__all__ = [
209 'server',
210 'from_file',
211 'from_object',
212 'run',
213 'tool',
214]