dtlpymcp 0.1.10__py3-none-any.whl → 0.1.11__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.
dtlpymcp/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from .utils.dtlpy_context import DataloopContext, MCPSource
2
2
 
3
- __version__ = "0.1.10"
3
+ __version__ = "0.1.11"
dtlpymcp/min_proxy.py CHANGED
@@ -28,7 +28,7 @@ def create_dataloop_mcp_server() -> FastMCP:
28
28
  log_level="DEBUG",
29
29
  )
30
30
  tool_name = "test"
31
- input_schema = {"properties": {"ping": {"type": "string", "default": "pong"}}, "required": ["ping"]}
31
+ input_schema = {"type": "object", "properties": {"ping": {"type": "string", "default": "pong"}}, "required": ["ping"]}
32
32
  # Create Dataloop context
33
33
  dynamic_pydantic_model_params = DataloopContext.build_pydantic_fields_from_schema(input_schema)
34
34
  arguments_model = create_model(f"{tool_name}Arguments", **dynamic_pydantic_model_params, __base__=ArgModelBase)
dtlpymcp/proxy.py CHANGED
@@ -118,7 +118,7 @@ def create_dataloop_mcp_server(sources_file: Optional[str] = None, init_timeout:
118
118
  return result
119
119
 
120
120
  tool_name = "test"
121
- input_schema = {"properties": {"ping": {"type": "string"}}, "required": ["ping"]}
121
+ input_schema = {"type": "object", "properties": {"ping": {"type": "string"}}, "required": ["ping"]}
122
122
  dynamic_pydantic_model_params = DataloopContext.build_pydantic_fields_from_schema(input_schema)
123
123
  arguments_model = create_model(f"{tool_name}Arguments", **dynamic_pydantic_model_params, __base__=ArgModelBase)
124
124
  resp = FuncMetadata(arg_model=arguments_model)
@@ -95,6 +95,10 @@ class DataloopContext:
95
95
  ns_tool_name = f"{server_name}.{tool_name}"
96
96
  description = tool.description
97
97
  input_schema = tool.inputSchema
98
+
99
+ # Normalize input schema to ensure it has "type": "object" at root level
100
+ # This is required by the MCP specification
101
+ input_schema = self.normalize_input_schema(input_schema)
98
102
 
99
103
  def build_handler(tool_name):
100
104
  async def inner(**kwargs):
@@ -230,6 +234,36 @@ class DataloopContext:
230
234
  logger.info(f"Discovered {len(tools.tools)} tools for source {source.dpk_name}")
231
235
  return (source.dpk_name, tools, call_fn)
232
236
 
237
+ @staticmethod
238
+ def normalize_input_schema(input_schema: dict) -> dict:
239
+ """
240
+ Normalize input schema to ensure it conforms to MCP specification.
241
+ The schema must have "type": "object" at the root level.
242
+ """
243
+ if not isinstance(input_schema, dict):
244
+ return {"type": "object", "properties": {}, "required": []}
245
+
246
+ # Create a copy to avoid mutating the original
247
+ normalized = input_schema.copy()
248
+
249
+ # Ensure type is "object" at root level
250
+ if "type" not in normalized:
251
+ normalized["type"] = "object"
252
+ elif normalized.get("type") != "object":
253
+ # If type exists but isn't "object", log a warning and fix it
254
+ logger.warning(f"Input schema has type '{normalized.get('type')}' instead of 'object', fixing...")
255
+ normalized["type"] = "object"
256
+
257
+ # Ensure properties exist
258
+ if "properties" not in normalized:
259
+ normalized["properties"] = {}
260
+
261
+ # Ensure required exists (can be empty list)
262
+ if "required" not in normalized:
263
+ normalized["required"] = []
264
+
265
+ return normalized
266
+
233
267
  @staticmethod
234
268
  def openapi_type_to_python(type_str):
235
269
  return {"string": str, "integer": int, "number": float, "boolean": bool, "array": list, "object": dict}.get(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dtlpymcp
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: STDIO MCP proxy server for Dataloop platform.
5
5
  Author-email: Your Name <your.email@example.com>
6
6
  Classifier: Programming Language :: Python :: 3.10
@@ -0,0 +1,10 @@
1
+ dtlpymcp/__init__.py,sha256=-iPfWD7k43HTz0akAm7BHONlJipmtYiMjmF1CCEj0us,87
2
+ dtlpymcp/__main__.py,sha256=ZsXN8guga8Qo-94bSvgC6u9s5gmmdyppUijb-_bCxCw,1347
3
+ dtlpymcp/min_proxy.py,sha256=QYGoqclGNN7ZMjoLzWBLCxUm4yT2xCoLTbtdFRsqlEk,2572
4
+ dtlpymcp/proxy.py,sha256=IzZrK6s37sXM-AM2L2m_K9AveT7uX_VSxwgrwggJYV4,6213
5
+ dtlpymcp/utils/dtlpy_context.py,sha256=6ad136vmk0Cstp10cAcY6YaZkUTgFzyvMlocIP6DwiE,12112
6
+ dtlpymcp-0.1.11.dist-info/METADATA,sha256=G895DOpzSG2bf9EzmzGIIO2MJgH0RtX6W48Z_eXqnRU,2190
7
+ dtlpymcp-0.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
+ dtlpymcp-0.1.11.dist-info/entry_points.txt,sha256=6hRVZNTjQevj7erwt9dAOURtPVrSrYu6uHXhAlhTaXQ,52
9
+ dtlpymcp-0.1.11.dist-info/top_level.txt,sha256=z85v20pIEnY3cBaWgwhU3EZS4WAZRywejhIutwd-iHk,9
10
+ dtlpymcp-0.1.11.dist-info/RECORD,,
@@ -1,10 +0,0 @@
1
- dtlpymcp/__init__.py,sha256=H33i9m9ILJX_o4GWGWBcCT_QoijFOU38yXubkbRRoYQ,87
2
- dtlpymcp/__main__.py,sha256=ZsXN8guga8Qo-94bSvgC6u9s5gmmdyppUijb-_bCxCw,1347
3
- dtlpymcp/min_proxy.py,sha256=n9KzWwaGU-8uUKRJigGHAnyZ6GXfNl5bwMpULfBrbEc,2554
4
- dtlpymcp/proxy.py,sha256=5r6T6kKo_liZI-5I0P7D8RaShvVTcsAOVZvnbPjJCDc,6195
5
- dtlpymcp/utils/dtlpy_context.py,sha256=qeKwptMx_fenYTRs5-l3711yPyo2iof_FoQX8jM3fmE,10670
6
- dtlpymcp-0.1.10.dist-info/METADATA,sha256=EA20TrysTutuhcOb-UG-7E1rDxW0WqoWd-0wMYP6880,2190
7
- dtlpymcp-0.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
8
- dtlpymcp-0.1.10.dist-info/entry_points.txt,sha256=6hRVZNTjQevj7erwt9dAOURtPVrSrYu6uHXhAlhTaXQ,52
9
- dtlpymcp-0.1.10.dist-info/top_level.txt,sha256=z85v20pIEnY3cBaWgwhU3EZS4WAZRywejhIutwd-iHk,9
10
- dtlpymcp-0.1.10.dist-info/RECORD,,