chat-agent-toolkit 1.2.1 → 1.2.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.
Files changed (68) hide show
  1. package/README.md +6 -6
  2. package/dist/config/config-manager.d.ts +23 -0
  3. package/dist/config/config-types.d.ts +58 -0
  4. package/dist/config/environment-variables.d.ts +6 -0
  5. package/dist/config/index.d.ts +18 -0
  6. package/dist/config/language-models-database.d.ts +93 -0
  7. package/dist/config/mcp-server-registry.d.ts +7 -0
  8. package/dist/config/model-registry.d.ts +69 -0
  9. package/dist/config/model-tester.d.ts +51 -0
  10. package/dist/config/model-utils.d.ts +44 -0
  11. package/dist/config/provider-ui-config.d.ts +6 -0
  12. package/dist/index.d.ts +23 -0
  13. package/dist/memory/agent-memory-manager.d.ts +125 -0
  14. package/dist/memory/example.d.ts +36 -0
  15. package/dist/memory/index.d.ts +18 -0
  16. package/dist/memory/mastra-integration.d.ts +146 -0
  17. package/dist/memory/storage/drizzle-storage.d.ts +82 -0
  18. package/dist/memory/storage/in-memory-storage.d.ts +75 -0
  19. package/dist/memory/storage/storage-interface.d.ts +37 -0
  20. package/dist/memory/types.d.ts +122 -0
  21. package/dist/models/providers.d.ts +5 -0
  22. package/dist/models/registry.d.ts +4 -0
  23. package/dist/models/types.d.ts +4 -0
  24. package/dist/research-agent.cjs.js +2 -0
  25. package/dist/research-agent.cjs.js.map +1 -0
  26. package/dist/research-agent.es.js +2 -0
  27. package/dist/research-agent.es.js.map +1 -0
  28. package/dist/search.d.ts +5 -0
  29. package/dist/tools/index.d.ts +12 -0
  30. package/dist/tools/open-connector-mastra.d.ts +137 -0
  31. package/dist/tools/open-connector-mcp.d.ts +88 -0
  32. package/dist/tools/qwksearch-api-tools.d.ts +149 -0
  33. package/dist/tools/search/doc-utils.d.ts +11 -0
  34. package/dist/tools/search/document.d.ts +14 -0
  35. package/dist/tools/search/index.d.ts +12 -0
  36. package/dist/tools/search/link-summarizer.d.ts +7 -0
  37. package/dist/tools/search/meta-search-types.d.ts +50 -0
  38. package/dist/tools/search/metaSearchAgent.d.ts +21 -0
  39. package/dist/tools/search/search-handlers.d.ts +27 -0
  40. package/dist/tools/search/suggestionGeneratorAgent.d.ts +8 -0
  41. package/dist/types.d.ts +2 -0
  42. package/dist/utils/chat-helpers.d.ts +10 -0
  43. package/dist/utils/index.d.ts +2 -0
  44. package/dist/utils/markdown-to-html.d.ts +5 -0
  45. package/dist/utils/outputParser.d.ts +22 -0
  46. package/dist/utils/provider-image-cropper.d.ts +120 -0
  47. package/package.json +16 -6
  48. package/src/config/config-manager.ts +0 -8
  49. package/src/config/environment-variables.ts +11 -3
  50. package/src/config/language-models-database.ts +50 -42
  51. package/src/config/model-registry.ts +20 -5
  52. package/src/config/model-tester.ts +2 -2
  53. package/src/connectors/{composio.json → open-connector.json} +21 -45
  54. package/src/index.ts +3 -0
  55. package/src/memory/ARCHITECTURE.md +1 -1
  56. package/src/memory/example.ts +6 -6
  57. package/src/memory/mastra-integration.ts +6 -11
  58. package/src/memory/storage/drizzle-storage.ts +60 -29
  59. package/src/memory/storage/in-memory-storage.ts +2 -2
  60. package/src/memory/storage/storage-interface.ts +1 -1
  61. package/src/models/types.ts +1 -1
  62. package/src/tools/{composio-mastra.ts → open-connector-mastra.ts} +58 -93
  63. package/src/tools/open-connector-mcp.ts +170 -0
  64. package/src/tools/search/doc-utils.ts +36 -8
  65. package/src/tools/search/metaSearchAgent.ts +11 -0
  66. package/src/tools/search/search-handlers.ts +13 -1
  67. package/src/tools/search/suggestionGeneratorAgent.ts +5 -3
  68. package/src/tools/composio-mcp.ts +0 -205
