universal-mcp 0.1.24rc9__py3-none-any.whl → 0.1.24rc11__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.
@@ -132,10 +132,10 @@ class AgentrRegistry(ToolRegistry):
132
132
  # Clear tools from tool manager before loading new tools
133
133
  self.tool_manager.clear_tools()
134
134
  if isinstance(tools, ToolConfig):
135
- print("Loading tools from tool config")
135
+ logger.info("Loading tools from tool config")
136
136
  self._load_tools_from_tool_config(tools, self.tool_manager)
137
137
  else:
138
- print("Loading tools from list")
138
+ logger.info("Loading tools from list")
139
139
  self._load_agentr_tools_from_list(tools, self.tool_manager)
140
140
  loaded_tools = self.tool_manager.list_tools(format=format)
141
141
  logger.info(f"Exporting {len(loaded_tools)} tools to {format} format")
@@ -521,7 +521,7 @@ Be friendly and concise, but list each set of apps clearly. Do not return any ot
521
521
  return result
522
522
 
523
523
  # Get all available apps from platform manager
524
- available_apps = self.app_registry.list_apps()
524
+ available_apps = self.app_registry.list_apps()
525
525
 
526
526
  logger.info(f"Found {len(available_apps)} available apps")
527
527
 
@@ -567,9 +567,9 @@ if __name__ == "__main__":
567
567
 
568
568
  agent = AutoAgent("Auto Agent", instructions, "azure/gpt-4.1", app_registry=app_registry)
569
569
 
570
- print("AutoAgent created successfully!")
571
- print(f"Agent name: {agent.name}")
572
- print(f"Agent instructions: {agent.instructions}")
573
- print(f"Agent model: {agent.model}")
570
+ logger.info("AutoAgent created successfully!")
571
+ logger.info(f"Agent name: {agent.name}")
572
+ logger.info(f"Agent instructions: {agent.instructions}")
573
+ logger.info(f"Agent model: {agent.model}")
574
574
 
575
575
  asyncio.run(agent.run_interactive())
@@ -8,13 +8,14 @@ async def main():
8
8
  agent = AutoAgent(
9
9
  name="autoagent",
10
10
  instructions="You are a helpful assistant that can use tools to help the user.",
11
- model="anthropic/claude-4-sonnet-20250514",
11
+ model="azure/gpt-4.1",
12
12
  tool_registry=AgentrRegistry(),
13
13
  )
