Skip to content

Commit d4ec62d

Browse files
committed
feat(cluster): add MCP server to work with Platform
1 parent 8f036ff commit d4ec62d

2 files changed

Lines changed: 67 additions & 0 deletions

File tree

setup.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
from setuptools import find_packages, setup
44

55
extras_require = {
6+
"mcp": [
7+
"mcp[cli]", # MCP Server & AI Computer Use
8+
],
69
"test": [ # `test` GitHub Action jobs uses this
710
"pytest>=6.0", # Core testing package
811
"pytest-xdist", # Multi-process runner
@@ -44,6 +47,7 @@
4447
+ extras_require["doc"]
4548
+ extras_require["release"]
4649
+ extras_require["dev"]
50+
+ extras_require["mcp"]
4751
)
4852

4953
with open("./README.md") as readme:

silverback/cluster/mcp.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
from collections.abc import AsyncIterator
2+
from contextlib import asynccontextmanager
3+
from dataclasses import dataclass
4+
5+
from fief_client import Fief
6+
from fief_client.integrations.cli import FiefAuth
7+
from mcp.server.fastmcp import Context, FastMCP
8+
9+
from silverback.cluster.client import PlatformClient
10+
from silverback.cluster.settings import PROFILE_PATH, PlatformProfile, ProfileSettings
11+
from silverback.cluster.types import ClusterHealth
12+
13+
14+
@dataclass
15+
class AppContext:
16+
platform: PlatformClient
17+
18+
19+
@asynccontextmanager
20+
async def lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
21+
settings = ProfileSettings.from_config_file()
22+
23+
# TODO: Allow loading arbitrary profiles
24+
profile = settings.profile["staging"]
25+
assert isinstance(profile, PlatformProfile)
26+
27+
auth = FiefAuth(
28+
Fief(
29+
settings.auth[profile.auth].host,
30+
settings.auth[profile.auth].client_id,
31+
),
32+
str(PROFILE_PATH.parent / f"{profile.auth}.json"),
33+
)
34+
platform = PlatformClient(
35+
base_url=profile.host,
36+
cookies=dict(session=auth.access_token_info()["access_token"]),
37+
)
38+
yield AppContext(platform=platform)
39+
40+
41+
mcp = FastMCP("silverback", dependencies=["silverback"], lifespan=lifespan)
42+
43+
44+
@mcp.resource("workspace://")
45+
def list_workspaces(ctx: Context) -> list[str]:
46+
"""Get the list of all available Workspaces"""
47+
platform = ctx.request_context.lifespan_context["platform"]
48+
return list(platform.workspaces)
49+
50+
51+
@mcp.resource("workspace://{workspace_name}")
52+
def list_clusters(workspace_name: str, ctx: Context) -> list[str]:
53+
"""Get the list of all Cluster names in a specific Workspace."""
54+
platform = ctx.request_context.lifespan_context["platform"]
55+
return list(platform.workspaces[workspace_name].clusters)
56+
57+
58+
@mcp.resource("cluster://{workspace_name}/{cluster_name}/health")
59+
def cluster_health(workspace_name: str, cluster_name: str, ctx: Context) -> ClusterHealth:
60+
"""Obtain the health of Bots and Networks in connected Cluster."""
61+
platform = ctx.request_context.lifespan_context["platform"]
62+
cluster = platform.get_cluster_client(workspace_name, cluster_name)
63+
return cluster.health

0 commit comments

Comments
 (0)