Skip to content

Commit 4bc5ba4

Browse files
authored
feat: add MCP Hub to sdk (#714)
1 parent e152cdb commit 4bc5ba4

7 files changed

Lines changed: 1179 additions & 20 deletions

File tree

src/sdk.ts

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { Agent } from './sdk/agent';
99
import { Scorer } from './sdk/scorer';
1010
import { NetworkPolicy } from './sdk/network-policy';
1111
import { GatewayConfig } from './sdk/gateway-config';
12+
import { McpConfig } from './sdk/mcp-config';
1213
import { Scenario } from './sdk/scenario';
1314

1415
// Import types used in this file
@@ -24,6 +25,7 @@ import type { AgentCreateParams, AgentListParams } from './resources/agents';
2425
import type { ScorerCreateParams, ScorerListParams } from './resources/scenarios/scorers';
2526
import type { NetworkPolicyCreateParams, NetworkPolicyListParams } from './resources/network-policies';
2627
import type { GatewayConfigCreateParams, GatewayConfigListParams } from './resources/gateway-configs';
28+
import type { McpConfigCreateParams, McpConfigListParams } from './resources/mcp-configs';
2729
import type { ScenarioListParams } from './resources/scenarios/scenarios';
2830
import { PollingOptions } from './lib/polling';
2931
import * as Shared from './resources/shared';
@@ -200,6 +202,8 @@ type ContentType = ObjectCreateParams['content_type'];
200202
* - `agent` - {@link AgentOps}
201203
* - `scorer` - {@link ScorerOps}
202204
* - `networkPolicy` - {@link NetworkPolicyOps}
205+
* - `gatewayConfig` - {@link GatewayConfigOps}
206+
* - `mcpConfig` - {@link McpConfigOps}
203207
*
204208
* See the documentation for each Operations class for more details.
205209
*
@@ -295,6 +299,15 @@ export class RunloopSDK {
295299
*/
296300
public readonly gatewayConfig: GatewayConfigOps;
297301

302+
/**
303+
* **MCP Config Operations** - {@link McpConfigOps} for creating and accessing {@link McpConfig} class instances.
304+
*
305+
* MCP configs define how to connect to upstream MCP (Model Context Protocol) servers. They specify
306+
* the target endpoint and which tools are allowed. Use with devboxes to securely connect to
307+
* MCP servers.
308+
*/
309+
public readonly mcpConfig: McpConfigOps;
310+
298311
/**
299312
* **Scenario Operations** - {@link ScenarioOps} for accessing {@link Scenario} class instances.
300313
*
@@ -317,6 +330,7 @@ export class RunloopSDK {
317330
this.scorer = new ScorerOps(this.api);
318331
this.networkPolicy = new NetworkPolicyOps(this.api);
319332
this.gatewayConfig = new GatewayConfigOps(this.api);
333+
this.mcpConfig = new McpConfigOps(this.api);
320334
this.scenario = new ScenarioOps(this.api);
321335
}
322336
}
@@ -1627,6 +1641,108 @@ export class GatewayConfigOps {
16271641
}
16281642
}
16291643

1644+
/**
1645+
* MCP Config SDK interface for managing MCP configurations.
1646+
*
1647+
* @category MCP Config
1648+
*
1649+
* @remarks
1650+
* ## Overview
1651+
*
1652+
* The `McpConfigOps` class provides a high-level abstraction for managing MCP configurations,
1653+
* which define how to connect to upstream MCP (Model Context Protocol) servers. MCP configs
1654+
* specify the target endpoint and which tools are allowed.
1655+
*
1656+
* ## Usage
1657+
*
1658+
* This interface is accessed via {@link RunloopSDK.mcpConfig}. You should construct
1659+
* a {@link RunloopSDK} instance and use it from there:
1660+
*
1661+
* @example
1662+
* ```typescript
1663+
* const runloop = new RunloopSDK();
1664+
* const mcpConfig = await runloop.mcpConfig.create({
1665+
* name: 'my-mcp-server',
1666+
* endpoint: 'https://mcp.example.com',
1667+
* allowed_tools: ['*'],
1668+
* });
1669+
*
1670+
* const info = await mcpConfig.getInfo();
1671+
* console.log(`MCP Config: ${info.name}`);
1672+
* ```
1673+
*/
1674+
export class McpConfigOps {
1675+
/**
1676+
* @private
1677+
*/
1678+
constructor(private client: RunloopAPI) {}
1679+
1680+
/**
1681+
* Create a new MCP config.
1682+
*
1683+
* @example
1684+
* ```typescript
1685+
* const runloop = new RunloopSDK();
1686+
* const mcpConfig = await runloop.mcpConfig.create({
1687+
* name: 'my-mcp-server',
1688+
* endpoint: 'https://mcp.example.com',
1689+
* allowed_tools: ['*'],
1690+
* description: 'MCP server for my tools',
1691+
* });
1692+
* ```
1693+
*
1694+
* @param {McpConfigCreateParams} params - Parameters for creating the MCP config.
1695+
* @param {Core.RequestOptions} [options] - Request options.
1696+
* @returns {Promise<McpConfig>} A {@link McpConfig} instance.
1697+
*/
1698+
async create(params: McpConfigCreateParams, options?: Core.RequestOptions): Promise<McpConfig> {
1699+
return McpConfig.create(this.client, params, options);
1700+
}
1701+
1702+
/**
1703+
* Get an MCP config object by its ID.
1704+
*
1705+
* @example
1706+
* ```typescript
1707+
* const runloop = new RunloopSDK();
1708+
* const mcpConfig = runloop.mcpConfig.fromId('mcp_1234567890');
1709+
* const info = await mcpConfig.getInfo();
1710+
* console.log(`MCP Config name: ${info.name}`);
1711+
* ```
1712+
*
1713+
* @param {string} id - The ID of the MCP config.
1714+
* @returns {McpConfig} A {@link McpConfig} instance.
1715+
*/
1716+
fromId(id: string): McpConfig {
1717+
return McpConfig.fromId(this.client, id);
1718+
}
1719+
1720+
/**
1721+
* List MCP configs with optional filters (paginated).
1722+
*
1723+
* @example
1724+
* ```typescript
1725+
* const runloop = new RunloopSDK();
1726+
* const configs = await runloop.mcpConfig.list({ limit: 10 });
1727+
* console.log(configs.map((c) => c.id));
1728+
* ```
1729+
*
1730+
* @param {McpConfigListParams} [params] - Optional filter parameters.
1731+
* @param {Core.RequestOptions} [options] - Request options.
1732+
* @returns {Promise<McpConfig[]>} An array of {@link McpConfig} instances.
1733+
*/
1734+
async list(params?: McpConfigListParams, options?: Core.RequestOptions): Promise<McpConfig[]> {
1735+
const result = await this.client.mcpConfigs.list(params, options);
1736+
const configs: McpConfig[] = [];
1737+
1738+
for await (const config of result) {
1739+
configs.push(McpConfig.fromId(this.client, config.id));
1740+
}
1741+
1742+
return configs;
1743+
}
1744+
}
1745+
16301746
/**
16311747
* Scenario SDK interface for managing scenarios.
16321748
*
@@ -1750,6 +1866,7 @@ export declare namespace RunloopSDK {
17501866
ScorerOps as ScorerOps,
17511867
NetworkPolicyOps as NetworkPolicyOps,
17521868
GatewayConfigOps as GatewayConfigOps,
1869+
McpConfigOps as McpConfigOps,
17531870
ScenarioOps as ScenarioOps,
17541871
Devbox as Devbox,
17551872
Blueprint as Blueprint,
@@ -1759,6 +1876,7 @@ export declare namespace RunloopSDK {
17591876
Scorer as Scorer,
17601877
NetworkPolicy as NetworkPolicy,
17611878
GatewayConfig as GatewayConfig,
1879+
McpConfig as McpConfig,
17621880
Scenario as Scenario,
17631881
};
17641882
}
@@ -1775,6 +1893,7 @@ export {
17751893
Agent,
17761894
Scorer,
17771895
NetworkPolicy,
1896+
McpConfig,
17781897
Execution,
17791898
ExecutionResult,
17801899
Scenario,

src/sdk/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ export { ExecutionResult } from './execution-result';
88
export { Scorer } from './scorer';
99
export { NetworkPolicy } from './network-policy';
1010
export { GatewayConfig } from './gateway-config';
11+
export { McpConfig } from './mcp-config';
1112
export { ScenarioRun } from './scenario-run';
1213
export { Scenario, type ScenarioRunParams } from './scenario';

src/sdk/mcp-config.ts

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import { Runloop } from '../index';
2+
import type * as Core from '../core';
3+
import type { McpConfigView, McpConfigCreateParams, McpConfigUpdateParams } from '../resources/mcp-configs';
4+
5+
/**
6+
* Object-oriented interface for working with MCP Configs.
7+
*
8+
* @category MCP Config
9+
*
10+
* @remarks
11+
* ## Overview
12+
*
13+
* The `McpConfig` class provides a high-level, object-oriented API for managing MCP configurations.
14+
* MCP configs define how to connect to upstream MCP (Model Context Protocol) servers, specifying the
15+
* target endpoint and which tools are allowed. They can be used with devboxes to securely connect
16+
* to MCP servers.
17+
*
18+
* ## Quickstart
19+
*
20+
* ```typescript
21+
* import { RunloopSDK } from '@runloop/api-client-ts';
22+
*
23+
* const runloop = new RunloopSDK();
24+
* const mcpConfig = await runloop.mcpConfig.create({
25+
* name: 'my-mcp-server',
26+
* endpoint: 'https://mcp.example.com',
27+
* allowed_tools: ['*'],
28+
* });
29+
*
30+
* const info = await mcpConfig.getInfo();
31+
* console.log(`MCP Config: ${info.name}`);
32+
* ```
33+
*/
34+
export class McpConfig {
35+
private client: Runloop;
36+
private _id: string;
37+
38+
private constructor(client: Runloop, id: string) {
39+
this.client = client;
40+
this._id = id;
41+
}
42+
43+
/**
44+
* Create a new McpConfig with the specified configuration.
45+
* This is the recommended way to create an MCP config.
46+
*
47+
* See the {@link McpConfigOps.create} method for calling this
48+
* @private
49+
*
50+
* @example
51+
* ```typescript
52+
* const runloop = new RunloopSDK();
53+
* const mcpConfig = await runloop.mcpConfig.create({
54+
* name: 'my-mcp-server',
55+
* endpoint: 'https://mcp.example.com',
56+
* allowed_tools: ['*'],
57+
* description: 'MCP server for my tools',
58+
* });
59+
* ```
60+
*
61+
* @param {Runloop} client - The Runloop client instance
62+
* @param {McpConfigCreateParams} params - Parameters for creating the MCP config
63+
* @param {Core.RequestOptions} [options] - Request options
64+
* @returns {Promise<McpConfig>} A {@link McpConfig} instance
65+
*/
66+
static async create(
67+
client: Runloop,
68+
params: McpConfigCreateParams,
69+
options?: Core.RequestOptions,
70+
): Promise<McpConfig> {
71+
const configData = await client.mcpConfigs.create(params, options);
72+
return new McpConfig(client, configData.id);
73+
}
74+
75+
/**
76+
* Create a McpConfig instance by ID without retrieving from API.
77+
* Use getInfo() to fetch the actual data when needed.
78+
*
79+
* See the {@link McpConfigOps.fromId} method for calling this
80+
* @private
81+
*
82+
* @example
83+
* ```typescript
84+
* const runloop = new RunloopSDK();
85+
* const mcpConfig = runloop.mcpConfig.fromId('mcp_1234567890');
86+
* const info = await mcpConfig.getInfo();
87+
* console.log(`MCP Config name: ${info.name}`);
88+
* ```
89+
*
90+
* @param {Runloop} client - The Runloop client instance
91+
* @param {string} id - The MCP config ID
92+
* @returns {McpConfig} A {@link McpConfig} instance
93+
*/
94+
static fromId(client: Runloop, id: string): McpConfig {
95+
return new McpConfig(client, id);
96+
}
97+
98+
/**
99+
* Get the MCP config ID.
100+
* @returns {string} The MCP config ID
101+
*/
102+
get id(): string {
103+
return this._id;
104+
}
105+
106+
/**
107+
* Get the complete MCP config data from the API.
108+
*
109+
* @example
110+
* ```typescript
111+
* const info = await mcpConfig.getInfo();
112+
* console.log(`MCP Config: ${info.name}, endpoint: ${info.endpoint}`);
113+
* ```
114+
*
115+
* @param {Core.RequestOptions} [options] - Request options
116+
* @returns {Promise<McpConfigView>} The MCP config data
117+
*/
118+
async getInfo(options?: Core.RequestOptions): Promise<McpConfigView> {
119+
return this.client.mcpConfigs.retrieve(this._id, options);
120+
}
121+
122+
/**
123+
* Update an existing McpConfig. All fields are optional.
124+
*
125+
* @example
126+
* ```typescript
127+
* const updated = await mcpConfig.update({
128+
* name: 'updated-mcp-name',
129+
* description: 'Updated description',
130+
* });
131+
* ```
132+
*
133+
* @param {McpConfigUpdateParams} params - Parameters for updating the MCP config
134+
* @param {Core.RequestOptions} [options] - Request options
135+
* @returns {Promise<McpConfigView>} The updated MCP config data
136+
*/
137+
async update(params: McpConfigUpdateParams, options?: Core.RequestOptions): Promise<McpConfigView> {
138+
return this.client.mcpConfigs.update(this._id, params, options);
139+
}
140+
141+
/**
142+
* Delete this MCP config. This action is irreversible.
143+
*
144+
* @private
145+
* See the {@link McpConfigOps.delete} method for calling this
146+
*
147+
* @example
148+
* ```typescript
149+
* await mcpConfig.delete();
150+
* ```
151+
*
152+
* @param {Core.RequestOptions} [options] - Request options
153+
* @returns {Promise<McpConfigView>} The deleted MCP config data
154+
*/
155+
async delete(options?: Core.RequestOptions): Promise<McpConfigView> {
156+
return this.client.mcpConfigs.delete(this._id, {}, options);
157+
}
158+
}

0 commit comments

Comments
 (0)