14
- result = await agent.invoke(
15
- user_input="Send an email to Manoj from my google mail account, manoj@agentr.dev, with the subject 'Hello from auto agent' and the body 'testing'"
14
+ await agent.invoke(
15
+ user_input="Please send the email from google-mail to manoj@agentr.dev, with subject hello and body hello from auto",
16
+ thread_id="12345",
16
17
  )
17
- print(result)
18
+ # from loguru import logger; logger.debug(result)
18
19
 
19
20
 
20
21
  if __name__ == "__main__":
@@ -33,43 +33,40 @@ async def build_graph(tool_registry: ToolRegistry, instructions: str = ""):
33
33
  """Ask the user a question. Use this tool to ask the user for any missing information for performing a task, or when you have multiple apps to choose from for performing a task."""
34
34
  full_question = question
35
35
  return f"ASKING_USER: {full_question}"
36
-
36
+
37
37
  @tool()
38
38
  async def load_tools(tools: list[str]) -> list[str]:
39
39
  """Choose the tools you want to use by passing their tool ids. Loads the tools for the chosen tools and returns the tool ids."""
40
40
  return tools
41
-
42
41
 
43
42
  async def call_model(
44
43
  state: State,
45
44
  runtime: Runtime[Context],
46
45
  ):
47
- system_prompt = runtime.context.system_prompt if runtime.context.system_prompt else SYSTEM_PROMPT
46
+ system_prompt = SYSTEM_PROMPT
48
47
  app_ids = await tool_registry.list_all_apps()
49
48
  connections = tool_registry.client.list_my_connections()
50
49
  connection_ids = set([connection["app_id"] for connection in connections])
51
- connected_apps = [app['id'] for app in app_ids if app["id"] in connection_ids]
52
- unconnected_apps = [app['id'] for app in app_ids if app["id"] not in connection_ids]
53
- app_id_descriptions = "These are the apps connected to the user's account:\n" + "\n".join([f"{app}" for app in connected_apps])
50
+ connected_apps = [app["id"] for app in app_ids if app["id"] in connection_ids]
51
+ unconnected_apps = [app["id"] for app in app_ids if app["id"] not in connection_ids]
52
+ app_id_descriptions = "These are the apps connected to the user's account:\n" + "\n".join(
53
+ [f"{app}" for app in connected_apps]
54
+ )
54
55
  if unconnected_apps:
55
- app_id_descriptions += "\n\nOther (not connected) apps: " + "\n".join([f"{app}" for app in unconnected_apps])
56
- print(app_id_descriptions)
56
+ app_id_descriptions += "\n\nOther (not connected) apps: " + "\n".join(
57
+ [f"{app}" for app in unconnected_apps]
58
+ )
59
+
57
60
  system_prompt = system_prompt.format(system_time=datetime.now(tz=UTC).isoformat(), app_ids=app_id_descriptions)
58
-
61
+
59
62
  messages = [{"role": "system", "content": system_prompt + "\n" + instructions}, *state["messages"]]
60
63
  model = load_chat_model(runtime.context.model)
61
64
  # Load tools from tool registry
62
65
  loaded_tools = await tool_registry.export_tools(tools=state["selected_tool_ids"], format=ToolFormat.LANGCHAIN)
63
66
  model_with_tools = model.bind_tools([search_tools, ask_user, load_tools, *loaded_tools], tool_choice="auto")
64
67
  response_raw = model_with_tools.invoke(messages)
65
- token_usage = state.get("token_usage", {})
66
- for key in ["input_tokens", "output_tokens", "total_tokens"]:
67
- if key in token_usage:
68
- token_usage[key] += response_raw.usage_metadata[key]
69
- else:
70
- token_usage[key] = response_raw.usage_metadata[key]
71
- response = cast(AIMessage, response_raw)
72
- return {"messages": [response], "token_usage": token_usage}
68
+ response = cast(AIMessage, response_raw)
69
+ return {"messages": [response]}
73
70
 
74
71
  # Define the conditional edge that determines whether to continue or not
75
72
  def should_continue(state: State):
@@ -108,15 +105,15 @@ async def build_graph(tool_registry: ToolRegistry, instructions: str = ""):
108
105
  tools = await search_tools.ainvoke(tool_call["args"])
109
106
  outputs.append(
110
107
  ToolMessage(
111
- content=json.dumps(tools)+"\n\nUse the load_tools tool to load the tools you want to use.",
108
+ content=json.dumps(tools) + "\n\nUse the load_tools tool to load the tools you want to use.",
112
109
  name=tool_call["name"],
113
110
  tool_call_id=tool_call["id"],
114
111
  )
115
112
  )
116
-
113
+
117
114
  elif tool_call["name"] == load_tools.name:
118
115
  tool_ids = await load_tools.ainvoke(tool_call["args"])
119
- print(tool_ids)
116
+
120
117
  outputs.append(
121
118
  ToolMessage(
122
119
  content=json.dumps(tool_ids),
@@ -132,23 +129,19 @@ async def build_graph(tool_registry: ToolRegistry, instructions: str = ""):
132
129
  ToolMessage(
133
130
  content=json.dumps(tool_result),
134
131
  name=tool_call["name"],
135
- tool_call_id=tool_call["id"],
136
- )
132
+ tool_call_id=tool_call["id"],
137
133
  )
134
+ )
138
135
  except Exception as e:
139
136
  outputs.append(
140
137
  ToolMessage(
141
- content=json.dumps("Error: "+str(e)),
138
+ content=json.dumps("Error: " + str(e)),
142
139
  name=tool_call["name"],
143
140
  tool_call_id=tool_call["id"],
144
141
  )
145
142
  )
146
143
  return {"messages": outputs, "selected_tool_ids": tool_ids}
147
144
 
148
-
149
-
150
-
151
-
152
145
  builder = StateGraph(State, context_schema=Context)
153
146
 
154
147
  builder.add_node("agent", call_model)
@@ -25,4 +25,3 @@ def _enqueue(left: list, right: list) -> list:
25
25
 
26
26
  class State(AgentState):
27
27
  selected_tool_ids: Annotated[list[str], _enqueue]
28
- token_usage: dict[str, int]
@@ -30,13 +30,37 @@ class BaseAgent:
30
30
 
31
31
  async def stream(self, thread_id: str, user_input: str):
32
32
  await self.ainit()
33
- async for event, _ in self._graph.astream(
33
+ async for event, metadata in self._graph.astream(
34
34
  {"messages": [{"role": "user", "content": user_input}]},
35
35
  config={"configurable": {"thread_id": thread_id}},
36
+ context={"system_prompt": self.instructions, "model": self.model},
36
37
  stream_mode="messages",
38
+ stream_usage=True,
37
39
  ):
40
+ # Only forward assistant token chunks that are not tool-related.
38
41
  event = cast(AIMessageChunk, event)
42
+ if "finish_reason" in event.response_metadata:
43
+ # Got LLM finish reason ignore it
44
+ # logger.debug(f"Finish event: {event}")
45
+ continue
46
+
47
+ # Skip chunks that correspond to tool calls or tool execution phases
48
+ # - tool_call_chunks present => model is emitting tool call(s)
49
+ # - metadata tags or node names may indicate tool/quiet phases
50
+ tags = metadata.get("tags", []) if isinstance(metadata, dict) else []
51
+
52
+ is_quiet = isinstance(tags, list) and ("quiet" in tags)
53
+
54
+ if is_quiet:
55
+ continue
56
+
57
+ # Emit only the token chunks for the final assistant message.
58
+ # logger.debug(f"Event: {event}, Metadata: {metadata}")
39
59
  yield event
60
+ # Send a final finished message
61
+ # The last event would be finish
62
+ event = cast(AIMessageChunk, event)
63
+ yield event
40
64
 
41
65
  async def stream_interactive(self, thread_id: str, user_input: str):
42
66
  await self.ainit()
@@ -101,4 +125,7 @@ class BaseAgent:
101
125
  self.cli.display_info("\nGoodbye! 👋")
102
126
  break
103
127
  except Exception as e:
128
+ import traceback
129
+
130
+ traceback.print_exc()
104
131
  self.cli.display_error(f"An error occurred: {str(e)}")
@@ -1,7 +1,7 @@
1
1
  from langchain_anthropic import ChatAnthropic
2
2
  from langchain_core.language_models import BaseChatModel
3
- from langchain_google_vertexai.model_garden import ChatAnthropicVertex
4
3
  from langchain_google_vertexai import ChatVertexAI
4
+ from langchain_google_vertexai.model_garden import ChatAnthropicVertex
5
5
  from langchain_openai import AzureChatOpenAI
6
6
 
7
7
 
@@ -26,5 +26,7 @@ def load_chat_model(fully_specified_name: str, tags: list[str] | None = None) ->
26
26
 
27
27
 
28
28
  if __name__ == "__main__":
29
+ from loguru import logger
30
+
29
31
  llm = load_chat_model("azure/gpt-4.1")
30
- print(llm.invoke("Hello, world!"))
32
+ logger.info(llm.invoke("Hello, world!"))
@@ -38,9 +38,9 @@ class ReactAgent(BaseAgent):
38
38
  if config.get("agentrServers")
39
39
  else []
40
40
  )
41
- print(agentr_tools)
41
+ logger.debug(agentr_tools)
42
42
  mcp_tools = await load_mcp_tools(config["mcpServers"]) if config.get("mcpServers") else []
43
- print(mcp_tools)
43
+ logger.debug(mcp_tools)
44
44
  tools = agentr_tools + mcp_tools
45
45
  else:
46
46
  tools = []
@@ -81,4 +81,4 @@ if __name__ == "__main__":
81
81
  result = asyncio.run(
82
82
  agent.invoke(user_input="Send an email with the subject 'testing react agent' to manoj@agentr.dev")
83
83
  )
84
- print(result["messages"][-1].content)
84
+ logger.info(result["messages"][-1].content)
@@ -66,7 +66,7 @@ class ClientTransport:
66
66
 
67
67
  async def _callback_handler(self) -> tuple[str, str | None]:
68
68
  """Handles the OAuth callback by waiting for and returning auth details."""
69
- print("⏳ Waiting for authorization callback...")
69
+ logger.info("⏳ Waiting for authorization callback...")
70
70
  try:
71
71
  auth_code = self.callback_server.wait_for_callback(timeout=300)
72
72
  return auth_code, self.callback_server.get_state()
@@ -86,7 +86,7 @@ class ClientTransport:
86
86
 
87
87
  async def _default_redirect_handler(self, authorization_url: str) -> None:
88
88
  """Default handler for OAuth redirects; opens URL in a web browser."""
89
- print(f"Opening browser for authorization: {authorization_url}")
89
+ logger.info(f"Opening browser for authorization: {authorization_url}")
90
90
  webbrowser.open(authorization_url)
91
91
 
92
92
  async def initialize(self, exit_stack: AsyncExitStack) -> None:
@@ -43,7 +43,7 @@ def _filter_by_name(tools: list[Tool], tool_names: list[str] | None) -> list[Too
43
43
  """
44
44
  if not tool_names:
45
45
  return tools
46
-
46
+ logger.debug(f"All tools: {[tool.name for tool in tools]}")
47
47
  logger.debug(f"Filtering tools by names: {tool_names}")
48
48
  tool_names_set = set(_sanitize_tool_names(tool_names))
49
49
  logger.debug(f"Tool names set: {tool_names_set}")
@@ -259,7 +259,7 @@ class ToolManager:
259
259
  except Exception as e:
260
260
  tool_name = getattr(function, "__name__", "unknown")
261
261
  logger.error(f"Failed to create Tool from '{tool_name}' in {app.name}: {e}")
262
- print([tool.name for tool in tools])
262
+ # logger.debug([tool.name for tool in tools])
263
263
  if tags:
264
264
  tools = _filter_by_tags(tools, tags)
265
265
 
@@ -11,7 +11,10 @@ from universal_mcp.utils.openapi.openapi import generate_api_client, generate_sc
11
11
 
12
12
  def echo(message: str, err: bool = False) -> None:
13
13
  """Echo a message to the console, with optional error flag."""
14
- print(message, file=os.sys.stderr if err else None)
14
+ if err:
15
+ logger.error(message)
16
+ else:
17
+ logger.info(message)
15
18
 
16
19
 
17
20
  def validate_and_load_schema(schema_path: Path) -> dict:
@@ -179,7 +179,9 @@ def _get_or_create_response_model(
179
179
 
180
180
  except Exception as e:
181
181
  # If model generation fails, log and continue with fallback
182
- print(f"Warning: Could not generate model for {method.upper()} {path}: {e}")
182
+ from loguru import logger
183
+
184
+ logger.warning(f"Could not generate model for {method.upper()} {path}: {e}")
183
185
 
184
186
  return None
185
187
 
@@ -486,7 +488,9 @@ def _generate_path_params(path: str) -> list[Parameters]:
486
488
  )
487
489
  )
488
490
  except Exception as e:
489
- print(f"Error generating path parameters {param_name}: {e}")
491
+ from loguru import logger
492
+
493
+ logger.error(f"Error generating path parameters {param_name}: {e}")
490
494
  raise e
491
495
  return parameters
492
496
 
@@ -919,11 +923,11 @@ def _generate_method_code(path, method, operation):
919
923
 
920
924
  # Combine required and optional arguments FOR DOCSTRING (as before, without types)
921
925
  args = required_args + optional_args
922
- print(f"[DEBUG] Final combined args for DOCSTRING: {args}") # DEBUG
926
+ # from loguru import logger; logger.debug(f"Final combined args for DOCSTRING: {args}") # DEBUG
923
927
 
924
928
  # Combine required and optional arguments FOR SIGNATURE (with types)
925
929
  signature_args_combined_typed = signature_required_args_typed + signature_optional_args_typed
926
- print(f"[DEBUG] Final combined args for SIGNATURE: {signature_args_combined_typed}") # DEBUG
930
+ # from loguru import logger; logger.debug(f"Final combined args for SIGNATURE: {signature_args_combined_typed}") # DEBUG
927
931
 
928
932
  # ----- Build Docstring -----
929
933
  # This section constructs the entire docstring for the generated method,
@@ -1288,7 +1292,11 @@ def generate_api_client(schema, class_name: str | None = None, filter_config_pat
1288
1292
  filter_config = None
1289
1293
  if filter_config_path:
1290
1294
  filter_config = load_filter_config(filter_config_path)
1291
- print(f"Loaded filter configuration from {filter_config_path} with {len(filter_config)} path specifications")
1295
+ from loguru import logger
1296
+
1297
+ logger.info(
1298
+ f"Loaded filter configuration from {filter_config_path} with {len(filter_config)} path specifications"
1299
+ )
1292
1300
 
1293
1301
  methods = []
1294
1302
  method_names = []
@@ -1345,19 +1353,29 @@ def generate_api_client(schema, class_name: str | None = None, filter_config_pat
1345
1353
  if method in ["get", "post", "put", "delete", "patch", "options", "head"]:
1346
1354
  # Apply filter configuration
1347
1355
  if not should_process_operation(path, method, filter_config):
1348
- print(f"Skipping method generation for '{method.upper()} {path}' due to filter configuration.")
1356
+ from loguru import logger
1357
+
1358
+ logger.info(
1359
+ f"Skipping method generation for '{method.upper()} {path}' due to filter configuration."
1360
+ )
1349
1361
  skipped_count += 1
1350
1362
  continue
1351
1363
 
1352
1364
  operation = path_info[method]
1353
- print(f"Generating method for: {method.upper()} {path}")
1365
+ from loguru import logger
1366
+
1367
+ logger.info(f"Generating method for: {method.upper()} {path}")
1354
1368
  method_code, func_name = _generate_method_code(path, method, operation)
1355
1369
  methods.append(method_code)
1356
1370
  method_names.append(func_name)
1357
1371
  processed_count += 1
1358
1372
 
1359
1373
  if filter_config is not None:
1360
- print(f"Selective generation complete: {processed_count} methods generated, {skipped_count} methods skipped.")
1374
+ from loguru import logger
1375
+
1376
+ logger.info(
1377
+ f"Selective generation complete: {processed_count} methods generated, {skipped_count} methods skipped."
1378
+ )
1361
1379
 
1362
1380
  # Generate list_tools method with all the function names
1363
1381
  tools_list = ",\n ".join([f"self.{name}" for name in method_names])
@@ -1453,4 +1471,6 @@ if __name__ == "__main__":
1453
1471
 
1454
1472
  schema = load_schema("openapi.yaml")
1455
1473
  code = generate_api_client(schema)
1456
- print(code)
1474
+ from loguru import logger
1475
+
1476
+ logger.info(code)
@@ -55,26 +55,28 @@ def add_hint_tags_to_docstrings(input_path: str, output_path: str):
55
55
  llm_failures
56
56
 
57
57
  total_functions += 1
58
- print(f"\n[{total_functions}] Processing function: {node.name}")
58
+ from loguru import logger
59
+
60
+ logger.info(f"Processing function: {node.name} ({total_functions})")
59
61
 
60
62
  http_method = self._find_http_method(node)
61
63
  tag_to_add = None
62
64
 
63
65
  if http_method:
64
66
  functions_with_http_methods += 1
65
- print(f" └─ Found HTTP method: {http_method.upper()}")
67
+ logger.debug(f"Found HTTP method: {http_method.upper()}")
66
68
 
67
69
  # Use simple agent to decide tag
68
- print(" └─ Calling LLM to determine tag...")
70
+ logger.debug("Calling LLM to determine tag...")
69
71
  tag_to_add = self._get_tag_suggestion_from_agent(node, http_method)
70
72
 
71
73
  if tag_to_add:
72
74
  functions_processed_by_llm += 1
73
- print(f" └─ LLM suggested tags: {tag_to_add}")
75
+ logger.info(f"LLM suggested tags: {tag_to_add}")
74
76
  else:
75
- print(" └─ LLM failed or returned invalid response")
77
+ logger.warning("LLM failed or returned invalid response")
76
78
  else:
77
- print(" └─ No HTTP method found - skipping")
79
+ logger.debug("No HTTP method found - skipping")
78
80
 
79
81
  if tag_to_add:
80
82
  docstring = ast.get_docstring(node, clean=False)
@@ -98,13 +100,13 @@ def add_hint_tags_to_docstrings(input_path: str, output_path: str):
98
100
  if isinstance(node.body[0], ast.Expr) and isinstance(node.body[0].value, ast.Constant):
99
101
  node.body[0].value.value = new_docstring
100
102
  functions_tagged += 1
101
- print(f" └─ ✅ Tags '{', '.join(tags_to_add)}' added successfully")
103
+ logger.info(f"Tags '{', '.join(tags_to_add)}' added successfully")
102
104
  else:
103
- print(f" └─ ⚠️ All tags '{tag_to_add}' already exist - skipping")
105
+ logger.warning(f"All tags '{tag_to_add}' already exist - skipping")
104
106
  else:
105
- print(" └─ ⚠️ No 'Tags:' section found in docstring - skipping")
107
+ logger.warning("No 'Tags:' section found in docstring - skipping")
106
108
  else:
107
- print(" └─ ⚠️ No docstring found - skipping")
109
+ logger.warning("No docstring found - skipping")
108
110
  return node
109
111
 
110
112
  def _get_tag_suggestion_from_agent(self, node, http_method):
@@ -232,7 +234,9 @@ Your answer (comma-separated tags or 'none'):"""
232
234
  except Exception as e:
233
235
  nonlocal llm_failures
234
236
  llm_failures += 1
235
- print(f" └─ LLM failed for function {function_name}: {e}")
237
+ from loguru import logger
238
+
239
+ logger.error(f"LLM failed for function {function_name}: {e}")
236
240
  # If LLM fails, return None (no tag added)
237
241
  return None
238
242
 
@@ -241,19 +245,18 @@ Your answer (comma-separated tags or 'none'):"""
241
245
  new_source = ast.unparse(new_tree)
242
246
 
243
247
  # Print summary statistics
244
- print(f"\n{'=' * 60}")
245
- print("📊 PROCESSING SUMMARY")
246
- print(f"{'=' * 60}")
247
- print(f"Total functions processed: {total_functions}")
248
- print(f"Functions with HTTP methods: {functions_with_http_methods}")
249
- print(f"Functions processed by LLM: {functions_processed_by_llm}")
250
- print(f"Functions successfully tagged: {functions_tagged}")
251
- print(f"LLM failures: {llm_failures}")
248
+ from loguru import logger
249
+
250
+ logger.info("📊 PROCESSING SUMMARY")
251
+ logger.info(f"Total functions processed: {total_functions}")
252
+ logger.info(f"Functions with HTTP methods: {functions_with_http_methods}")
253
+ logger.info(f"Functions processed by LLM: {functions_processed_by_llm}")
254
+ logger.info(f"Functions successfully tagged: {functions_tagged}")
255
+ logger.info(f"LLM failures: {llm_failures}")
252
256
  if functions_with_http_methods > 0:
253
- print(
257
+ logger.info(
254
258
  f"LLM success rate: {(functions_processed_by_llm / functions_with_http_methods * 100):.1f}% of HTTP functions"
255
259
  )
256
- print(f"{'=' * 60}")
257
260
 
258
261
  # Format with Black in memory
259
262
  try:
@@ -262,14 +265,14 @@ Your answer (comma-separated tags or 'none'):"""
262
265
  formatted_content = black.format_file_contents(new_source, fast=False, mode=black.FileMode())
263
266
  with open(output_path, "w", encoding="utf-8") as f:
264
267
  f.write(formatted_content)
265
- print(f"Black formatting applied successfully to: {output_path}")
268
+ logger.info(f"Black formatting applied successfully to: {output_path}")
266
269
  except ImportError:
267
- print(f"Black not installed. Skipping formatting for: {output_path}")
270
+ logger.warning(f"Black not installed. Skipping formatting for: {output_path}")
268
271
  # Write unformatted version if Black is not available
269
272
  with open(output_path, "w", encoding="utf-8") as f:
270
273
  f.write(new_source)
271
274
  except Exception as e:
272
- print(f"Black formatting failed for {output_path}: {e}")
275
+ logger.error(f"Black formatting failed for {output_path}: {e}")
273
276
  # Write unformatted version if Black formatting fails
274
277
  with open(output_path, "w", encoding="utf-8") as f:
275
278
  f.write(new_source)
@@ -282,6 +282,8 @@ async def test_{app_name}_test_case_{i}({app_name}_test_case_{i}):
282
282
  with open(output_file, "w") as f:
283
283
  f.write(file_content)
284
284
 
285
- print(f"✅ Generated {output_file} with {len(multi_test_case.test_cases)} test cases for {app_name}")
285
+ from loguru import logger
286
+
287
+ logger.info(f"✅ Generated {output_file} with {len(multi_test_case.test_cases)} test cases for {app_name}")
286
288
  for i, test_case in enumerate(multi_test_case.test_cases, 1):
287
- print(f" Test Case {i}: {len(test_case.tools)} tools, {len(test_case.tasks)} tasks")
289
+ logger.info(f" Test Case {i}: {len(test_case.tools)} tools, {len(test_case.tasks)} tasks")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp
3
- Version: 0.1.24rc9
3
+ Version: 0.1.24rc11
4
4
  Summary: Universal MCP acts as a middle ware for your API applications. It can store your credentials, authorize, enable disable apps on the fly and much more.
5
5
  Author-email: Manoj Bajaj <manojbajaj95@gmail.com>
6
6
  License: MIT
@@ -10,24 +10,24 @@ universal_mcp/agentr/README.md,sha256=t15pVgkCwZM5wzgLgrf0Zv6hVL7dPmKXvAeTf8CiXP
10
10
  universal_mcp/agentr/__init__.py,sha256=fv1ZnOCduIUiJ9oN4e6Ya_hA2oWQvcEuDU3Ek1vEufI,180
11
11
  universal_mcp/agentr/client.py,sha256=TQgwrNc7dEMXuprELf0Q-fdYdrH92Ppd7PUDZoD-KcY,7429
12
12
  universal_mcp/agentr/integration.py,sha256=V5GjqocqS02tRoI8MeV9PL6m-BzejwBzgJhOHo4MxAE,4212
13
- universal_mcp/agentr/registry.py,sha256=O60qOsuby1GTkgc9GXVf9BjHmjMTyDbxqbDfIJ13CJ4,6583
13
+ universal_mcp/agentr/registry.py,sha256=GOCltEqVegBca_r-8ljxQqEJnNAlx3MF0DAw-cAUhbQ,6595
14
14
  universal_mcp/agentr/server.py,sha256=bIPmHMiKKwnUYnxmfZVRh1thcn7Rytm_-bNiXTfANzc,2098
15
15
  universal_mcp/agents/__init__.py,sha256=AMBDQs3p5PePjzdoHYNoPYEsUK_PLHGNVPGxK7yrKVo,270
16
- universal_mcp/agents/auto.py,sha256=BknCoeexTbFvwmVzYdGiiH72S_r6_5s9tmjH9M0I4d4,25410
17
- universal_mcp/agents/base.py,sha256=o41gxvwOqWY0IZnupAHfKeH7OG0dgHUQDDpqntsFg6M,4128
16
+ universal_mcp/agents/auto.py,sha256=zQHtWTL0L88j9zFN44xHbGhKzYZ_TEuzHMTVc0TzTRU,25433
17
+ universal_mcp/agents/base.py,sha256=Ta9fOw-ncP4S2j2lXeQzYNPBaWbThcEC_PvJwjzaHzE,5307
18
18
  universal_mcp/agents/cli.py,sha256=7GdRBpu9rhZPiC2vaNQXWI7K-0yCnvdlmE0IFpvy2Gk,539
19
19
  universal_mcp/agents/hil.py,sha256=6xi0hhK5g-rhCrAMcGbjcKMReLWPC8rnFZMBOF3N_cY,3687
20
- universal_mcp/agents/llm.py,sha256=jollWOAUv15IouzbLpuqKzbjj2x2ioZUukSQNyNjb4Y,1382
21
- universal_mcp/agents/react.py,sha256=g2PwqxYe7v7wCMDCCQhTtGU1eFmSsF4g7T_t9d-v0ho,3012
20
+ universal_mcp/agents/llm.py,sha256=GncfbrM7FbMQJ305jCq78PVN4Jh4hOBskLcdgBd69sY,1419
21
+ universal_mcp/agents/react.py,sha256=bjTq1SzNUSeCCDMrrfXsUBu_F_mGzow_jRx5KrQ-HVg,3032
22
22
  universal_mcp/agents/simple.py,sha256=JL8TFyXlA1F4zcArgKhlqVIbLWXetwM05z4MPDJgFeI,1367
23
23
  universal_mcp/agents/tools.py,sha256=7Vdw0VZYxXVAzAYSpRKWHzVl9Ll6NOnVRlc4cTXguUQ,1335
24
24
  universal_mcp/agents/utils.py,sha256=7kwFpD0Rv6JqHG-LlNCVwSu_xRX-N119mUmiBroHJL4,4109
25
25
  universal_mcp/agents/autoagent/__init__.py,sha256=E_vMnFz8Z120qdqaKXPNP_--4Tes4jImen7m_iZvtVo,913
26
- universal_mcp/agents/autoagent/__main__.py,sha256=ps0cT7b9DN-jQK8pOKFVRZf3Oz_dVSBSYWOa8sc7VNc,647
26
+ universal_mcp/agents/autoagent/__main__.py,sha256=cnR5VuuTgcF4bE2XdpJGXVQtA7x_c5M1d-exAff4Mvw,651
27
27
  universal_mcp/agents/autoagent/context.py,sha256=RgjW1uCslucxYJpdmi4govd-0V1_9e6Y_kjWl3FpLrE,847
28
- universal_mcp/agents/autoagent/graph.py,sha256=0vjJD_FIwaAijAnqyvZ5BtfTvLKB3xwPqej16e-D-kE,7250
28
+ universal_mcp/agents/autoagent/graph.py,sha256=IWJLV3PL-0dmPvDckrtjJkgO6Zgt47kRk8Yprnn52dY,6768
29
29
  universal_mcp/agents/autoagent/prompts.py,sha256=ptnXyOarigq96nVW-P1ceT2WRilKvh7NPfE_Cy0NTz4,719
30
- universal_mcp/agents/autoagent/state.py,sha256=pTKbgTK8TTx7qIioVt98u9KZpeWacWaRmKJWRv3Jj40,791
30
+ universal_mcp/agents/autoagent/state.py,sha256=TQeGZD99okclkoCh5oz-VYIlEsC9yLQyDpnBnm7QCN8,759
31
31
  universal_mcp/agents/autoagent/studio.py,sha256=nfVRzPXwBjDORHA0wln2k3Nz-zQXNKgZMvgeqBvkdtM,644
32
32
  universal_mcp/agents/autoagent/utils.py,sha256=AFq-8scw_WlSZxDnTzxSNrOSiGYsIlqkqtQLDWf_rMU,431
33
33
  universal_mcp/agents/codeact/__init__.py,sha256=5D_I3lI_3tWjZERRoFav_bPe9UDaJ53pDzZYtyixg3E,10097
@@ -39,7 +39,7 @@ universal_mcp/applications/application.py,sha256=pGF9Rb2D6qzlaSwlcfZ-dNqPtsLkQTq
39
39
  universal_mcp/applications/sample/app.py,sha256=E0JwaWD7qytwawb_iWc1pBnJ-Te7MMtab4MxOOebLdc,8972
40
40
  universal_mcp/client/oauth.py,sha256=O00zOUfQxINaruFU2zt-64DIR1_mAqrY8ykLQo-teJU,8679
41
41
  universal_mcp/client/token_store.py,sha256=6VAzjzJG49wYvmEDqksFvb-fVqdjHIKWv7yYyh_AuF8,3912
42
- universal_mcp/client/transport.py,sha256=xgAKBJ1-yCcTtl9cxzJgRn6to5Y9EvCwLc_WpDck3Dg,11838
42
+ universal_mcp/client/transport.py,sha256=qqtb0ky6yvLBxsaA9-oFU0v9MwfcQb4eomq-O2fmwtQ,11850
43
43
  universal_mcp/integrations/__init__.py,sha256=tfzLyPEPly5tfIcT8K6-oKCr_MEFGxOROHy_NeVy0KM,200
44
44
  universal_mcp/integrations/integration.py,sha256=H-hOoDHqk78A4Fi_TGN7OOFS7PDfqXK_nedH8iSz-6A,16459
45
45
  universal_mcp/servers/__init__.py,sha256=speBb_E94UJa4A6Fv8RHFeoJ7cR-q2bCMtKV7R21P5w,142
@@ -50,7 +50,7 @@ universal_mcp/tools/__init__.py,sha256=jC8hsqfTdtn32yU57AVFUXiU3ZmUOCfCERSCaNEIH
50
50
  universal_mcp/tools/adapters.py,sha256=YJ2oqgc8JgmtsdRRtvO-PO0Q0bKqTJ4Y3J6yxlESoTo,3947
51
51
  universal_mcp/tools/docstring_parser.py,sha256=efEOE-ME7G5Jbbzpn7pN2xNuyu2M5zfZ1Tqu1lRB0Gk,8392
52
52
  universal_mcp/tools/func_metadata.py,sha256=F4jd--hoZWKPBbZihVtluYKUsIdXdq4a0VWRgMl5k-Q,10838
53
- universal_mcp/tools/manager.py,sha256=24Rkn5Uvv_AuYAtjeMq986bJ7uzTaGE1290uB9eDtRE,10435
53
+ universal_mcp/tools/manager.py,sha256=U2-OQY4FGTDKS4IEOZTLVLcdqMC2vVghS0p_iLXX2Gc,10507
54
54
  universal_mcp/tools/registry.py,sha256=etluwUwf2EfiGBoqQFZ1nf2xcPWtrJn0N4Qhcg7UGCU,2440
55
55
  universal_mcp/tools/tools.py,sha256=Lk-wUO3rfhwdxaRANtC7lQr5fXi7nclf0oHzxNAb79Q,4927
56
56
  universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
@@ -60,20 +60,20 @@ universal_mcp/utils/prompts.py,sha256=FJhqE0gPXDzYHS8gOjAVrdqVxc9X12ESnpd4C3jDSM
60
60
  universal_mcp/utils/singleton.py,sha256=RoOiKxBOAhp0TK1QaMDYi-8GjRcy2Vh-bAOuIAcYan0,775
61
61
  universal_mcp/utils/testing.py,sha256=J857Xt5K-hMxTc8UNJWlkzLbca1zObjwNhNXzYGxBHI,8009
62
62
  universal_mcp/utils/openapi/__inti__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
- universal_mcp/utils/openapi/api_generator.py,sha256=892AWoOCzzvFHVfSpEBg1m4LFRnWMmOSeY0DgLDW0fU,6960
63
+ universal_mcp/utils/openapi/api_generator.py,sha256=sygUE8Sropq3Pz09N1kSwGelgnTCAz_lOGspTaYCWEs,6985
64
64
  universal_mcp/utils/openapi/api_splitter.py,sha256=io7fV-E8hUIR4NxFlakqydbgrQF6aBAnZHPMlpxw-wc,20967
65
65
  universal_mcp/utils/openapi/cli.py,sha256=az5ObS74R-MmDCOZ1PHTJVKZJrHnsBOAweOUa7A-GqA,25918
66
66
  universal_mcp/utils/openapi/docgen.py,sha256=DNmwlhg_-TRrHa74epyErMTRjV2nutfCQ7seb_Rq5hE,21366
67
67
  universal_mcp/utils/openapi/filters.py,sha256=96FajO5nLbvjNPy2A1HvSS9jqpzMDHd4q_QTP-DIsPI,3842
68
- universal_mcp/utils/openapi/openapi.py,sha256=0Pn_ugkEwL0eMtctjc0XDMPZdB3SBOqza_J6BK8i_SY,62165
69
- universal_mcp/utils/openapi/postprocessor.py,sha256=NKvpXi73INRXxj1KOu8Ph3loWGICx2Uyy2Q8uOOqBoc,12177
68
+ universal_mcp/utils/openapi/openapi.py,sha256=mcmahLJrR-CS-r2RDaYOgMV1Eq7ZuCHMk7_Qrijadh4,62613
69
+ universal_mcp/utils/openapi/postprocessor.py,sha256=j_OZ5u2VCb44rfvnJZdKcxQRyGgrEVMr8ue9oN0Ed7A,12235
70
70
  universal_mcp/utils/openapi/preprocessor.py,sha256=r4n0WQI__OzPL8FTza7jxiM4EYeZwa-3tvEJaJYZC44,63081
71
71
  universal_mcp/utils/openapi/readme.py,sha256=R2Jp7DUXYNsXPDV6eFTkLiy7MXbSULUj1vHh4O_nB4c,2974
72
- universal_mcp/utils/openapi/test_generator.py,sha256=h44gQXEXmrw4pD3-XNHKB7T9c2lDomqrJxVO6oszCqM,12186
72
+ universal_mcp/utils/openapi/test_generator.py,sha256=vucBh9klWmQOUA740TFwfM9ry2nkwKWQiNRcsiZ9HbY,12229
73
73
  universal_mcp/utils/templates/README.md.j2,sha256=Mrm181YX-o_-WEfKs01Bi2RJy43rBiq2j6fTtbWgbTA,401
74
74
  universal_mcp/utils/templates/api_client.py.j2,sha256=972Im7LNUAq3yZTfwDcgivnb-b8u6_JLKWXwoIwXXXQ,908
75
- universal_mcp-0.1.24rc9.dist-info/METADATA,sha256=8fuQP2tvQjMrU4RrHqhSEdQmN1YyesKjz_9aJ4r-l1w,3143
76
- universal_mcp-0.1.24rc9.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
77
- universal_mcp-0.1.24rc9.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
78
- universal_mcp-0.1.24rc9.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
79
- universal_mcp-0.1.24rc9.dist-info/RECORD,,
75
+ universal_mcp-0.1.24rc11.dist-info/METADATA,sha256=wptNoLSs4TFv7_nDGfXDIHpQSuFcNCcAMx_dRNUWra0,3144
76
+ universal_mcp-0.1.24rc11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
77
+ universal_mcp-0.1.24rc11.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
78
+ universal_mcp-0.1.24rc11.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
79
+ universal_mcp-0.1.24rc11.dist-info/RECORD,,