@opentiny/next-sdk 0.1.3 → 0.1.4

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 (58) hide show
  1. package/McpSdk.ts +14 -0
  2. package/WebAgent.ts +5 -0
  3. package/WebMcp.ts +18 -0
  4. package/Zod.ts +1 -0
  5. package/agent/AgentModelProvider.ts +150 -35
  6. package/agent/type.ts +1 -1
  7. package/agent/utils/getAISDKTools.ts +35 -0
  8. package/dist/agent/AgentModelProvider.d.ts +43 -4
  9. package/dist/agent/AgentModelProvider.js +145 -24
  10. package/dist/agent/type.d.ts +1 -1
  11. package/dist/agent/utils/getAISDKTools.d.ts +8 -0
  12. package/dist/agent/utils/getAISDKTools.js +36 -0
  13. package/dist/index.d.ts +5 -4
  14. package/dist/index.es.dev.js +42947 -0
  15. package/dist/index.es.js +17998 -17742
  16. package/dist/index.js +10 -4
  17. package/dist/index.umd.dev.js +43341 -0
  18. package/dist/index.umd.js +285 -114
  19. package/dist/mcpsdk@1.17.0.dev.js +21391 -0
  20. package/dist/mcpsdk@1.17.0.es.dev.js +21389 -0
  21. package/dist/mcpsdk@1.17.0.es.js +14505 -0
  22. package/dist/mcpsdk@1.17.0.js +16 -0
  23. package/dist/remoter/createRemoter.d.ts +10 -2
  24. package/dist/remoter/createRemoter.js +312 -55
  25. package/dist/webagent.dev.js +27509 -0
  26. package/dist/webagent.es.dev.js +27115 -0
  27. package/dist/webagent.es.js +21448 -0
  28. package/dist/webagent.js +529 -0
  29. package/dist/webmcp-full.dev.js +22915 -0
  30. package/dist/webmcp-full.es.dev.js +22911 -0
  31. package/dist/webmcp-full.es.js +15821 -0
  32. package/dist/webmcp-full.js +16 -0
  33. package/dist/webmcp.dev.js +1373 -0
  34. package/dist/webmcp.es.dev.js +1366 -0
  35. package/dist/webmcp.es.js +1232 -0
  36. package/dist/webmcp.js +1 -0
  37. package/dist/zod@3.25.76.dev.js +4039 -0
  38. package/dist/zod@3.25.76.es.dev.js +4035 -0
  39. package/dist/zod@3.25.76.es.js +2947 -0
  40. package/dist/zod@3.25.76.js +1 -0
  41. package/index.ts +16 -4
  42. package/package.json +16 -4
  43. package/remoter/createRemoter.ts +327 -62
  44. package/runtime.html +98 -0
  45. package/script/utils.ts +26 -0
  46. package/vite.config.mcpSdk.ts +28 -0
  47. package/vite.config.ts +13 -12
  48. package/vite.config.webAgent.ts +19 -0
  49. package/vite.config.webMcp.ts +40 -0
  50. package/vite.config.webMcpFull.ts +19 -0
  51. package/vite.config.zod.ts +23 -0
  52. package/agent/utils/aiProviderFactories.ts +0 -7
  53. package/agent/utils/index.ts +0 -79
  54. package/dist/agent/utils/aiProviderFactories.d.ts +0 -6
  55. package/dist/agent/utils/aiProviderFactories.js +0 -6
  56. package/dist/agent/utils/index.d.ts +0 -14
  57. package/dist/agent/utils/index.js +0 -72
  58. package/dist/index.cjs.js +0 -365
package/McpSdk.ts ADDED
@@ -0,0 +1,14 @@
1
+ import Ajv from 'ajv'
2
+ export { Ajv }
3
+ export * from '@modelcontextprotocol/sdk/types.js'
4
+ export * from '@modelcontextprotocol/sdk/shared/uriTemplate.js'
5
+ export * from '@modelcontextprotocol/sdk/server/completable.js'
6
+ export * from '@modelcontextprotocol/sdk/shared/metadataUtils.js'
7
+ export * from '@modelcontextprotocol/sdk/client/index.js'
8
+ export * from '@modelcontextprotocol/sdk/client/auth.js'
9
+ export * from '@modelcontextprotocol/sdk/client/sse.js'
10
+ export * from '@modelcontextprotocol/sdk/client/streamableHttp.js'
11
+ // @ts-ignore
12
+ export * from '@modelcontextprotocol/sdk/server/mcp.js'
13
+ export * from '@modelcontextprotocol/sdk/shared/transport.js'
14
+ export * from '@modelcontextprotocol/sdk/shared/protocol.js'
package/WebAgent.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { AgentModelProvider } from './agent/AgentModelProvider'
2
+ export { createRemoter } from './remoter/createRemoter'
3
+ export { getAISDKTools } from './agent/utils/getAISDKTools'
4
+ export { QrCode, type QrCodeOption } from './remoter/QrCode'
5
+ export type * from './agent/type'
package/WebMcp.ts ADDED
@@ -0,0 +1,18 @@
1
+ import Ajv from 'ajv'
2
+ export * from './WebMcpServer'
3
+ export * from './WebMcpClient'
4
+ export { Ajv }
5
+ export { z } from 'zod'
6
+ export { AuthClientProvider } from '@opentiny/next'
7
+ export { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js'
8
+ export { UriTemplate } from '@modelcontextprotocol/sdk/shared/uriTemplate.js'
9
+ export { completable } from '@modelcontextprotocol/sdk/server/completable.js'
10
+ export { getDisplayName } from '@modelcontextprotocol/sdk/shared/metadataUtils.js'
11
+ export type * from 'zod'
12
+ export type * from '@opentiny/next'
13
+ export type * from '@modelcontextprotocol/sdk/types.js'
14
+ export type * from '@modelcontextprotocol/sdk/shared/protocol.js'
15
+ export type * from '@modelcontextprotocol/sdk/shared/transport.js'
16
+ export type * from '@modelcontextprotocol/sdk/client/sse.js'
17
+ export type * from '@modelcontextprotocol/sdk/client/streamableHttp.js'
18
+ export type * from '@modelcontextprotocol/sdk/server/mcp.js'
package/Zod.ts ADDED
@@ -0,0 +1 @@
1
+ export { z } from 'zod'
@@ -1,16 +1,41 @@
1
1
  import { streamText, stepCountIs, generateText } from 'ai'
2
+ import { experimental_createMCPClient as createMCPClient, experimental_MCPClientConfig as MCPClientConfig } from 'ai'
2
3
  import type { ToolSet } from 'ai'
3
- import { getMcpClients, getMcpTools } from './utils'
4
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
4
5
  import type { IAgentModelProviderOption, McpServerConfig } from './type'
5
- import { AIProviderFactories } from './utils/aiProviderFactories'
6
6
  import { ProviderV2 } from '@ai-sdk/provider'
7
7
  import { OpenAIProvider } from '@ai-sdk/openai'
8
+ import { createOpenAI } from '@ai-sdk/openai'
9
+ import { createDeepSeek } from '@ai-sdk/deepseek'
8
10
 
11
+ export const AIProviderFactories = {
12
+ ['openai']: createOpenAI,
13
+ ['deepseek']: createDeepSeek
14
+ }
15
+
16
+ type ChatMethodFn = typeof streamText | typeof generateText
17
+
18
+ /** 一个通用的ai-sdk的agent封装
19
+ * @summary 内部自动管理了 llm, mcpServer, ai-sdk的clients 和 tools
20
+ * @returns 暴露了 chat, chatStream方法
21
+ */
9
22
  export class AgentModelProvider {
10
23
  llm: ProviderV2 | OpenAIProvider
11
- mcpServers: McpServerConfig[]
12
- isGetMcpClients = false
24
+ /** mcpServers 允许为配置为 McpServerConfig, 或者任意的 MCPTransport
25
+ * 参考: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#initializing-an-mcp-client */
26
+ mcpServers: McpServerConfig[] = []
27
+ /** ai-sdk的 mcpClient */
13
28
  mcpClients: any[] = []
29
+ /** 所有的tools */
30
+ mcpTools: Array<Record<string, any>> = []
31
+ /** 需要实时过滤掉的tools name*/
32
+ ignoreToolnames: string[] = []
33
+
34
+ /** 在 chat 之前,自动更新 所有的tools */
35
+ autoUpdateTools = true
36
+
37
+ /** chat 时,自动更新 所有的tools 后的事件 */
38
+ onUpdatedTools: (() => void) | undefined
14
39
 
15
40
  constructor({ llmConfig, mcpServers, llm }: IAgentModelProviderOption) {
16
41
  // 1、保存 mcpServer
@@ -36,53 +61,143 @@ export class AgentModelProvider {
36
61
  }
37
62
  }
38
63
 
39
- async initClients() {
40
- if (!this.isGetMcpClients) {
41
- this.mcpClients = await getMcpClients(this.mcpServers)
42
- this.isGetMcpClients = true
64
+ /** 创建一个 ai-sdk的 mcpClient, 创建失败则返回 Null */
65
+ private async _createOneClient(serverConfig: McpServerConfig) {
66
+ try {
67
+ let transport: MCPClientConfig['transport']
68
+ // transport 一定是 streamableHttp 或者就是: ai-sdk允许的 transport
69
+ if ('type' in serverConfig && serverConfig.type.toLocaleLowerCase() === 'streamablehttp') {
70
+ transport = new StreamableHTTPClientTransport(new URL(serverConfig.url))
71
+ } else {
72
+ transport = serverConfig as MCPClientConfig['transport']
73
+ }
74
+
75
+ return createMCPClient({ transport: transport as MCPClientConfig['transport'] })
76
+ } catch (error) {
77
+ console.error(`Failed to create MCP client`, serverConfig, error)
78
+ return null
43
79
  }
44
80
  }
45
- async chat({
46
- model,
47
- maxSteps = 5,
48
- ...options
49
- }: Parameters<typeof generateText>[0] & { maxSteps?: number }): Promise<any> {
50
- if (!this.llm) {
51
- throw new Error('LLM is not initialized')
81
+ /** 创建 ai-sdk的 mcpClient, 失败则保存为null */
82
+ private async _createMpcClients() {
83
+ // 使用 Promise.all 并行处理所有 mcpServer 项
84
+ this.mcpClients = await Promise.all(
85
+ this.mcpServers.map(async (server) => {
86
+ return this._createOneClient(server)
87
+ })
88
+ )
89
+ }
90
+ /** 创建所有 mcpClients 的 tools, 失败则保存为null */
91
+ private async _createMpcTools() {
92
+ this.mcpTools = await Promise.all(
93
+ this.mcpClients.map(async (client) => {
94
+ try {
95
+ return client ? await client?.tools?.() : null
96
+ } catch (error) {
97
+ return null
98
+ }
99
+ })
100
+ )
101
+ }
102
+ /** 关闭所有的 clients */
103
+ async closeAll() {
104
+ await Promise.all(
105
+ this.mcpClients.map(async (client) => {
106
+ try {
107
+ client.close()
108
+ } catch (error) {}
109
+ })
110
+ )
111
+ }
112
+
113
+ async initClientsAndTools() {
114
+ await this._createMpcClients()
115
+ await this._createMpcTools()
116
+ }
117
+
118
+ async updateMcpServers(mcpServers: McpServerConfig[]) {
119
+ await this.closeAll()
120
+ this.mcpServers = mcpServers
121
+ await this.initClientsAndTools()
122
+ }
123
+
124
+ async insertMcpServer(mcpServer: McpServerConfig) {
125
+ const find = this.mcpServers.find((item: any) => item.url === mcpServer.url)
126
+
127
+ if (!find) {
128
+ this.mcpServers = [...this.mcpServers, mcpServer]
129
+ const client = await this._createOneClient(mcpServer)
130
+ this.mcpClients.push(client)
131
+ this.mcpTools.push((await client?.tools?.()) as Record<string, any>)
132
+ return true
52
133
  }
134
+ return false
135
+ }
136
+ /** 通过引用,删除一个 mcpServers mcpClients mcpTools ignoreToolnames */
137
+ removeMcpServer(mcpServer: McpServerConfig) {
138
+ const index = this.mcpServers.findIndex((server) => server === mcpServer)
53
139
 
54
- // 每次会话需要获取最新的工具列表,因为工具是会发生变化的
55
- await this.initClients()
56
- const tools = await getMcpTools(this.mcpClients, options)
140
+ // 移除
141
+ this.mcpServers.splice(index, 1)
57
142
 
58
- return generateText({
59
- // @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
60
- model: this.llm(model),
61
- tools: tools as ToolSet,
62
- stopWhen: stepCountIs(maxSteps),
63
- ...options
143
+ // 移除
144
+ const delClient = this.mcpClients[index]
145
+ this.mcpClients.splice(index, 1)
146
+ try {
147
+ delClient?.close()
148
+ } catch (error) {}
149
+
150
+ // 移除 tools
151
+ const delTool = this.mcpTools[index]
152
+ this.mcpTools.splice(index, 1)
153
+
154
+ // 移除 ignoreToolnames
155
+ if (delTool) {
156
+ Object.keys(delTool).forEach((toolName) => {
157
+ this.ignoreToolnames = this.ignoreToolnames.filter((name) => name !== toolName)
158
+ })
159
+ }
160
+ }
161
+
162
+ /** 创建临时允许调用的tools集合 */
163
+ tempMergeTools(extraTool = {}) {
164
+ const toolsResult = this.mcpTools.reduce((acc, curr) => ({ ...acc, ...curr }), {})
165
+ Object.assign(toolsResult, extraTool)
166
+
167
+ this.ignoreToolnames.forEach((name) => {
168
+ delete toolsResult[name]
64
169
  })
170
+
171
+ return toolsResult
65
172
  }
66
173
 
67
- async chatStream({
68
- model,
69
- maxSteps = 5,
70
- ...options
71
- }: Parameters<typeof streamText>[0] & { maxSteps?: number }): Promise<any> {
174
+ async _chat(
175
+ chatMethod: ChatMethodFn,
176
+ { model, maxSteps = 5, ...options }: Parameters<typeof generateText>[0] & { maxSteps?: number }
177
+ ): Promise<any> {
72
178
  if (!this.llm) {
73
179
  throw new Error('LLM is not initialized')
74
180
  }
75
181
 
76
- // 每次会话需要获取最新的工具列表,因为工具是会发生变化的
77
- await this.initClients()
78
- const tools = await getMcpTools(this.mcpClients, options)
182
+ if (this.autoUpdateTools) {
183
+ await this._createMpcTools()
184
+ this.onUpdatedTools?.()
185
+ }
79
186
 
80
- return streamText({
81
- // @ts-ignore 同上
187
+ return chatMethod({
188
+ // @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
82
189
  model: this.llm(model),
83
- tools: tools as ToolSet,
190
+ tools: this.tempMergeTools(options.tools) as ToolSet,
84
191
  stopWhen: stepCountIs(maxSteps),
85
192
  ...options
86
193
  })
87
194
  }
195
+
196
+ async chat(options: Parameters<typeof generateText>[0] & { maxSteps?: number }): Promise<any> {
197
+ return this._chat(generateText, options)
198
+ }
199
+
200
+ async chatStream(options: Parameters<typeof streamText>[0] & { maxSteps?: number }): Promise<any> {
201
+ return this._chat(streamText, options as any)
202
+ }
88
203
  }
package/agent/type.ts CHANGED
@@ -14,7 +14,7 @@ export interface IAgentModelProviderLlmConfig {
14
14
  }
15
15
 
16
16
  /** Mcp Server的配置对象 */
17
- export type McpServerConfig = { type: 'streamableHttp' | 'sse'; url: string } | { transport: MCPTransport }
17
+ export type McpServerConfig = { type: 'streamableHttp' | 'sse'; url: string } & { transport: MCPTransport }
18
18
 
19
19
  /** */
20
20
  export interface IAgentModelProviderOption {
@@ -0,0 +1,35 @@
1
+ import { dynamicTool, jsonSchema, Tool, ToolCallOptions, ToolSet } from 'ai'
2
+ import { WebMcpClient } from '../../WebMcpClient'
3
+
4
+ /**
5
+ * 快速 从官方 mcp 或 WebMcpClient 这2种client中, 抽取成 ai-sdk 所需要的 tool的对象
6
+ * @params client 一个已连接好的 WebMcpClient
7
+ * @returns ai-sdk的 tool 格式的对象。
8
+ */
9
+ export const getAISDKTools = async (client: WebMcpClient): Promise<ToolSet> => {
10
+ const tools: Record<string, Tool> = {}
11
+
12
+ try {
13
+ const listToolsResult = await client.listTools()
14
+
15
+ for (const { name, description, inputSchema } of listToolsResult.tools) {
16
+ const execute = async (args: any, options: ToolCallOptions): Promise<any> => {
17
+ return client.callTool({ name, arguments: args }, { signal: options?.abortSignal })
18
+ }
19
+
20
+ tools[name] = dynamicTool({
21
+ description,
22
+ inputSchema: jsonSchema({
23
+ ...inputSchema,
24
+ properties: (inputSchema.properties as Record<string, any>) ?? {},
25
+ additionalProperties: false
26
+ }),
27
+ execute
28
+ })
29
+ }
30
+
31
+ return tools
32
+ } catch (error) {
33
+ throw error
34
+ }
35
+ }
@@ -2,17 +2,56 @@ import { streamText, generateText } from 'ai';
2
2
  import type { IAgentModelProviderOption, McpServerConfig } from './type';
3
3
  import { ProviderV2 } from '@ai-sdk/provider';
4
4
  import { OpenAIProvider } from '@ai-sdk/openai';
5
+ import { createOpenAI } from '@ai-sdk/openai';
6
+ import { createDeepSeek } from '@ai-sdk/deepseek';
7
+ export declare const AIProviderFactories: {
8
+ openai: typeof createOpenAI;
9
+ deepseek: typeof createDeepSeek;
10
+ };
11
+ type ChatMethodFn = typeof streamText | typeof generateText;
12
+ /** 一个通用的ai-sdk的agent封装
13
+ * @summary 内部自动管理了 llm, mcpServer, ai-sdk的clients 和 tools
14
+ * @returns 暴露了 chat, chatStream方法
15
+ */
5
16
  export declare class AgentModelProvider {
6
17
  llm: ProviderV2 | OpenAIProvider;
18
+ /** mcpServers 允许为配置为 McpServerConfig, 或者任意的 MCPTransport
19
+ * 参考: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#initializing-an-mcp-client */
7
20
  mcpServers: McpServerConfig[];
8
- isGetMcpClients: boolean;
21
+ /** ai-sdk的 mcpClient */
9
22
  mcpClients: any[];
23
+ /** 所有的tools */
24
+ mcpTools: Array<Record<string, any>>;
25
+ /** 需要实时过滤掉的tools name*/
26
+ ignoreToolnames: string[];
27
+ /** 在 chat 之前,自动更新 所有的tools */
28
+ autoUpdateTools: boolean;
29
+ /** chat 时,自动更新 所有的tools 后的事件 */
30
+ onUpdatedTools: (() => void) | undefined;
10
31
  constructor({ llmConfig, mcpServers, llm }: IAgentModelProviderOption);
11
- initClients(): Promise<void>;
12
- chat({ model, maxSteps, ...options }: Parameters<typeof generateText>[0] & {
32
+ /** 创建一个 ai-sdk的 mcpClient, 创建失败则返回 Null */
33
+ private _createOneClient;
34
+ /** 创建 ai-sdk的 mcpClient, 失败则保存为null */
35
+ private _createMpcClients;
36
+ /** 创建所有 mcpClients 的 tools, 失败则保存为null */
37
+ private _createMpcTools;
38
+ /** 关闭所有的 clients */
39
+ closeAll(): Promise<void>;
40
+ initClientsAndTools(): Promise<void>;
41
+ updateMcpServers(mcpServers: McpServerConfig[]): Promise<void>;
42
+ insertMcpServer(mcpServer: McpServerConfig): Promise<boolean>;
43
+ /** 通过引用,删除一个 mcpServers mcpClients mcpTools ignoreToolnames */
44
+ removeMcpServer(mcpServer: McpServerConfig): void;
45
+ /** 创建临时允许调用的tools集合 */
46
+ tempMergeTools(extraTool?: {}): Record<string, any>;
47
+ _chat(chatMethod: ChatMethodFn, { model, maxSteps, ...options }: Parameters<typeof generateText>[0] & {
13
48
  maxSteps?: number;
14
49
  }): Promise<any>;
15
- chatStream({ model, maxSteps, ...options }: Parameters<typeof streamText>[0] & {
50
+ chat(options: Parameters<typeof generateText>[0] & {
51
+ maxSteps?: number;
52
+ }): Promise<any>;
53
+ chatStream(options: Parameters<typeof streamText>[0] & {
16
54
  maxSteps?: number;
17
55
  }): Promise<any>;
18
56
  }
57
+ export {};
@@ -19,12 +19,31 @@ var __rest = (this && this.__rest) || function (s, e) {
19
19
  return t;
20
20
  };
21
21
  import { streamText, stepCountIs, generateText } from 'ai';
22
- import { getMcpClients, getMcpTools } from './utils';
23
- import { AIProviderFactories } from './utils/aiProviderFactories';
22
+ import { experimental_createMCPClient as createMCPClient } from 'ai';
23
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
24
+ import { createOpenAI } from '@ai-sdk/openai';
25
+ import { createDeepSeek } from '@ai-sdk/deepseek';
26
+ export const AIProviderFactories = {
27
+ ['openai']: createOpenAI,
28
+ ['deepseek']: createDeepSeek
29
+ };
30
+ /** 一个通用的ai-sdk的agent封装
31
+ * @summary 内部自动管理了 llm, mcpServer, ai-sdk的clients 和 tools
32
+ * @returns 暴露了 chat, chatStream方法
33
+ */
24
34
  export class AgentModelProvider {
25
35
  constructor({ llmConfig, mcpServers, llm }) {
26
- this.isGetMcpClients = false;
36
+ /** mcpServers 允许为配置为 McpServerConfig, 或者任意的 MCPTransport
37
+ * 参考: https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling#initializing-an-mcp-client */
38
+ this.mcpServers = [];
39
+ /** ai-sdk的 mcpClient */
27
40
  this.mcpClients = [];
41
+ /** 所有的tools */
42
+ this.mcpTools = [];
43
+ /** 需要实时过滤掉的tools name*/
44
+ this.ignoreToolnames = [];
45
+ /** 在 chat 之前,自动更新 所有的tools */
46
+ this.autoUpdateTools = true;
28
47
  // 1、保存 mcpServer
29
48
  this.mcpServers = mcpServers || [];
30
49
  // 2、保存 llm
@@ -48,40 +67,142 @@ export class AgentModelProvider {
48
67
  throw new Error('Either llmConfig or llm must be provided');
49
68
  }
50
69
  }
51
- initClients() {
70
+ /** 创建一个 ai-sdk的 mcpClient, 创建失败则返回 Null */
71
+ _createOneClient(serverConfig) {
52
72
  return __awaiter(this, void 0, void 0, function* () {
53
- if (!this.isGetMcpClients) {
54
- this.mcpClients = yield getMcpClients(this.mcpServers);
55
- this.isGetMcpClients = true;
73
+ try {
74
+ let transport;
75
+ // transport 一定是 streamableHttp 或者就是: ai-sdk允许的 transport
76
+ if ('type' in serverConfig && serverConfig.type.toLocaleLowerCase() === 'streamablehttp') {
77
+ transport = new StreamableHTTPClientTransport(new URL(serverConfig.url));
78
+ }
79
+ else {
80
+ transport = serverConfig;
81
+ }
82
+ return createMCPClient({ transport: transport });
83
+ }
84
+ catch (error) {
85
+ console.error(`Failed to create MCP client`, serverConfig, error);
86
+ return null;
56
87
  }
57
88
  });
58
89
  }
59
- chat(_a) {
90
+ /** 创建 ai-sdk的 mcpClient, 失败则保存为null */
91
+ _createMpcClients() {
60
92
  return __awaiter(this, void 0, void 0, function* () {
61
- var { model, maxSteps = 5 } = _a, options = __rest(_a, ["model", "maxSteps"]);
62
- if (!this.llm) {
63
- throw new Error('LLM is not initialized');
93
+ // 使用 Promise.all 并行处理所有 mcpServer
94
+ this.mcpClients = yield Promise.all(this.mcpServers.map((server) => __awaiter(this, void 0, void 0, function* () {
95
+ return this._createOneClient(server);
96
+ })));
97
+ });
98
+ }
99
+ /** 创建所有 mcpClients 的 tools, 失败则保存为null */
100
+ _createMpcTools() {
101
+ return __awaiter(this, void 0, void 0, function* () {
102
+ this.mcpTools = yield Promise.all(this.mcpClients.map((client) => __awaiter(this, void 0, void 0, function* () {
103
+ var _a;
104
+ try {
105
+ return client ? yield ((_a = client === null || client === void 0 ? void 0 : client.tools) === null || _a === void 0 ? void 0 : _a.call(client)) : null;
106
+ }
107
+ catch (error) {
108
+ return null;
109
+ }
110
+ })));
111
+ });
112
+ }
113
+ /** 关闭所有的 clients */
114
+ closeAll() {
115
+ return __awaiter(this, void 0, void 0, function* () {
116
+ yield Promise.all(this.mcpClients.map((client) => __awaiter(this, void 0, void 0, function* () {
117
+ try {
118
+ client.close();
119
+ }
120
+ catch (error) { }
121
+ })));
122
+ });
123
+ }
124
+ initClientsAndTools() {
125
+ return __awaiter(this, void 0, void 0, function* () {
126
+ yield this._createMpcClients();
127
+ yield this._createMpcTools();
128
+ });
129
+ }
130
+ updateMcpServers(mcpServers) {
131
+ return __awaiter(this, void 0, void 0, function* () {
132
+ yield this.closeAll();
133
+ this.mcpServers = mcpServers;
134
+ yield this.initClientsAndTools();
135
+ });
136
+ }
137
+ insertMcpServer(mcpServer) {
138
+ return __awaiter(this, void 0, void 0, function* () {
139
+ var _a;
140
+ const find = this.mcpServers.find((item) => item.url === mcpServer.url);
141
+ if (!find) {
142
+ this.mcpServers = [...this.mcpServers, mcpServer];
143
+ const client = yield this._createOneClient(mcpServer);
144
+ this.mcpClients.push(client);
145
+ this.mcpTools.push((yield ((_a = client === null || client === void 0 ? void 0 : client.tools) === null || _a === void 0 ? void 0 : _a.call(client))));
146
+ return true;
64
147
  }
65
- // 每次会话需要获取最新的工具列表,因为工具是会发生变化的
66
- yield this.initClients();
67
- const tools = yield getMcpTools(this.mcpClients, options);
68
- return generateText(Object.assign({
69
- // @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
70
- model: this.llm(model), tools: tools, stopWhen: stepCountIs(maxSteps) }, options));
148
+ return false;
149
+ });
150
+ }
151
+ /** 通过引用,删除一个 mcpServers mcpClients mcpTools ignoreToolnames */
152
+ removeMcpServer(mcpServer) {
153
+ const index = this.mcpServers.findIndex((server) => server === mcpServer);
154
+ // 移除
155
+ this.mcpServers.splice(index, 1);
156
+ // 移除
157
+ const delClient = this.mcpClients[index];
158
+ this.mcpClients.splice(index, 1);
159
+ try {
160
+ delClient === null || delClient === void 0 ? void 0 : delClient.close();
161
+ }
162
+ catch (error) { }
163
+ // 移除 tools
164
+ const delTool = this.mcpTools[index];
165
+ this.mcpTools.splice(index, 1);
166
+ // 移除 ignoreToolnames
167
+ if (delTool) {
168
+ Object.keys(delTool).forEach((toolName) => {
169
+ this.ignoreToolnames = this.ignoreToolnames.filter((name) => name !== toolName);
170
+ });
171
+ }
172
+ }
173
+ /** 创建临时允许调用的tools集合 */
174
+ tempMergeTools(extraTool = {}) {
175
+ const toolsResult = this.mcpTools.reduce((acc, curr) => (Object.assign(Object.assign({}, acc), curr)), {});
176
+ Object.assign(toolsResult, extraTool);
177
+ this.ignoreToolnames.forEach((name) => {
178
+ delete toolsResult[name];
71
179
  });
180
+ return toolsResult;
72
181
  }
73
- chatStream(_a) {
182
+ _chat(chatMethod, _a) {
74
183
  return __awaiter(this, void 0, void 0, function* () {
184
+ var _b;
75
185
  var { model, maxSteps = 5 } = _a, options = __rest(_a, ["model", "maxSteps"]);
76
186
  if (!this.llm) {
77
187
  throw new Error('LLM is not initialized');
78
188
  }
79
- // 每次会话需要获取最新的工具列表,因为工具是会发生变化的
80
- yield this.initClients();
81
- const tools = yield getMcpTools(this.mcpClients, options);
82
- return streamText(Object.assign({
83
- // @ts-ignore 同上
84
- model: this.llm(model), tools: tools, stopWhen: stepCountIs(maxSteps) }, options));
189
+ if (this.autoUpdateTools) {
190
+ yield this._createMpcTools();
191
+ (_b = this.onUpdatedTools) === null || _b === void 0 ? void 0 : _b.call(this);
192
+ }
193
+ return chatMethod(Object.assign({
194
+ // @ts-ignore ProviderV2 是所有llm的父类, 在每一个具体的llm 类都有一个选择model的函数用法
195
+ model: this.llm(model), tools: this.tempMergeTools(options.tools), stopWhen: stepCountIs(maxSteps) }, options));
196
+ });
197
+ }
198
+ chat(options) {
199
+ return __awaiter(this, void 0, void 0, function* () {
200
+ return this._chat(generateText, options);
201
+ });
202
+ }
203
+ chatStream(options) {
204
+ return __awaiter(this, void 0, void 0, function* () {
205
+ return this._chat(streamText, options);
85
206
  });
86
207
  }
87
208
  }
@@ -15,7 +15,7 @@ export interface IAgentModelProviderLlmConfig {
15
15
  export type McpServerConfig = {
16
16
  type: 'streamableHttp' | 'sse';
17
17
  url: string;
18
- } | {
18
+ } & {
19
19
  transport: MCPTransport;
20
20
  };
21
21
  /** */
@@ -0,0 +1,8 @@
1
+ import { ToolSet } from 'ai';
2
+ import { WebMcpClient } from '../../WebMcpClient';
3
+ /**
4
+ * 快速 从官方 mcp 或 WebMcpClient 这2种client中, 抽取成 ai-sdk 所需要的 tool的对象
5
+ * @params client 一个已连接好的 WebMcpClient
6
+ * @returns ai-sdk的 tool 格式的对象。
7
+ */
8
+ export declare const getAISDKTools: (client: WebMcpClient) => Promise<ToolSet>;
@@ -0,0 +1,36 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { dynamicTool, jsonSchema } from 'ai';
11
+ /**
12
+ * 快速 从官方 mcp 或 WebMcpClient 这2种client中, 抽取成 ai-sdk 所需要的 tool的对象
13
+ * @params client 一个已连接好的 WebMcpClient
14
+ * @returns ai-sdk的 tool 格式的对象。
15
+ */
16
+ export const getAISDKTools = (client) => __awaiter(void 0, void 0, void 0, function* () {
17
+ var _a;
18
+ const tools = {};
19
+ try {
20
+ const listToolsResult = yield client.listTools();
21
+ for (const { name, description, inputSchema } of listToolsResult.tools) {
22
+ const execute = (args, options) => __awaiter(void 0, void 0, void 0, function* () {
23
+ return client.callTool({ name, arguments: args }, { signal: options === null || options === void 0 ? void 0 : options.abortSignal });
24
+ });
25
+ tools[name] = dynamicTool({
26
+ description,
27
+ inputSchema: jsonSchema(Object.assign(Object.assign({}, inputSchema), { properties: (_a = inputSchema.properties) !== null && _a !== void 0 ? _a : {}, additionalProperties: false })),
28
+ execute
29
+ });
30
+ }
31
+ return tools;
32
+ }
33
+ catch (error) {
34
+ throw error;
35
+ }
36
+ });
package/dist/index.d.ts CHANGED
@@ -1,6 +1,4 @@
1
1
  import Ajv from 'ajv';
2
- export * from './WebMcpServer';
3
- export * from './WebMcpClient';
4
2
  export { Ajv };
5
3
  export { z } from 'zod';
6
4
  export { AuthClientProvider } from '@opentiny/next';
@@ -16,7 +14,10 @@ export type * from '@modelcontextprotocol/sdk/shared/transport.js';
16
14
  export type * from '@modelcontextprotocol/sdk/client/sse.js';
17
15
  export type * from '@modelcontextprotocol/sdk/client/streamableHttp.js';
18
16
  export type * from '@modelcontextprotocol/sdk/server/mcp.js';
19
- export { AgentModelProvider } from './agent/AgentModelProvider';
17
+ export * from './WebMcpServer';
18
+ export * from './WebMcpClient';
20
19
  export { createRemoter } from './remoter/createRemoter';
21
- export { getAISDKTools } from './agent/utils';
20
+ export { AgentModelProvider } from './agent/AgentModelProvider';
21
+ export { getAISDKTools } from './agent/utils/getAISDKTools';
22
22
  export { QrCode, type QrCodeOption } from './remoter/QrCode';
23
+ export type * from './agent/type';