@@ -14,15 +14,40 @@ import type {
14
14
  } from "../types";
15
15
 
16
16
  /**
17
- * Drizzle-based storage adapter
17
+ * The Drizzle table passed to {@link DrizzleMemoryStorage} must expose these
18
+ * columns (see {@link createMemorySchema} for the expected shape).
19
+ */
20
+ export interface MemoryTable {
21
+ id: any;
22
+ user_id: any;
23
+ memory_type: any;
24
+ content: any;
25
+ importance: any;
26
+ access_count: any;
27
+ metadata: any;
28
+ created_at: any;
29
+ updated_at: any;
30
+ }
31
+
32
+ /**
33
+ * Drizzle-based storage adapter.
34
+ *
35
+ * Pass the Drizzle database instance and the memory table object defined in
36
+ * your schema (not a table-name string) so queries reference real columns:
37
+ *
38
+ * ```ts
39
+ * import { sqliteTable, text, integer, real } from "drizzle-orm/sqlite-core";
40
+ * const userMemories = sqliteTable("user_memories", { ... });
41
+ * const storage = new DrizzleMemoryStorage(db, userMemories);
42
+ * ```
18
43
  */
19
44
  export class DrizzleMemoryStorage implements IMemoryStorage {
20
45
  private db: any;
21
- private tableName: string;
46
+ private table: MemoryTable & Record<string, any>;
22
47
 
23
- constructor(db: any, tableName: string = "user_memories") {
48
+ constructor(db: any, table: MemoryTable & Record<string, any>) {
24
49
  this.db = db;
25
- this.tableName = tableName;
50
+ this.table = table;
26
51
  }
27
52
 
28
53
  /**
@@ -36,7 +61,7 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
36
61
  metadata?: Record<string, any>,
37
62
  ): Promise<string> {
38
63
  const result = await this.db
39
- .insert(this.tableName)
64
+ .insert(this.table)
40
65
  .values({
41
66
  user_id: userId,
42
67
  memory_type: memoryType,
@@ -47,7 +72,7 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
47
72
  created_at: new Date(),
48
73
  updated_at: new Date(),
49
74
  })
50
- .returning({ id: "id" });
75
+ .returning({ id: this.table.id });
51
76
 
52
77
  return result[0]?.id;
53
78
  }
@@ -61,31 +86,35 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
61
86
  limit: number = 10,
62
87
  options: MemorySearchOptions = {},
63
88
  ): Promise<MemoryRecord[]> {
64
- const conditions = [eq("user_id", userId)];
89
+ const conditions = [eq(this.table.user_id, userId)];
65
90
 
66
91
  if (query && query.trim()) {
67
- conditions.push(like("content", `%${query}%`));
92
+ conditions.push(like(this.table.content, `%${query}%`));
68
93
  }
69
94
 
70
95
  if (options.memoryType) {
71
- conditions.push(eq("memory_type", options.memoryType));
96
+ conditions.push(eq(this.table.memory_type, options.memoryType));
72
97
  }
73
98
 
74
99
  const results = await this.db
75
100
  .select({
76
- id: "id",
77
- user_id: "user_id",
78
- memory_type: "memory_type",
79
- content: "content",
80
- importance: "importance",
81
- access_count: "access_count",
82
- metadata: "metadata",
83
- created_at: "created_at",
84
- updated_at: "updated_at",
101
+ id: this.table.id,
102
+ user_id: this.table.user_id,
103
+ memory_type: this.table.memory_type,
104
+ content: this.table.content,
105
+ importance: this.table.importance,
106
+ access_count: this.table.access_count,
107
+ metadata: this.table.metadata,
108
+ created_at: this.table.created_at,
109
+ updated_at: this.table.updated_at,
85
110
  })
86
- .from(this.tableName)
111
+ .from(this.table)
87
112
  .where(and(...conditions))
88
- .orderBy(desc("importance"), desc("access_count"), desc("updated_at"))
113
+ .orderBy(
114
+ desc(this.table.importance),
115
+ desc(this.table.access_count),
116
+ desc(this.table.updated_at),
117
+ )
89
118
  .limit(Math.min(limit, 50)); // Cap at 50 for performance
90
119
 
91
120
  return results as MemoryRecord[];
@@ -110,13 +139,15 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
110
139
  return [];
111
140
  }
112
141
 
113
- const conditions = searchTerms.map((term) => like("content", `%${term}%`));
142
+ const conditions = searchTerms.map((term) =>
143
+ like(this.table.content, `%${term}%`),
144
+ );
114
145
 
115
146
  const results = await this.db
116
147
  .select()
117
- .from(this.tableName)
118
- .where(and(eq("user_id", userId), or(...conditions)))
119
- .orderBy(desc("importance"), desc("updated_at"))
148
+ .from(this.table)
149
+ .where(and(eq(this.table.user_id, userId), or(...conditions)))
150
+ .orderBy(desc(this.table.importance), desc(this.table.updated_at))
120
151
  .limit(limit);
121
152
 
122
153
  return results as MemoryRecord[];
@@ -134,7 +165,7 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
134
165
 
135
166
  if (updates.access_count !== undefined) {
136
167
  if (typeof updates.access_count === "object" && updates.access_count.increment) {
137
- updateData.access_count = sql`access_count + ${updates.access_count.increment}`;
168
+ updateData.access_count = sql`${this.table.access_count} + ${updates.access_count.increment}`;
138
169
  } else {
139
170
  updateData.access_count = updates.access_count;
140
171
  }
@@ -148,14 +179,14 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
148
179
  updateData.metadata = updates.metadata;
149
180
  }
150
181
 
151
- await this.db.update(this.tableName).set(updateData).where(eq("id", id));
182
+ await this.db.update(this.table).set(updateData).where(eq(this.table.id, id));
152
183
  }
153
184
 
154
185
  /**
155
186
  * Delete a memory record
156
187
  */
157
188
  async deleteMemory(id: string): Promise<void> {
158
- await this.db.delete(this.tableName).where(eq("id", id));
189
+ await this.db.delete(this.table).where(eq(this.table.id, id));
159
190
  }
160
191
 
161
192
  /**
@@ -164,8 +195,8 @@ export class DrizzleMemoryStorage implements IMemoryStorage {
164
195
  async getMemoryById(id: string): Promise<MemoryRecord | null> {
165
196
  const results = await this.db
166
197
  .select()
167
- .from(this.tableName)
168
- .where(eq("id", id))
198
+ .from(this.table)
199
+ .where(eq(this.table.id, id))
169
200
  .limit(1);
170
201
 
171
202
  return (results[0] as MemoryRecord) || null;
@@ -11,7 +11,7 @@
11
11
  * - Conflict resolution
12
12
  */
13
13
 
14
- import { generateLanguageResponse } from "write-language";
14
+ import { writeLanguageResponse } from "write-language";
15
15
  import type { IMemoryStorage } from "./storage-interface";
16
16
  import type {
17
17
  MemoryRecord,
@@ -422,7 +422,7 @@ export class SimpleMemory {
422
422
  conversationText: string,
423
423
  ): Promise<ExtractedFact[]> {
424
424
  try {
425
- const { extract: factsResponse } = await generateLanguageResponse({
425
+ const { extract: factsResponse } = await writeLanguageResponse({
426
426
  agent: "remember-facts",
427
427
  chat_history: conversationText,
428
428
  provider: "groq",
@@ -10,7 +10,7 @@ import type {
10
10
  MemoryType,
11
11
  MemorySearchOptions,
12
12
  MemoryUpdate,
13
- } from "./types";
13
+ } from "../types";
14
14
 
15
15
  /**
16
16
  * Storage interface that any database adapter must implement
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * @fileoverview Re-export model types from config directory
3
3
  */
4
- export type { Model, ConfigModelProvider } from "../config/config-types";
4
+ export type { Model, ConfigModelProvider, MinimalProvider } from "../config/config-types";
@@ -1,34 +1,34 @@
1
1
  /**
2
- * @fileoverview Composio + Mastra Integration
2
+ * @fileoverview OpenConnector + Mastra Integration
3
3
  *
4
- * Connects Composio's MCP endpoint to Mastra agents.
5
- * Composio provides the tools, Mastra provides the agent framework.
4
+ * Connects OpenConnector's MCP endpoint to Mastra agents.
5
+ * OpenConnector provides the tools, Mastra provides the agent framework.
6
6
  *
7
7
  * Architecture:
8
- * 1. Create Composio Tool Router session → Get MCP URL + headers
9
- * 2. Configure Mastra MCPClient with URL + headers
8
+ * 1. Connect to OpenConnector Worker URL at /mcp/sse
9
+ * 2. Configure Mastra MCPClient with URL + auth headers
10
10
  * 3. Get tools with mcp.listTools() or mcp.listToolsets()
11
11
  * 4. Create Mastra Agent with tools
12
12
  * 5. Execute agent.generate() with multi-step tool calling
13
13
  *
14
- * @see https://composio.dev/toolkits/composio/framework/mastra-ai
14
+ * @see https://github.com/OpenSourceAGI/open-connector
15
15
  */
16
16
 
17
- import { Composio } from '@composio/core';
18
17
  import { Agent } from '@mastra/core/agent';
19
18
  import { MCPClient } from '@mastra/mcp';
20
- import type { Tool } from '@mastra/core';
21
19
 
22
20
  /**
23
- * Configuration for Composio + Mastra integration
21
+ * Configuration for OpenConnector + Mastra integration
24
22
  */
25
- export interface ComposioMastraConfig {
26
- /** Composio API key */
27
- composioApiKey: string;
23
+ export interface OpenConnectorMastraConfig {
24
+ /** OpenConnector admin token */
25
+ adminToken: string;
26
+ /** Base URL of the deployed OpenConnector Worker */
27
+ baseUrl: string;
28
28
  /** User ID for scoping the session */
29
29
  userId: string;
30
- /** Toolkits to enable */
31
- toolkits: string[];
30
+ /** Apps to enable */
31
+ apps: string[];
32
32
  /** Agent configuration */
33
33
  agent: {
34
34
  id: string;
@@ -42,67 +42,36 @@ export interface ComposioMastraConfig {
42
42
  }
43
43
 
44
44
  /**
45
- * Composio + Mastra session manager
45
+ * OpenConnector + Mastra session manager
46
46
  * Handles MCP connection lifecycle and agent creation
47
47
  */
48
- export class ComposioMastraSession {
49
- private composio: Composio;
48
+ export class OpenConnectorMastraSession {
50
49
  private mcpClient: MCPClient | null = null;
51
50
  private agent: Agent | null = null;
52
- private sessionEndpoint: { url: string; headers: Record<string, string> } | null =
53
- null;
54
51
 
55
- constructor(private config: ComposioMastraConfig) {
56
- this.composio = new Composio({
57
- apiKey: config.composioApiKey,
58
- });
59
- }
60
-
61
- /**
62
- * Create Composio Tool Router session
63
- * Returns MCP endpoint URL + auth headers
64
- */
65
- private async createSession() {
66
- if (this.sessionEndpoint) {
67
- return this.sessionEndpoint;
68
- }
69
-
70
- // Create Composio session with specified toolkits
71
- const session = await this.composio.toolsets.create({
72
- userId: this.config.userId,
73
- toolkits: this.config.toolkits,
74
- });
75
-
76
- this.sessionEndpoint = {
77
- url: session.mcp.url,
78
- headers: {
79
- 'x-api-key': this.config.composioApiKey,
80
- ...session.mcp.headers,
81
- },
82
- };
83
-
84
- return this.sessionEndpoint;
85
- }
52
+ constructor(private config: OpenConnectorMastraConfig) {}
86
53
 
87
54
  /**
88
55
  * Get or create Mastra MCP client
89
- * Connects to Composio's MCP endpoint via HTTP
56
+ * Connects to OpenConnector's MCP endpoint via HTTP
90
57
  */
91
58
  async getMCPClient(): Promise<MCPClient> {
92
59
  if (this.mcpClient) {
93
60
  return this.mcpClient;
94
61
  }
95
62
 
96
- const endpoint = await this.createSession();
63
+ const mcpUrl = `${this.config.baseUrl}/mcp/sse`;
97
64
 
98
65
  // Create Mastra MCP client
99
66
  this.mcpClient = new MCPClient({
100
- id: `composio-${this.config.userId}`,
67
+ id: `open-connector-${this.config.userId}`,
101
68
  servers: {
102
- composio: {
103
- url: new URL(endpoint.url),
69
+ openconnector: {
70
+ url: new URL(mcpUrl),
104
71
  requestInit: {
105
- headers: endpoint.headers,
72
+ headers: {
73
+ Authorization: `Bearer ${this.config.adminToken}`,
74
+ },
106
75
  },
107
76
  },
108
77
  },
@@ -112,16 +81,16 @@ export class ComposioMastraSession {
112
81
  }
113
82
 
114
83
  /**
115
- * Get tools from Composio MCP
84
+ * Get tools from OpenConnector MCP
116
85
  * Use for static agent setup (same tools for all requests)
117
86
  */
118
- async getTools(): Promise<Record<string, Tool>> {
87
+ async getTools() {
119
88
  const mcp = await this.getMCPClient();
120
89
  return await mcp.listTools();
121
90
  }
122
91
 
123
92
  /**
124
- * Get toolsets from Composio MCP
93
+ * Get toolsets from OpenConnector MCP
125
94
  * Use for dynamic per-request tool configuration
126
95
  */
127
96
  async getToolsets() {
@@ -130,7 +99,7 @@ export class ComposioMastraSession {
130
99
  }
131
100
 
132
101
  /**
133
- * Create or get Mastra agent with Composio tools
102
+ * Create or get Mastra agent with OpenConnector tools
134
103
  * Agent is cached and reused across generate() calls
135
104
  */
136
105
  async getAgent(): Promise<Agent> {
@@ -163,7 +132,8 @@ export class ComposioMastraSession {
163
132
  prompt: string,
164
133
  options?: {
165
134
  maxSteps?: number;
166
- context?: Record<string, any>;
135
+ /** Extra context messages passed to the agent (model messages) */
136
+ context?: any[];
167
137
  }
168
138
  ) {
169
139
  const agent = await this.getAgent();
@@ -184,20 +154,20 @@ export class ComposioMastraSession {
184
154
  this.mcpClient = null;
185
155
  }
186
156
  this.agent = null;
187
- this.sessionEndpoint = null;
188
157
  }
189
158
  }
190
159
 
191
160
  /**
192
- * Quick helper to create a Composio + Mastra agent
161
+ * Quick helper to create an OpenConnector + Mastra agent
193
162
  * For one-off usage without session management
194
163
  *
195
164
  * @example
196
165
  * ```ts
197
- * const result = await createComposioMastraAgent({
198
- * composioApiKey: process.env.COMPOSIO_API_KEY!,
166
+ * const result = await createOpenConnectorMastraAgent({
167
+ * adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
168
+ * baseUrl: 'https://open-connector.example.workers.dev',
199
169
  * userId: 'user-123',
200
- * toolkits: ['GMAIL', 'SLACK'],
170
+ * apps: ['gmail', 'slack'],
201
171
  * agent: {
202
172
  * id: 'email-agent',
203
173
  * name: 'Email Assistant',
@@ -207,20 +177,23 @@ export class ComposioMastraSession {
207
177
  * }).generate('Check my unread emails');
208
178
  * ```
209
179
  */
210
- export async function createComposioMastraAgent(config: ComposioMastraConfig) {
211
- const session = new ComposioMastraSession(config);
180
+ export async function createOpenConnectorMastraAgent(
181
+ config: OpenConnectorMastraConfig
182
+ ) {
183
+ const session = new OpenConnectorMastraSession(config);
212
184
  await session.getAgent(); // Initialize
213
185
  return session;
214
186
  }
215
187
 
216
188
  /**
217
- * Create Mastra agent with dynamic per-request toolsets
189
+ * Create Mastra agent with dynamic per-request apps
218
190
  * Better for multi-user scenarios where tools vary per request
219
191
  *
220
192
  * @example
221
193
  * ```ts
222
- * const agent = await createDynamicComposioAgent({
223
- * composioApiKey: process.env.COMPOSIO_API_KEY!,
194
+ * const agent = await createDynamicOpenConnectorAgent({
195
+ * adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
196
+ * baseUrl: 'https://open-connector.example.workers.dev',
224
197
  * agent: {
225
198
  * id: 'dynamic-agent',
226
199
  * name: 'Dynamic Assistant',
@@ -229,16 +202,17 @@ export async function createComposioMastraAgent(config: ComposioMastraConfig) {
229
202
  * },
230
203
  * });
231
204
  *
232
- * // Each request can have different userId/toolkits
205
+ * // Each request can have different userId/apps
233
206
  * const result = await agent.generate({
234
207
  * userId: 'user-123',
235
- * toolkits: ['GMAIL'],
208
+ * apps: ['gmail'],
236
209
  * prompt: 'Check emails',
237
210
  * });
238
211
  * ```
239
212
  */
240
- export async function createDynamicComposioAgent(config: {
241
- composioApiKey: string;
213
+ export async function createDynamicOpenConnectorAgent(config: {
214
+ adminToken: string;
215
+ baseUrl: string;
242
216
  agent: {
243
217
  id: string;
244
218
  name: string;
@@ -247,33 +221,24 @@ export async function createDynamicComposioAgent(config: {
247
221
  maxSteps?: number;
248
222
  };
249
223
  }) {
250
- const composio = new Composio({
251
- apiKey: config.composioApiKey,
252
- });
253
-
254
224
  return {
255
225
  async generate(params: {
256
226
  userId: string;
257
- toolkits: string[];
227
+ apps: string[];
258
228
  prompt: string;
259
229
  maxSteps?: number;
260
230
  }) {
261
- // Create session for this user/toolkits
262
- const session = await composio.toolsets.create({
263
- userId: params.userId,
264
- toolkits: params.toolkits,
265
- });
231
+ const mcpUrl = `${config.baseUrl}/mcp/sse`;
266
232
 
267
233
  // Connect MCP client
268
234
  const mcp = new MCPClient({
269
- id: `composio-${params.userId}`,
235
+ id: `open-connector-${params.userId}`,
270
236
  servers: {
271
- composio: {
272
- url: new URL(session.mcp.url),
237
+ openconnector: {
238
+ url: new URL(mcpUrl),
273
239
  requestInit: {
274
240
  headers: {
275
- 'x-api-key': config.composioApiKey,
276
- ...session.mcp.headers,
241
+ Authorization: `Bearer ${config.adminToken}`,
277
242
  },
278
243
  },
279
244
  },
@@ -284,18 +249,18 @@ export async function createDynamicComposioAgent(config: {
284
249
  // Get toolsets for this request
285
250
  const toolsets = await mcp.listToolsets();
286
251
 
287
- // Create agent with dynamic toolsets
252
+ // Create agent; toolsets are provided per-request at generate time
288
253
  const agent = new Agent({
289
254
  id: config.agent.id,
290
255
  name: config.agent.name,
291
256
  instructions: config.agent.instructions,
292
257
  model: config.agent.model,
293
- toolsets,
294
258
  });
295
259
 
296
- // Execute
260
+ // Execute with dynamic toolsets
297
261
  return await agent.generate(params.prompt, {
298
262
  maxSteps: params.maxSteps || config.agent.maxSteps || 5,
263
+ toolsets,
299
264
  });
300
265
  } finally {
301
266
  await mcp.disconnect();
@@ -0,0 +1,170 @@
1
+ /**
2
+ * @fileoverview OpenConnector MCP Integration for AI SDK v5
3
+ *
4
+ * OpenConnector is a self-hosted Cloudflare Workers integration platform
5
+ * that provides OAuth-managed access to 100+ apps. This module creates
6
+ * MCP clients connected to OpenConnector's HTTP endpoints, fetches
7
+ * available tools, and passes them to AI SDK models.
8
+ *
9
+ * Architecture:
10
+ * 1. Connect to OpenConnector Worker URL at /mcp/sse
11
+ * 2. Authenticate with admin token via Authorization header
12
+ * 3. Fetch tools with client.tools()
13
+ * 4. Pass to streamText/generateText
14
+ *
15
+ * @see https://github.com/OpenSourceAGI/open-connector
16
+ */
17
+
18
+ import { createMCPClient } from '@ai-sdk/mcp';
19
+ import type { MCPClient } from '@ai-sdk/mcp';
20
+ import type { ToolSet } from 'ai';
21
+
22
+ /**
23
+ * Configuration for OpenConnector MCP session
24
+ */
25
+ export interface OpenConnectorMCPConfig {
26
+ /** OpenConnector admin token (OPEN_CONNECTOR_ADMIN_TOKEN) */
27
+ adminToken: string;
28
+ /** Base URL of the deployed OpenConnector Worker */
29
+ baseUrl: string;
30
+ /** User ID to scope the session */
31
+ userId: string;
32
+ /** Apps to enable (e.g., ['gmail', 'notion', 'slack']) */
33
+ apps: string[];
34
+ }
35
+
36
+ /**
37
+ * OpenConnector MCP session wrapper
38
+ * Manages the lifecycle of MCP client connections to OpenConnector
39
+ */
40
+ export class OpenConnectorMCPSession {
41
+ private client: MCPClient | null = null;
42
+
43
+ constructor(private config: OpenConnectorMCPConfig) {}
44
+
45
+ /**
46
+ * Get or create the MCP client connection
47
+ * Uses HTTP SSE transport as provided by OpenConnector
48
+ */
49
+ async getClient(): Promise<MCPClient> {
50
+ if (this.client) {
51
+ return this.client;
52
+ }
53
+
54
+ // Construct MCP endpoint URL
55
+ const mcpUrl = `${this.config.baseUrl}/mcp/sse`;
56
+
57
+ // Connect to OpenConnector MCP endpoint via HTTP
58
+ this.client = await createMCPClient({
59
+ transport: {
60
+ type: 'http',
61
+ url: mcpUrl,
62
+ headers: {
63
+ Authorization: `Bearer ${this.config.adminToken}`,
64
+ },
65
+ redirect: 'error',
66
+ },
67
+ });
68
+
69
+ return this.client;
70
+ }
71
+
72
+ /**
73
+ * Get all available tools from OpenConnector MCP
74
+ * These tools can be passed directly to streamText/generateText
75
+ *
76
+ * @returns Tools object compatible with AI SDK
77
+ */
78
+ async getTools(): Promise<ToolSet> {
79
+ const client = await this.getClient();
80
+ return (await client.tools()) as ToolSet;
81
+ }
82
+
83
+ /**
84
+ * Close the MCP connection
85
+ * Should be called after request completion or in finally block
86
+ */
87
+ async close() {
88
+ if (this.client) {
89
+ await this.client.close();
90
+ this.client = null;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Health check for the OpenConnector Worker
96
+ */
97
+ async healthCheck(): Promise<boolean> {
98
+ try {
99
+ const response = await fetch(`${this.config.baseUrl}/health`, {
100
+ headers: {
101
+ Authorization: `Bearer ${this.config.adminToken}`,
102
+ },
103
+ });
104
+ return response.ok;
105
+ } catch {
106
+ return false;
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Helper function to create a one-shot OpenConnector MCP session
113
+ * For quick tool usage without managing session lifecycle
114
+ *
115
+ * @example
116
+ * ```ts
117
+ * const tools = await getOpenConnectorTools({
118
+ * adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
119
+ * baseUrl: 'https://open-connector.example.workers.dev',
120
+ * userId: 'user-123',
121
+ * apps: ['gmail', 'slack'],
122
+ * });
123
+ *
124
+ * const result = await generateText({
125
+ * model: openai('gpt-4o'),
126
+ * prompt: 'Check my unread emails',
127
+ * tools,
128
+ * });
129
+ * ```
130
+ */
131
+ export async function getOpenConnectorTools(
132
+ config: OpenConnectorMCPConfig
133
+ ): Promise<ToolSet> {
134
+ const session = new OpenConnectorMCPSession(config);
135
+ try {
136
+ return await session.getTools();
137
+ } finally {
138
+ await session.close();
139
+ }
140
+ }
141
+
142
+ /**
143
+ * Create a reusable OpenConnector MCP session
144
+ * Better for multiple requests with the same apps
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * const session = await createOpenConnectorSession({
149
+ * adminToken: process.env.OPEN_CONNECTOR_ADMIN_TOKEN!,
150
+ * baseUrl: 'https://open-connector.example.workers.dev',
151
+ * userId: 'user-123',
152
+ * apps: ['gmail', 'notion'],
153
+ * });
154
+ *
155
+ * try {
156
+ * const tools = await session.getTools();
157
+ * const result = await streamText({ model, messages, tools });
158
+ * } finally {
159
+ * await session.close();
160
+ * }
161
+ * ```
162
+ */
163
+ export async function createOpenConnectorSession(
164
+ config: OpenConnectorMCPConfig
165
+ ): Promise<OpenConnectorMCPSession> {
166
+ const session = new OpenConnectorMCPSession(config);
167
+ // Pre-initialize the connection
168
+ await session.getClient();
169
+ return session;
170
+ }