im-connector 0.0.0-stage → 1.0.1

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +85 -2
  3. package/dist/cli/errors.d.ts +45 -0
  4. package/dist/cli/errors.d.ts.map +1 -0
  5. package/dist/cli/errors.js +75 -0
  6. package/dist/cli/errors.js.map +1 -0
  7. package/dist/cli/runner.d.ts +33 -0
  8. package/dist/cli/runner.d.ts.map +1 -0
  9. package/dist/cli/runner.js +136 -0
  10. package/dist/cli/runner.js.map +1 -0
  11. package/dist/index.d.ts +8 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +7 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/mcp/server.d.ts +14 -0
  16. package/dist/mcp/server.d.ts.map +1 -0
  17. package/dist/mcp/server.js +108 -0
  18. package/dist/mcp/server.js.map +1 -0
  19. package/dist/providers/dingtalk.d.ts +4 -0
  20. package/dist/providers/dingtalk.d.ts.map +1 -0
  21. package/dist/providers/dingtalk.js +23 -0
  22. package/dist/providers/dingtalk.js.map +1 -0
  23. package/dist/providers/registry.d.ts +4 -0
  24. package/dist/providers/registry.d.ts.map +1 -0
  25. package/dist/providers/registry.js +11 -0
  26. package/dist/providers/registry.js.map +1 -0
  27. package/dist/providers/types.d.ts +23 -0
  28. package/dist/providers/types.d.ts.map +1 -0
  29. package/dist/providers/types.js +2 -0
  30. package/dist/providers/types.js.map +1 -0
  31. package/dist/providers/wecom.d.ts +4 -0
  32. package/dist/providers/wecom.d.ts.map +1 -0
  33. package/dist/providers/wecom.js +17 -0
  34. package/dist/providers/wecom.js.map +1 -0
  35. package/mcp-bundle/README.md +49 -0
  36. package/mcp-bundle/cordis.patch.yml +9 -0
  37. package/mcp-bundle/icon.svg +7 -0
  38. package/mcp-bundle/locale/en.json +6 -0
  39. package/mcp-bundle/locale/zh.json +6 -0
  40. package/mcp-bundle/package.json +9 -0
  41. package/package.json +64 -4
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 im-connector contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,86 @@
1
- # Temporary Holding Version
1
+ # im-connector
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 让 AI Agent 通过 MCP 调用**钉钉(dws)**和**企业微信(wecom-cli)**的 CLI,在渠道里干活:发消息、写日志/日报、建待办、查日程、处理审批。
4
+
5
+ > 本包只负责「Agent → 渠道」方向。在群里/私聊里与机器人对话(渠道 → Agent)请用 dsh-im 插件。
6
+
7
+ ## 前置条件
8
+
9
+ - Node.js >= 18
10
+ - **钉钉**:`npm i -g dingtalk-workspace-cli`,然后 `dws auth login --recommend`
11
+ - **企业微信**:`npm i -g @wecom/cli`,然后 `wecom-cli auth init --noninteractive` 扫码授权
12
+
13
+ 连接器不保存任何凭据,直接用两个 CLI 自己的登录态。
14
+
15
+ ## 安装
16
+
17
+ ```bash
18
+ npx -y im-connector # 直接用,无需安装
19
+ npm i -g im-connector # 或全局安装
20
+ ```
21
+
22
+ ## 配置 MCP 客户端
23
+
24
+ 通用 MCP 客户端(如 Claude Desktop):
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "im": { "command": "npx", "args": ["-y", "im-connector"] }
30
+ }
31
+ }
32
+ ```
33
+
34
+ **DSH 用户**一条命令即可(装包 + 注册 MCP 连接):
35
+
36
+ ```
37
+ plugin_manager install_bundle target: im-connector
38
+ ```
39
+
40
+ 安装后工具名为 `mcp__im__run`。
41
+
42
+ ## 使用
43
+
44
+ Agent 调用 `mcp__im__run`,参数是 `{ provider, args }`,`args` 就是对应 CLI 的原生命令参数:
45
+
46
+ ```json
47
+ // 发消息
48
+ { "provider": "dingtalk", "args": ["chat", "+messages-send", "--group", "<群ID>", "--markdown", "内容", "--yes"] }
49
+
50
+ // 待办
51
+ { "provider": "dingtalk", "args": ["todo", "+create", "--title", "整理今日测试报告", "--due", "2026-10-23 18:00"] }
52
+ { "provider": "dingtalk", "args": ["todo", "+get-my-tasks"] }
53
+
54
+ // 日志 / 日报周报
55
+ { "provider": "dingtalk", "args": ["report", "+create", "--template", "日报", "--content", "..."] }
56
+
57
+ // 日程 / 审批 / 通讯录
58
+ { "provider": "dingtalk", "args": ["calendar", "+today"] }
59
+ { "provider": "dingtalk", "args": ["oa", "approval", "list-pending"] }
60
+ { "provider": "dingtalk", "args": ["contact", "+me"] }
61
+
62
+ // 企业微信
63
+ { "provider": "wecom", "args": ["contact", "users", "search", "--keywords", "张三"] }
64
+ ```
65
+
66
+ 完整命令见各 CLI 的 `--help`(如 `dws chat --help`、`wecom-cli message --help`)。
67
+
68
+ ## 说明
69
+
70
+ - **写操作**(发消息、提交审批等)请先让 Agent 确认意图;不确定时用 `--dry-run` 预览(两平台都支持)
71
+ - 参数会原样透传给 CLI,返回其 JSON 输出
72
+ - 支持的 provider:`dingtalk`、`wecom`
73
+
74
+ ## 开发
75
+
76
+ ```bash
77
+ pnpm install
78
+ pnpm verify # typecheck + 测试 + 构建 + MCP 冒烟
79
+ ```
80
+
81
+ 发布(维护者):
82
+
83
+ ```bash
84
+ npm version patch
85
+ npm publish --registry=https://registry.npmjs.org/
86
+ ```
@@ -0,0 +1,45 @@
1
+ /** CLI 错误信封(dws 风格;其它 CLI 若无结构化信封则回退到原始 stderr)。 */
2
+ export interface CliErrorEnvelope {
3
+ error?: {
4
+ code?: number | string;
5
+ category?: string;
6
+ message?: string;
7
+ reason?: string;
8
+ retryable?: boolean;
9
+ retry_after_seconds?: number;
10
+ hint?: string;
11
+ actions?: string[];
12
+ details?: unknown;
13
+ trace_id?: string;
14
+ server_error_code?: string;
15
+ };
16
+ }
17
+ /** 由底层 CLI 命令失败引发的统一错误。 */
18
+ export declare class CliError extends Error {
19
+ readonly code?: number | string;
20
+ readonly category?: string;
21
+ readonly reason?: string;
22
+ readonly retryable?: boolean;
23
+ readonly hint?: string;
24
+ readonly actions?: string[];
25
+ readonly command: string;
26
+ readonly stderr: string;
27
+ readonly exitCode: number | null;
28
+ constructor(init: {
29
+ message: string;
30
+ command: string;
31
+ stderr?: string;
32
+ exitCode?: number | null;
33
+ code?: number | string;
34
+ category?: string;
35
+ reason?: string;
36
+ retryable?: boolean;
37
+ hint?: string;
38
+ actions?: string[];
39
+ });
40
+ toJSON(): Record<string, unknown>;
41
+ }
42
+ export declare function isCliError(e: unknown): e is CliError;
43
+ /** 从 stderr 文本提取结构化错误信封;失败返回 undefined(调用方回退原始文本)。 */
44
+ export declare function parseErrorEnvelope(stderr: string): CliErrorEnvelope | undefined;
45
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/cli/errors.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,mBAAmB,CAAC,EAAE,MAAM,CAAC;QAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;QACnB,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,iBAAiB,CAAC,EAAE,MAAM,CAAC;KAC5B,CAAC;CACH;AAED,2BAA2B;AAC3B,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;gBAErB,IAAI,EAAE;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;QACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB;IAcD,MAAM,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAclC;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,QAAQ,CAEpD;AAED,sDAAsD;AACtD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAgB/E"}
@@ -0,0 +1,75 @@
1
+ /** 由底层 CLI 命令失败引发的统一错误。 */
2
+ export class CliError extends Error {
3
+ code;
4
+ category;
5
+ reason;
6
+ retryable;
7
+ hint;
8
+ actions;
9
+ command;
10
+ stderr;
11
+ exitCode;
12
+ constructor(init) {
13
+ super(init.message);
14
+ this.name = "CliError";
15
+ this.code = init.code;
16
+ this.category = init.category;
17
+ this.reason = init.reason;
18
+ this.retryable = init.retryable;
19
+ this.hint = init.hint;
20
+ this.actions = init.actions;
21
+ this.command = init.command;
22
+ this.stderr = init.stderr ?? "";
23
+ this.exitCode = init.exitCode ?? null;
24
+ }
25
+ toJSON() {
26
+ return {
27
+ name: this.name,
28
+ message: this.message,
29
+ command: this.command,
30
+ code: this.code,
31
+ category: this.category,
32
+ reason: this.reason,
33
+ retryable: this.retryable,
34
+ hint: this.hint,
35
+ actions: this.actions,
36
+ exitCode: this.exitCode,
37
+ };
38
+ }
39
+ }
40
+ export function isCliError(e) {
41
+ return e instanceof CliError;
42
+ }
43
+ /** 从 stderr 文本提取结构化错误信封;失败返回 undefined(调用方回退原始文本)。 */
44
+ export function parseErrorEnvelope(stderr) {
45
+ const text = stderr.trim();
46
+ if (!text)
47
+ return undefined;
48
+ const direct = tryParse(text);
49
+ if (direct?.error)
50
+ return direct;
51
+ const start = text.indexOf("{");
52
+ const end = text.lastIndexOf("}");
53
+ if (start >= 0 && end > start) {
54
+ const parsed = tryParse(text.slice(start, end + 1));
55
+ if (parsed?.error)
56
+ return parsed;
57
+ }
58
+ for (const line of text.split(/\r?\n/)) {
59
+ const parsed = tryParse(line.trim());
60
+ if (parsed?.error)
61
+ return parsed;
62
+ }
63
+ return undefined;
64
+ }
65
+ function tryParse(text) {
66
+ if (!text)
67
+ return undefined;
68
+ try {
69
+ return JSON.parse(text);
70
+ }
71
+ catch {
72
+ return undefined;
73
+ }
74
+ }
75
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/cli/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { ImProviderSpec } from "../providers/types.js";
2
+ export interface CliRunOptions {
3
+ env?: NodeJS.ProcessEnv;
4
+ cwd?: string;
5
+ signal?: AbortSignal;
6
+ /** 覆盖 bin(测试注入 fake CLI 用)。 */
7
+ bin?: string;
8
+ }
9
+ export interface CliExecution {
10
+ /** 人类可读命令,如 `wecom-cli contact users search`。 */
11
+ command: string;
12
+ args: string[];
13
+ stdout: string;
14
+ stderr: string;
15
+ exitCode: number | null;
16
+ /** stdout 解析后的 JSON(无法解析时为原始文本)。 */
17
+ data: unknown;
18
+ }
19
+ /**
20
+ * 通用 CLI 透传执行器:按 provider 规格定位 CLI(npm 全局 bin 脚本 → node 直跑,
21
+ * 规避 Windows shim),追加 provider 的 formatArgs,收集 stdout/stderr,解析 JSON,
22
+ * 非零退出时映射错误信封为 CliError。
23
+ */
24
+ export declare class CliRunner {
25
+ private readonly spec;
26
+ constructor(spec: ImProviderSpec);
27
+ get providerId(): string;
28
+ /** 运行并返回解析后的 stdout JSON;失败抛 CliError。 */
29
+ runJson(args: string[], opts?: CliRunOptions): Promise<unknown>;
30
+ run(args: string[], opts?: CliRunOptions): Promise<CliExecution>;
31
+ private launch;
32
+ }
33
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/cli/runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG5D,MAAM,WAAW,aAAa;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,+BAA+B;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,oCAAoC;IACpC,IAAI,EAAE,OAAO,CAAC;CACf;AAQD;;;;GAIG;AACH,qBAAa,SAAS;IACR,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,cAAc;IAEjD,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED,0CAA0C;IACpC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC;IAK/D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;YAmExD,MAAM;CAwBrB"}
@@ -0,0 +1,136 @@
1
+ import { spawn } from "node:child_process";
2
+ import { existsSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { CliError, parseErrorEnvelope } from "./errors.js";
5
+ /**
6
+ * 通用 CLI 透传执行器:按 provider 规格定位 CLI(npm 全局 bin 脚本 → node 直跑,
7
+ * 规避 Windows shim),追加 provider 的 formatArgs,收集 stdout/stderr,解析 JSON,
8
+ * 非零退出时映射错误信封为 CliError。
9
+ */
10
+ export class CliRunner {
11
+ spec;
12
+ constructor(spec) {
13
+ this.spec = spec;
14
+ }
15
+ get providerId() {
16
+ return this.spec.id;
17
+ }
18
+ /** 运行并返回解析后的 stdout JSON;失败抛 CliError。 */
19
+ async runJson(args, opts) {
20
+ const exec = await this.run(args, opts);
21
+ return exec.data;
22
+ }
23
+ async run(args, opts) {
24
+ const spec = await this.launch(opts?.bin);
25
+ const finalArgs = [...spec.prefix, ...args, ...this.spec.formatArgs];
26
+ const command = `${this.spec.bin} ${args.join(" ")}`;
27
+ return new Promise((resolve, reject) => {
28
+ const child = spawn(spec.command, finalArgs, {
29
+ shell: spec.shell,
30
+ cwd: opts?.cwd,
31
+ env: { ...process.env, ...opts?.env },
32
+ stdio: ["ignore", "pipe", "pipe"],
33
+ windowsHide: true,
34
+ });
35
+ let stdout = "";
36
+ let stderr = "";
37
+ child.stdout.on("data", (d) => {
38
+ stdout += d.toString("utf8");
39
+ });
40
+ child.stderr.on("data", (d) => {
41
+ stderr += d.toString("utf8");
42
+ });
43
+ const onAbort = () => {
44
+ try {
45
+ child.kill("SIGTERM");
46
+ }
47
+ catch {
48
+ /* ignore */
49
+ }
50
+ };
51
+ if (opts?.signal) {
52
+ if (opts.signal.aborted)
53
+ onAbort();
54
+ else
55
+ opts.signal.addEventListener("abort", onAbort, { once: true });
56
+ }
57
+ child.on("error", (e) => {
58
+ reject(new CliError({
59
+ message: `Failed to launch ${this.spec.bin} (${spec.command}): ${e.message}`,
60
+ command,
61
+ retryable: true,
62
+ }));
63
+ });
64
+ child.on("exit", (code) => {
65
+ opts?.signal?.removeEventListener("abort", onAbort);
66
+ const parsed = parseStdoutJson(stdout);
67
+ if (code !== 0) {
68
+ const envelope = parseErrorEnvelope(stderr);
69
+ reject(new CliError({
70
+ message: envelope?.error?.message ?? stderr.trim() ?? `${this.spec.bin} exited with code ${code}`,
71
+ command,
72
+ stderr,
73
+ exitCode: code,
74
+ code: envelope?.error?.code,
75
+ category: envelope?.error?.category,
76
+ reason: envelope?.error?.reason,
77
+ retryable: envelope?.error?.retryable,
78
+ hint: envelope?.error?.hint,
79
+ actions: envelope?.error?.actions,
80
+ }));
81
+ return;
82
+ }
83
+ resolve({ command, args: finalArgs, stdout, stderr, exitCode: code, data: parsed });
84
+ });
85
+ });
86
+ }
87
+ async launch(binOverride) {
88
+ const env = process.env[this.spec.envBin ?? ""]?.trim();
89
+ const bin = binOverride?.trim() || env || this.spec.bin;
90
+ // 1) 显式 node 脚本
91
+ if (bin !== this.spec.bin && /\.(c?js|mjs)$/i.test(bin) && existsSync(bin)) {
92
+ return { command: process.execPath, prefix: [bin], shell: false };
93
+ }
94
+ // 2) 显式可执行文件
95
+ if (bin !== this.spec.bin && existsSync(bin)) {
96
+ return { command: bin, prefix: [], shell: false };
97
+ }
98
+ // 3) 默认 bin:解析 npm 全局包内脚本
99
+ if (bin === this.spec.bin) {
100
+ const globalRoot = await npmGlobalRoot();
101
+ if (globalRoot) {
102
+ const script = join(globalRoot, ...this.spec.binScript.split("/"));
103
+ if (existsSync(script)) {
104
+ return { command: process.execPath, prefix: [script], shell: false };
105
+ }
106
+ }
107
+ }
108
+ // 4) 回退:shell 执行(Windows shim)
109
+ return { command: bin, prefix: [], shell: process.platform === "win32" };
110
+ }
111
+ }
112
+ function parseStdoutJson(stdout) {
113
+ const text = stdout.trim();
114
+ if (!text)
115
+ return null;
116
+ try {
117
+ return JSON.parse(text);
118
+ }
119
+ catch {
120
+ return text;
121
+ }
122
+ }
123
+ async function npmGlobalRoot() {
124
+ try {
125
+ const { execFile } = await import("node:child_process");
126
+ const { promisify } = await import("node:util");
127
+ const run = promisify(execFile);
128
+ const { stdout } = await run("npm", ["root", "-g"], { timeout: 10_000, windowsHide: true });
129
+ const root = String(stdout).trim();
130
+ return root || null;
131
+ }
132
+ catch {
133
+ return null;
134
+ }
135
+ }
136
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/cli/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { CliError, isCliError, parseErrorEnvelope, type CliErrorEnvelope } from "./cli/errors.js";
2
+ export { CliRunner, type CliExecution, type CliRunOptions } from "./cli/runner.js";
3
+ export type { ImProviderSpec } from "./providers/types.js";
4
+ export { dingtalk } from "./providers/dingtalk.js";
5
+ export { wecom } from "./providers/wecom.js";
6
+ export { getProvider, listProviders } from "./providers/registry.js";
7
+ export { buildMcpServer, type McpServerOptions } from "./mcp/server.js";
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,kBAAkB,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAClG,OAAO,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACnF,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ export { CliError, isCliError, parseErrorEnvelope } from "./cli/errors.js";
2
+ export { CliRunner } from "./cli/runner.js";
3
+ export { dingtalk } from "./providers/dingtalk.js";
4
+ export { wecom } from "./providers/wecom.js";
5
+ export { getProvider, listProviders } from "./providers/registry.js";
6
+ export { buildMcpServer } from "./mcp/server.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,kBAAkB,EAAyB,MAAM,iBAAiB,CAAC;AAClG,OAAO,EAAE,SAAS,EAAyC,MAAM,iBAAiB,CAAC;AAEnF,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACrE,OAAO,EAAE,cAAc,EAAyB,MAAM,iBAAiB,CAAC"}
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
3
+ /**
4
+ * 构建统一 IM 透传 MCP server:暴露一个 `run { provider, args }` 工具,
5
+ * 按 provider 注册表路由到底层 CLI。新增平台只需在 registry 追加 spec。
6
+ */
7
+ export interface McpServerOptions {
8
+ name?: string;
9
+ version?: string;
10
+ /** 测试/覆盖用:provider id → CLI 入口路径。 */
11
+ binOverrides?: Record<string, string>;
12
+ }
13
+ export declare function buildMcpServer(options?: McpServerOptions): Server;
14
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AA6CnE;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qCAAqC;IACrC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,gBAAqB,GAAG,MAAM,CA+DrE"}
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ import { pathToFileURL } from "node:url";
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
+ import { getProvider, listProviders } from "../providers/registry.js";
7
+ import { CliRunner } from "../cli/runner.js";
8
+ import { isCliError } from "../cli/errors.js";
9
+ function buildRunTool() {
10
+ const providers = listProviders();
11
+ const lines = providers
12
+ .map((p) => {
13
+ const ex = p.examples.map((e) => ` ${e}`).join("\n");
14
+ return `- ${p.id}(${p.displayName},\`${p.bin}\`):\n${ex}`;
15
+ })
16
+ .join("\n");
17
+ return {
18
+ name: "run",
19
+ description: `统一 IM 透传:执行指定平台的 CLI 命令并返回其 JSON 输出。已接入平台:\n${lines}\n\n` +
20
+ `provider 选平台,args 是该平台 CLI 的命令字符串数组。写操作(发消息/提交/审批等)需用户明确意图,必要时加 --yes(钉钉)或先用 --dry-run 预览。`,
21
+ inputSchema: {
22
+ type: "object",
23
+ properties: {
24
+ provider: {
25
+ type: "string",
26
+ enum: providers.map((p) => p.id),
27
+ description: `IM 平台标识:${providers.map((p) => `${p.id}=${p.displayName}`).join(",")}`,
28
+ },
29
+ args: {
30
+ type: "array",
31
+ items: { type: "string" },
32
+ description: "对应平台 CLI 的命令及参数(字符串数组)。",
33
+ },
34
+ },
35
+ required: ["provider", "args"],
36
+ },
37
+ };
38
+ }
39
+ export function buildMcpServer(options = {}) {
40
+ const server = new Server({ name: options.name ?? "im", version: options.version ?? "0.1.0" }, { capabilities: { tools: {} } });
41
+ const runTool = buildRunTool();
42
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
43
+ tools: [runTool],
44
+ }));
45
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
46
+ if (request.params.name !== "run") {
47
+ return {
48
+ content: [{ type: "text", text: `Unknown tool: ${request.params.name}. Only "run" is available.` }],
49
+ isError: true,
50
+ };
51
+ }
52
+ const { provider, args } = request.params.arguments ?? {};
53
+ const spec = getProvider(provider);
54
+ if (!spec) {
55
+ return {
56
+ content: [
57
+ {
58
+ type: "text",
59
+ text: `未知平台 "${provider}"。可用:${listProviders().map((p) => p.id).join(",")}`,
60
+ },
61
+ ],
62
+ isError: true,
63
+ };
64
+ }
65
+ if (!Array.isArray(args) || args.length === 0 || !args.every((a) => typeof a === "string")) {
66
+ return {
67
+ content: [
68
+ {
69
+ type: "text",
70
+ text: '参数 args 必须是非空字符串数组,例如 {"provider":"dingtalk","args":["contact","+me"]}',
71
+ },
72
+ ],
73
+ isError: true,
74
+ };
75
+ }
76
+ try {
77
+ const runner = new CliRunner(spec);
78
+ const result = await runner.runJson(args, {
79
+ bin: options.binOverrides?.[spec.id],
80
+ });
81
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
82
+ }
83
+ catch (e) {
84
+ const message = isCliError(e)
85
+ ? JSON.stringify(e.toJSON())
86
+ : e instanceof Error
87
+ ? e.message
88
+ : String(e);
89
+ return {
90
+ content: [{ type: "text", text: `${spec.displayName} run failed: ${message}` }],
91
+ isError: true,
92
+ };
93
+ }
94
+ });
95
+ return server;
96
+ }
97
+ async function main() {
98
+ const server = buildMcpServer();
99
+ await server.connect(new StdioServerTransport());
100
+ }
101
+ const invokedDirectly = process.argv[1] !== undefined && import.meta.url === pathToFileURL(process.argv[1]).href;
102
+ if (invokedDirectly) {
103
+ main().catch((e) => {
104
+ console.error(e);
105
+ process.exit(1);
106
+ });
107
+ }
108
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ImProviderSpec } from "./types.js";
2
+ /** 钉钉:通过 dws(dingtalk-workspace-cli)透传。 */
3
+ export declare const dingtalk: ImProviderSpec;
4
+ //# sourceMappingURL=dingtalk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dingtalk.d.ts","sourceRoot":"","sources":["../../src/providers/dingtalk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,2CAA2C;AAC3C,eAAO,MAAM,QAAQ,EAAE,cAoBtB,CAAC"}
@@ -0,0 +1,23 @@
1
+ /** 钉钉:通过 dws(dingtalk-workspace-cli)透传。 */
2
+ export const dingtalk = {
3
+ id: "dingtalk",
4
+ displayName: "钉钉",
5
+ bin: "dws",
6
+ npmPackage: "dingtalk-workspace-cli",
7
+ binScript: "dingtalk-workspace-cli/bin/dws.js",
8
+ formatArgs: ["--format", "json"],
9
+ envBin: "DINGTALK_DWS_BIN",
10
+ examples: [
11
+ '["contact","+me"]',
12
+ '["contact","+search-user","--query","张三"]',
13
+ '["calendar","+today"]',
14
+ '["todo","+get-my-tasks"]',
15
+ '["oa","approval","list-pending"] / ["oa","approval","detail","--instance-id","<id>"]',
16
+ '["attendance","+check-result","--users","u1,u2","--start","2026-10-01","--end","2026-10-10"]',
17
+ '["report","inbox","list"] / ["report","entry","get","--report-id","<id>"]',
18
+ '["doc","read","--node","<docId|url>"] / ["wiki","+space-list"]',
19
+ '["chat","+chat-messages","--group","<群名|id>","--limit","20"] / ["chat","+search-msg","--query","<kw>"]',
20
+ '写:["chat","+messages-send","--group","<cid>","--markdown","内容","--title","标题","--yes"]',
21
+ ],
22
+ };
23
+ //# sourceMappingURL=dingtalk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dingtalk.js","sourceRoot":"","sources":["../../src/providers/dingtalk.ts"],"names":[],"mappings":"AAEA,2CAA2C;AAC3C,MAAM,CAAC,MAAM,QAAQ,GAAmB;IACtC,EAAE,EAAE,UAAU;IACd,WAAW,EAAE,IAAI;IACjB,GAAG,EAAE,KAAK;IACV,UAAU,EAAE,wBAAwB;IACpC,SAAS,EAAE,mCAAmC;IAC9C,UAAU,EAAE,CAAC,UAAU,EAAE,MAAM,CAAC;IAChC,MAAM,EAAE,kBAAkB;IAC1B,QAAQ,EAAE;QACR,mBAAmB;QACnB,2CAA2C;QAC3C,uBAAuB;QACvB,0BAA0B;QAC1B,sFAAsF;QACtF,8FAA8F;QAC9F,2EAA2E;QAC3E,gEAAgE;QAChE,wGAAwG;QACxG,wFAAwF;KACzF;CACF,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { ImProviderSpec } from "./types.js";
2
+ export declare function listProviders(): ImProviderSpec[];
3
+ export declare function getProvider(id: string): ImProviderSpec | undefined;
4
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAOjD,wBAAgB,aAAa,IAAI,cAAc,EAAE,CAEhD;AAED,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAElE"}
@@ -0,0 +1,11 @@
1
+ import { dingtalk } from "./dingtalk.js";
2
+ import { wecom } from "./wecom.js";
3
+ /** 已注册的 IM 平台。新增飞书 / Discord 时在此追加。 */
4
+ const providers = [dingtalk, wecom];
5
+ export function listProviders() {
6
+ return providers;
7
+ }
8
+ export function getProvider(id) {
9
+ return providers.find((p) => p.id === id);
10
+ }
11
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,uCAAuC;AACvC,MAAM,SAAS,GAAqB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AAEtD,MAAM,UAAU,aAAa;IAC3B,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * 一个 IM 平台(provider)接入规格:如何找到它的 CLI、如何请求 JSON 输出。
3
+ * 未来接入飞书 / Discord 等,只需新增一个 spec 并注册进 registry。
4
+ */
5
+ export interface ImProviderSpec {
6
+ /** 稳定 id,用于 MCP 工具的 provider 参数,如 "dingtalk" / "wecom"。 */
7
+ id: string;
8
+ /** 人类可读名称。 */
9
+ displayName: string;
10
+ /** 默认命令名(PATH 上的 shim),如 "dws" / "wecom-cli"。 */
11
+ bin: string;
12
+ /** npm 全局包名,用于解析 bin 脚本(规避 Windows .cmd/.ps1 shim)。 */
13
+ npmPackage: string;
14
+ /** 包内 bin 脚本相对路径(含作用域,用 / 分隔),如 "@wecom/cli/bin/wecom.js"。 */
15
+ binScript: string;
16
+ /** 追加在业务参数之后、用于请求 JSON 输出的 flag;JSON 为默认输出的 CLI 用空数组。 */
17
+ formatArgs: string[];
18
+ /** 覆盖 bin 的环境变量名(可选),如 "DINGTALK_DWS_BIN"。 */
19
+ envBin?: string;
20
+ /** 展示在 MCP 工具描述里的示例命令(数组形式,便于模型理解)。 */
21
+ examples: string[];
22
+ }
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,2DAA2D;IAC3D,EAAE,EAAE,MAAM,CAAC;IACX,cAAc;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/providers/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,4 @@
1
+ import type { ImProviderSpec } from "./types.js";
2
+ /** 企业微信:通过 wecom-cli(@wecom/cli)透传。JSON 为默认输出,无需 --format。 */
3
+ export declare const wecom: ImProviderSpec;
4
+ //# sourceMappingURL=wecom.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wecom.d.ts","sourceRoot":"","sources":["../../src/providers/wecom.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,8DAA8D;AAC9D,eAAO,MAAM,KAAK,EAAE,cAcnB,CAAC"}
@@ -0,0 +1,17 @@
1
+ /** 企业微信:通过 wecom-cli(@wecom/cli)透传。JSON 为默认输出,无需 --format。 */
2
+ export const wecom = {
3
+ id: "wecom",
4
+ displayName: "企业微信",
5
+ bin: "wecom-cli",
6
+ npmPackage: "@wecom/cli",
7
+ binScript: "@wecom/cli/bin/wecom.js",
8
+ formatArgs: [],
9
+ envBin: "WECOM_CLI_BIN",
10
+ examples: [
11
+ '["contact","users","search","--keywords","张三"]',
12
+ '["chat","messages","list","--chat-id","<id>","--begin-time","2026-10-01 00:00:00","--end-time","2026-10-21 00:00:00"]',
13
+ '["auth","show","--status"]',
14
+ '通用形态:["<service>","<resource>","<operation>",...flags];--schema 查看方法 schema,--dry-run 预览不发送。',
15
+ ],
16
+ };
17
+ //# sourceMappingURL=wecom.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wecom.js","sourceRoot":"","sources":["../../src/providers/wecom.ts"],"names":[],"mappings":"AAEA,8DAA8D;AAC9D,MAAM,CAAC,MAAM,KAAK,GAAmB;IACnC,EAAE,EAAE,OAAO;IACX,WAAW,EAAE,MAAM;IACnB,GAAG,EAAE,WAAW;IAChB,UAAU,EAAE,YAAY;IACxB,SAAS,EAAE,yBAAyB;IACpC,UAAU,EAAE,EAAE;IACd,MAAM,EAAE,eAAe;IACvB,QAAQ,EAAE;QACR,gDAAgD;QAChD,uHAAuH;QACvH,4BAA4B;QAC5B,8FAA8F;KAC/F;CACF,CAAC"}
@@ -0,0 +1,49 @@
1
+ # mcp-bundle:DSH MCP 连接 bundle
2
+
3
+ 按 DSH 官方推荐方式(`references/mcp-bundle.md`「Connect an MCP server」)做的**配置型 bundle**:只插入一条 `@deepseek-ai/dsh-mcp-client` 行,把 `im-connector` 注册成一个 MCP 连接,模型侧工具名为 `mcp__im__run`。
4
+
5
+ ## 推荐安装(一步到位)
6
+
7
+ npm 包 `im-connector` 本身声明了 `dsh.bundle.patch`(指向本目录的 patch),所以装上包即完成注册:
8
+
9
+ ```
10
+ plugin_manager install_bundle target: im-connector
11
+ ```
12
+
13
+ 安装后 DSH 会:装包 → 应用 patch → 新增 MCP 连接(`serverName: im`),工具为 `mcp__im__run`。
14
+
15
+ ## 手工安装(已有包或本地调试)
16
+
17
+ 把本目录复制到任意位置,直接 `plugin_manager install_bundle`(target 指向该目录)。patch 用的是官方 stdio 形式:
18
+
19
+ ```yaml
20
+ - insert:
21
+ - id: im-connector-mcp
22
+ name: '@deepseek-ai/dsh-mcp-client'
23
+ config:
24
+ serverName: im
25
+ transport: stdio
26
+ command: npx
27
+ args: ['-y', 'im-connector']
28
+ failOnStartupError: true
29
+ ```
30
+
31
+ 要点:
32
+ - `command: npx` 跨平台可用(MCP SDK 的 stdio 传输基于 cross-spawn,Windows 能解析 `npx.cmd`)。
33
+ - **不需要配 env**:`im-connector` 会通过 `npm root -g` 自动解析 `dws` / `wecom-cli` 的 bin 脚本。需要覆盖时再加 env,且**不要把凭据写进 patch**(可用 Loader 的 `!!js process.env.X` 引用环境变量)。
34
+ - `failOnStartupError: true`:连接失败时让该行激活失败,便于发现问题(官方模板同款)。
35
+ - 对照官方 `templates/mcp/`:manifest 只需 name/version/`dsh.bundle.patch`(配置型 bundle 无 Host/Client 入口文件),display 元数据走 `locale/*.json` + `icon.svg`。
36
+
37
+ > ⚠️ 个别 Windows 环境下 `npx` 转发 stdio 到本包 server 不稳定(`npx --version` 与其它包正常,但管道下 MCP 握手被关闭)。遇到这种情况改用 node + 绝对路径:
38
+
39
+ ```yaml
40
+ config:
41
+ serverName: im
42
+ transport: stdio
43
+ command: node
44
+ args: ['<npm root -g>/im-connector/dist/mcp/server.js']
45
+ ```
46
+
47
+ ## 验证
48
+
49
+ 安装后在会话里调用 `mcp__im__run`(例如 `{ provider: "dingtalk", args: ["contact", "+me"] }`)确认连接可用。
@@ -0,0 +1,9 @@
1
+ - insert:
2
+ - id: im-connector-mcp
3
+ name: '@deepseek-ai/dsh-mcp-client'
4
+ config:
5
+ serverName: im
6
+ transport: stdio
7
+ command: npx
8
+ args: ['-y', 'im-connector']
9
+ failOnStartupError: true
@@ -0,0 +1,7 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
2
+ <rect x="4" y="20" width="14" height="24" rx="5" fill="#0089ff"/>
3
+ <rect x="22" y="12" width="14" height="24" rx="5" fill="#0089ff"/>
4
+ <rect x="40" y="20" width="14" height="24" rx="5" fill="#0089ff"/>
5
+ <path d="M20 32h16" stroke="#0089ff" stroke-width="3" stroke-linecap="round"/>
6
+ <circle cx="32" cy="44" r="3" fill="#4aa3ff"/>
7
+ </svg>
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "IM Connector",
4
+ "description": "Unified IM passthrough for DingTalk (dws) and WeCom (wecom-cli); extensible to Feishu, Discord and more."
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "IM 连接器",
4
+ "description": "统一 IM 透传:钉钉(dws)与企业微信(wecom-cli),可扩展飞书、Discord 等平台。"
5
+ }
6
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "@local/im-connector-mcp",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "exports": { "./locale/*.json": "./locale/*.json", "./icon": "./icon.svg" },
7
+ "files": ["cordis.patch.yml", "locale/*.json", "icon.svg"],
8
+ "dsh": { "bundle": { "patch": "./cordis.patch.yml" } }
9
+ }
package/package.json CHANGED
@@ -1,6 +1,66 @@
1
1
  {
2
2
  "name": "im-connector",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.1",
4
+ "description": "MCP server that lets agents drive DingTalk (dws) and WeCom (wecom-cli) CLIs: send messages, write reports, create todos, query calendars and approvals. Extensible provider registry for more IM platforms.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": "./dist/index.js",
10
+ "./locale/*.json": "./mcp-bundle/locale/*.json",
11
+ "./icon": "./mcp-bundle/icon.svg"
12
+ },
13
+ "bin": {
14
+ "im-connector": "dist/mcp/server.js"
15
+ },
16
+ "dsh": {
17
+ "bundle": {
18
+ "patch": "./mcp-bundle/cordis.patch.yml"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "mcp-bundle",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsc -p tsconfig.json",
29
+ "typecheck": "tsc -p tsconfig.json --noEmit",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "mcp": "node dist/mcp/server.js",
33
+ "smoke:mcp": "node scripts/mcp-smoke.mjs",
34
+ "verify": "pnpm typecheck && pnpm test && pnpm build && pnpm smoke:mcp",
35
+ "prepublishOnly": "npm run typecheck && npm run test && npm run build && npm run smoke:mcp"
36
+ },
37
+ "engines": {
38
+ "node": ">=18"
39
+ },
40
+ "dependencies": {
41
+ "@modelcontextprotocol/sdk": "^1.12.0"
42
+ },
43
+ "devDependencies": {
44
+ "@types/node": "^22.10.0",
45
+ "typescript": "^5.7.0",
46
+ "vitest": "^3.0.0"
47
+ },
48
+ "keywords": [
49
+ "mcp",
50
+ "mcp-server",
51
+ "modelcontextprotocol",
52
+ "im",
53
+ "dingtalk",
54
+ "dws",
55
+ "wecom",
56
+ "wecom-cli",
57
+ "connector",
58
+ "agent",
59
+ "feishu",
60
+ "discord"
61
+ ],
62
+ "publishConfig": {
63
+ "access": "public"
64
+ },
65
+ "license": "MIT"
66
+ }