55# Initialize the MCP server
66mcp = FastMCP ("Self-Extending MCP Server" )
77
8+ built_in_tools = {
9+ "get_tools" : {
10+ "description" : "Get a list of all available tools in the MCP server." ,
11+ "parameters" : {}
12+ },
13+ "add_tool" : {
14+ "description" : "Add a new tool to the MCP server." ,
15+ "parameters" : {
16+ "name" : "Name of the tool (required)" ,
17+ "code" : "Python code implementing the tool function (required)" ,
18+ "description" : "Description of what the tool does (required)" ,
19+ "param_descriptions" : "Dictionary of parameter names to descriptions (optional)"
20+ }
21+ },
22+ "call_tool" : {
23+ "description" : "Call a registered tool with the given arguments." ,
24+ "parameters" : {
25+ "name" : "Name of the tool to call (required)" ,
26+ "args" : "Dictionary of arguments to pass to the tool"
27+ }
28+ }
29+ }
830
931# Tool registry to track dynamically added tools
1032class ToolRegistry :
1133 def __init__ (self ):
1234 self .tools = {} # name -> function
1335 self .metadata = {} # name -> metadata
1436
15- def register (self , name : str , func : Callable , description : str ):
37+ def register (self , name : str , func : Callable , description : str , param_descriptions : Dict [ str , str ] = None ):
1638 """Register a new tool in the registry."""
1739 self .tools [name ] = func
18- self .metadata [name ] = {"name" : name , "description" : description }
40+ self .metadata [name ] = {
41+ "name" : name ,
42+ "description" : description ,
43+ "parameters" : param_descriptions or {}
44+ }
1945
2046 def get_tool (self , name : str ) -> Optional [Callable ]:
2147 """Get a tool by name."""
@@ -49,19 +75,23 @@ def get_tools() -> Dict[str, Any]:
4975 try :
5076 tools = registry .list_tools ()
5177
52- # Add the built-in tools
53- built_in_tools = ["get_tools" , "add_tool" , "call_tool" ]
54-
5578 # Combine built-in tools with dynamic tools
56- all_tools = [{"name" : tool , "built_in" : True } for tool in built_in_tools ]
79+ all_tools = []
80+ for name , info in built_in_tools .items ():
81+ all_tools .append ({
82+ "name" : name ,
83+ "description" : info ["description" ],
84+ "parameters" : info ["parameters" ],
85+ "built_in" : True
86+ })
87+
5788 for tool in tools :
58- all_tools .append (
59- {
60- "name" : tool ["name" ],
61- "description" : tool ["description" ],
62- "built_in" : False ,
63- }
64- )
89+ all_tools .append ({
90+ "name" : tool ["name" ],
91+ "description" : tool ["description" ],
92+ "parameters" : tool ["parameters" ],
93+ "built_in" : False
94+ })
6595
6696 return {"status" : "success" , "tools" : all_tools }
6797 except Exception as e :
@@ -70,18 +100,35 @@ def get_tools() -> Dict[str, Any]:
70100
71101# Core functionality: Add a new tool
72102@mcp .tool ()
73- def add_tool (name : str , code : str , description : str ) -> Dict [str , Any ]:
103+ def add_tool (name : str = None , code : str = None , description : str = None , param_descriptions : Dict [ str , str ] = None ) -> Dict [str , Any ]:
74104 """Add a new tool to the MCP server.
75105
76106 Args:
77107 name: Name of the tool
78108 code: Python code implementing the tool function
79109 description: Description of what the tool does
110+ param_descriptions: Dictionary of parameter names to descriptions
80111
81112 Returns:
82113 Dictionary with operation status
83114 """
84115 try :
116+ # Validate required parameters
117+ missing_params = []
118+ if name is None :
119+ missing_params .append ("name" )
120+ if code is None :
121+ missing_params .append ("code" )
122+ if description is None :
123+ missing_params .append ("description" )
124+
125+ if missing_params :
126+ return {
127+ "status" : "error" ,
128+ "message" : f"Missing required parameters: { ', ' .join (missing_params )} " ,
129+ "usage_example" : "add_tool(name='tool_name', code='def tool_name(param1, param2):\\ n # code here\\ n return {\" status\" : \" success\" }', description='Tool description', param_descriptions={'param1': 'Description of param1', 'param2': 'Description of param2'})"
130+ }
131+
85132 # Check if tool already exists
86133 if registry .has_tool (name ) or hasattr (mcp , name ):
87134 return {"status" : "error" , "message" : f"Tool '{ name } ' already exists" }
@@ -109,9 +156,16 @@ def add_tool(name: str, code: str, description: str) -> Dict[str, Any]:
109156 }
110157
111158 # Register the tool with our registry
112- registry .register (name , func , description )
159+ registry .register (name , func , description , param_descriptions )
113160
114- return {"status" : "success" , "message" : f"Tool '{ name } ' added successfully" }
161+ # Get the parameter information to return
162+ params = registry .get_metadata (name )["parameters" ]
163+
164+ return {
165+ "status" : "success" ,
166+ "message" : f"Tool '{ name } ' added successfully" ,
167+ "parameters" : params
168+ }
115169
116170 except SyntaxError as e :
117171 return {
@@ -127,7 +181,7 @@ def add_tool(name: str, code: str, description: str) -> Dict[str, Any]:
127181
128182# Core functionality: Call a tool
129183@mcp .tool ()
130- def call_tool (name : str , args : Dict [str , Any ]) -> Dict [str , Any ]:
184+ def call_tool (name : str , args : Dict [str , Any ] = None ) -> Dict [str , Any ]:
131185 """Call a registered tool with the given arguments.
132186
133187 Args:
@@ -137,29 +191,41 @@ def call_tool(name: str, args: Dict[str, Any]) -> Dict[str, Any]:
137191 Returns:
138192 Dictionary with the tool's response
139193 """
194+
195+ args = args or {}
196+
140197 try :
141198 # Check if it's a built-in tool
142- if name in [ "get_tools" , "add_tool" , "call_tool" ] :
199+ if name in built_in_tools :
143200 return {
144201 "status" : "error" ,
145202 "message" : f"Cannot call built-in tool '{ name } ' using call_tool" ,
203+ "note" : f"Use the { name } function directly instead of call_tool" ,
204+ "parameters" : built_in_tools [name ]["parameters" ]
146205 }
147206
148207 # Get the tool
149208 tool = registry .get_tool (name )
150209
151210 if not tool :
152- return {"status" : "error" , "message" : f"Tool '{ name } ' not found" }
211+ return {
212+ "status" : "error" ,
213+ "message" : f"Tool '{ name } ' not found" ,
214+ "available_tools" : [t ["name" ] for t in registry .list_tools ()]
215+ }
153216
154217 # Call the tool with the provided arguments
155218 try :
156219 result = tool (** args )
157220 return result
158221 except TypeError as e :
159222 # Likely an argument mismatch
223+ params = registry .get_metadata (name )["parameters" ]
160224 return {
161225 "status" : "error" ,
162226 "message" : f"Argument error calling tool '{ name } ': { str (e )} " ,
227+ "expected_parameters" : params ,
228+ "usage_example" : f"call_tool(name='{ name } ', args={{'param1': value1, 'param2': value2, ...}})"
163229 }
164230 except Exception as e :
165231 return {
0 commit comments