universal-mcp 0.1.23rc2__py3-none-any.whl → 0.1.24rc3__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.
Files changed (69) hide show
  1. universal_mcp/agentr/__init__.py +6 -0
  2. universal_mcp/agentr/agentr.py +30 -0
  3. universal_mcp/{utils/agentr.py → agentr/client.py} +22 -7
  4. universal_mcp/agentr/integration.py +104 -0
  5. universal_mcp/agentr/registry.py +91 -0
  6. universal_mcp/agentr/server.py +51 -0
  7. universal_mcp/agents/__init__.py +6 -0
  8. universal_mcp/agents/auto.py +576 -0
  9. universal_mcp/agents/base.py +88 -0
  10. universal_mcp/agents/cli.py +27 -0
  11. universal_mcp/agents/codeact/__init__.py +243 -0
  12. universal_mcp/agents/codeact/sandbox.py +27 -0
  13. universal_mcp/agents/codeact/test.py +15 -0
  14. universal_mcp/agents/codeact/utils.py +61 -0
  15. universal_mcp/agents/hil.py +104 -0
  16. universal_mcp/agents/llm.py +10 -0
  17. universal_mcp/agents/react.py +58 -0
  18. universal_mcp/agents/simple.py +40 -0
  19. universal_mcp/agents/utils.py +111 -0
  20. universal_mcp/analytics.py +44 -14
  21. universal_mcp/applications/__init__.py +42 -75
  22. universal_mcp/applications/application.py +187 -133
  23. universal_mcp/applications/sample/app.py +245 -0
  24. universal_mcp/cli.py +14 -231
  25. universal_mcp/client/oauth.py +122 -18
  26. universal_mcp/client/token_store.py +62 -3
  27. universal_mcp/client/{client.py → transport.py} +127 -48
  28. universal_mcp/config.py +189 -49
  29. universal_mcp/exceptions.py +54 -6
  30. universal_mcp/integrations/__init__.py +0 -18
  31. universal_mcp/integrations/integration.py +185 -168
  32. universal_mcp/servers/__init__.py +2 -14
  33. universal_mcp/servers/server.py +84 -258
  34. universal_mcp/stores/store.py +126 -93
  35. universal_mcp/tools/__init__.py +3 -0
  36. universal_mcp/tools/adapters.py +20 -11
  37. universal_mcp/tools/func_metadata.py +1 -1
  38. universal_mcp/tools/manager.py +38 -53
  39. universal_mcp/tools/registry.py +41 -0
  40. universal_mcp/tools/tools.py +24 -3
  41. universal_mcp/types.py +10 -0
  42. universal_mcp/utils/common.py +245 -0
  43. universal_mcp/utils/installation.py +3 -4
  44. universal_mcp/utils/openapi/api_generator.py +71 -17
  45. universal_mcp/utils/openapi/api_splitter.py +0 -1
  46. universal_mcp/utils/openapi/cli.py +669 -0
  47. universal_mcp/utils/openapi/filters.py +114 -0
  48. universal_mcp/utils/openapi/openapi.py +315 -23
  49. universal_mcp/utils/openapi/postprocessor.py +275 -0
  50. universal_mcp/utils/openapi/preprocessor.py +63 -8
  51. universal_mcp/utils/openapi/test_generator.py +287 -0
  52. universal_mcp/utils/prompts.py +634 -0
  53. universal_mcp/utils/singleton.py +4 -1
  54. universal_mcp/utils/testing.py +196 -8
  55. universal_mcp-0.1.24rc3.dist-info/METADATA +68 -0
  56. universal_mcp-0.1.24rc3.dist-info/RECORD +70 -0
  57. universal_mcp/applications/README.md +0 -122
  58. universal_mcp/client/__main__.py +0 -30
  59. universal_mcp/client/agent.py +0 -96
  60. universal_mcp/integrations/README.md +0 -25
  61. universal_mcp/servers/README.md +0 -79
  62. universal_mcp/stores/README.md +0 -74
  63. universal_mcp/tools/README.md +0 -86
  64. universal_mcp-0.1.23rc2.dist-info/METADATA +0 -283
  65. universal_mcp-0.1.23rc2.dist-info/RECORD +0 -51
  66. /universal_mcp/{utils → tools}/docstring_parser.py +0 -0
  67. {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc3.dist-info}/WHEEL +0 -0
  68. {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc3.dist-info}/entry_points.txt +0 -0
  69. {universal_mcp-0.1.23rc2.dist-info → universal_mcp-0.1.24rc3.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,7 @@ from pathlib import Path
6
6
 
7
7
  from loguru import logger
8
8
 
9
- from universal_mcp.utils.openapi.openapi import generate_api_client, load_schema
9
+ from universal_mcp.utils.openapi.openapi import generate_api_client, generate_schemas_file, load_schema
10
10
 
11
11
 
12
12
  def echo(message: str, err: bool = False) -> None:
@@ -55,21 +55,43 @@ def test_correct_output(gen_file: Path):
55
55
  return True
56
56
 
57
57
 
58
+ def format_with_black(file_path: Path) -> bool:
59
+ """Format the given Python file with Black. Returns True if successful, False otherwise."""
60
+ try:
61
+ import black
62
+
63
+ content = file_path.read_text(encoding="utf-8")
64
+
65
+ formatted_content = black.format_file_contents(content, fast=False, mode=black.FileMode())
66
+
67
+ file_path.write_text(formatted_content, encoding="utf-8")
68
+
69
+ logger.info("Black formatting applied successfully to: %s", file_path)
70
+ return True
71
+ except ImportError:
72
+ logger.warning("Black not installed. Skipping formatting for: %s", file_path)
73
+ return False
74
+ except Exception as e:
75
+ logger.warning("Black formatting failed for %s: %s", file_path, e)
76
+ return False
77
+
78
+
58
79
  def generate_api_from_schema(
59
80
  schema_path: Path,
60
81
  output_path: Path | None = None,
61
82
  class_name: str | None = None,
62
- ) -> tuple[Path, Path]:
83
+ filter_config_path: str | None = None,
84
+ ) -> tuple[Path, Path] | dict:
63
85
  """
64
- Generate API client from OpenAPI schema and write to app.py with a README.
86
+ Generate API client from OpenAPI schema and write to app.py and schemas.py.
65
87
 
66
88
  Steps:
67
89
  1. Parse and validate the OpenAPI schema.
68
- 2. Generate client code.
90
+ 2. Generate client code and schemas.
69
91
  3. Ensure output directory exists.
70
- 4. Write code to an intermediate app_generated.py and perform basic import checks.
71
- 5. Copy/overwrite intermediate file to app.py.
72
- 6. Collect tools and generate README.md.
92
+ 4. Write code to intermediate files and perform basic import checks.
93
+ 5. Copy/overwrite intermediate files to app.py and schemas.py.
94
+ 6. Format the final files with Black.
73
95
  """
