Skip to content

Commit ebda119

Browse files
edis-uipathclaude
andcommitted
chore: update uipath sdk to 2.8
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 93a4c2b commit ebda119

15 files changed

Lines changed: 687 additions & 1445 deletions

File tree

.vscode/settings.json

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
{
2+
"window.title": "${rootName}${separator}${activeEditorMedium}",
3+
"files.exclude": {
4+
"**/*.pyc": true,
5+
"**/__pycache__": true,
6+
".pytest_cache": true,
7+
".mypy_cache": true,
8+
".ruff_cache": true,
9+
".venv": true
10+
},
11+
"search.exclude": {
12+
"**/__pycache__": true,
13+
"**/*.pyc": true,
14+
".venv": true,
15+
".pytest_cache": true,
16+
".mypy_cache": true,
17+
".ruff_cache": true
18+
},
19+
// Formatting
20+
"editor.formatOnSave": true,
21+
"[python]": {
22+
"editor.defaultFormatter": "charliermarsh.ruff",
23+
"editor.codeActionsOnSave": {
24+
"source.organizeImports": "explicit"
25+
}
26+
},
27+
"workbench.colorCustomizations": {
28+
"titleBar.activeBackground": "#0099cc",
29+
"titleBar.inactiveBackground": "#0099cc"
30+
},
31+
"python.testing.pytestArgs": [
32+
"tests"
33+
],
34+
"python.testing.unittestEnabled": false,
35+
"python.testing.pytestEnabled": true
36+
}

