@xiongtao.xt/tau-plugins 0.9.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/SYNC.md
CHANGED
|
@@ -1,21 +1,37 @@
|
|
|
1
1
|
# 同步存储插件
|
|
2
2
|
|
|
3
|
-
需要 SDK 0.
|
|
3
|
+
需要 SDK 0.10.0 及以上,以及包含渲染端同步注册支持的 Tau 0.59.0 客户端构建。插件只在渲染进程执行,沿用main.js入口,不声明manifest.sync,也不提供Node后台产物。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## 注册与职责
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
在activate(context)中调用context.sync.register({ id: context.pluginId, name, create })。一个插件注册一个提供方,create(config)根据本次任务的JSON配置返回下列五个方法;停用或激活失败时注册自动回收。create在真正发起任务时调用,打开配置页不会连接存储服务。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
| 方法 | 返回值 | 用途 |
|
|
10
|
+
| ------------------------------- | ------------------------- | ---------------------------------------------------- |
|
|
11
|
+
| uploadFile(name, bytes) | Promise<boolean> | 普通上传 |
|
|
12
|
+
| downloadFile(name) | Promise<Uint8Array> | 读取对象 |
|
|
13
|
+
| fileExists(name) | Promise<boolean> | 检查对象是否存在 |
|
|
14
|
+
| listFiles(prefix?) | Promise<RemoteFileInfo[]> | 内部完成分页,返回相对路径、名称、大小及可选修改时间 |
|
|
15
|
+
| createFileIfAbsent(name, bytes) | Promise<boolean> | 按远端原子条件创建对象 |
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
SyncProvider、SyncProviderDefinition和RemoteFileInfo类型从@tau/plugins/sync导入。该模块仅提供纯契约与声明辅助函数,不是Node执行入口。
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
客户端负责同步内容、对象命名、版本提交、冲突、资源计划和恢复。插件负责存储服务请求,不增加能力声明、服务商探测或独立同步引擎。条件创建不能用先查询再覆盖替代;请求失败后由客户端按原提交规则核验结果。
|
|
20
|
+
|
|
21
|
+
## 网络与依赖
|
|
22
|
+
|
|
23
|
+
通过context.fetch发送请求。它由宿主提供网络传输,并与插件生命周期关联。签名、URL与协议逻辑在插件内执行;浏览器可用的SDK可以把自己的HTTP传输接到context.fetch。
|
|
24
|
+
|
|
25
|
+
普通npm依赖随main.js按浏览器目标打包;不导入fs、http、Node Buffer或其他Node内置模块,不借用宿主node_modules,不另打包Node依赖目录。保留模板external配置。
|
|
14
26
|
|
|
15
27
|
## 配置界面
|
|
16
28
|
|
|
17
|
-
|
|
29
|
+
通过context.settings.register({ id: "sync", title, target: "sync", component })将配置表单挂在“设置→同步”。每个插件注册一个同步配置分区。
|
|
30
|
+
|
|
31
|
+
组件从PluginSettingsProps.syncConfig.value读取配置,通过await syncConfig.save(config)保存。字段和校验由插件定义;失败时保留输入并展示错误。凭据不要写入日志或工作区context.storage;宿主按插件ID在本机应用级保存配置。
|
|
32
|
+
|
|
33
|
+
客户端每次任务固定配置。关闭设置页不影响任务,停用插件保留配置;运行中的任务阻止停用和卸载。窗口关闭或崩溃时任务不会转移到Node进程继续执行。CLI不再提供同步功能。
|
|
18
34
|
|
|
19
|
-
|
|
35
|
+
## 从旧同步示例升级
|
|
20
36
|
|
|
21
|
-
|
|
37
|
+
SDK0.9.0的manifest.sync/sync.js示例已撤回。将存储实现作为普通模块由main.js导入,在activate内注册,并改用浏览器兼容依赖及context.fetch;删除manifest.sync,重新打包。不要通过其他字段恢复Node入口。
|
package/package.json
CHANGED
|
@@ -7,8 +7,10 @@ import type { PluginEditor } from "./editor";
|
|
|
7
7
|
import type { PluginEditorExtension } from "./editor";
|
|
8
8
|
import type { MarkdownCodec } from "../../markdown/src/index";
|
|
9
9
|
import type { PluginSettings } from "./settings";
|
|
10
|
+
import type { PluginSync } from "./sync";
|
|
10
11
|
import type { PluginSidebar } from "./sidebar";
|
|
11
12
|
import type { PluginExcerpts, PluginMaterials } from "./excerpts";
|
|
13
|
+
import type { PluginMCP } from "./mcp";
|
|
12
14
|
import type { JsonValue } from "./json";
|
|
13
15
|
export type { JsonValue } from "./json";
|
|
14
16
|
export interface Disposable {
|
|
@@ -36,12 +38,14 @@ export interface PluginContext {
|
|
|
36
38
|
readonly pages: PluginPages;
|
|
37
39
|
readonly editor: PluginEditor;
|
|
38
40
|
readonly settings: PluginSettings;
|
|
41
|
+
readonly sync: PluginSync;
|
|
39
42
|
readonly sidebar: PluginSidebar;
|
|
40
43
|
readonly excerpts: PluginExcerpts;
|
|
41
44
|
readonly materials: PluginMaterials;
|
|
42
45
|
readonly fetch: typeof globalThis.fetch;
|
|
43
46
|
readonly services: PluginServices;
|
|
44
47
|
readonly ai: PluginAI;
|
|
48
|
+
readonly mcp: PluginMCP;
|
|
45
49
|
/** 将订阅等资源交给宿主,在停用或激活失败时逆序回收。 */
|
|
46
50
|
register(resource: Disposable): Disposable;
|
|
47
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;
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { JsonValue } from "./json";
|
|
2
2
|
export type { JsonValue } from "./json";
|
|
3
|
+
import type { Disposable } from "./contract";
|
|
4
|
+
export interface PluginSync {
|
|
5
|
+
register(definition: SyncProviderDefinition): Disposable;
|
|
6
|
+
}
|
|
3
7
|
export interface RemoteFileInfo {
|
|
4
8
|
name: string;
|
|
5
9
|
path: string;
|