orb-cloud-mcp 0.1.0__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.
- orb_cloud_mcp/__init__.py +3 -0
- orb_cloud_mcp/cache.py +25 -0
- orb_cloud_mcp/client.py +20 -0
- orb_cloud_mcp/py.typed +0 -0
- orb_cloud_mcp/server.py +43 -0
- orb_cloud_mcp/tools/__init__.py +0 -0
- orb_cloud_mcp/tools/datasets.py +108 -0
- orb_cloud_mcp/tools/devices.py +138 -0
- orb_cloud_mcp/tools/organizations.py +57 -0
- orb_cloud_mcp/tools/speedtest.py +20 -0
- orb_cloud_mcp-0.1.0.dist-info/METADATA +12 -0
- orb_cloud_mcp-0.1.0.dist-info/RECORD +14 -0
- orb_cloud_mcp-0.1.0.dist-info/WHEEL +4 -0
- orb_cloud_mcp-0.1.0.dist-info/entry_points.txt +3 -0
orb_cloud_mcp/cache.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Shared TTL cache for stable Orb Cloud API responses."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from cachetools import TTLCache
|
|
6
|
+
|
|
7
|
+
_DEFAULT_TTL = 300 # seconds
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _ttl() -> int:
|
|
11
|
+
return int(os.environ.get("ORB_CLOUD_CACHE_TTL", _DEFAULT_TTL))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# Module-level cache shared across tools. Sized generously; in practice only a
|
|
15
|
+
# handful of organizations and their device lists will ever be stored.
|
|
16
|
+
cache: TTLCache = TTLCache(maxsize=256, ttl=_ttl())
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def cache_key(*args: object) -> tuple:
|
|
20
|
+
"""Build a cache key scoped to the current API token.
|
|
21
|
+
|
|
22
|
+
The token is hashed so it is never stored in plaintext as a dict key,
|
|
23
|
+
preventing accidental exposure in logs or debug output.
|
|
24
|
+
"""
|
|
25
|
+
return (hash(os.environ.get("ORB_CLOUD_API_KEY")), *args)
|
orb_cloud_mcp/client.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Orb Cloud client factory, reads credentials from environment."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
from orb_cloud_client.client import OrbCloudClientAsync
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_client() -> OrbCloudClientAsync:
|
|
9
|
+
"""Return an authenticated async Orb Cloud client.
|
|
10
|
+
|
|
11
|
+
Raises:
|
|
12
|
+
RuntimeError: If ORB_CLOUD_API_KEY is not set.
|
|
13
|
+
"""
|
|
14
|
+
token = os.environ.get("ORB_CLOUD_API_KEY")
|
|
15
|
+
if not token:
|
|
16
|
+
raise RuntimeError(
|
|
17
|
+
"ORB_CLOUD_API_KEY environment variable is not set. "
|
|
18
|
+
"Set it to your Orb Cloud API token."
|
|
19
|
+
)
|
|
20
|
+
return OrbCloudClientAsync(token=token)
|
orb_cloud_mcp/py.typed
ADDED
|
File without changes
|
orb_cloud_mcp/server.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"""FastMCP server for Orb Cloud."""
|
|
2
|
+
|
|
3
|
+
from fastmcp import FastMCP
|
|
4
|
+
|
|
5
|
+
from orb_cloud_mcp.tools.organizations import list_organizations
|
|
6
|
+
from orb_cloud_mcp.tools.devices import list_devices, get_device_telemetry
|
|
7
|
+
from orb_cloud_mcp.tools.speedtest import trigger_speedtest
|
|
8
|
+
from orb_cloud_mcp.tools.datasets import configure_temp_datasets
|
|
9
|
+
|
|
10
|
+
mcp = FastMCP(
|
|
11
|
+
name="orb-cloud",
|
|
12
|
+
instructions="Manage Orb Cloud devices, organizations, and run diagnostics.",
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# --- Tools ---
|
|
16
|
+
|
|
17
|
+
mcp.tool()(list_organizations)
|
|
18
|
+
mcp.tool()(list_devices)
|
|
19
|
+
mcp.tool()(get_device_telemetry)
|
|
20
|
+
mcp.tool()(trigger_speedtest)
|
|
21
|
+
mcp.tool()(configure_temp_datasets)
|
|
22
|
+
|
|
23
|
+
# --- Resources ---
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@mcp.resource("orb://organizations")
|
|
27
|
+
async def resource_organizations() -> list:
|
|
28
|
+
"""All Orb Cloud organizations accessible with the configured API key."""
|
|
29
|
+
return await list_organizations()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@mcp.resource("orb://organizations/{organization_id}/devices")
|
|
33
|
+
async def resource_devices(organization_id: str) -> list:
|
|
34
|
+
"""Stable configuration details for all devices in an Orb Cloud organization."""
|
|
35
|
+
return await list_devices(organization_id)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def main() -> None:
|
|
39
|
+
mcp.run()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
if __name__ == "__main__":
|
|
43
|
+
main()
|
|
File without changes
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""MCP tool to configure temporary dataset push on Orb Cloud devices."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from pydantic import BaseModel, Field
|
|
6
|
+
|
|
7
|
+
from orb_cloud_mcp.client import get_client
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DataPushConfig(BaseModel):
|
|
11
|
+
"""Configuration for pushing data to a custom HTTP endpoint."""
|
|
12
|
+
|
|
13
|
+
url: str = Field(..., description="Destination URL to push data to.")
|
|
14
|
+
datasets: list[str] | None = Field(
|
|
15
|
+
None,
|
|
16
|
+
description="Dataset names to include (e.g. ['responsiveness_1s', 'speed_results']).",
|
|
17
|
+
)
|
|
18
|
+
enabled: bool | None = Field(None, description="Whether pushing is enabled.")
|
|
19
|
+
identifiable: bool | None = Field(
|
|
20
|
+
None, description="Whether to include identifiable data."
|
|
21
|
+
)
|
|
22
|
+
format: str | None = Field(None, description="Payload format (e.g. 'json').")
|
|
23
|
+
interval_ms: int | None = Field(None, description="Push interval in milliseconds.")
|
|
24
|
+
buffer_kb: int | None = Field(None, description="Buffer size in kilobytes.")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DataAPIConfig(BaseModel):
|
|
28
|
+
"""Configuration for exposing a local data API on the device."""
|
|
29
|
+
|
|
30
|
+
enabled: bool | None = Field(None, description="Whether the data API is enabled.")
|
|
31
|
+
datasets: list[str] | None = Field(
|
|
32
|
+
None, description="Dataset names to expose via the API."
|
|
33
|
+
)
|
|
34
|
+
identifiable: bool | None = Field(
|
|
35
|
+
None, description="Whether to include identifiable data."
|
|
36
|
+
)
|
|
37
|
+
api_key: str | None = Field(None, description="API key for the local data API.")
|
|
38
|
+
port: int | None = Field(None, description="Port for the local data API.")
|
|
39
|
+
buffer: int | None = Field(None, description="Buffer size.")
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class DatasetsConfig(BaseModel):
|
|
43
|
+
"""Top-level dataset configuration."""
|
|
44
|
+
|
|
45
|
+
datasets: list[str] | None = Field(None, description="Dataset names to collect.")
|
|
46
|
+
enabled: bool | None = Field(
|
|
47
|
+
None, description="Whether data collection is enabled."
|
|
48
|
+
)
|
|
49
|
+
push: DataPushConfig | None = Field(
|
|
50
|
+
None, description="Push data to a custom HTTP endpoint."
|
|
51
|
+
)
|
|
52
|
+
cloud_push: DataPushConfig | None = Field(
|
|
53
|
+
None, description="Push data to Orb Cloud."
|
|
54
|
+
)
|
|
55
|
+
api: DataAPIConfig | None = Field(
|
|
56
|
+
None, description="Expose data via a local API endpoint on the device."
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
async def configure_temp_datasets(
|
|
61
|
+
device_id: str,
|
|
62
|
+
duration: str = Field(
|
|
63
|
+
..., description="How long to enable (e.g. '30m', '1h', '2h')."
|
|
64
|
+
),
|
|
65
|
+
datasets_config: DatasetsConfig | None = None,
|
|
66
|
+
) -> dict[str, Any]:
|
|
67
|
+
"""Configure temporary dataset collection and push for an Orb Cloud device.
|
|
68
|
+
|
|
69
|
+
Enables the device to push data to a custom endpoint or expose a local API
|
|
70
|
+
for a fixed duration. After the duration expires, the device reverts to its
|
|
71
|
+
default configuration.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
device_id: The Orb device ID to configure.
|
|
75
|
+
duration: How long to enable the configuration (e.g. '30m', '1h').
|
|
76
|
+
datasets_config: Dataset collection and push configuration. If omitted,
|
|
77
|
+
only the duration is updated.
|
|
78
|
+
"""
|
|
79
|
+
from orb_cloud_client.models.generic import TempDatasetsRequest
|
|
80
|
+
from orb_cloud_client.models.config import Datasets, DataPush, DataAPI
|
|
81
|
+
|
|
82
|
+
def _to_data_push(cfg: DataPushConfig | None) -> DataPush | None:
|
|
83
|
+
if cfg is None:
|
|
84
|
+
return None
|
|
85
|
+
return DataPush(**cfg.model_dump(exclude_none=True))
|
|
86
|
+
|
|
87
|
+
def _to_data_api(cfg: DataAPIConfig | None) -> DataAPI | None:
|
|
88
|
+
if cfg is None:
|
|
89
|
+
return None
|
|
90
|
+
return DataAPI(**cfg.model_dump(exclude_none=True))
|
|
91
|
+
|
|
92
|
+
sdk_datasets: Datasets | None = None
|
|
93
|
+
if datasets_config is not None:
|
|
94
|
+
sdk_datasets = Datasets(
|
|
95
|
+
datasets=datasets_config.datasets,
|
|
96
|
+
enabled=datasets_config.enabled,
|
|
97
|
+
push=_to_data_push(datasets_config.push),
|
|
98
|
+
cloud_push=_to_data_push(datasets_config.cloud_push),
|
|
99
|
+
api=_to_data_api(datasets_config.api),
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
request = TempDatasetsRequest(
|
|
103
|
+
duration=duration,
|
|
104
|
+
datasets_config=sdk_datasets,
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
async with get_client() as client:
|
|
108
|
+
return await client.configure_temporary_datasets(device_id, request)
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"""MCP tools for Orb Cloud devices."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from orb_cloud_client.models.generic import Device, OrbScore
|
|
6
|
+
|
|
7
|
+
from orb_cloud_mcp.cache import cache, cache_key
|
|
8
|
+
from orb_cloud_mcp.client import get_client
|
|
9
|
+
|
|
10
|
+
_CACHE_KEY = "list_devices"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def list_devices(organization_id: str) -> list[dict[str, Any]]:
|
|
14
|
+
"""List devices in an Orb Cloud organization with stable configuration details.
|
|
15
|
+
|
|
16
|
+
Returns device identity, hardware info, location, and configuration — data
|
|
17
|
+
that changes rarely. For real-time connectivity and performance scores, use
|
|
18
|
+
get_device_telemetry instead.
|
|
19
|
+
|
|
20
|
+
Args:
|
|
21
|
+
organization_id: The organization ID to list devices for.
|
|
22
|
+
"""
|
|
23
|
+
key = cache_key(_CACHE_KEY, organization_id)
|
|
24
|
+
if key in cache:
|
|
25
|
+
return cache[key]
|
|
26
|
+
|
|
27
|
+
async with get_client() as client:
|
|
28
|
+
devices = await client.get_organization_devices(organization_id)
|
|
29
|
+
result = [_serialize_stable(d) for d in devices]
|
|
30
|
+
cache[key] = result
|
|
31
|
+
return result
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def get_device_telemetry(
|
|
35
|
+
organization_id: str,
|
|
36
|
+
device_id: str | None = None,
|
|
37
|
+
) -> list[dict[str, Any]]:
|
|
38
|
+
"""Get live telemetry for devices in an Orb Cloud organization.
|
|
39
|
+
|
|
40
|
+
Returns real-time connectivity status and Orb performance scores. If
|
|
41
|
+
device_id is provided, returns telemetry for that device only.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
organization_id: The organization ID to query devices for.
|
|
45
|
+
device_id: Optional Orb device ID to filter to a single device.
|
|
46
|
+
"""
|
|
47
|
+
async with get_client() as client:
|
|
48
|
+
devices = await client.get_organization_devices(organization_id)
|
|
49
|
+
|
|
50
|
+
if device_id is not None:
|
|
51
|
+
devices = [d for d in devices if d.orb_id == device_id]
|
|
52
|
+
|
|
53
|
+
return [_serialize_telemetry(d) for d in devices]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _serialize_score(score: OrbScore | None) -> dict[str, Any] | None:
|
|
57
|
+
if score is None:
|
|
58
|
+
return None
|
|
59
|
+
result: dict[str, Any] = {
|
|
60
|
+
"score": score.score,
|
|
61
|
+
"display": score.display,
|
|
62
|
+
"included": score.included,
|
|
63
|
+
"value": score.value,
|
|
64
|
+
"duration_ms": score.duration_ms,
|
|
65
|
+
"score_version": score.score_version,
|
|
66
|
+
}
|
|
67
|
+
if score.components:
|
|
68
|
+
result["components"] = {
|
|
69
|
+
k: _serialize_score(v) for k, v in score.components.items()
|
|
70
|
+
}
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def _serialize_stable(device: Device) -> dict[str, Any]:
|
|
75
|
+
"""Serialize the stable, slowly-changing fields of a device."""
|
|
76
|
+
info: dict[str, Any] = {}
|
|
77
|
+
if device.summary:
|
|
78
|
+
s = device.summary
|
|
79
|
+
info["firmware_version"] = s.version
|
|
80
|
+
if s.tags:
|
|
81
|
+
if s.tags.geoip:
|
|
82
|
+
g = s.tags.geoip
|
|
83
|
+
info["geoip"] = {
|
|
84
|
+
"city": g.city,
|
|
85
|
+
"state": g.state,
|
|
86
|
+
"country": g.country,
|
|
87
|
+
"country_code": g.country_code,
|
|
88
|
+
"isp_name": g.isp_name,
|
|
89
|
+
"latitude": g.latitude,
|
|
90
|
+
"longitude": g.longitude,
|
|
91
|
+
}
|
|
92
|
+
if s.tags.device_info:
|
|
93
|
+
di = s.tags.device_info
|
|
94
|
+
info["device_info"] = {
|
|
95
|
+
"name": di.name,
|
|
96
|
+
"full_name": di.full_name,
|
|
97
|
+
"version": di.version,
|
|
98
|
+
"cpu_count": di.cpu_count,
|
|
99
|
+
"operating_system": di.operating_system,
|
|
100
|
+
}
|
|
101
|
+
if s.tags.network_interface:
|
|
102
|
+
ni = s.tags.network_interface
|
|
103
|
+
info["network_interface"] = {
|
|
104
|
+
"name": ni.name,
|
|
105
|
+
"type": ni.type,
|
|
106
|
+
"local_ip": ni.local_ip,
|
|
107
|
+
"mac_address": ni.mac_address,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
"orb_id": device.orb_id,
|
|
112
|
+
"name": device.name,
|
|
113
|
+
"can_notify": device.can_notify,
|
|
114
|
+
"tags": device.tags,
|
|
115
|
+
"config": device.config,
|
|
116
|
+
"created_ts": device.created_ts,
|
|
117
|
+
**info,
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def _serialize_telemetry(device: Device) -> dict[str, Any]:
|
|
122
|
+
"""Serialize the live, frequently-changing fields of a device."""
|
|
123
|
+
scores: dict[str, Any] = {}
|
|
124
|
+
if device.summary:
|
|
125
|
+
s = device.summary
|
|
126
|
+
scores["summary_ts"] = s.created_ts
|
|
127
|
+
if s.orb_score:
|
|
128
|
+
scores["orb_score"] = _serialize_score(s.orb_score)
|
|
129
|
+
if s.orb_scores:
|
|
130
|
+
scores["orb_scores"] = [_serialize_score(sc) for sc in s.orb_scores]
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
"orb_id": device.orb_id,
|
|
134
|
+
"name": device.name,
|
|
135
|
+
"is_connected": device.is_connected.value,
|
|
136
|
+
"is_connected_updated_at": device.is_connected_updated_at,
|
|
137
|
+
**scores,
|
|
138
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"""MCP tools and resources for Orb Cloud organizations."""
|
|
2
|
+
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from orb_cloud_client.models.server import OrganizationsResponse
|
|
6
|
+
|
|
7
|
+
from orb_cloud_mcp.cache import cache, cache_key
|
|
8
|
+
from orb_cloud_mcp.client import get_client
|
|
9
|
+
|
|
10
|
+
_CACHE_KEY = "list_organizations"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async def list_organizations() -> list[dict[str, Any]]:
|
|
14
|
+
"""List all Orb Cloud organizations accessible with the configured API key."""
|
|
15
|
+
key = cache_key(_CACHE_KEY)
|
|
16
|
+
if key in cache:
|
|
17
|
+
return cache[key]
|
|
18
|
+
|
|
19
|
+
async with get_client() as client:
|
|
20
|
+
orgs = await client.get_organizations()
|
|
21
|
+
result = [_serialize_org(o) for o in orgs]
|
|
22
|
+
cache[key] = result
|
|
23
|
+
return result
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _serialize_org(org: OrganizationsResponse) -> dict[str, Any]:
|
|
27
|
+
plan = None
|
|
28
|
+
if org.plan:
|
|
29
|
+
limits = None
|
|
30
|
+
if org.plan.limits:
|
|
31
|
+
limits = {
|
|
32
|
+
"devices": org.plan.limits.devices,
|
|
33
|
+
"users": org.plan.limits.users,
|
|
34
|
+
"deployment_tokens": org.plan.limits.deployment_tokens,
|
|
35
|
+
}
|
|
36
|
+
plan = {
|
|
37
|
+
"name": org.plan.name,
|
|
38
|
+
"features": org.plan.features,
|
|
39
|
+
"limits": limits,
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
usage = None
|
|
43
|
+
if org.usage:
|
|
44
|
+
usage = {
|
|
45
|
+
"devices": org.usage.devices,
|
|
46
|
+
"users": org.usage.users,
|
|
47
|
+
"deployment_tokens": org.usage.deployment_tokens,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
"organization_id": org.organization_id,
|
|
52
|
+
"name": org.name,
|
|
53
|
+
"customer_id": org.customer_id,
|
|
54
|
+
"subscription_id": org.subscription_id,
|
|
55
|
+
"plan": plan,
|
|
56
|
+
"usage": usage,
|
|
57
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""MCP tool to trigger speed tests on Orb Cloud devices."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal
|
|
4
|
+
|
|
5
|
+
from orb_cloud_mcp.client import get_client
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
async def trigger_speedtest(
|
|
9
|
+
device_id: str,
|
|
10
|
+
test_type: Literal["content", "top"],
|
|
11
|
+
) -> dict[str, Any]:
|
|
12
|
+
"""Trigger a speed test on an Orb Cloud device.
|
|
13
|
+
|
|
14
|
+
Args:
|
|
15
|
+
device_id: The Orb device ID to run the speed test on.
|
|
16
|
+
test_type: The type of speed test — 'content' measures content delivery
|
|
17
|
+
performance, 'top' measures peak throughput.
|
|
18
|
+
"""
|
|
19
|
+
async with get_client() as client:
|
|
20
|
+
return await client.trigger_speedtest(device_id, test_type)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: orb-cloud-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: MCP server for Orb Cloud device management and data analysis
|
|
5
|
+
Author: Brian Connelly
|
|
6
|
+
Author-email: Brian Connelly <bdc@bconnelly.net>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
Requires-Dist: cachetools>=7.0.4
|
|
9
|
+
Requires-Dist: fastmcp>=2.0
|
|
10
|
+
Requires-Dist: orb-cloud-client>=1.3.3
|
|
11
|
+
Requires-Dist: pydantic>=2.0
|
|
12
|
+
Requires-Python: >=3.10
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
orb_cloud_mcp/__init__.py,sha256=iwtL2XPlsOy5MtEiGxCo2RlWFykz_dN8mE9j92hblV4,73
|
|
2
|
+
orb_cloud_mcp/cache.py,sha256=pbEIlyf6gGVYPZ7UuiQOiuDfU4FyK8HcRHU8km0Pvxc,731
|
|
3
|
+
orb_cloud_mcp/client.py,sha256=m_gjsp_tTuxtay2C-rNMJ1u3_nqoblqZreoaiYO61MI,574
|
|
4
|
+
orb_cloud_mcp/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
orb_cloud_mcp/server.py,sha256=d_DU7v65X1iz4OYgEW0FzA4E-C_O__gV5aOL0mRshvs,1177
|
|
6
|
+
orb_cloud_mcp/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
|
+
orb_cloud_mcp/tools/datasets.py,sha256=x0cvwbmw-Zxdg4dT9dRUKiPNrnVwrR-v1nIStnDcAzo,4087
|
|
8
|
+
orb_cloud_mcp/tools/devices.py,sha256=P3QkPkjCDsyP8Vc8gzkDdL-RAjP_7ZUoXFjBbvMCBJU,4555
|
|
9
|
+
orb_cloud_mcp/tools/organizations.py,sha256=CFnSkSa9-uWzH30vieDmdypFRFMPkie3CqQ2pfkZZww,1604
|
|
10
|
+
orb_cloud_mcp/tools/speedtest.py,sha256=skTpedUdS07ZHaFJ_MoXrbyDZvFNH5532gZ2fHNzcpI,632
|
|
11
|
+
orb_cloud_mcp-0.1.0.dist-info/WHEEL,sha256=mydTeHxOpFHo-DnYhAd_3ATePms-g4rrYvM7wJK8P-U,80
|
|
12
|
+
orb_cloud_mcp-0.1.0.dist-info/entry_points.txt,sha256=px4lDagsuu_DHSLjW0IaQ0qvkXLp-7Yff6CvYMddamg,61
|
|
13
|
+
orb_cloud_mcp-0.1.0.dist-info/METADATA,sha256=WpWZmZ_kiSF8H5A8J2Zr1zvQRg7a5UE_fbBC1PQk2Vw,376
|
|
14
|
+
orb_cloud_mcp-0.1.0.dist-info/RECORD,,
|