pyproject.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
[project]
22
name = "uipath-mcp"
3-
version = "0.0.108"
3+
version = "0.0.109"
44
description = "UiPath MCP SDK"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"
77
dependencies = [
88
"mcp==1.24.0",
99
"pysignalr==1.3.0",
10-
"uipath>=2.1.108, <2.2.0",
10+
"uipath>=2.8.23, <2.9.0",
11+
"uipath-runtime>=0.8.0, <0.9.0",
1112
]
1213
classifiers = [
1314
"Development Status :: 3 - Alpha",
@@ -25,6 +26,9 @@ maintainers = [
2526
[project.entry-points."uipath.middlewares"]
2627
register = "uipath_mcp.middlewares:register_middleware"
2728

29+
[project.entry-points."uipath.runtime.factories"]
30+
mcp = "uipath_mcp._cli._runtime:register_runtime_factory"
31+
2832
[project.urls]
2933
Homepage = "https://uipath.com"
3034
Repository = "https://github.com/UiPath/uipath-mcp-python"
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""UiPath MCP Runtime package."""
2+
3+
from uipath.runtime import (
4+
UiPathRuntimeContext,
5+
UiPathRuntimeFactoryProtocol,
6+
UiPathRuntimeFactoryRegistry,
7+
)
8+
9+
from uipath_mcp._cli._runtime._factory import UiPathMcpRuntimeFactory
10+
from uipath_mcp._cli._runtime._runtime import UiPathMcpRuntime
11+
12+
13+
def register_runtime_factory() -> None:
14+
"""Register the MCP factory. Called automatically via entry point."""
15+
16+
def create_factory(
17+
context: UiPathRuntimeContext | None = None,
18+
) -> UiPathRuntimeFactoryProtocol:
19+
return UiPathMcpRuntimeFactory(
20+
context=context if context else UiPathRuntimeContext(),
21+
)
22+
23+
UiPathRuntimeFactoryRegistry.register("mcp", create_factory, "mcp.json")
24+
25+
26+
__all__ = [
27+
"register_runtime_factory",
28+
"UiPathMcpRuntimeFactory",
29+
"UiPathMcpRuntime",
30+
]

src/uipath_mcp/_cli/_runtime/_context.py

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,4 @@
11
from enum import Enum
2-
from typing import Optional
3-
4-
from uipath._cli._runtime._contracts import UiPathRuntimeContext
5-
6-
from .._utils._config import McpConfig
7-
8-
9-
class UiPathMcpRuntimeContext(UiPathRuntimeContext):
10-
"""Context information passed throughout the runtime execution."""
11-
12-
config: Optional[McpConfig] = None
13-
folder_key: Optional[str] = None
14-
server_id: Optional[str] = None
15-
server_slug: Optional[str] = None
16-
17-
@classmethod
18-
def from_config(
19-
cls, config_path: str | None = None, **kwargs: object
20-
) -> "UiPathMcpRuntimeContext":
21-
"""Load configuration from uipath.json file with MCP-specific handling."""
22-
# Use the parent's implementation
23-
instance = super().from_config(config_path, **kwargs)
24-
25-
# Convert to our type (since parent returns UiPathRuntimeContext)
26-
mcp_instance = cls(**instance.model_dump())
27-
28-
# Add AgentHub-specific configuration handling
29-
import json
30-
import os
31-
32-
path = config_path or "uipath.json"
33-
if os.path.exists(path):
34-
with open(path, "r") as f:
35-
config = json.load(f)
36-
37-
config_runtime = config.get("runtime", {})
38-
if "fpsContext" in config_runtime:
39-
fps_context = config_runtime["fpsContext"]
40-
mcp_instance.server_id = fps_context.get("Id")
41-
mcp_instance.server_slug = fps_context.get("Slug")
42-
return mcp_instance
432

443

454
class UiPathServerType(Enum):

src/uipath_mcp/_cli/_runtime/_exception.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from enum import Enum
22
from typing import Optional, Union
33

4-
from uipath._cli._runtime._contracts import (
4+
from uipath.runtime.errors import (
55
UiPathBaseRuntimeError,
66
UiPathErrorCategory,
77
UiPathErrorCode,
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
"""Factory for creating MCP runtime instances."""
2+
3+
import logging
4+
import uuid
5+
from typing import Any
6+
7+
from uipath.runtime import (
8+
UiPathRuntimeContext,
9+
UiPathRuntimeFactorySettings,
10+
UiPathRuntimeProtocol,
11+
)
12+
from uipath.runtime.errors import UiPathErrorCategory
13+
from uipath.runtime.storage import UiPathRuntimeStorageProtocol
14+
15+
from uipath_mcp._cli._runtime._exception import McpErrorCode, UiPathMcpRuntimeError
16+
from uipath_mcp._cli._runtime._runtime import UiPathMcpRuntime
17+
from uipath_mcp._cli._utils._config import McpConfig
18+
19+
logger = logging.getLogger(__name__)
20+
21+
22+
class UiPathMcpRuntimeFactory:
23+
"""Factory for creating MCP runtimes from mcp.json configuration."""
24+
25+
def __init__(
26+
self,
27+
context: UiPathRuntimeContext,
28+
):
29+
"""Initialize the factory.
30+
31+
Args:
32+
context: UiPathRuntimeContext to use for runtime creation.
33+
"""
34+
self.context = context
35+
self._mcp_config: McpConfig | None = None
36+
37+
def _load_mcp_config(self) -> McpConfig:
38+
"""Load mcp.json configuration."""
39+
if self._mcp_config is None:
40+
self._mcp_config = McpConfig()
41+
return self._mcp_config
42+
43+
def discover_entrypoints(self) -> list[str]:
44+
"""Discover all MCP server entrypoints.
45+
46+
Returns:
47+
List of server names that can be used as entrypoints.
48+
"""
49+
mcp_config = self._load_mcp_config()
50+
if not mcp_config.exists:
51+
return []
52+
return mcp_config.get_server_names()
53+
54+
async def discover_runtimes(self) -> list[UiPathRuntimeProtocol]:
55+
"""Discover runtime instances for all entrypoints.
56+
This is not running as part of a job, but is intended for the dev machine.
57+
58+
Returns:
59+
List of UiPathMcpRuntime instances, one per entrypoint.
60+
"""
61+
entrypoints = self.discover_entrypoints()
62+
runtimes: list[UiPathRuntimeProtocol] = []
63+
64+
for entrypoint in entrypoints:
65+
runtime = await self.new_runtime(entrypoint, entrypoint)
66+
runtimes.append(runtime)
67+
68+
return runtimes
69+
70+
async def new_runtime(
71+
self, entrypoint: str, runtime_id: str, **kwargs: Any
72+
) -> UiPathRuntimeProtocol:
73+
"""Create a new MCP runtime instance.
74+
75+
Args:
76+
entrypoint: Server name from mcp.json.
77+
runtime_id: Unique identifier for the runtime instance.
78+
79+
Returns:
80+
Configured UiPathMcpRuntime instance.
81+
82+
Raises:
83+
UiPathMcpRuntimeError: If configuration is invalid or server not found.
84+
"""
85+
mcp_config = self._load_mcp_config()
86+
87+
if not mcp_config.exists:
88+
raise UiPathMcpRuntimeError(
89+
McpErrorCode.CONFIGURATION_ERROR,
90+
"Invalid configuration",
91+
"mcp.json not found",
92+
UiPathErrorCategory.DEPLOYMENT,
93+
)
94+
95+
server = mcp_config.get_server(entrypoint)
96+
if not server:
97+
available = ", ".join(mcp_config.get_server_names())
98+
raise UiPathMcpRuntimeError(
99+
McpErrorCode.SERVER_NOT_FOUND,
100+
"MCP server not found",
101+
f"Server '{entrypoint}' not found. Available: {available}",
102+
UiPathErrorCategory.DEPLOYMENT,
103+
)
104+
105+
# Validate runtime_id is a valid UUID, generate new one if not
106+
try:
107+
uuid.UUID(runtime_id)
108+
except ValueError:
109+
runtime_id = str(uuid.uuid4())
110+
111+
return UiPathMcpRuntime(
112+
server=server,
113+
runtime_id=runtime_id,
114+
entrypoint=entrypoint,
115+
folder_key=self.context.folder_key,
116+
server_id=self.context.mcp_server_id,
117+
server_slug=self.context.mcp_server_slug,
118+
)
119+
120+
async def get_storage(self) -> UiPathRuntimeStorageProtocol | None:
121+
"""Get factory storage.
122+
123+
MCP servers are long-running processes and don't need
124+
cross-invocation state persistence.
125+
"""
126+
return None
127+
128+
async def get_settings(self) -> UiPathRuntimeFactorySettings | None:
129+
"""Get factory settings."""
130+
return None
131+
132+
async def dispose(self) -> None:
133+
"""Cleanup factory resources."""
134+
self._mcp_config = None

0 commit comments

Comments
 (0)