structurize 3.3.1__tar.gz → 3.4.0__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.
- {structurize-3.3.1/structurize.egg-info → structurize-3.4.0}/PKG-INFO +1 -1
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/_version.py +3 -3
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotize.py +1 -1
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/choice_inference.py +13 -5
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/commands.json +26 -0
- structurize-3.4.0/avrotize/mcp_server.py +253 -0
- {structurize-3.3.1 → structurize-3.4.0/structurize.egg-info}/PKG-INFO +1 -1
- {structurize-3.3.1 → structurize-3.4.0}/structurize.egg-info/SOURCES.txt +2 -0
- {structurize-3.3.1 → structurize-3.4.0}/.gitignore +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/LICENSE +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/MANIFEST.in +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/README.md +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/__init__.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/__main__.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/asn1toavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotocpp.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotocsharp.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotocsv.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotodatapackage.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotodb.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotogo.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotographql.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotoiceberg.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotojava.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotojs.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotojsons.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotojstruct.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotokusto.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotomd.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotools.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotoparquet.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotoproto.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotopython.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotorust.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotots.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrotoxsd.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/avrovalidator.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/cddltostructure.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/common.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/constants.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/csvtoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/datapackagetoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/dependencies/cpp/vcpkg/vcpkg.json +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/dependencies/typescript/node22/package.json +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/dependency_resolver.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/dependency_version.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/jsonstoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/jsonstostructure.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/jsontoschema.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/jstructtoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/kstructtoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/kustotoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/kustotojstruct.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/openapitostructure.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/parquettoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/proto2parser.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/proto3parser.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/prototoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/schema_inference.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/sqltoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretocddl.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretocpp.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretocsharp.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretocsv.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretodatapackage.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretodb.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretogo.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretographql.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretoiceberg.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretojava.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretojs.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretojsons.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretokusto.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretomd.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretoproto.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretopython.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretorust.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretots.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/structuretoxsd.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/validate.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/xmltoschema.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/avrotize/xsdtoavro.py +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/build.ps1 +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/build.sh +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/pyproject.toml +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/setup.cfg +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/structurize.egg-info/dependency_links.txt +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/structurize.egg-info/entry_points.txt +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/structurize.egg-info/requires.txt +0 -0
- {structurize-3.3.1 → structurize-3.4.0}/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
|
+
Version: 3.4.0
|
|
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.
|
|
32
|
-
__version_tuple__ = version_tuple = (3,
|
|
31
|
+
__version__ = version = '3.4.0'
|
|
32
|
+
__version_tuple__ = version_tuple = (3, 4, 0)
|
|
33
33
|
|
|
34
|
-
__commit_id__ = commit_id = '
|
|
34
|
+
__commit_id__ = commit_id = 'gbd45fcc09'
|
|
@@ -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
|
|
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:
|
|
@@ -214,11 +214,19 @@ def _detect_discriminators(
|
|
|
214
214
|
if len(values) < 2:
|
|
215
215
|
continue
|
|
216
216
|
|
|
217
|
-
#
|
|
218
|
-
#
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
217
|
+
# Discriminators must be identifier-like strings (type names, enum values)
|
|
218
|
+
# Valid: "PlayerTracking", "ball_data", "goal-event", "Event.Type"
|
|
219
|
+
# Invalid: "1", "2024/2025", "true", "2024-01-15T10:30:00Z", UUIDs
|
|
220
|
+
import re
|
|
221
|
+
def is_valid_discriminator(s: str) -> bool:
|
|
222
|
+
"""Check if a string looks like a type name or identifier."""
|
|
223
|
+
if not s or not isinstance(s, str):
|
|
224
|
+
return False
|
|
225
|
+
# Must start with a letter, contain only alphanumeric, underscore, hyphen, dot
|
|
226
|
+
# This matches typical identifiers: PascalCase, camelCase, snake_case, kebab-case
|
|
227
|
+
return bool(re.match(r'^[A-Za-z][A-Za-z0-9_\-\.]*$', s))
|
|
228
|
+
|
|
229
|
+
if not all(is_valid_discriminator(v) for v in values):
|
|
222
230
|
continue
|
|
223
231
|
|
|
224
232
|
# Single cluster with multiple values - check if values create distinct groups
|
|
@@ -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
|
+
Version: 3.4.0
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{structurize-3.3.1 → structurize-3.4.0}/avrotize/dependencies/typescript/node22/package.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|