Description
sanitize_for_json in server.py:74-83 recursively walks objects but has no cycle detection. If an sktime estimator contains circular references in its attributes (some do via parent/child pointers), this causes RecursionError and crashes the MCP server.
def sanitize_for_json(obj):
if isinstance(obj, dict):
return {str(k): sanitize_for_json(v) for k, v in obj.items()} # no cycle check
elif isinstance(obj, (list, tuple)):
return [sanitize_for_json(item) for item in obj] # no cycle check
The hasattr(obj, "__dict__") fallback on line 81 catches most non-dict/list objects by converting to str(), but dict/list cycles are uncaught.
How to reproduce
Any tool returning a result containing a circular reference will trigger this. Likely scenario: an estimator with a parent attribute pointing back to a container.
Suggested fix
Track visited objects by id():
def sanitize_for_json(obj, _seen=None):
if _seen is None:
_seen = set()
obj_id = id(obj)
if obj_id in _seen:
return str(obj)
_seen.add(obj_id)
if isinstance(obj, dict):
return {str(k): sanitize_for_json(v, _seen) for k, v in obj.items()}
...
Alternatively, wrap the top-level call in try/except RecursionError.
Found while reading the codebase for PR #114 work.
Description
sanitize_for_jsoninserver.py:74-83recursively walks objects but has no cycle detection. If an sktime estimator contains circular references in its attributes (some do via parent/child pointers), this causesRecursionErrorand crashes the MCP server.The
hasattr(obj, "__dict__")fallback on line 81 catches most non-dict/list objects by converting tostr(), but dict/list cycles are uncaught.How to reproduce
Any tool returning a result containing a circular reference will trigger this. Likely scenario: an estimator with a
parentattribute pointing back to a container.Suggested fix
Track visited objects by
id():Alternatively, wrap the top-level call in
try/except RecursionError.Found while reading the codebase for PR #114 work.