structurize 3.3.2__tar.gz → 3.4.1__tar.gz

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 (90) hide show
  1. {structurize-3.3.2/structurize.egg-info → structurize-3.4.1}/PKG-INFO +1 -1
  2. {structurize-3.3.2 → structurize-3.4.1}/avrotize/_version.py +3 -3
  3. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotize.py +1 -1
  4. {structurize-3.3.2 → structurize-3.4.1}/avrotize/commands.json +26 -0
  5. structurize-3.4.1/avrotize/mcp_server.py +253 -0
  6. {structurize-3.3.2 → structurize-3.4.1/structurize.egg-info}/PKG-INFO +1 -1
  7. {structurize-3.3.2 → structurize-3.4.1}/structurize.egg-info/SOURCES.txt +2 -0
  8. {structurize-3.3.2 → structurize-3.4.1}/.gitignore +0 -0
  9. {structurize-3.3.2 → structurize-3.4.1}/LICENSE +0 -0
  10. {structurize-3.3.2 → structurize-3.4.1}/MANIFEST.in +0 -0
  11. {structurize-3.3.2 → structurize-3.4.1}/README.md +0 -0
  12. {structurize-3.3.2 → structurize-3.4.1}/avrotize/__init__.py +0 -0
  13. {structurize-3.3.2 → structurize-3.4.1}/avrotize/__main__.py +0 -0
  14. {structurize-3.3.2 → structurize-3.4.1}/avrotize/asn1toavro.py +0 -0
  15. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotocpp.py +0 -0
  16. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotocsharp.py +0 -0
  17. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotocsv.py +0 -0
  18. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotodatapackage.py +0 -0
  19. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotodb.py +0 -0
  20. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotogo.py +0 -0
  21. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotographql.py +0 -0
  22. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotoiceberg.py +0 -0
  23. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotojava.py +0 -0
  24. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotojs.py +0 -0
  25. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotojsons.py +0 -0
  26. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotojstruct.py +0 -0
  27. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotokusto.py +0 -0
  28. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotomd.py +0 -0
  29. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotools.py +0 -0
  30. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotoparquet.py +0 -0
  31. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotoproto.py +0 -0
  32. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotopython.py +0 -0
  33. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotorust.py +0 -0
  34. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotots.py +0 -0
  35. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrotoxsd.py +0 -0
  36. {structurize-3.3.2 → structurize-3.4.1}/avrotize/avrovalidator.py +0 -0
  37. {structurize-3.3.2 → structurize-3.4.1}/avrotize/cddltostructure.py +0 -0
  38. {structurize-3.3.2 → structurize-3.4.1}/avrotize/choice_inference.py +0 -0
  39. {structurize-3.3.2 → structurize-3.4.1}/avrotize/common.py +0 -0
  40. {structurize-3.3.2 → structurize-3.4.1}/avrotize/constants.py +0 -0
  41. {structurize-3.3.2 → structurize-3.4.1}/avrotize/csvtoavro.py +0 -0
  42. {structurize-3.3.2 → structurize-3.4.1}/avrotize/datapackagetoavro.py +0 -0
  43. {structurize-3.3.2 → structurize-3.4.1}/avrotize/dependencies/cpp/vcpkg/vcpkg.json +0 -0
  44. {structurize-3.3.2 → structurize-3.4.1}/avrotize/dependencies/typescript/node22/package.json +0 -0
  45. {structurize-3.3.2 → structurize-3.4.1}/avrotize/dependency_resolver.py +0 -0
  46. {structurize-3.3.2 → structurize-3.4.1}/avrotize/dependency_version.py +0 -0
  47. {structurize-3.3.2 → structurize-3.4.1}/avrotize/jsonstoavro.py +0 -0
  48. {structurize-3.3.2 → structurize-3.4.1}/avrotize/jsonstostructure.py +0 -0
  49. {structurize-3.3.2 → structurize-3.4.1}/avrotize/jsontoschema.py +0 -0
  50. {structurize-3.3.2 → structurize-3.4.1}/avrotize/jstructtoavro.py +0 -0
  51. {structurize-3.3.2 → structurize-3.4.1}/avrotize/kstructtoavro.py +0 -0
  52. {structurize-3.3.2 → structurize-3.4.1}/avrotize/kustotoavro.py +0 -0
  53. {structurize-3.3.2 → structurize-3.4.1}/avrotize/kustotojstruct.py +0 -0
  54. {structurize-3.3.2 → structurize-3.4.1}/avrotize/openapitostructure.py +0 -0
  55. {structurize-3.3.2 → structurize-3.4.1}/avrotize/parquettoavro.py +0 -0
  56. {structurize-3.3.2 → structurize-3.4.1}/avrotize/proto2parser.py +0 -0
  57. {structurize-3.3.2 → structurize-3.4.1}/avrotize/proto3parser.py +0 -0
  58. {structurize-3.3.2 → structurize-3.4.1}/avrotize/prototoavro.py +0 -0
  59. {structurize-3.3.2 → structurize-3.4.1}/avrotize/schema_inference.py +0 -0
  60. {structurize-3.3.2 → structurize-3.4.1}/avrotize/sqltoavro.py +0 -0
  61. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretocddl.py +0 -0
  62. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretocpp.py +0 -0
  63. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretocsharp.py +0 -0
  64. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretocsv.py +0 -0
  65. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretodatapackage.py +0 -0
  66. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretodb.py +0 -0
  67. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretogo.py +0 -0
  68. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretographql.py +0 -0
  69. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretoiceberg.py +0 -0
  70. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretojava.py +0 -0
  71. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretojs.py +0 -0
  72. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretojsons.py +0 -0
  73. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretokusto.py +0 -0
  74. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretomd.py +0 -0
  75. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretoproto.py +0 -0
  76. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretopython.py +0 -0
  77. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretorust.py +0 -0
  78. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretots.py +0 -0
  79. {structurize-3.3.2 → structurize-3.4.1}/avrotize/structuretoxsd.py +0 -0
  80. {structurize-3.3.2 → structurize-3.4.1}/avrotize/validate.py +0 -0
  81. {structurize-3.3.2 → structurize-3.4.1}/avrotize/xmltoschema.py +0 -0
  82. {structurize-3.3.2 → structurize-3.4.1}/avrotize/xsdtoavro.py +0 -0
  83. {structurize-3.3.2 → structurize-3.4.1}/build.ps1 +0 -0
  84. {structurize-3.3.2 → structurize-3.4.1}/build.sh +0 -0
  85. {structurize-3.3.2 → structurize-3.4.1}/pyproject.toml +0 -0
  86. {structurize-3.3.2 → structurize-3.4.1}/setup.cfg +0 -0
  87. {structurize-3.3.2 → structurize-3.4.1}/structurize.egg-info/dependency_links.txt +0 -0
  88. {structurize-3.3.2 → structurize-3.4.1}/structurize.egg-info/entry_points.txt +0 -0
  89. {structurize-3.3.2 → structurize-3.4.1}/structurize.egg-info/requires.txt +0 -0
  90. {structurize-3.3.2 → structurize-3.4.1}/structurize.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structurize
