@open1s/ezbos 1.3.1 → 1.3.3

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.
package/README.md CHANGED
@@ -315,6 +315,38 @@ const mcpTools = await started.listMcpTools();
315
315
  console.log(`MCP tools available: ${mcpTools.length}`);
316
316
  ```
317
317
 
318
+ ### MCP Status Callback
319
+
320
+ Get real-time notifications when each MCP server connects or fails. Useful for UI status updates.
321
+
322
+ ```ts
323
+ const agent = brain.agent('my-agent', {
324
+ onMcpStatus: (namespace, status, error) => {
325
+ console.log(`[MCP] ${namespace}: ${status}`);
326
+ // Update UI status indicator
327
+ },
328
+ })
329
+ .with_mcp_process('files', 'npx', ['-y', '@modelcontextprotocol/server-filesystem', '/tmp'])
330
+ .with_mcp_http('api', 'http://localhost:3000/mcp');
331
+
332
+ const started = await agent.start();
333
+ ```
334
+
335
+ Callback parameters:
336
+ - `namespace` - MCP server name
337
+ - `status` - `'connected'` | `'failed'`
338
+ - `error` - error message string (only present when `status === 'failed'`)
339
+
340
+ The build continues even if an MCP server fails — use the callback to track which ones succeeded or failed.
341
+
342
+ Also works with `BrainOS.with()`:
343
+
344
+ ```ts
345
+ const agent = await BrainOS.with('my-agent', {
346
+ onMcpStatus: (ns, s, e) => { /* ... */ },
347
+ });
348
+ ```
349
+
318
350
  ## Skills
319
351
 
320
352
  Add domain-specific instructions to the system prompt.
package/dist/agent.d.ts CHANGED
@@ -8,6 +8,7 @@ export interface JsContent {
8
8
  base64?: string;
9
9
  name?: string;
10
10
  }
11
+ export type McpStatusCallback = (namespace: string, type: 'process' | 'http', comm: string, status: 'connected' | 'failed', error?: string) => void;
11
12
  export declare class AgentBuilder {
12
13
  private _inner;
13
14
  private _tools;
@@ -16,6 +17,7 @@ export declare class AgentBuilder {
16
17
  private _mcp;
17
18
  private _skillsDirs;
18
19
  private _inlineSkills;
20
+ private _onMcpStatus?;
19
21
  private _config;
20
22
  constructor(name: string, options?: {
21
23
  model?: string;
@@ -30,6 +32,7 @@ export declare class AgentBuilder {
30
32
  rateLimitCapacity?: number;
31
33
  rateLimitWindowSecs?: number;
32
34
  rateLimitMaxRetries?: number;
35
+ onMcpStatus?: McpStatusCallback;
33
36
  });
34
37
  with_model(model: string): this;
35
38
  with_baseUrl(url: string): this;
package/dist/agent.js CHANGED
@@ -11,6 +11,7 @@ export class AgentBuilder {
11
11
  _mcp = [];
12
12
  _skillsDirs = [];
13
13
  _inlineSkills = [];
14
+ _onMcpStatus;
14
15
  _config;
15
16
  constructor(name, options = {}) {
16
17
  this._config = {
@@ -28,6 +29,7 @@ export class AgentBuilder {
28
29
  rateLimitWindowSecs: options.rateLimitWindowSecs,
29
30
  rateLimitMaxRetries: options.rateLimitMaxRetries,
30
31
  };
32
+ this._onMcpStatus = options.onMcpStatus;
31
33
  }
32
34
  with_model(model) {
33
35
  this._config.model = model;
@@ -159,11 +161,23 @@ export class AgentBuilder {
159
161
  }) : undefined);
160
162
  }
161
163
  for (const mcp of this._mcp) {
162
- if (mcp.type === 'process' && mcp.command && mcp.args) {
163
- await this._inner.addMcpServer(mcp.namespace, mcp.command, mcp.args);
164
+ let added = false;
165
+ try {
166
+ if (mcp.type === 'process' && mcp.command && mcp.args) {
167
+ await this._inner.addMcpServer(mcp.namespace, mcp.command, mcp.args);
168
+ added = true;
169
+ }
170
+ else if (mcp.type === 'http' && mcp.url) {
171
+ await this._inner.addMcpServerHttp(mcp.namespace, mcp.url);
172
+ added = true;
173
+ }
174
+ if (added) {
175
+ this._onMcpStatus?.(mcp.namespace, mcp.type, mcp.type === 'process' ? mcp.command : mcp.url, 'connected');
176
+ }
164
177
  }
165
- else if (mcp.type === 'http' && mcp.url) {
166
- await this._inner.addMcpServerHttp(mcp.namespace, mcp.url);
178
+ catch (err) {
179
+ this._onMcpStatus?.(mcp.namespace, mcp.type, mcp.type === 'process' ? mcp.command : mcp.url, 'failed', String(err));
180
+ console.warn(`[agent] MCP server "${mcp.namespace}" connection failed, skipping:`, err);
167
181
  }
168
182
  }
169
183
  let systemPrompt = this._config.systemPrompt || '';
package/dist/brainos.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import * as jsbos from '@open1s/jsbos';
2
- import { AgentBuilder, Agent } from './agent.js';
2
+ import { AgentBuilder, Agent, McpStatusCallback } from './agent.js';
3
3
  interface BrainOSOptions {
4
4
  model?: string;
5
5
  baseUrl?: string;
6
6
  apiKey?: string;
7
+ onMcpStatus?: McpStatusCallback;
7
8
  }
8
9
  interface BusOptions {
9
10
  mode?: string;
@@ -29,6 +30,7 @@ export declare class BrainOS {
29
30
  temperature?: number;
30
31
  timeoutSecs?: number;
31
32
  maxTokens?: number;
33
+ onMcpStatus?: McpStatusCallback;
32
34
  }): AgentBuilder;
33
35
  get bus(): jsbos.Bus;
34
36
  publish(topic: string, payload: any, isJson?: boolean): Promise<void>;
package/dist/brainos.js CHANGED
@@ -47,11 +47,8 @@ export class BrainOS {
47
47
  throw new Error('BrainOS not started. Call start() first.');
48
48
  }
49
49
  return new AgentBuilder(name, {
50
- ...this._options,
51
50
  ...options,
52
- apiKey: options.apiKey || this._options.apiKey,
53
- model: options.model || this._options.model,
54
- baseUrl: options.baseUrl || this._options.baseUrl,
51
+ ...this._options,
55
52
  });
56
53
  }
57
54
  get bus() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open1s/ezbos",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Simple BrainOS - Easy wrapper for @open1s/jsbos",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -40,7 +40,7 @@
40
40
  ],
41
41
  "license": "MIT",
42
42
  "dependencies": {
43
- "@open1s/jsbos": "^2.3.0"
43
+ "@open1s/jsbos": "^2.3.2"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@modelcontextprotocol/sdk": "^1.29.0",
package/src/agent.ts CHANGED
@@ -17,6 +17,8 @@ export interface JsContent {
17
17
  const DEFAULT_MODEL = 'nvidia/meta/llama-3.1-8b-instruct';
18
18
  const DEFAULT_BASE_URL = 'https://integrate.api.nvidia.com/v1';
19
19
 
20
+ export type McpStatusCallback = (namespace: string,type: 'process' | 'http',comm: string, status: 'connected' | 'failed', error?: string) => void;
21
+
20
22
  export class AgentBuilder {
21
23
  private _inner: jsbos.Agent | null = null;
22
24
  private _tools: InternalToolDef[] = [];
@@ -25,6 +27,7 @@ export class AgentBuilder {
25
27
  private _mcp: Array<{ type: 'process' | 'http', namespace: string, command?: string, args?: string[], url?: string }> = [];
26
28
  private _skillsDirs: string[] = [];
27
29
  private _inlineSkills: SkillDef[] = [];
30
+ private _onMcpStatus?: McpStatusCallback;
28
31
  private _config: {
29
32
  name: string;
30
33
  model: string;
@@ -54,6 +57,7 @@ export class AgentBuilder {
54
57
  rateLimitCapacity?: number;
55
58
  rateLimitWindowSecs?: number;
56
59
  rateLimitMaxRetries?: number;
60
+ onMcpStatus?: McpStatusCallback;
57
61
  } = {}) {
58
62
  this._config = {
59
63
  name,
@@ -70,6 +74,7 @@ export class AgentBuilder {
70
74
  rateLimitWindowSecs: options.rateLimitWindowSecs,
71
75
  rateLimitMaxRetries: options.rateLimitMaxRetries,
72
76
  };
77
+ this._onMcpStatus = options.onMcpStatus;
73
78
  }
74
79
 
75
80
  with_model(model: string): this {
@@ -233,10 +238,21 @@ export class AgentBuilder {
233
238
  }
234
239
 
235
240
  for (const mcp of this._mcp) {
236
- if (mcp.type === 'process' && mcp.command && mcp.args) {
237
- await this._inner.addMcpServer(mcp.namespace, mcp.command, mcp.args);
238
- } else if (mcp.type === 'http' && mcp.url) {
239
- await this._inner.addMcpServerHttp(mcp.namespace, mcp.url);
241
+ let added = false;
242
+ try {
243
+ if (mcp.type === 'process' && mcp.command && mcp.args) {
244
+ await this._inner.addMcpServer(mcp.namespace, mcp.command, mcp.args);
245
+ added = true;
246
+ } else if (mcp.type === 'http' && mcp.url) {
247
+ await this._inner.addMcpServerHttp(mcp.namespace, mcp.url);
248
+ added = true;
249
+ }
250
+ if (added) {
251
+ this._onMcpStatus?.(mcp.namespace, mcp.type, mcp.type === 'process' ? mcp.command! : mcp.url!, 'connected');
252
+ }
253
+ } catch (err) {
254
+ this._onMcpStatus?.(mcp.namespace, mcp.type, mcp.type === 'process' ? mcp.command! : mcp.url!, 'failed', String(err));
255
+ console.warn(`[agent] MCP server "${mcp.namespace}" connection failed, skipping:`, err);
240
256
  }
241
257
  }
242
258
 
package/src/brainos.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import * as jsbos from '@open1s/jsbos';
2
- import { AgentBuilder, Agent } from './agent.js';
2
+ import { AgentBuilder, Agent, McpStatusCallback } from './agent.js';
3
3
 
4
4
  interface BrainOSOptions {
5
5
  model?: string;
6
6
  baseUrl?: string;
7
7
  apiKey?: string;
8
+ onMcpStatus?: McpStatusCallback;
8
9
  }
9
10
 
10
11
  interface BusOptions {
@@ -73,16 +74,14 @@ export class BrainOS {
73
74
  temperature?: number;
74
75
  timeoutSecs?: number;
75
76
  maxTokens?: number;
77
+ onMcpStatus?: McpStatusCallback;
76
78
  } = {}): AgentBuilder {
77
79
  if (!this._started) {
78
80
  throw new Error('BrainOS not started. Call start() first.');
79
81
  }
80
82
  return new AgentBuilder(name, {
81
- ...this._options,
82
83
  ...options,
83
- apiKey: options.apiKey || this._options.apiKey,
84
- model: options.model || this._options.model,
85
- baseUrl: options.baseUrl || this._options.baseUrl,
84
+ ...this._options,
86
85
  });
87
86
  }
88
87