Skip to content

Commit 9de76d2

Browse files
feat(mcp): Add organization info to check_airbyte_cloud_workspace tool (#897)
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent 69f6c96 commit 9de76d2

File tree

3 files changed

+93
-11
lines changed

3 files changed

+93
-11
lines changed

airbyte/_util/api_util.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,3 +1672,39 @@ def list_workspaces_in_organization(
16721672
payload["pagination"]["rowOffset"] += page_size
16731673

16741674
return result
1675+
1676+
1677+
def get_workspace_organization_info(
1678+
workspace_id: str,
1679+
*,
1680+
api_root: str,
1681+
client_id: SecretString,
1682+
client_secret: SecretString,
1683+
) -> dict[str, Any]:
1684+
"""Get organization info for a workspace.
1685+
1686+
Uses the Config API endpoint: POST /v1/workspaces/get_organization_info
1687+
1688+
This is an efficient O(1) lookup that directly retrieves the organization
1689+
info for a workspace without needing to iterate through all organizations.
1690+
1691+
Args:
1692+
workspace_id: The workspace ID to look up
1693+
api_root: The API root URL
1694+
client_id: OAuth client ID
1695+
client_secret: OAuth client secret
1696+
1697+
Returns:
1698+
Dictionary containing organization info:
1699+
- organizationId: The organization ID
1700+
- organizationName: The organization name
1701+
- sso: Whether SSO is enabled
1702+
- billing: Billing information (optional)
1703+
"""
1704+
return _make_config_api_request(
1705+
path="/workspaces/get_organization_info",
1706+
json={"workspaceId": workspace_id},
1707+
api_root=api_root,
1708+
client_id=client_id,
1709+
client_secret=client_secret,
1710+
)

airbyte/cloud/workspaces.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from __future__ import annotations
3737

3838
from dataclasses import dataclass
39+
from functools import cached_property
3940
from pathlib import Path
4041
from typing import TYPE_CHECKING, Any, Literal
4142

@@ -83,6 +84,35 @@ def workspace_url(self) -> str | None:
8384
"""The web URL of the workspace."""
8485
return f"{get_web_url_root(self.api_root)}/workspaces/{self.workspace_id}"
8586

87+
@cached_property
88+
def _organization_info(self) -> dict[str, Any]:
89+
"""Fetch and cache organization info for this workspace.
90+
91+
Uses the Config API endpoint for an efficient O(1) lookup.
92+
"""
93+
return api_util.get_workspace_organization_info(
94+
workspace_id=self.workspace_id,
95+
api_root=self.api_root,
96+
client_id=self.client_id,
97+
client_secret=self.client_secret,
98+
)
99+
100+
@property
101+
def organization_id(self) -> str | None:
102+
"""The ID of the organization this workspace belongs to.
103+
104+
This value is cached after the first lookup.
105+
"""
106+
return self._organization_info.get("organizationId")
107+
108+
@property
109+
def organization_name(self) -> str | None:
110+
"""The name of the organization this workspace belongs to.
111+
112+
This value is cached after the first lookup.
113+
"""
114+
return self._organization_info.get("organizationName")
115+
86116
# Test connection and creds
87117

88118
def connect(self) -> None:

airbyte/mcp/cloud_ops.py

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,16 @@ class CloudOrganizationResult(BaseModel):
152152
class CloudWorkspaceResult(BaseModel):
153153
"""Information about a workspace in Airbyte Cloud."""
154154

155-
id: str
155+
workspace_id: str
156156
"""The workspace ID."""
157-
name: str
157+
workspace_name: str
158158
"""Display name of the workspace."""
159+
workspace_url: str | None = None
160+
"""URL to access the workspace in Airbyte Cloud."""
159161
organization_id: str
160162
"""ID of the organization this workspace belongs to."""
163+
organization_name: str | None = None
164+
"""Name of the organization this workspace belongs to."""
161165

162166

163167
class LogReadResult(BaseModel):
@@ -463,18 +467,30 @@ def check_airbyte_cloud_workspace(
463467
default=None,
464468
),
465469
],
466-
) -> str:
470+
) -> CloudWorkspaceResult:
467471
"""Check if we have a valid Airbyte Cloud connection and return workspace info.
468472
469-
Returns workspace ID and workspace URL for verification.
473+
Returns workspace details including workspace ID, name, and organization info.
470474
"""
471475
workspace: CloudWorkspace = _get_cloud_workspace(workspace_id)
472-
workspace.connect()
476+
api_root = resolve_cloud_api_url()
477+
client_id = resolve_cloud_client_id()
478+
client_secret = resolve_cloud_client_secret()
473479

474-
return (
475-
f"✅ Successfully connected to Airbyte Cloud workspace.\n"
476-
f"Workspace ID: {workspace.workspace_id}\n"
477-
f"Workspace URL: {workspace.workspace_url}"
480+
# Get workspace details from the public API
481+
workspace_response = api_util.get_workspace(
482+
workspace_id=workspace.workspace_id,
483+
api_root=api_root,
484+
client_id=client_id,
485+
client_secret=client_secret,
486+
)
487+
488+
return CloudWorkspaceResult(
489+
workspace_id=workspace_response.workspace_id,
490+
workspace_name=workspace_response.name,
491+
workspace_url=workspace.workspace_url,
492+
organization_id=workspace.organization_id or "[error: organization ID not discovered]",
493+
organization_name=workspace.organization_name,
478494
)
479495

480496

@@ -1242,8 +1258,8 @@ def list_cloud_workspaces(
12421258

12431259
return [
12441260
CloudWorkspaceResult(
1245-
id=ws.get("workspaceId", ""),
1246-
name=ws.get("name", ""),
1261+
workspace_id=ws.get("workspaceId", ""),
1262+
workspace_name=ws.get("name", ""),
12471263
organization_id=ws.get("organizationId", ""),
12481264
)
12491265
for ws in workspaces

0 commit comments

Comments
 (0)