universal-mcp 0.1.20rc2__py3-none-any.whl → 0.1.22rc1__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.
@@ -225,10 +225,17 @@ def generate_description_llm(
225
225
  if len(param_context_str) > 1000: # Limit context size
226
226
  param_context_str = param_context_str[:1000] + "..."
227
227
 
228
- user_prompt = f"""Generate a clear, brief description for the API parameter named "{param_name}" located "{param_in}" for the "{method.upper()}" operation at path "{path_key}".
229
- Context (parameter details): {param_context_str}
230
- Respond ONLY with the *SINGLE LINE* description text."""
231
- fallback_text = f"[LLM could not generate description for parameter {param_name} in {method.upper()} {path_key}]" # More specific fallback
228
+ current_description = context.get("current_description", None)
229
+ if current_description and isinstance(current_description, str) and current_description.strip():
230
+ user_prompt = f"""The current description for the API parameter named '{param_name}' located '{param_in}' for the '{method.upper()}' operation at path '{path_key}' is:\n'{current_description.strip()}'\n\nTask: Rewrite and enrich this description so it is clear, self-contained, and makes sense to a user. If the description is cut off, incomplete, or awkward, make it complete and natural. Ensure it is concise and under {MAX_DESCRIPTION_LENGTH} characters. Do not include any links, HTML, markdown, or any notes or comments about the character limit. Respond ONLY with the improved single-line description."""
231
+ fallback_text = (
232
+ f"[LLM could not generate description for parameter {param_name} in {method.upper()} {path_key}]"
233
+ )
234
+ else:
235
+ user_prompt = f"""Generate a clear, brief description for the API parameter named "{param_name}" located "{param_in}" for the "{method.upper()}" operation at path "{path_key}".\nContext (parameter details): {param_context_str}\nRespond ONLY with the *SINGLE LINE* description text."""
236
+ fallback_text = (
237
+ f"[LLM could not generate description for parameter {param_name} in {method.upper()} {path_key}]"
238
+ )
232
239
 
233
240
  elif description_type == "api_description":
234
241
  api_title = context.get("title", "Untitled API")
@@ -236,6 +243,24 @@ def generate_description_llm(
236
243
  Respond ONLY with the description text."""
237
244
  fallback_text = f"[LLM could not generate description for API '{api_title}']" # More specific fallback
238
245
 
246
+ elif description_type == "operation_id":
247
+ path_key = context.get("path_key", "unknown path")
248
+ method = context.get("method", "unknown method")
249
+ operation_context_str = json.dumps(
250
+ context.get("operation_value", {}),
251
+ indent=None,
252
+ separators=(",", ":"),
253
+ sort_keys=True,
254
+ )
255
+ if len(operation_context_str) > 500:
256
+ operation_context_str = operation_context_str[:500] + "..."
257
+ user_prompt = f"""Generate a short, unique, and readable operationId for the OpenAPI operation at path '{path_key}' using the '{method.upper()}' method.\n- The operationId MUST be a single word in camelCase or snake_case.\n- It MUST NOT exceed 30 characters.\n- It should be descriptive of the action and resource, e.g., 'getUser', 'createOrder', 'listInvoices', 'deleteUserById'.\n- Do NOT include spaces or special characters.\n- Respond ONLY with the operationId string, with NO explanation, NO notes, NO formatting, NO markdown, and NO extra text.\nContext (operation details): {operation_context_str}"""
258
+ fallback_text = f"[LLM could not generate operationId for {method.upper()} {path_key}]"
259
+ logger.info("\n--- LLM OperationId Generation Prompt ---")
260
+ logger.info(f"System prompt:\n{system_prompt}")
261
+ logger.info(f"User prompt:\n{user_prompt}")
262
+ logger.info("--- End LLM OperationId Prompt ---\n")
263
+
239
264
  else:
240
265
  logger.error(f"Invalid description_type '{description_type}' passed to generate_description_llm.")
241
266
  return "[Invalid description type specified]"
@@ -244,6 +269,10 @@ def generate_description_llm(
244
269
  logger.error(f"User prompt was not generated for description_type '{description_type}'.")
245
270
  return fallback_text
246
271
 
272
+ # If user_prompt_override is provided in context, use it
273
+ if context and "user_prompt_override" in context:
274
+ user_prompt = context["user_prompt_override"]
275
+
247
276
  messages = [
248
277
  {"role": "system", "content": system_prompt},
249
278
  {"role": "user", "content": user_prompt},
@@ -716,6 +745,7 @@ def process_parameter(
716
745
 
717
746
  simplified_context = simplify_parameter_context(parameter)
718
747
 
748
+ current_description = parameter.get("description", "")
719
749
  generated_description = generate_description_llm(
720
750
  description_type="parameter",
721
751
  model=llm_model,
@@ -725,6 +755,7 @@ def process_parameter(
725
755
  "param_name": param_name,
726
756
  "param_in": param_in,
727
757
  "parameter_details": simplified_context,
758
+ "current_description": current_description,
728
759
  },
729
760
  )
730
761
  parameter["description"] = generated_description
@@ -764,6 +795,8 @@ def process_operation(
764
795
  method: str,
765
796
  llm_model: str,
766
797
  enhance_all: bool, # New flag
798
+ summaries_only: bool = False,
799
+ operation_ids_only: bool = False,
767
800
  ):
768
801
  operation_location_base = f"paths.{path_key}.{method.lower()}"
769
802
 
@@ -775,6 +808,26 @@ def process_operation(
775
808
  logger.debug(f"Skipping extension operation '{operation_location_base}'.")
776
809
  return
777
810
 
811
+ # --- Ensure operationId is present, using LLM if missing, but only if not summaries_only ---
812
+ if (operation_ids_only or not summaries_only) and (
813
+ "operationId" not in operation_value or not operation_value["operationId"]
814
+ ):
815
+ simplified_context = simplify_operation_context(operation_value)
816
+ generated_operation_id = generate_description_llm(
817
+ description_type="operation_id",
818
+ model=llm_model,
819
+ context={
820
+ "path_key": path_key,
821
+ "method": method,
822
+ "operation_value": simplified_context,
823
+ },
824
+ )
825
+ operation_value["operationId"] = sanitize_operation_id(generated_operation_id)
826
+ logger.info(f"Added operationId '{operation_value['operationId']}' to '{operation_location_base}'.")
827
+
828
+ if operation_ids_only:
829
+ return
830
+
778
831
  # --- Process Summary ---
779
832
  operation_summary = operation_value.get("summary")
780
833
 
@@ -814,24 +867,27 @@ def process_operation(
814
867
  )
815
868
 
816
869
  # --- Process Parameters ---
817
- parameters = operation_value.get("parameters")
818
- if isinstance(parameters, list):
819
- for _i, parameter in enumerate(parameters):
820
- process_parameter(
821
- parameter,
822
- operation_location_base,
823
- path_key,
824
- method,
825
- llm_model,
826
- enhance_all, # Pass enhance_all
870
+ if not summaries_only:
871
+ parameters = operation_value.get("parameters")
872
+ if isinstance(parameters, list):
873
+ for _i, parameter in enumerate(parameters):
874
+ process_parameter(
875
+ parameter,
876
+ operation_location_base,
877
+ path_key,
878
+ method,
879
+ llm_model,
880
+ enhance_all,
881
+ )
882
+ elif parameters is not None:
883
+ logger.warning(
884
+ f"'parameters' field for operation '{operation_location_base}' is not a list. Skipping parameter processing."
827
885
  )
828
- elif parameters is not None:
829
- logger.warning(
830
- f"'parameters' field for operation '{operation_location_base}' is not a list. Skipping parameter processing."
831
- )
832
886
 
833
887
 
834
- def process_paths(paths: dict, llm_model: str, enhance_all: bool): # New flag
888
+ def process_paths(
889
+ paths: dict, llm_model: str, enhance_all: bool, summaries_only: bool = False, operation_ids_only: bool = False
890
+ ):
835
891
  if not isinstance(paths, dict):
836
892
  logger.warning("'paths' field is not a dictionary. Skipping path processing.")
837
893
  return
@@ -853,7 +909,9 @@ def process_paths(paths: dict, llm_model: str, enhance_all: bool): # New flag
853
909
  "patch",
854
910
  "trace",
855
911
  ]:
856
- process_operation(operation_value, path_key, method, llm_model, enhance_all) # Pass enhance_all
912
+ process_operation(
913
+ operation_value, path_key, method, llm_model, enhance_all, summaries_only, operation_ids_only
914
+ )
857
915
  elif method.lower().startswith("x-"):
858
916
  logger.debug(f"Skipping processing of method extension '{method.lower()}' in path '{path_key}'.")
859
917
  continue
@@ -916,18 +974,89 @@ def process_info_section(schema_data: dict, llm_model: str, enhance_all: bool):
916
974
  )
917
975
 
918
976
 
919
- def preprocess_schema_with_llm(schema_data: dict, llm_model: str, enhance_all: bool): # New flag
977
+ def find_duplicate_operation_ids(schema_data: dict) -> dict:
978
+ """Returns a dict mapping duplicate operationIds to a list of (path, method) tuples where they occur."""
979
+ operation_id_map = {}
980
+ paths = schema_data.get("paths", {})
981
+ for path_key, path_value in paths.items():
982
+ if not isinstance(path_value, dict):
983
+ continue
984
+ for method, operation_value in path_value.items():
985
+ if method.lower() not in ["get", "put", "post", "delete", "options", "head", "patch", "trace"]:
986
+ continue
987
+ if not isinstance(operation_value, dict):
988
+ continue
989
+ op_id = operation_value.get("operationId")
990
+ if op_id:
991
+ operation_id_map.setdefault(op_id, []).append((path_key, method))
992
+ # Only keep duplicates
993
+ return {k: v for k, v in operation_id_map.items() if len(v) > 1}
994
+
995
+
996
+ def regenerate_duplicate_operation_ids(schema_data: dict, llm_model: str):
997
+ """For each duplicate operationId, re-run the LLM to generate a new one, providing used operationIds to avoid."""
998
+ used_operation_ids = set()
999
+ paths = schema_data.get("paths", {})
1000
+ # First, collect all unique operationIds
1001
+ for _path_key, path_value in paths.items():
1002
+ if not isinstance(path_value, dict):
1003
+ continue
1004
+ for method, operation_value in path_value.items():
1005
+ if method.lower() not in ["get", "put", "post", "delete", "options", "head", "patch", "trace"]:
1006
+ continue
1007
+ if not isinstance(operation_value, dict):
1008
+ continue
1009
+ op_id = operation_value.get("operationId")
1010
+ if op_id:
1011
+ used_operation_ids.add(op_id)
1012
+ # Now, find and fix duplicates
1013
+ duplicates = find_duplicate_operation_ids(schema_data)
1014
+ for _op_id, occurrences in duplicates.items():
1015
+ # Keep the first occurrence, fix the rest
1016
+ for _path_key, method in occurrences[1:]:
1017
+ operation_value = paths[_path_key][method]
1018
+ simplified_context = simplify_operation_context(operation_value)
1019
+ # Prompt LLM with used_operation_ids to avoid
1020
+ avoid_list = list(used_operation_ids)
1021
+ user_prompt = f"Generate a short, unique, and readable operationId for the OpenAPI operation at path '{_path_key}' using the '{method.upper()}' method.\n- The operationId MUST be a single word in camelCase or snake_case.\n- It MUST NOT exceed 30 characters.\n- It should be descriptive of the action and resource, e.g., 'getUser', 'createOrder', 'listInvoices', 'deleteUserById'.\n- Do NOT include spaces or special characters.\n- Respond ONLY with the operationId string, with NO explanation, NO notes, NO formatting, NO markdown, and NO extra text.\n- Avoid these operationIds: {avoid_list}\nContext (operation details): {json.dumps(simplified_context, separators=(',', ':'), sort_keys=True)[:500]}"
1022
+ # Use the same LLM call as before, but override the user_prompt
1023
+ generated_operation_id = generate_description_llm(
1024
+ description_type="operation_id",
1025
+ model=llm_model,
1026
+ context={
1027
+ "path_key": _path_key,
1028
+ "method": method,
1029
+ "operation_value": simplified_context,
1030
+ "user_prompt_override": user_prompt,
1031
+ },
1032
+ )
1033
+ operation_value["operationId"] = sanitize_operation_id(generated_operation_id)
1034
+ used_operation_ids.add(operation_value["operationId"])
1035
+ logger.info(f"Regenerated duplicate operationId for {_path_key} {method}: {operation_value['operationId']}")
1036
+
1037
+
1038
+ def preprocess_schema_with_llm(
1039
+ schema_data: dict, llm_model: str, enhance_all: bool, summaries_only: bool = False, operation_ids_only: bool = False
1040
+ ):
920
1041
  """
921
1042
  Processes the schema to add/enhance descriptions/summaries using an LLM.
922
1043
  Decides whether to generate based on the 'enhance_all' flag and existing content.
1044
+ If summaries_only is True, only operation summaries (and info.description) are enriched.
1045
+ If operation_ids_only is True, only missing operationIds are generated (never overwritten).
923
1046
  Assumes basic schema structure validation (info, title) has already passed.
924
1047
  """
925
- logger.info(f"\n--- Starting LLM Generation (enhance_all={enhance_all}) ---")
1048
+ logger.info(
1049
+ f"\n--- Starting LLM Generation (enhance_all={enhance_all}, summaries_only={summaries_only}, operation_ids_only={operation_ids_only}) ---"
1050
+ )
926
1051
 
927
- process_info_section(schema_data, llm_model, enhance_all)
1052
+ # Only process info section if not operation_ids_only
1053
+ if not operation_ids_only:
1054
+ process_info_section(schema_data, llm_model, enhance_all)
928
1055
 
929
1056
  paths = schema_data.get("paths")
930
- process_paths(paths, llm_model, enhance_all)
1057
+ process_paths(paths, llm_model, enhance_all, summaries_only, operation_ids_only)
1058
+
1059
+ # After process_paths, regenerate_duplicate_operation_ids(schema_data, llm_model)
931
1060
 
932
1061
  logger.info("--- LLM Generation Complete ---")
933
1062
 
@@ -1007,8 +1136,11 @@ def run_preprocessing(
1007
1136
  " [1] Generate [bold]only missing[/bold] descriptions/summaries [green](default)[/green]",
1008
1137
  " [2] Generate/Enhance [bold]all[/bold] descriptions/summaries",
1009
1138
  " [3] [bold red]Quit[/bold red] (exit without changes)",
1139
+ " [4] Generate/Enhance [bold]only operation summaries[/bold]",
1140
+ " [5] Generate [bold]only missing operationIds[/bold]",
1141
+ " [6] [bold]Enrich only parameter descriptions (LLM, ≤250 chars, run after clean-up)[/bold]",
1010
1142
  ]
1011
- valid_choices = ["1", "2", "3"]
1143
+ valid_choices = ["1", "2", "3", "4", "5", "6"]
1012
1144
  default_choice = "1" # Default to filling missing
1013
1145
 
1014
1146
  else: # total_missing_or_fallback == 0
@@ -1027,8 +1159,11 @@ def run_preprocessing(
1027
1159
  prompt_options = [
1028
1160
  " [2] Generate/Enhance [bold]all[/bold] descriptions/summaries",
1029
1161
  " [3] [bold red]Quit[/bold red] [green](default)[/green]",
1162
+ " [4] Generate/Enhance [bold]only operation summaries[/bold]",
1163
+ " [5] Generate [bold]only missing operationIds[/bold]",
1164
+ " [6] [bold]Enrich only parameter descriptions (LLM, ≤250 chars, run after clean-up)[/bold]",
1030
1165
  ]
1031
- valid_choices = ["2", "3"]
1166
+ valid_choices = ["2", "3", "4", "5", "6"]
1032
1167
  default_choice = "3" # Default to quitting if nothing missing
1033
1168
 
1034
1169
  for option_text in prompt_options:
@@ -1046,19 +1181,50 @@ def run_preprocessing(
1046
1181
  raise typer.Exit(0)
1047
1182
  elif choice == "1":
1048
1183
  enhance_all = False
1184
+ summaries_only = False
1185
+ operation_ids_only = False
1049
1186
  break # Exit prompt loop
1050
1187
  elif choice == "2":
1051
1188
  enhance_all = True
1189
+ summaries_only = False
1190
+ operation_ids_only = False
1191
+ break # Exit prompt loop
1192
+ elif choice == "4":
1193
+ enhance_all = True # or False, doesn't matter since we skip parameters
1194
+ summaries_only = True
1195
+ operation_ids_only = False
1196
+ break # Exit prompt loop
1197
+ elif choice == "5":
1198
+ enhance_all = False
1199
+ summaries_only = False
1200
+ operation_ids_only = True
1052
1201
  break # Exit prompt loop
1202
+ elif choice == "6":
1203
+ console.print(
1204
+ "[blue]Enriching only parameter descriptions using the LLM (≤250 chars, only if current description is longer)...[/blue]"
1205
+ )
1206
+ try:
1207
+ enrich_parameter_descriptions(schema_data, model, max_length=250)
1208
+ console.print("[green]Parameter description enrichment complete.[/green]")
1209
+ except Exception as e:
1210
+ console.print(f"[red]Error during parameter description enrichment: {e}[/red]")
1211
+ import traceback
1212
+
1213
+ traceback.print_exc(file=sys.stderr)
1214
+ raise typer.Exit(1) from e
1215
+ enhance_all = summaries_only = operation_ids_only = False
1216
+ break
1053
1217
 
1054
1218
  perform_generation = False
1055
- if enhance_all or choice == "1" and total_missing_or_fallback > 0:
1219
+ if operation_ids_only or summaries_only or enhance_all or (choice == "1" and total_missing_or_fallback > 0):
1056
1220
  perform_generation = True
1057
1221
 
1058
1222
  if perform_generation:
1059
- console.print(f"[blue]Starting LLM generation with Enhance All: {enhance_all}[/blue]")
1223
+ console.print(
1224
+ f"[blue]Starting LLM generation with Enhance All: {enhance_all}, Summaries Only: {summaries_only}, OperationIds Only: {operation_ids_only}[/blue]"
1225
+ )
1060
1226
  try:
1061
- preprocess_schema_with_llm(schema_data, model, enhance_all)
1227
+ preprocess_schema_with_llm(schema_data, model, enhance_all, summaries_only, operation_ids_only)
1062
1228
  console.print("[green]LLM generation complete.[/green]")
1063
1229
  except Exception as e:
1064
1230
  console.print(f"[red]Error during LLM generation: {e}[/red]")
@@ -1091,3 +1257,80 @@ def run_preprocessing(
1091
1257
  console.print("\n[bold green]--- Schema Processing and Saving Complete ---[/bold green]")
1092
1258
  console.print(f"Processed schema saved to: [blue]{output_path}[/blue]")
1093
1259
  console.print("[bold blue]Preprocessor finished successfully.[/bold blue]")
1260
+
1261
+
1262
+ def enrich_parameter_descriptions(schema_data: dict, llm_model: str, max_length: int = 250):
1263
+ """
1264
+ Enriches parameter descriptions using the LLM, but ONLY if the current description is longer than max_length chars.
1265
+ Only processes parameter descriptions, does not touch examples or other fields.
1266
+ """
1267
+ MAX_ATTEMPTS = 3
1268
+ paths = schema_data.get("paths")
1269
+ if not isinstance(paths, dict):
1270
+ return
1271
+ for path_key, path_value in paths.items():
1272
+ if not isinstance(path_value, dict):
1273
+ continue
1274
+ for method, operation_value in path_value.items():
1275
+ if not (
1276
+ isinstance(operation_value, dict)
1277
+ and method.lower() in ["get", "put", "post", "delete", "options", "head", "patch", "trace"]
1278
+ ):
1279
+ continue
1280
+ parameters = operation_value.get("parameters")
1281
+ if isinstance(parameters, list):
1282
+ for parameter in parameters:
1283
+ if isinstance(parameter, dict):
1284
+ param_name = parameter.get("name")
1285
+ param_in = parameter.get("in")
1286
+ # Only enrich if name and in are present
1287
+ if not (
1288
+ isinstance(param_name, str)
1289
+ and param_name.strip()
1290
+ and isinstance(param_in, str)
1291
+ and param_in.strip()
1292
+ ):
1293
+ continue
1294
+ current_description = parameter.get("description", "")
1295
+ if not isinstance(current_description, str) or len(current_description) <= max_length:
1296
+ continue
1297
+ logger.info(
1298
+ f"Enriching parameter description >{max_length} chars: path='{path_key}', method='{method}', param_name='{param_name}', param_in='{param_in}', length={len(current_description)}"
1299
+ )
1300
+ simplified_context = simplify_parameter_context(parameter)
1301
+ attempt = 0
1302
+ generated_description = current_description
1303
+ while attempt < MAX_ATTEMPTS:
1304
+ generated_description = generate_description_llm(
1305
+ description_type="parameter",
1306
+ model=llm_model,
1307
+ context={
1308
+ "path_key": path_key,
1309
+ "method": method,
1310
+ "param_name": param_name,
1311
+ "param_in": param_in,
1312
+ "parameter_details": simplified_context,
1313
+ "current_description": generated_description,
1314
+ },
1315
+ )
1316
+ if isinstance(generated_description, str) and len(generated_description) <= max_length:
1317
+ break
1318
+ attempt += 1
1319
+ # If still too long, truncate
1320
+ if isinstance(generated_description, str) and len(generated_description) > max_length:
1321
+ generated_description = generated_description[:max_length].rstrip() + "..."
1322
+ parameter["description"] = generated_description
1323
+
1324
+
1325
+ def sanitize_operation_id(llm_response: str) -> str:
1326
+ """Extracts the first valid operationId from the LLM response."""
1327
+ for line in llm_response.splitlines():
1328
+ line = line.strip()
1329
+ # Skip empty lines and markdown/comments
1330
+ if not line or line.startswith("#") or line.startswith("*") or line.startswith("**"):
1331
+ continue
1332
+ # Only allow valid operationId patterns (alphanumeric, camelCase, snake_case, max 30 chars)
1333
+ if re.match(r"^[a-zA-Z_][a-zA-Z0-9_]{0,29}$", line):
1334
+ return line
1335
+ # Fallback: return the first word
1336
+ return llm_response.strip().split()[0] if llm_response.strip() else ""
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: universal-mcp
3
- Version: 0.1.20rc2
3
+ Version: 0.1.22rc1
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
7
7
  License-File: LICENSE
8
8
  Requires-Python: >=3.11
9
+ Requires-Dist: black>=25.1.0
9
10
  Requires-Dist: cookiecutter>=2.6.0
10
11
  Requires-Dist: gql[all]>=3.5.2
11
12
  Requires-Dist: jinja2>=3.1.3
@@ -6,40 +6,40 @@ universal_mcp/exceptions.py,sha256=-pbeZhpNieJfnSd2-WM80pU8W8mK8VHXcSjky0BHwdk,6
6
6
  universal_mcp/logger.py,sha256=VmH_83efpErLEDTJqz55Dp0dioTXfGvMBLZUx5smOLc,2116
7
7
  universal_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  universal_mcp/applications/README.md,sha256=eqbizxaTxKH2O1tyIJR2yI0Db5TQxtgPd_vbpWyCa2Y,3527
9
- universal_mcp/applications/__init__.py,sha256=7iml45r5jYX8_iiYeTRnMeBTfFb7rdygp5e9f1KiPSw,3361
9
+ universal_mcp/applications/__init__.py,sha256=No_tptWkYFcbE6Z3tMEpqUbpHXlaCOa8__yqWB5sTjY,3360
10
10
  universal_mcp/applications/application.py,sha256=3cQ5BVWmC2gU4fgpM5wZ3ByTe7iGbQriNPVSWxclaiU,17744
11
11
  universal_mcp/integrations/README.md,sha256=lTAPXO2nivcBe1q7JT6PRa6v9Ns_ZersQMIdw-nmwEA,996
12
12
  universal_mcp/integrations/__init__.py,sha256=X8iEzs02IlXfeafp6GMm-cOkg70QdjnlTRuFo24KEfo,916
13
- universal_mcp/integrations/integration.py,sha256=QvZlq3G5OU4tHPv9uq9Nv5NFe30NdUsJU-Av474n0_o,13154
13
+ universal_mcp/integrations/integration.py,sha256=uKucut4AKTN2M-K8Aqsm2qtchLqlQRWMU8L287X7VyQ,13043
14
14
  universal_mcp/servers/README.md,sha256=ytFlgp8-LO0oogMrHkMOp8SvFTwgsKgv7XhBVZGNTbM,2284
15
15
  universal_mcp/servers/__init__.py,sha256=eBZCsaZjiEv6ZlRRslPKgurQxmpHLQyiXv2fTBygHnM,532
16
- universal_mcp/servers/server.py,sha256=6xRUxTJHiX0AqEWbAZ6eb6jEkvuBX5Qpkb53hmKcfc0,12822
16
+ universal_mcp/servers/server.py,sha256=7IiivuINr1CjZ6gX8xMgsoTHOevbiHa9U1pUDJGNRIE,13251
17
17
  universal_mcp/stores/README.md,sha256=jrPh_ow4ESH4BDGaSafilhOVaN8oQ9IFlFW-j5Z5hLA,2465
18
18
  universal_mcp/stores/__init__.py,sha256=quvuwhZnpiSLuojf0NfmBx2xpaCulv3fbKtKaSCEmuM,603
19
19
  universal_mcp/stores/store.py,sha256=mxnmOVlDNrr8OKhENWDtCIfK7YeCBQcGdS6I2ogRCsU,6756
20
20
  universal_mcp/tools/README.md,sha256=RuxliOFqV1ZEyeBdj3m8UKfkxAsfrxXh-b6V4ZGAk8I,2468
21
21
  universal_mcp/tools/__init__.py,sha256=Fatza_R0qYWmNF1WQSfUZZKQFu5qf-16JhZzdmyx3KY,333
22
- universal_mcp/tools/adapters.py,sha256=OCZuWxLscys6mw1Q5ctQFshv9q3szlikwHhn4j5PMnE,1432
23
- universal_mcp/tools/func_metadata.py,sha256=zIDXgIBvu5Gh8aNlg-Q7cZZos9Iky75MS0Me0BraXeM,8086
24
- universal_mcp/tools/manager.py,sha256=iwywaTjVGvBCJJasfwDWrASUleYqxenm4S-0txdhCF0,8076
22
+ universal_mcp/tools/adapters.py,sha256=n06Nz18L_4dq3iwBchNq9vHsX7whqFZ0g5iuz_0gyaM,2076
23
+ universal_mcp/tools/func_metadata.py,sha256=XvdXSZEzvgbH70bc-Zu0B47CD7f_rm--vblq4en3n0Q,8181
24
+ universal_mcp/tools/manager.py,sha256=ao_ovTyca8HR4uwHdL_lTWNdquxcqRx6FaLA4U1lZvQ,11242
25
25
  universal_mcp/tools/tools.py,sha256=qiuuLe0mCWtxXp6E5ISDDaNojCrMLfV1r5L8peFoJfg,3327
26
26
  universal_mcp/utils/__init__.py,sha256=8wi4PGWu-SrFjNJ8U7fr2iFJ1ktqlDmSKj1xYd7KSDc,41
27
- universal_mcp/utils/agentr.py,sha256=YmX6hvFW84keJKTZqP3jPz4rP9DM5wHZ0vTMHfxO6AI,3360
27
+ universal_mcp/utils/agentr.py,sha256=a7D3I4oKvdovoumeSdChhHBcZNrEtKHHb4L4O8Gm_l0,2870
28
28
  universal_mcp/utils/common.py,sha256=HEZC2Mhilb8DrGXQG2tboAIw1r4veGilGWjfnPF1lyA,888
29
- universal_mcp/utils/docstring_parser.py,sha256=6oIeCjOUirFdVpXdGZt5zDKje6jmCY42-GeYOc_7r2I,11317
29
+ universal_mcp/utils/docstring_parser.py,sha256=SKIfAiFHiqxqageayYFlpsexipy8tN7N4RLT6GIzfoQ,7672
30
30
  universal_mcp/utils/installation.py,sha256=ItOfBFhKOh4DLz237jgAz_Fn0uOMdrKXw0n5BaUZZNs,7286
31
31
  universal_mcp/utils/singleton.py,sha256=kolHnbS9yd5C7z-tzaUAD16GgI-thqJXysNi3sZM4No,733
32
32
  universal_mcp/utils/openapi/__inti__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  universal_mcp/utils/openapi/api_generator.py,sha256=FjtvbnWuI1P8W8wXuKLCirUtsqQ4HI_TuQrhpA4SqTs,4749
34
- universal_mcp/utils/openapi/api_splitter.py,sha256=6O2y7fcCo2k3ixLr6_9-aAZx2kas3UAxQhqJy1esNkE,18829
34
+ universal_mcp/utils/openapi/api_splitter.py,sha256=S-rT3wsJWUVhU_Tv_ibNNAlQ79SfWOcU6qaa_rFfd5o,20806
35
35
  universal_mcp/utils/openapi/docgen.py,sha256=DNmwlhg_-TRrHa74epyErMTRjV2nutfCQ7seb_Rq5hE,21366
36
- universal_mcp/utils/openapi/openapi.py,sha256=EQME-VC5ccXpukIF0h96YsQOZj6oWip8W7a0bRN3s_k,45677
37
- universal_mcp/utils/openapi/preprocessor.py,sha256=qLYv4ekors5B2OU_YUvXICYQ7XYhAOEPyAnKtnBvNpM,46699
36
+ universal_mcp/utils/openapi/openapi.py,sha256=3DWpxVZk9LGGDLrpE7BfSjurd_FJg30oWUiaEv3wjm0,51105
37
+ universal_mcp/utils/openapi/preprocessor.py,sha256=PPIM3Uu8DYi3dRKdqi9thr9ufeUgkr2K08ri1BwKpoQ,60835
38
38
  universal_mcp/utils/openapi/readme.py,sha256=R2Jp7DUXYNsXPDV6eFTkLiy7MXbSULUj1vHh4O_nB4c,2974
39
39
  universal_mcp/utils/templates/README.md.j2,sha256=Mrm181YX-o_-WEfKs01Bi2RJy43rBiq2j6fTtbWgbTA,401
40
40
  universal_mcp/utils/templates/api_client.py.j2,sha256=972Im7LNUAq3yZTfwDcgivnb-b8u6_JLKWXwoIwXXXQ,908
41
- universal_mcp-0.1.20rc2.dist-info/METADATA,sha256=WiatokzuBAxnApe-BKs-hr-fWMO8mqPUUZwCE6RjHdI,12125
42
- universal_mcp-0.1.20rc2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- universal_mcp-0.1.20rc2.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
44
- universal_mcp-0.1.20rc2.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
45
- universal_mcp-0.1.20rc2.dist-info/RECORD,,
41
+ universal_mcp-0.1.22rc1.dist-info/METADATA,sha256=VAB3kMzP5KOKpWoBC12I7i3gW2JmSJLvx92Go9qINv8,12154
42
+ universal_mcp-0.1.22rc1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
+ universal_mcp-0.1.22rc1.dist-info/entry_points.txt,sha256=QlBrVKmA2jIM0q-C-3TQMNJTTWOsOFQvgedBq2rZTS8,56
44
+ universal_mcp-0.1.22rc1.dist-info/licenses/LICENSE,sha256=NweDZVPslBAZFzlgByF158b85GR0f5_tLQgq1NS48To,1063
45
+ universal_mcp-0.1.22rc1.dist-info/RECORD,,