3
- Version: 3.3.2
3
+ Version: 3.4.1
4
4
  Summary: Tools to convert from and to JSON Structure from various other schema languages.
5
5
  Author-email: Clemens Vasters <clemensv@microsoft.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '3.3.2'
32
- __version_tuple__ = version_tuple = (3, 3, 2)
31
+ __version__ = version = '3.4.1'
32
+ __version_tuple__ = version_tuple = (3, 4, 1)
33
33
 
34
- __commit_id__ = commit_id = 'gdcb1a6825'
34
+ __commit_id__ = commit_id = 'g12ad80ab6'
@@ -92,7 +92,7 @@ def main():
92
92
  print(f"Error: Command {args.command} not found.")
93
93
  exit(1)
94
94
 
95
- input_file_path = args.input or getattr(args, 'avsc', None) or getattr(args, 'proto', None) or getattr(args, 'jsons', None) or getattr(args, 'xsd', None) or getattr(args, 'kusto_uri', None) or getattr(args, 'parquet', None) or getattr(args, 'asn', None) or getattr(args, 'kstruct', None)
95
+ input_file_path = getattr(args, 'input', None) or getattr(args, 'avsc', None) or getattr(args, 'proto', None) or getattr(args, 'jsons', None) or getattr(args, 'xsd', None) or getattr(args, 'kusto_uri', None) or getattr(args, 'parquet', None) or getattr(args, 'asn', None) or getattr(args, 'kstruct', None)
96
96
  temp_input = None
