sitebay-mcp 0.1.1751285665__py3-none-any.whl → 0.1.1757492007__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.
- sitebay_mcp/__init__.py +2 -2
- sitebay_mcp/client.py +34 -48
- sitebay_mcp/resources.py +6 -50
- sitebay_mcp/server.py +263 -339
- sitebay_mcp/tools/operations.py +45 -129
- sitebay_mcp/tools/sites.py +94 -87
- {sitebay_mcp-0.1.1751285665.dist-info → sitebay_mcp-0.1.1757492007.dist-info}/METADATA +67 -31
- sitebay_mcp-0.1.1757492007.dist-info/RECORD +14 -0
- sitebay_mcp-0.1.1751285665.dist-info/RECORD +0 -14
- {sitebay_mcp-0.1.1751285665.dist-info → sitebay_mcp-0.1.1757492007.dist-info}/WHEEL +0 -0
- {sitebay_mcp-0.1.1751285665.dist-info → sitebay_mcp-0.1.1757492007.dist-info}/entry_points.txt +0 -0
- {sitebay_mcp-0.1.1751285665.dist-info → sitebay_mcp-0.1.1757492007.dist-info}/licenses/LICENSE +0 -0
sitebay_mcp/__init__.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
SiteBay MCP Server
|
3
3
|
|
4
4
|
Provides Model Context Protocol (MCP) integration for SiteBay WordPress hosting platform.
|
5
|
-
Allows Claude Code users to manage WordPress sites, execute commands,
|
5
|
+
Allows Claude Code users to manage WordPress sites, execute commands,
|
6
6
|
backups, and more through natural language interactions.
|
7
7
|
"""
|
8
8
|
|
@@ -12,4 +12,4 @@ __email__ = "support@sitebay.org"
|
|
12
12
|
|
13
13
|
from .server import main
|
14
14
|
|
15
|
-
__all__ = ["main"]
|
15
|
+
__all__ = ["main"]
|
sitebay_mcp/client.py
CHANGED
@@ -27,7 +27,8 @@ class SiteBayClient:
|
|
27
27
|
self._client = httpx.AsyncClient(
|
28
28
|
base_url=self.BASE_URL,
|
29
29
|
timeout=timeout,
|
30
|
-
headers=self.auth.get_headers()
|
30
|
+
headers=self.auth.get_headers(),
|
31
|
+
follow_redirects=True
|
31
32
|
)
|
32
33
|
|
33
34
|
async def __aenter__(self):
|
@@ -266,35 +267,39 @@ class SiteBayClient:
|
|
266
267
|
return await self.delete(f"/site/{fqdn}")
|
267
268
|
|
268
269
|
# Site Operations Methods
|
269
|
-
async def execute_shell_command(
|
270
|
+
async def execute_shell_command(
|
271
|
+
self,
|
272
|
+
fqdn: str,
|
273
|
+
cmd: str,
|
274
|
+
cwd: Optional[str] = None,
|
275
|
+
auto_track_dir: Optional[bool] = None,
|
276
|
+
) -> Any:
|
270
277
|
"""Execute a shell command on a site"""
|
271
|
-
|
272
|
-
|
273
|
-
|
278
|
+
payload: Dict[str, Any] = {"cmd": cmd}
|
279
|
+
if cwd is not None:
|
280
|
+
payload["cwd"] = cwd
|
281
|
+
if auto_track_dir is not None:
|
282
|
+
payload["auto_track_dir"] = auto_track_dir
|
283
|
+
return await self.post(f"/site/{fqdn}/cmd", json_data=payload)
|
284
|
+
|
285
|
+
async def edit_file(
|
286
|
+
self,
|
287
|
+
fqdn: str,
|
288
|
+
file_path: str,
|
289
|
+
file_edit_using_search_replace_blocks: str,
|
290
|
+
) -> str:
|
274
291
|
"""Edit a file in the site's wp-content directory"""
|
275
292
|
return await self.post(
|
276
293
|
f"/site/{fqdn}/wpfile_diff_edit",
|
277
|
-
json_data={
|
294
|
+
json_data={
|
295
|
+
"file_path": file_path,
|
296
|
+
"file_edit_using_search_replace_blocks": file_edit_using_search_replace_blocks,
|
297
|
+
},
|
278
298
|
)
|
279
299
|
|
280
|
-
|
281
|
-
"""Get site events"""
|
282
|
-
params = {"after_datetime": after_datetime} if after_datetime else None
|
283
|
-
response = await self.get(f"/site/{fqdn}/event", params=params)
|
284
|
-
return response.get("results", [])
|
285
|
-
|
286
|
-
# Staging Methods
|
287
|
-
async def create_staging_site(self, fqdn: str, staging_data: Dict[str, Any]) -> Dict[str, Any]:
|
288
|
-
"""Create a staging site"""
|
289
|
-
return await self.post(f"/site/{fqdn}/stage", json_data=staging_data)
|
300
|
+
# Site events endpoint removed (not present in schema)
|
290
301
|
|
291
|
-
|
292
|
-
"""Delete a staging site"""
|
293
|
-
return await self.delete(f"/site/{fqdn}/stage")
|
294
|
-
|
295
|
-
async def commit_staging_site(self, fqdn: str) -> Dict[str, Any]:
|
296
|
-
"""Commit staging site to live"""
|
297
|
-
return await self.post(f"/site/{fqdn}/stage/commit")
|
302
|
+
# Staging methods removed (no longer supported)
|
298
303
|
|
299
304
|
# Backup/Restore Methods
|
300
305
|
async def get_backup_commits(self, fqdn: str, number_to_fetch: int = 10) -> List[Dict[str, Any]]:
|
@@ -312,22 +317,7 @@ class SiteBayClient:
|
|
312
317
|
return response.get("results", [])
|
313
318
|
|
314
319
|
# External Path Methods
|
315
|
-
|
316
|
-
"""List external paths for a site"""
|
317
|
-
response = await self.get(f"/site/{fqdn}/external_path")
|
318
|
-
return response.get("results", [])
|
319
|
-
|
320
|
-
async def create_external_path(self, fqdn: str, path_data: Dict[str, Any]) -> Dict[str, Any]:
|
321
|
-
"""Create an external path"""
|
322
|
-
return await self.post(f"/site/{fqdn}/external_path", json_data=path_data)
|
323
|
-
|
324
|
-
async def update_external_path(self, fqdn: str, path_id: str, path_data: Dict[str, Any]) -> Dict[str, Any]:
|
325
|
-
"""Update an external path"""
|
326
|
-
return await self.patch(f"/site/{fqdn}/external_path/{path_id}", json_data=path_data)
|
327
|
-
|
328
|
-
async def delete_external_path(self, fqdn: str, path_id: str) -> Dict[str, Any]:
|
329
|
-
"""Delete an external path"""
|
330
|
-
return await self.delete(f"/site/{fqdn}/external_path/{path_id}")
|
320
|
+
# External path methods removed (no longer supported)
|
331
321
|
|
332
322
|
# Proxy Methods
|
333
323
|
async def wordpress_proxy(self, proxy_data: Dict[str, Any]) -> Any:
|
@@ -348,16 +338,12 @@ class SiteBayClient:
|
|
348
338
|
response = await self.get("/team")
|
349
339
|
return response.get("results", [])
|
350
340
|
|
351
|
-
#
|
352
|
-
async def
|
353
|
-
"""List available
|
354
|
-
response = await self.get("/
|
341
|
+
# Ready-made site catalog
|
342
|
+
async def list_ready_made_sites(self) -> List[Dict[str, Any]]:
|
343
|
+
"""List available ready-made sites"""
|
344
|
+
response = await self.get("/ready_made_site")
|
355
345
|
return response.get("results", [])
|
356
346
|
|
357
|
-
async def list_regions(self) -> List[Dict[str, Any]]:
|
358
|
-
"""List available regions"""
|
359
|
-
return await self.get("/region")
|
360
|
-
|
361
347
|
# Account Methods
|
362
348
|
async def get_affiliate_referrals(self) -> List[Dict[str, Any]]:
|
363
349
|
"""Get affiliate referrals"""
|
@@ -366,4 +352,4 @@ class SiteBayClient:
|
|
366
352
|
|
367
353
|
async def create_checkout_session(self, checkout_data: Dict[str, Any]) -> Dict[str, Any]:
|
368
354
|
"""Create Stripe checkout session"""
|
369
|
-
return await self.post("/create_checkout_session", json_data=checkout_data)
|
355
|
+
return await self.post("/create_checkout_session", json_data=checkout_data)
|
sitebay_mcp/resources.py
CHANGED
@@ -34,7 +34,7 @@ async def get_site_config_resource(ctx: Context, site_fqdn: str) -> str:
|
|
34
34
|
config = {
|
35
35
|
"site_info": {
|
36
36
|
"domain": site.get("fqdn"),
|
37
|
-
"title": site.get("wp_title"),
|
37
|
+
"title": site.get("wordpress_blog_name") or site.get("wp_title"),
|
38
38
|
"status": site.get("status"),
|
39
39
|
"region": site.get("region_name"),
|
40
40
|
"created": site.get("created_at"),
|
@@ -64,50 +64,7 @@ async def get_site_config_resource(ctx: Context, site_fqdn: str) -> str:
|
|
64
64
|
return f"Error: {str(e)}"
|
65
65
|
|
66
66
|
|
67
|
-
|
68
|
-
"""
|
69
|
-
Get site events/logs as a resource.
|
70
|
-
|
71
|
-
Args:
|
72
|
-
ctx: FastMCP context
|
73
|
-
site_fqdn: Site domain name
|
74
|
-
limit: Maximum number of events to fetch
|
75
|
-
|
76
|
-
Returns:
|
77
|
-
JSON formatted site events
|
78
|
-
"""
|
79
|
-
try:
|
80
|
-
await ctx.info(f"Fetching events resource for: {site_fqdn}")
|
81
|
-
|
82
|
-
from .server import initialize_client
|
83
|
-
client = await initialize_client()
|
84
|
-
|
85
|
-
events = await client.get_site_events(site_fqdn)
|
86
|
-
|
87
|
-
# Limit and format events
|
88
|
-
limited_events = events[:limit]
|
89
|
-
|
90
|
-
formatted_events = {
|
91
|
-
"site": site_fqdn,
|
92
|
-
"total_events": len(events),
|
93
|
-
"showing": len(limited_events),
|
94
|
-
"events": [
|
95
|
-
{
|
96
|
-
"timestamp": event.get("created_at"),
|
97
|
-
"type": event.get("event_type"),
|
98
|
-
"status": event.get("status"),
|
99
|
-
"description": event.get("description"),
|
100
|
-
"metadata": event.get("metadata", {})
|
101
|
-
}
|
102
|
-
for event in limited_events
|
103
|
-
]
|
104
|
-
}
|
105
|
-
|
106
|
-
return json.dumps(formatted_events, indent=2)
|
107
|
-
|
108
|
-
except SiteBayError as e:
|
109
|
-
await ctx.error(f"Error fetching events for {site_fqdn}: {str(e)}")
|
110
|
-
return f"Error: {str(e)}"
|
67
|
+
# Site events resource removed (not present in schema)
|
111
68
|
|
112
69
|
|
113
70
|
async def get_account_summary_resource(ctx: Context) -> str:
|
@@ -129,15 +86,14 @@ async def get_account_summary_resource(ctx: Context) -> str:
|
|
129
86
|
# Get sites and teams in parallel
|
130
87
|
sites = await client.list_sites()
|
131
88
|
teams = await client.list_teams()
|
132
|
-
|
133
|
-
|
89
|
+
# Regions endpoint removed; ready-made sites replaces templates
|
90
|
+
ready_made_sites = await client.list_ready_made_sites()
|
134
91
|
|
135
92
|
summary: dict[str, Any] = {
|
136
93
|
"account_overview": {
|
137
94
|
"total_sites": len(sites),
|
138
95
|
"total_teams": len(teams),
|
139
|
-
"
|
140
|
-
"available_templates": len(templates)
|
96
|
+
"available_ready_made_sites": len(ready_made_sites)
|
141
97
|
},
|
142
98
|
"sites_by_status": {},
|
143
99
|
"sites_by_region": {},
|
@@ -168,4 +124,4 @@ async def get_account_summary_resource(ctx: Context) -> str:
|
|
168
124
|
|
169
125
|
except SiteBayError as e:
|
170
126
|
await ctx.error(f"Error fetching account summary: {str(e)}")
|
171
|
-
return f"Error: {str(e)}"
|
127
|
+
return f"Error: {str(e)}"
|