Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/runloop_api_client/sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
SnapshotOps,
BenchmarkOps,
BlueprintOps,
McpConfigOps,
GatewayConfigOps,
NetworkPolicyOps,
StorageObjectOps,
Expand All @@ -29,6 +30,7 @@
AsyncSnapshotOps,
AsyncBenchmarkOps,
AsyncBlueprintOps,
AsyncMcpConfigOps,
AsyncGatewayConfigOps,
AsyncNetworkPolicyOps,
AsyncStorageObjectOps,
Expand All @@ -40,6 +42,7 @@
from .benchmark import Benchmark
from .blueprint import Blueprint
from .execution import Execution
from .mcp_config import McpConfig
from .async_agent import AsyncAgent
from .async_devbox import AsyncDevbox, AsyncNamedShell
from .async_scorer import AsyncScorer
Expand All @@ -53,6 +56,7 @@
from .async_benchmark import AsyncBenchmark
from .async_blueprint import AsyncBlueprint
from .async_execution import AsyncExecution
from .async_mcp_config import AsyncMcpConfig
from .execution_result import ExecutionResult
from .scenario_builder import ScenarioBuilder
from .async_scenario_run import AsyncScenarioRun
Expand Down Expand Up @@ -86,6 +90,8 @@
"AsyncStorageObjectOps",
"NetworkPolicyOps",
"AsyncNetworkPolicyOps",
"McpConfigOps",
"AsyncMcpConfigOps",
"GatewayConfigOps",
"AsyncGatewayConfigOps",
# Resource classes
Expand Down Expand Up @@ -118,6 +124,8 @@
"AsyncStorageObject",
"NetworkPolicy",
"AsyncNetworkPolicy",
"McpConfig",
"AsyncMcpConfig",
"GatewayConfig",
"AsyncGatewayConfig",
"NamedShell",
Expand Down
15 changes: 15 additions & 0 deletions src/runloop_api_client/sdk/_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@
ScenarioListParams,
BenchmarkListParams,
BlueprintListParams,
McpConfigListParams,
ObjectDownloadParams,
ScenarioUpdateParams,
BenchmarkCreateParams,
BenchmarkUpdateParams,
BlueprintCreateParams,
McpConfigCreateParams,
McpConfigUpdateParams,
DevboxUploadFileParams,
GatewayConfigListParams,
NetworkPolicyListParams,
Expand Down Expand Up @@ -266,6 +269,18 @@ class SDKNetworkPolicyUpdateParams(NetworkPolicyUpdateParams, LongRequestOptions
pass


class SDKMcpConfigCreateParams(McpConfigCreateParams, LongRequestOptions):
pass


class SDKMcpConfigListParams(McpConfigListParams, BaseRequestOptions):
pass


class SDKMcpConfigUpdateParams(McpConfigUpdateParams, LongRequestOptions):
pass


class SDKGatewayConfigCreateParams(GatewayConfigCreateParams, LongRequestOptions):
pass

Expand Down
63 changes: 63 additions & 0 deletions src/runloop_api_client/sdk/async_.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@
SDKScorerCreateParams,
SDKBenchmarkListParams,
SDKBlueprintListParams,
SDKMcpConfigListParams,
SDKBenchmarkCreateParams,
SDKBlueprintCreateParams,
SDKMcpConfigCreateParams,
SDKDiskSnapshotListParams,
SDKGatewayConfigListParams,
SDKNetworkPolicyListParams,
Expand All @@ -42,6 +44,7 @@
from .async_snapshot import AsyncSnapshot
from .async_benchmark import AsyncBenchmark
from .async_blueprint import AsyncBlueprint
from .async_mcp_config import AsyncMcpConfig
from ..lib.context_loader import TarFilter, build_directory_tar
from .async_gateway_config import AsyncGatewayConfig
from .async_network_policy import AsyncNetworkPolicy
Expand Down Expand Up @@ -1011,6 +1014,62 @@ async def list(self, **params: Unpack[SDKGatewayConfigListParams]) -> list[Async
return [AsyncGatewayConfig(self._client, item.id) for item in page.gateway_configs]


class AsyncMcpConfigOps:
"""High-level async manager for creating and managing MCP configurations.

Accessed via ``runloop.mcp_config`` from :class:`AsyncRunloopSDK`, provides methods
to create, retrieve, update, delete, and list MCP configs. MCP configs define
how to connect to upstream MCP (Model Context Protocol) servers, specifying the
target endpoint and which tools are allowed.

Example:
>>> runloop = AsyncRunloopSDK()
>>> mcp_config = await runloop.mcp_config.create(
... name="my-mcp-server",
... endpoint="https://mcp.example.com",
... allowed_tools=["*"],
... )
"""

def __init__(self, client: AsyncRunloop) -> None:
"""Initialize AsyncMcpConfigOps.

:param client: AsyncRunloop client instance
:type client: AsyncRunloop
"""
self._client = client

async def create(self, **params: Unpack[SDKMcpConfigCreateParams]) -> AsyncMcpConfig:
"""Create a new MCP config.

:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKMcpConfigCreateParams` for available parameters
:return: The newly created MCP config
:rtype: AsyncMcpConfig
"""
response = await self._client.mcp_configs.create(**params)
return AsyncMcpConfig(self._client, response.id)

def from_id(self, mcp_config_id: str) -> AsyncMcpConfig:
"""Get an AsyncMcpConfig instance for an existing MCP config ID.

:param mcp_config_id: ID of the MCP config
:type mcp_config_id: str
:return: AsyncMcpConfig instance for the given ID
:rtype: AsyncMcpConfig
"""
return AsyncMcpConfig(self._client, mcp_config_id)

async def list(self, **params: Unpack[SDKMcpConfigListParams]) -> list[AsyncMcpConfig]:
"""List all MCP configs, optionally filtered by parameters.

:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKMcpConfigListParams` for available parameters
:return: List of MCP configs
:rtype: list[AsyncMcpConfig]
"""
page = await self._client.mcp_configs.list(**params)
return [AsyncMcpConfig(self._client, item.id) for item in page.mcp_configs]


class AsyncRunloopSDK:
"""High-level asynchronous entry point for the Runloop SDK.

Expand Down Expand Up @@ -1040,6 +1099,8 @@ class AsyncRunloopSDK:
:vartype network_policy: AsyncNetworkPolicyOps
:ivar gateway_config: High-level async interface for gateway config management
:vartype gateway_config: AsyncGatewayConfigOps
:ivar mcp_config: High-level async interface for MCP config management
:vartype mcp_config: AsyncMcpConfigOps

Example:
>>> runloop = AsyncRunloopSDK() # Uses RUNLOOP_API_KEY env var
Expand All @@ -1055,6 +1116,7 @@ class AsyncRunloopSDK:
devbox: AsyncDevboxOps
blueprint: AsyncBlueprintOps
gateway_config: AsyncGatewayConfigOps
mcp_config: AsyncMcpConfigOps
network_policy: AsyncNetworkPolicyOps
scenario: AsyncScenarioOps
scorer: AsyncScorerOps
Expand Down Expand Up @@ -1104,6 +1166,7 @@ def __init__(
self.devbox = AsyncDevboxOps(self.api)
self.blueprint = AsyncBlueprintOps(self.api)
self.gateway_config = AsyncGatewayConfigOps(self.api)
self.mcp_config = AsyncMcpConfigOps(self.api)
self.network_policy = AsyncNetworkPolicyOps(self.api)
self.scenario = AsyncScenarioOps(self.api)
self.scorer = AsyncScorerOps(self.api)
Expand Down
95 changes: 95 additions & 0 deletions src/runloop_api_client/sdk/async_mcp_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""McpConfig resource class for asynchronous operations."""

from __future__ import annotations

from typing_extensions import Unpack, override

from ._types import BaseRequestOptions, LongRequestOptions, SDKMcpConfigUpdateParams
from .._client import AsyncRunloop
from ..types.mcp_config_view import McpConfigView


class AsyncMcpConfig:
"""Asynchronous wrapper around an MCP config resource.

MCP configs define how to connect to upstream MCP (Model Context Protocol) servers.
They specify the target endpoint and which tools are allowed. Use with devboxes to
securely connect to MCP servers.

Example:
>>> runloop = AsyncRunloopSDK()
>>> mcp_config = await runloop.mcp_config.create(
... name="my-mcp-server",
... endpoint="https://mcp.example.com",
... allowed_tools=["*"],
... )
>>> info = await mcp_config.get_info()
>>> print(f"MCP Config: {info.name}")
"""

def __init__(
self,
client: AsyncRunloop,
mcp_config_id: str,
) -> None:
"""Initialize the wrapper.

:param client: Generated AsyncRunloop client
:type client: AsyncRunloop
:param mcp_config_id: McpConfig ID returned by the API
:type mcp_config_id: str
"""
self._client = client
self._id = mcp_config_id

@override
def __repr__(self) -> str:
return f"<AsyncMcpConfig id={self._id!r}>"

@property
def id(self) -> str:
"""Return the MCP config ID.

:return: Unique MCP config ID
:rtype: str
"""
return self._id

async def get_info(
self,
**options: Unpack[BaseRequestOptions],
) -> McpConfigView:
"""Retrieve the latest MCP config details.

:param options: Optional request configuration
:return: API response describing the MCP config
:rtype: McpConfigView
"""
return await self._client.mcp_configs.retrieve(
self._id,
**options,
)

async def update(self, **params: Unpack[SDKMcpConfigUpdateParams]) -> McpConfigView:
"""Update the MCP config.

:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKMcpConfigUpdateParams` for available parameters
:return: Updated MCP config view
:rtype: McpConfigView
"""
return await self._client.mcp_configs.update(self._id, **params)

async def delete(
self,
**options: Unpack[LongRequestOptions],
) -> McpConfigView:
"""Delete the MCP config. This action is irreversible.

:param options: Optional long-running request configuration
:return: API response acknowledging deletion
:rtype: McpConfigView
"""
return await self._client.mcp_configs.delete(
self._id,
**options,
)
95 changes: 95 additions & 0 deletions src/runloop_api_client/sdk/mcp_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
"""McpConfig resource class for synchronous operations."""

from __future__ import annotations

from typing_extensions import Unpack, override

from ._types import BaseRequestOptions, LongRequestOptions, SDKMcpConfigUpdateParams
from .._client import Runloop
from ..types.mcp_config_view import McpConfigView


class McpConfig:
"""Synchronous wrapper around an MCP config resource.

MCP configs define how to connect to upstream MCP (Model Context Protocol) servers.
They specify the target endpoint and which tools are allowed. Use with devboxes to
securely connect to MCP servers.

Example:
>>> runloop = RunloopSDK()
>>> mcp_config = runloop.mcp_config.create(
... name="my-mcp-server",
... endpoint="https://mcp.example.com",
... allowed_tools=["*"],
... )
>>> info = mcp_config.get_info()
>>> print(f"MCP Config: {info.name}")
"""

def __init__(
self,
client: Runloop,
mcp_config_id: str,
) -> None:
"""Initialize the wrapper.

:param client: Generated Runloop client
:type client: Runloop
:param mcp_config_id: McpConfig ID returned by the API
:type mcp_config_id: str
"""
self._client = client
self._id = mcp_config_id

@override
def __repr__(self) -> str:
return f"<McpConfig id={self._id!r}>"

@property
def id(self) -> str:
"""Return the MCP config ID.

:return: Unique MCP config ID
:rtype: str
"""
return self._id

def get_info(
self,
**options: Unpack[BaseRequestOptions],
) -> McpConfigView:
"""Retrieve the latest MCP config details.

:param options: Optional request configuration
:return: API response describing the MCP config
:rtype: McpConfigView
"""
return self._client.mcp_configs.retrieve(
self._id,
**options,
)

def update(self, **params: Unpack[SDKMcpConfigUpdateParams]) -> McpConfigView:
"""Update the MCP config.

:param params: See :typeddict:`~runloop_api_client.sdk._types.SDKMcpConfigUpdateParams` for available parameters
:return: Updated MCP config view
:rtype: McpConfigView
"""
return self._client.mcp_configs.update(self._id, **params)

def delete(
self,
**options: Unpack[LongRequestOptions],
) -> McpConfigView:
"""Delete the MCP config. This action is irreversible.

:param options: Optional long-running request configuration
:return: API response acknowledging deletion
:rtype: McpConfigView
"""
return self._client.mcp_configs.delete(
self._id,
**options,
)
Loading