97
97
  skip_input_file_handling = command.get('skip_input_file_handling', False)
98
98
  if not skip_input_file_handling:
@@ -4405,5 +4405,31 @@
4405
4405
  "required": false
4406
4406
  }
4407
4407
  ]
4408
+ },
4409
+ {
4410
+ "command": "mcp",
4411
+ "description": "Run Avrotize as a local MCP server exposing conversion tools",
4412
+ "group": "7_Utility",
4413
+ "function": {
4414
+ "name": "avrotize.mcp_server.run_mcp_server",
4415
+ "args": {
4416
+ "transport": "args.transport"
4417
+ }
4418
+ },
4419
+ "extensions": [],
4420
+ "args": [
4421
+ {
4422
+ "name": "--transport",
4423
+ "type": "str",
4424
+ "help": "MCP transport type",
4425
+ "choices": [
4426
+ "stdio"
4427
+ ],
4428
+ "default": "stdio",
4429
+ "required": false
4430
+ }
4431
+ ],
4432
+ "prompts": [],
4433
+ "skip_input_file_handling": true
4408
4434
  }
4409
4435
  ]
@@ -0,0 +1,253 @@
1
+ """MCP server integration for Avrotize conversions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import os
7
+ import tempfile
8
+ from typing import Any, Dict, List
9
+
10
+ from avrotize.avrotize import dynamic_import, load_commands
11
+
12
+
13
+ def _command_dest(arg: Dict[str, Any]) -> str:
14
+ name = arg["name"]
15
+ if name.startswith("-"):
16
+ return arg.get("dest", name.lstrip("-").replace("-", "_").replace(".", "_"))
17
+ return name
18
+
19
+
20
+ def _coerce_value(value: Any, arg_type: str) -> Any:
21
+ if value is None:
22
+ return None
23
+ if arg_type == "bool":
24
+ if isinstance(value, bool):
25
+ return value
26
+ if isinstance(value, (int, float)):
27
+ return bool(value)
28
+ sval = str(value).strip().lower()
29
+ return sval in {"1", "true", "yes", "y", "on"}
30
+ if arg_type == "int":
31
+ return int(value)
32
+ if arg_type == "float":
33
+ return float(value)
34
+ return str(value) if arg_type == "str" else value
35
+
36
+
37
+ def _build_namespace(command: Dict[str, Any], options: Dict[str, Any]) -> argparse.Namespace:
38
+ namespace = argparse.Namespace()
39
+ normalized_options = {
40
+ key.lstrip("-").replace("-", "_"): value
41
+ for key, value in (options or {}).items()
42
+ }
43
+
44
+ for arg in command.get("args", []):
45
+ dest = _command_dest(arg)
46
+ default_value = arg.get("default", False if arg.get("type") == "bool" else None)
47
+ setattr(namespace, dest, default_value)
48
+ if dest in normalized_options:
49
+ setattr(namespace, dest, _coerce_value(normalized_options[dest], arg["type"]))
50
+
51
+ return namespace
52
+
53
+
54
+ def _resolve_input_path(command_args: argparse.Namespace, explicit_input_path: str | None) -> str | None:
55
+ if explicit_input_path:
56
+ return explicit_input_path
57
+ return (
58
+ getattr(command_args, "input", None)
59
+ or getattr(command_args, "avsc", None)
60
+ or getattr(command_args, "proto", None)
61
+ or getattr(command_args, "jsons", None)
62
+ or getattr(command_args, "xsd", None)
63
+ or getattr(command_args, "kusto_uri", None)
64
+ or getattr(command_args, "parquet", None)
65
+ or getattr(command_args, "asn", None)
66
+ or getattr(command_args, "kstruct", None)
67
+ )
68
+
69
+
70
+ def _find_command(command_name: str) -> Dict[str, Any] | None:
71
+ return next((cmd for cmd in load_commands() if cmd.get("command") == command_name), None)
72
+
73
+
74
+ def _list_commands() -> List[Dict[str, Any]]:
75
+ commands = load_commands()
76
+ result: List[Dict[str, Any]] = []
77
+ for command in commands:
78
+ if command.get("command") == "mcp":
79
+ continue
80
+ result.append(
81
+ {
82
+ "command": command.get("command"),
83
+ "description": command.get("description"),
84
+ "group": command.get("group"),
85
+ "args": [arg.get("name") for arg in command.get("args", [])],
86
+ }
87
+ )
88
+ return result
89
+
90
+
91
+ def _describe_capabilities() -> Dict[str, Any]:
92
+ commands = load_commands()
93
+ command_names = [cmd.get("command") for cmd in commands if cmd.get("command") != "mcp"]
94
+ return {
95
+ "server": "avrotize",
96
+ "purpose": "Schema conversion and schema-driven code generation",
97
+ "use_when": [
98
+ "Converting between schema formats (Avro, JSON Schema, Proto, XSD, Parquet, etc.)",
99
+ "Generating code from Avro/JSON Structure schemas (C#, Java, Python, TypeScript, JavaScript, Rust, Go, C++)",
100
+ "Inferring schemas from sample JSON/XML/CSV/parquet inputs",
101
+ ],
102
+ "do_not_use_when": [
103
+ "Task is unrelated to schema conversion or code generation",
104
+ "Task requires arbitrary code execution outside avrotize command set",
105
+ ],
106
+ "recommended_flow": [
107
+ "Call describe_capabilities for high-level routing",
108
+ "Call list_conversions to discover available commands",
109
+ "Call get_conversion(command) to inspect required args/options",
110
+ "Call run_conversion(...) to execute",
111
+ ],
112
+ "tools": {
113
+ "describe_capabilities": "High-level guidance for when and how to use this server",
114
+ "list_conversions": "List available conversion/code generation commands",
115
+ "get_conversion": "Inspect metadata and args for a specific command",
116
+ "run_conversion": "Execute a specific conversion command",
117
+ },
118
+ "command_count": len(command_names),
119
+ "commands": command_names,
120
+ }
121
+
122
+
123
+ def _execute_conversion(
124
+ command_name: str,
125
+ input_path: str | None = None,
126
+ input_content: str | None = None,
127
+ output_path: str | None = None,
128
+ options: Dict[str, Any] | None = None,
129
+ ) -> Dict[str, Any]:
130
+ command = _find_command(command_name)
131
+ if not command:
132
+ raise ValueError(f"Unknown command '{command_name}'.")
133
+
134
+ command_args = _build_namespace(command, options or {})
135
+ temp_input_path = None
136
+ temp_output_path = None
137
+
138
+ try:
139
+ resolved_input = _resolve_input_path(command_args, input_path)
140
+ skip_input_file_handling = command.get("skip_input_file_handling", False)
141
+ if not skip_input_file_handling and not resolved_input:
142
+ if input_content is None:
143
+ raise ValueError("This command requires input_path or input_content.")
144
+ temp_input = tempfile.NamedTemporaryFile(delete=False, mode="w", encoding="utf-8")
145
+ temp_input.write(input_content)
146
+ temp_input.flush()
147
+ temp_input.close()
148
+ temp_input_path = temp_input.name
149
+ resolved_input = temp_input_path
150
+
151
+ if not output_path and any(v == "output_file_path" for v in command.get("function", {}).get("args", {}).values()):
152
+ temp_output = tempfile.NamedTemporaryFile(delete=False, mode="w", encoding="utf-8")
153
+ temp_output_path = temp_output.name
154
+ temp_output.close()
155
+ output_path = temp_output_path
156
+
157
+ module_name, func_name = command["function"]["name"].rsplit(".", 1)
158
+ func = dynamic_import(module_name, func_name)
159
+
160
+ func_args: Dict[str, Any] = {}
161
+ for arg_name, arg_value in command["function"]["args"].items():
162
+ if arg_value == "input_file_path":
163
+ func_args[arg_name] = resolved_input
164
+ elif arg_value == "output_file_path":
165
+ func_args[arg_name] = output_path
166
+ elif isinstance(arg_value, str) and arg_value.startswith("args."):
167
+ attr_name = arg_value[5:]
168
+ if hasattr(command_args, attr_name):
169
+ func_args[arg_name] = getattr(command_args, attr_name)
170
+ else:
171
+ func_args[arg_name] = arg_value
172
+
173
+ func(**func_args)
174
+
175
+ output_content = None
176
+ if temp_output_path and os.path.exists(temp_output_path):
177
+ with open(temp_output_path, "r", encoding="utf-8") as out_file:
178
+ output_content = out_file.read()
179
+
180
+ return {
181
+ "success": True,
182
+ "command": command_name,
183
+ "output_path": output_path,
184
+ "output_content": output_content,
185
+ }
186
+ finally:
187
+ if temp_input_path and os.path.exists(temp_input_path):
188
+ os.remove(temp_input_path)
189
+ if temp_output_path and os.path.exists(temp_output_path):
190
+ os.remove(temp_output_path)
191
+
192
+
193
+ def run_mcp_server(transport: str = "stdio"):
194
+ """Run avrotize as a local MCP server.
195
+
196
+ Exposes conversion tools to MCP clients.
197
+ """
198
+ try:
199
+ from mcp.server.fastmcp import FastMCP
200
+ except ImportError as exc:
201
+ raise RuntimeError(
202
+ "MCP support is not installed. Install with: pip install mcp"
203
+ ) from exc
204
+
205
+ if transport != "stdio":
206
+ raise ValueError("Only 'stdio' transport is currently supported.")
207
+
208
+ mcp = FastMCP("avrotize")
209
+
210
+ @mcp.tool()
211
+ def describe_capabilities() -> Dict[str, Any]:
212
+ """Describe when this server should be used and how to invoke it."""
213
+ return _describe_capabilities()
214
+
215
+ @mcp.tool()
216
+ def list_conversions() -> List[Dict[str, Any]]:
217
+ """List available Avrotize conversion commands."""
218
+ return _list_commands()
219
+
220
+ @mcp.tool()
221
+ def get_conversion(command: str) -> Dict[str, Any]:
222
+ """Get metadata for a specific conversion command."""
223
+ cmd = _find_command(command)
224
+ if not cmd:
225
+ raise ValueError(f"Unknown command '{command}'.")
226
+ return {
227
+ "command": cmd.get("command"),
228
+ "description": cmd.get("description"),
229
+ "group": cmd.get("group"),
230
+ "args": cmd.get("args", []),
231
+ }
232
+
233
+ @mcp.tool()
234
+ def run_conversion(
235
+ command: str,
236
+ input_path: str = "",
237
+ input_content: str = "",
238
+ output_path: str = "",
239
+ options: Dict[str, Any] | None = None,
240
+ ) -> Dict[str, Any]:
241
+ """Run a conversion command and return conversion output information."""
242
+ return _execute_conversion(
243
+ command_name=command,
244
+ input_path=input_path or None,
245
+ input_content=input_content or None,
246
+ output_path=output_path or None,
247
+ options=options or {},
248
+ )
249
+
250
+ try:
251
+ mcp.run(transport="stdio")
252
+ except TypeError:
253
+ mcp.run()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: structurize
3
- Version: 3.3.2
3
+ Version: 3.4.1
4
4
  Summary: Tools to convert from and to JSON Structure from various other schema languages.
5
5
  Author-email: Clemens Vasters <clemensv@microsoft.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -51,6 +51,7 @@ pyproject.toml
51
51
  ../avrotize/kstructtoavro.py
52
52
  ../avrotize/kustotoavro.py
53
53
  ../avrotize/kustotojstruct.py
54
+ ../avrotize/mcp_server.py
54
55
  ../avrotize/openapitostructure.py
55
56
  ../avrotize/parquettoavro.py
56
57
  ../avrotize/proto2parser.py
@@ -225,6 +226,7 @@ avrotize/jstructtoavro.py
225
226
  avrotize/kstructtoavro.py
226
227
  avrotize/kustotoavro.py
227
228
  avrotize/kustotojstruct.py
229
+ avrotize/mcp_server.py
228
230
  avrotize/openapitostructure.py
229
231
  avrotize/parquettoavro.py
230
232
  avrotize/proto2parser.py
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes