@xiongtao.xt/tau-plugins 0.10.0 → 0.11.0

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/MCP.md ADDED
@@ -0,0 +1,89 @@
1
+ # 插件 MCP
2
+
3
+ 通过 `context.mcp.register()` 向 Tau 的 AI 提供工具,一个插件可以注册多个 MCP。它们直接出现在已有 MCP 页面和聊天快捷面板,用户可以整项启停、逐工具启停,不需要插件自行开发管理界面。
4
+
5
+ 需要 SDK 0.11.0 和包含此能力的 Tau 0.59.0 桌面客户端构建。旧客户端没有 `context.mcp`,应检查并明确提示升级;SDK 类型版本不能替代客户端能力检查。
6
+
7
+ ## 本地工具和外部服务器
8
+
9
+ 每次注册填写局部 `id`、`name` 和可选 `description`,再提供 `tools` 或 `transport`,两者互斥。相同插件内 MCP 的 ID 不能重复;不同插件可以使用相同局部 ID。每个 MCP 中的工具名称唯一。
10
+
11
+ 下面是一个完整插件示例。第一项提供本地查询函数;第二项连接外部 MCP,示例地址须替换成真实服务。
12
+
13
+ ```ts
14
+ import { definePlugin } from "@tau/plugins";
15
+
16
+ declare const __PLUGIN_META__: { id: string; name: string; version: string };
17
+
18
+ export default definePlugin({
19
+ ...__PLUGIN_META__,
20
+ create: () => ({
21
+ activate(context) {
22
+ if (!context.mcp) throw new Error("请升级到支持插件 MCP 的 Tau 客户端");
23
+
24
+ context.mcp.register({
25
+ id: "notes",
26
+ name: "我的笔记",
27
+ description: "读取本插件保存的笔记",
28
+ tools: [
29
+ {
30
+ name: "read_note",
31
+ description: "按笔记键读取本插件中的一条笔记",
32
+ inputSchema: {
33
+ type: "object",
34
+ properties: { key: { type: "string", description: "笔记键" } },
35
+ required: ["key"],
36
+ additionalProperties: false,
37
+ },
38
+ async execute(args, { signal }) {
39
+ signal.throwIfAborted();
40
+ if (typeof args.key !== "string") throw new Error("请提供笔记键");
41
+ const note = await context.storage.get(args.key);
42
+ signal.throwIfAborted();
43
+ return { content: note === undefined ? "未找到笔记" : JSON.stringify(note) };
44
+ },
45
+ },
46
+ ],
47
+ });
48
+
49
+ context.mcp.register({
50
+ id: "remote",
51
+ name: "外部知识服务",
52
+ transport: { type: "streamable-http", url: "https://your-service.example/mcp" },
53
+ });
54
+ },
55
+ }),
56
+ });
57
+ ```
58
+
59
+ 本地工具填写 `name`、`description`、对象类型的 JSON Schema `inputSchema`,以及 `execute(args, { signal })`。执行结果为 `{ content: string }`,结构化数据可用 JSON.stringify 返回。工具名称使用 1–128 位字母、数字、点、横线或下划线;宿主会生成全局工具名称,作者不要自行拼接命名空间。所有插件工具沿用现有 execute 级审批。
60
+
61
+ 需要本地进程时,把 transport 改为下面的结构,命令、参数、工作目录与应用内手动添加 MCP 的含义相同:
62
+
63
+ ```ts
64
+ context.mcp.register({
65
+ id: "local-server",
66
+ name: "本地 MCP 服务",
67
+ transport: {
68
+ type: "stdio",
69
+ command: "node",
70
+ args: ["/path/to/your-server.mjs"],
71
+ },
72
+ });
73
+ ```
74
+
75
+ 该片段放在 activate(context) 内,路径须替换。不会自动安装 Node、Python、npm 包或其他依赖,启动前须具备对应运行环境。stdio 支持可选 args、env、cwd;streamable-http 支持可选 headers。不要把密钥、令牌或用户机器路径打进分发包,用户可在 MCP 页面配置本机连接参数。
76
+
77
+ ## 管理和生命周期
78
+
79
+ - 激活成功后才展示和提供工具;重复启用不会重复登记。激活失败、插件停用、切库或卸载自动回收。
80
+ - MCP 页面关闭一项只关闭该项 AI 能力,不停用插件的页面、命令或其他 MCP。用户选择会跨启用和重启保留,重新注册不会强行开启。
81
+ - 用户可管理每个工具的开关。插件提供的名称和说明由作者维护;外部服务器支持连接配置、日志和重连,插件函数没有连接配置。
82
+ - 返回的 Disposable 可提前注销单项 MCP,无需再交给 context.register。
83
+ - 工具调用 signal 在取消、插件停用、整项或对应工具关闭时中止,调用上限为 60 秒。异步代码应响应 signal;取消不能撤销已经完成的写入或外部请求。
84
+ - 旧实例、旧数据库和重连前的调用不能转交给新实例。不要缓存上下文到下一次启用。
85
+ - Skill 可描述这些工具的用途;ctx.ai.chat/stream 仍是文本生成接口,不会因为注册 MCP 而自动获得工具调用能力。
86
+
87
+ ## 验证
88
+
89
+ 检查类型并打包后,在包含此实现的客户端启用插件:确认两项 MCP 出现在现有页面和快捷面板;测试整项开关、逐工具开关、外部连接配置和重连,再测试停用、重新启用及重启后偏好保留。真实服务器连接与模型调用需使用自己的服务和已配置的模型。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiongtao.xt/tau-plugins",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,6 +10,7 @@ import type { PluginSettings } from "./settings";
10
10
  import type { PluginSync } from "./sync";
11
11
  import type { PluginSidebar } from "./sidebar";
12
12
  import type { PluginExcerpts, PluginMaterials } from "./excerpts";
13
+ import type { PluginMCP } from "./mcp";
13
14
  import type { JsonValue } from "./json";
14
15
  export type { JsonValue } from "./json";
15
16
  export interface Disposable {
@@ -44,6 +45,7 @@ export interface PluginContext {
44
45
  readonly fetch: typeof globalThis.fetch;
45
46
  readonly services: PluginServices;
46
47
  readonly ai: PluginAI;
48
+ readonly mcp: PluginMCP;
47
49
  /** 将订阅等资源交给宿主,在停用或激活失败时逆序回收。 */
48
50
  register(resource: Disposable): Disposable;
49
51
  }
@@ -8,6 +8,7 @@ export * from "./sidebar";
8
8
  export type * from "./excerpts";
9
9
  export type * from "./services";
10
10
  export type { PluginSkill } from "./skills";
11
+ export type { PluginMCP, PluginMCPDefinition, PluginMCPTool, PluginMCPTransport } from "./mcp";
11
12
  export type { PluginPageDefinition, PluginPageHandle, PluginPageParams, PluginPageProps, PluginPages, } from "./pages";
12
13
  export declare function definePlugin(definition: Omit<PluginDefinition, "apiVersion" | "create"> & Partial<Pick<PluginDefinition, "create">>): PluginDefinition;
13
14
  export type { PluginAI, PluginAIFeature, PluginAIRequest, PluginAIResult, PluginAIEvent, } from "./ai";
@@ -0,0 +1,45 @@
1
+ import type { Disposable } from "./contract";
2
+ import type { JsonValue } from "./json";
3
+ export type PluginMCPTransport = {
4
+ type: "stdio";
5
+ command: string;
6
+ args?: string[];
7
+ env?: Record<string, string>;
8
+ cwd?: string;
9
+ } | {
10
+ type: "streamable-http";
11
+ url: string;
12
+ headers?: Record<string, string>;
13
+ };
14
+ export interface PluginMCPTool {
15
+ name: string;
16
+ description: string;
17
+ inputSchema: {
18
+ type: "object";
19
+ properties?: Record<string, JsonValue>;
20
+ [key: string]: JsonValue | undefined;
21
+ };
22
+ execute(args: Record<string, JsonValue>, context: {
23
+ signal: AbortSignal;
24
+ }): Promise<{
25
+ content: string;
26
+ }> | {
27
+ content: string;
28
+ };
29
+ }
30
+ export type PluginMCPDefinition = {
31
+ id: string;
32
+ name: string;
33
+ description?: string;
34
+ } & ({
35
+ tools: readonly PluginMCPTool[];
36
+ transport?: never;
37
+ } | {
38
+ transport: PluginMCPTransport;
39
+ tools?: never;
40
+ });
41
+ export interface PluginMCP {
42
+ /** 同一插件可注册多个 MCP;停用时由宿主自动回收。 */
43
+ register(definition: PluginMCPDefinition): Disposable;
44
+ }
45
+ export declare function snapshotMCPDefinition(definition: PluginMCPDefinition): PluginMCPDefinition;