74
96
  # Local imports for logging and file operations
75
97
 
@@ -83,10 +105,13 @@ def generate_api_from_schema(
83
105
  logger.error("Failed to load or validate schema: %s", e)
84
106
  raise
85
107
 
86
- # 2. Generate client code
108
+ # 2. Generate client code and schemas
87
109
  try:
88
- code = generate_api_client(schema, class_name)
110
+ code = generate_api_client(schema, class_name, filter_config_path)
89
111
  logger.info("API client code generated.")
112
+
113
+ schemas_code = generate_schemas_file(schema, class_name, filter_config_path)
114
+ logger.info("Schemas code generated.")
90
115
  except Exception as e:
91
116
  logger.error("Code generation failed: %s", e)
92
117
  raise
@@ -94,7 +119,7 @@ def generate_api_from_schema(
94
119
  # If no output_path provided, return raw code
95
120
  if not output_path:
96
121
  logger.debug("No output_path provided, returning code as string.")
97
- return {"code": code}
122
+ return {"code": code, "schemas_code": schemas_code}
98
123
 
99
124
  # 3. Ensure output directory exists
100
125
  target_dir = output_path
@@ -102,25 +127,37 @@ def generate_api_from_schema(
102
127
  logger.info("Creating output directory: %s", target_dir)
103
128
  target_dir.mkdir(parents=True, exist_ok=True)
104
129
 
105
- # 4. Write to intermediate file and perform basic checks
130
+ # 4. Write to intermediate files and perform basic checks
106
131
  gen_file = target_dir / "app_generated.py"
132
+ schemas_gen_file = target_dir / "schemas_generated.py"
133
+
107
134
  logger.info("Writing generated code to intermediate file: %s", gen_file)
108
135
  with open(gen_file, "w") as f:
109
136
  f.write(code)
110
137
 
111
- if not test_correct_output(gen_file):
112
- logger.error("Generated code validation failed for '%s'. Aborting generation.", gen_file)
138
+ logger.info("Writing schemas code to intermediate file: %s", schemas_gen_file)
139
+ with open(schemas_gen_file, "w") as f:
140
+ f.write(schemas_code)
141
+
142
+ # Test schemas file first (no relative imports)
143
+ if not test_correct_output(schemas_gen_file):
144
+ logger.error("Generated schemas validation failed for '%s'. Aborting generation.", schemas_gen_file)
113
145
  logger.info("Next steps:")
114
146
  logger.info(" 1) Review your OpenAPI schema for potential mismatches.")
115
147
  logger.info(
116
148
  " 2) Inspect '%s' for syntax or logic errors in the generated code.",
117
- gen_file,
149
+ schemas_gen_file,
118
150
  )
119
151
  logger.info(" 3) Correct the issues and re-run the command.")
120
152
  return {"error": "Validation failed. See logs above for detailed instructions."}
121
153
 
122
- # 5. Copy to final app.py (overwrite if exists)
154
+ # Skip testing app file since it has relative imports - just do a basic syntax check
155
+ logger.info("Skipping detailed validation for app file due to relative imports.")
156
+
157
+ # 5. Copy to final files (overwrite if exists)
123
158
  app_file = target_dir / "app.py"
159
+ schemas_file = target_dir / "schemas.py"
160
+
124
161
  if app_file.exists():
125
162
  logger.warning("Overwriting existing file: %s", app_file)
126
163
  else:
@@ -128,11 +165,28 @@ def generate_api_from_schema(
128
165
  shutil.copy(gen_file, app_file)
129
166
  logger.info("App file written to: %s", app_file)
130
167
 
131
- # Cleanup intermediate file
168
+ if schemas_file.exists():
169
+ logger.warning("Overwriting existing file: %s", schemas_file)
170
+ else:
171
+ logger.info("Creating new file: %s", schemas_file)
172
+ shutil.copy(schemas_gen_file, schemas_file)
173
+ logger.info("Schemas file written to: %s", schemas_file)
174
+
175
+ # 6. Format the final files with Black
176
+ format_with_black(app_file)
177
+ format_with_black(schemas_file)
178
+
179
+ # Cleanup intermediate files
132
180
  try:
133
181
  os.remove(gen_file)
134
182
  logger.debug("Cleaned up intermediate file: %s", gen_file)
135
183
  except Exception as e:
136
184
  logger.warning("Could not remove intermediate file %s: %s", gen_file, e)
137
185
 
138
- return app_file
186
+ try:
187
+ os.remove(schemas_gen_file)
188
+ logger.debug("Cleaned up intermediate schemas file: %s", schemas_gen_file)
189
+ except Exception as e:
190
+ logger.warning("Could not remove intermediate schemas file %s: %s", schemas_gen_file, e)
191
+
192
+ return app_file, schemas_file
@@ -155,7 +155,6 @@ class MethodTransformer(ast.NodeTransformer):
155
155
 
156
156
 
157
157
  def split_generated_app_file(input_app_file: Path, output_dir: Path, package_name: str = None):
158
-
159
158
  content = input_app_file.read_text()
160
159
  tree = ast.parse(content)
161
160