xovis-sdk 1.0.0-a13 → 1.0.0-a14
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.
- package/README.md +1 -1
- package/docs/index.md +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/smithery.yaml +2 -2
- package/src/xovis/mcp/server.py +40 -1
- package/uv.lock +1 -1
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
| **Core SDK** | **Integrations** | **Agentic Layer** |
|
|
6
6
|
|:---:|:---:|:---:|
|
|
7
|
-
| [](https://pypi.org/project/xovis-sdk/1.0.
|
|
7
|
+
| [](https://pypi.org/project/xovis-sdk/1.0.0a14/) | [](https://smithery.ai/server/xovis-sdk) | [](https://modelcontextprotocol.io/) |
|
|
8
8
|
| [](https://github.com/xovis-open-sdk/xovis-sdk) | [](https://openai.com/) | [](https://langchain.com/) |
|
|
9
9
|
| [](https://opensource.org/licenses/MIT) | [](https://www.anthropic.com/) | [](https://crewai.com/) |
|
|
10
10
|
| [](https://badge.fury.io/js/xovis-sdk) | [](https://smithery.ai/server/xovis-sdk) | [](https://cursor.sh/) |
|
package/docs/index.md
CHANGED
|
@@ -5,7 +5,7 @@ Welcome to the **xovis-sdk** documentation. This is an enterprise-grade, high-pe
|
|
|
5
5
|
Compliance Note: This project is an independent, open-source initiative. It is not officially affiliated with, maintained by, or endorsed by Xovis AG.
|
|
6
6
|
|
|
7
7
|
[](https://github.com/xovis-open-sdk/xovis-sdk)
|
|
8
|
-
[](https://pypi.org/project/xovis-sdk/1.0.
|
|
8
|
+
[](https://pypi.org/project/xovis-sdk/1.0.0a14/)
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
[](https://modelcontextprotocol.io/)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xovis-sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.0a14",
|
|
4
4
|
"description": "Unofficial Xovis Hardware integration via MCP. Features zero-trust format-preserving pseudonymization (AIPrivacySession) and human-in-the-loop safety guardrails (XovisSafetyGuardrail) for critical operations.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"xovis",
|
package/pyproject.toml
CHANGED
package/smithery.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
name: xovis-mcp
|
|
2
2
|
displayName: Xovis SDK MCP Server
|
|
3
3
|
description: Unofficial Xovis Hardware integration via MCP. Features zero-trust format-preserving pseudonymization (AIPrivacySession) and human-in-the-loop safety guardrails (XovisSafetyGuardrail) for critical operations.
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.0a14
|
|
5
5
|
homepage: https://github.com/xovis-open-sdk/xovis-sdk
|
|
6
6
|
category: Data
|
|
7
7
|
categories:
|
|
@@ -48,7 +48,7 @@ startCommand:
|
|
|
48
48
|
command: 'uvx',
|
|
49
49
|
args: [
|
|
50
50
|
'-q',
|
|
51
|
-
'--from', 'xovis-sdk[mcp]==1.0.
|
|
51
|
+
'--from', 'xovis-sdk[mcp]==1.0.0a14',
|
|
52
52
|
'xovis-mcp'
|
|
53
53
|
],
|
|
54
54
|
env: {
|
package/src/xovis/mcp/server.py
CHANGED
|
@@ -49,6 +49,42 @@ def _get_active_client_context() -> Union[DeviceClient, HubClient]:
|
|
|
49
49
|
)
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def _normalize_schema(schema: Any) -> Any:
|
|
53
|
+
"""
|
|
54
|
+
Recursively normalizes Pydantic JSON schemas to strict Draft 7 format required by Anthropic/Smithery.
|
|
55
|
+
Strips 'anyOf' and enforces strict 'type' parameters.
|
|
56
|
+
"""
|
|
57
|
+
if isinstance(schema, dict):
|
|
58
|
+
if "anyOf" in schema:
|
|
59
|
+
types = []
|
|
60
|
+
for sub in schema.pop("anyOf"):
|
|
61
|
+
if isinstance(sub, dict) and "type" in sub:
|
|
62
|
+
if isinstance(sub["type"], list):
|
|
63
|
+
types.extend(sub["type"])
|
|
64
|
+
else:
|
|
65
|
+
types.append(sub["type"])
|
|
66
|
+
if types:
|
|
67
|
+
types = list(set(types))
|
|
68
|
+
schema["type"] = types[0] if len(types) == 1 else types
|
|
69
|
+
|
|
70
|
+
# Ensure all object properties have a type if they are properties
|
|
71
|
+
if "properties" in schema and isinstance(schema["properties"], dict):
|
|
72
|
+
for prop_name, prop_val in schema["properties"].items():
|
|
73
|
+
if isinstance(prop_val, dict):
|
|
74
|
+
if "type" not in prop_val and "anyOf" not in prop_val and "$ref" not in prop_val:
|
|
75
|
+
prop_val["type"] = "object"
|
|
76
|
+
|
|
77
|
+
# Recurse into all dictionary values
|
|
78
|
+
for key, value in schema.items():
|
|
79
|
+
schema[key] = _normalize_schema(value)
|
|
80
|
+
|
|
81
|
+
elif isinstance(schema, list):
|
|
82
|
+
for i, item in enumerate(schema):
|
|
83
|
+
schema[i] = _normalize_schema(item)
|
|
84
|
+
|
|
85
|
+
return schema
|
|
86
|
+
|
|
87
|
+
|
|
52
88
|
@server.list_tools()
|
|
53
89
|
async def handle_list_tools() -> list[Tool]:
|
|
54
90
|
"""
|
|
@@ -74,11 +110,14 @@ async def handle_list_tools() -> list[Tool]:
|
|
|
74
110
|
if safety_level:
|
|
75
111
|
description = f"[{safety_level.name}] {description}"
|
|
76
112
|
|
|
113
|
+
raw_schema = tool["args_model"].model_json_schema()
|
|
114
|
+
normalized_schema = _normalize_schema(raw_schema)
|
|
115
|
+
|
|
77
116
|
mcp_tools.append(
|
|
78
117
|
Tool(
|
|
79
118
|
name=tool["name"],
|
|
80
119
|
description=description,
|
|
81
|
-
inputSchema=
|
|
120
|
+
inputSchema=normalized_schema,
|
|
82
121
|
)
|
|
83
122
|
)
|
|
84
123
|
return mcp_tools
|