@opentiny/webmcp-cli 0.0.1-alpha.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.
@@ -0,0 +1,219 @@
1
+ ;(function(){
2
+ "use strict";
3
+ (() => {
4
+ // webmcp-tools/excalidraw.com/index.ts
5
+ var _excalidrawMcp = navigator.modelContext;
6
+ if (!_excalidrawMcp || typeof _excalidrawMcp.registerTool !== "function") {
7
+ console.warn("[webmcp-tools] excalidraw.com: navigator.modelContext.registerTool \u672A\u5C31\u7EEA\uFF0C\u8DF3\u8FC7\u6CE8\u5165");
8
+ } else if (!window.__webmcptools_excalidraw) {
9
+ const mcp = _excalidrawMcp;
10
+ try {
11
+ let getExcalidrawAPIFromDOM = function(domElement) {
12
+ if (!domElement) return null;
13
+ const reactFiberKey = Object.keys(domElement).find(
14
+ (key) => key.startsWith("__reactFiber$") || key.startsWith("__reactInternalInstance$")
15
+ );
16
+ if (!reactFiberKey) return null;
17
+ let fiberNode = domElement[reactFiberKey];
18
+ function isExcalidrawAPI(obj) {
19
+ return typeof obj === "object" && obj !== null && typeof obj.updateScene === "function" && typeof obj.getSceneElements === "function" && typeof obj.getAppState === "function";
20
+ }
21
+ function findApiInObject(objToSearch) {
22
+ if (isExcalidrawAPI(objToSearch)) return objToSearch;
23
+ if (typeof objToSearch === "object" && objToSearch !== null) {
24
+ for (const key in objToSearch) {
25
+ if (Object.prototype.hasOwnProperty.call(objToSearch, key)) {
26
+ const found = findApiInObject(objToSearch[key]);
27
+ if (found) return found;
28
+ }
29
+ }
30
+ }
31
+ return null;
32
+ }
33
+ let excalidrawApi = null;
34
+ let attempts = 0;
35
+ const MAX_TRAVERSAL = 25;
36
+ while (fiberNode && attempts < MAX_TRAVERSAL) {
37
+ if (fiberNode.stateNode?.props) {
38
+ const api = findApiInObject(fiberNode.stateNode.props);
39
+ if (api) {
40
+ excalidrawApi = api;
41
+ break;
42
+ }
43
+ }
44
+ if (fiberNode.memoizedProps) {
45
+ const api = findApiInObject(fiberNode.memoizedProps);
46
+ if (api) {
47
+ excalidrawApi = api;
48
+ break;
49
+ }
50
+ }
51
+ if ([0, 2, 11, 14, 15].includes(fiberNode.tag) && fiberNode.memoizedState) {
52
+ let hook = fiberNode.memoizedState;
53
+ let hookAttempts = 0;
54
+ while (hook && hookAttempts < 15) {
55
+ const api = findApiInObject(hook.memoizedState);
56
+ if (api) {
57
+ excalidrawApi = api;
58
+ break;
59
+ }
60
+ hook = hook.next;
61
+ hookAttempts++;
62
+ }
63
+ if (excalidrawApi) break;
64
+ }
65
+ fiberNode = fiberNode.return;
66
+ attempts++;
67
+ }
68
+ if (excalidrawApi) {
69
+ ;
70
+ window.excalidrawAPI = excalidrawApi;
71
+ }
72
+ return excalidrawApi;
73
+ }, createFullElement = function(skeleton) {
74
+ const id = skeleton.id || Math.random().toString(36).substring(2, 9);
75
+ const el = {
76
+ seed: Math.floor(Math.random() * 2 ** 31),
77
+ versionNonce: Math.floor(Math.random() * 2 ** 31),
78
+ updated: Date.now(),
79
+ isDeleted: false,
80
+ fillStyle: "hachure",
81
+ strokeWidth: 1,
82
+ strokeStyle: "solid",
83
+ roughness: 1,
84
+ opacity: 100,
85
+ angle: 0,
86
+ groupIds: [],
87
+ strokeColor: "#000000",
88
+ backgroundColor: "transparent",
89
+ version: 1,
90
+ locked: false,
91
+ ...skeleton,
92
+ id
93
+ };
94
+ if (["arrow", "line", "freedraw"].includes(el.type)) {
95
+ if (!el.points || !Array.isArray(el.points)) {
96
+ el.points = [[0, 0], [100, 100]];
97
+ }
98
+ }
99
+ return el;
100
+ };
101
+ getExcalidrawAPIFromDOM2 = getExcalidrawAPIFromDOM, createFullElement2 = createFullElement;
102
+ const targetEl = document.querySelector(".excalidraw-app");
103
+ if (targetEl) getExcalidrawAPIFromDOM(targetEl);
104
+ const handlers = {
105
+ getSceneElements: () => {
106
+ try {
107
+ return window.excalidrawAPI.getSceneElements();
108
+ } catch (e) {
109
+ return { error: true, msg: e.message };
110
+ }
111
+ },
112
+ addElement: (param) => {
113
+ try {
114
+ const existing = window.excalidrawAPI.getSceneElements();
115
+ const newElements = [
116
+ ...existing,
117
+ ...param.eles.map((ele, idx) => {
118
+ const el = createFullElement(ele);
119
+ el.index = `a${existing.length + idx + 1}`;
120
+ return el;
121
+ })
122
+ ];
123
+ window.excalidrawAPI.updateScene({ elements: newElements, commitToHistory: true });
124
+ return { success: true };
125
+ } catch (e) {
126
+ return { error: true, msg: e.message };
127
+ }
128
+ },
129
+ deleteElement: (param) => {
130
+ try {
131
+ const existing = window.excalidrawAPI.getSceneElements();
132
+ const idx = existing.findIndex((e) => e.id === param.id);
133
+ if (idx >= 0) {
134
+ const newElements = [...existing];
135
+ newElements.splice(idx, 1);
136
+ window.excalidrawAPI.updateScene({ elements: newElements, commitToHistory: true });
137
+ return { success: true };
138
+ }
139
+ return { error: true, msg: "element not found" };
140
+ } catch (e) {
141
+ return { error: true, msg: e.message };
142
+ }
143
+ },
144
+ updateElement: (param) => {
145
+ try {
146
+ const existing = [...window.excalidrawAPI.getSceneElements()];
147
+ param.forEach((item) => {
148
+ const idx = existing.findIndex((e) => e.id === item.id);
149
+ if (idx >= 0) {
150
+ existing[idx] = {
151
+ ...existing[idx],
152
+ ...item,
153
+ version: (existing[idx].version || 1) + 1,
154
+ updated: Date.now()
155
+ };
156
+ }
157
+ });
158
+ window.excalidrawAPI.updateScene({ elements: existing, commitToHistory: true });
159
+ return { success: true };
160
+ } catch (e) {
161
+ return { error: true, msg: e.message };
162
+ }
163
+ },
164
+ cleanup: () => {
165
+ try {
166
+ window.excalidrawAPI.resetScene();
167
+ return { success: true };
168
+ } catch (e) {
169
+ return { error: true, msg: e.message };
170
+ }
171
+ }
172
+ };
173
+ mcp.registerTool({
174
+ name: "excalidraw_execute_command",
175
+ title: "Excalidraw \u753B\u5E03\u64CD\u4F5C",
176
+ description: "\u6267\u884C\u547D\u4EE4\u4E0E Excalidraw \u753B\u5E03\u4EA4\u4E92\uFF0C\u652F\u6301\u83B7\u53D6/\u6DFB\u52A0/\u66F4\u65B0/\u5220\u9664\u5143\u7D20\u4EE5\u53CA\u6E05\u7A7A\u753B\u5E03\u3002\u4F7F\u7528\u524D\u8BF7\u5148\u9605\u8BFB\u753B\u56FE skill \u6307\u5BFC\u3002",
177
+ inputSchema: {
178
+ type: "object",
179
+ properties: {
180
+ eventName: {
181
+ type: "string",
182
+ description: "\u547D\u4EE4\u7C7B\u578B\uFF1AgetSceneElements-\u83B7\u53D6\u753B\u5E03\u5143\u7D20\uFF0CaddElement-\u6DFB\u52A0\u5143\u7D20\uFF0CupdateElement-\u66F4\u65B0\u5143\u7D20\uFF0CdeleteElement-\u5220\u9664\u5143\u7D20\uFF0Ccleanup-\u6E05\u7A7A\u753B\u5E03"
183
+ },
184
+ payload: {
185
+ type: "string",
186
+ description: '\u4F20\u7ED9\u547D\u4EE4\u7684\u53C2\u6570\uFF0C\u5FC5\u987B\u662F JSON \u5B57\u7B26\u4E32\u3002addElement \u65F6 payload \u4E3A {"eles": [...\u5143\u7D20\u6570\u7EC4]}\uFF0CupdateElement \u65F6\u4E3A\u5143\u7D20\u6570\u7EC4'
187
+ }
188
+ },
189
+ required: ["eventName"]
190
+ },
191
+ execute: async ({ eventName, payload }) => {
192
+ if (!window.excalidrawAPI) {
193
+ const el = document.querySelector(".excalidraw-app");
194
+ if (el) getExcalidrawAPIFromDOM(el);
195
+ }
196
+ const handler = handlers[eventName];
197
+ if (!handler) {
198
+ return {
199
+ content: [{
200
+ type: "text",
201
+ text: JSON.stringify({ error: true, msg: `unknown command: ${eventName}. \u53EF\u7528\u547D\u4EE4: ${Object.keys(handlers).join(", ")}` })
202
+ }]
203
+ };
204
+ }
205
+ const param = JSON.parse(payload || "{}");
206
+ const result = handler(param);
207
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
208
+ }
209
+ });
210
+ window.__webmcptools_excalidraw = true;
211
+ console.log("[webmcp-tools] excalidraw.com \u5DE5\u5177\u6CE8\u518C\u6210\u529F");
212
+ } catch (e) {
213
+ console.error("[webmcp-tools] excalidraw.com \u5DE5\u5177\u6CE8\u518C\u5931\u8D25:", e.message);
214
+ }
215
+ }
216
+ var getExcalidrawAPIFromDOM2;
217
+ var createFullElement2;
218
+ })();
219
+ })();
@@ -0,0 +1,76 @@
1
+ ;(function(){
2
+ "use strict";
3
+ (() => {
4
+ // webmcp-tools/www.baidu.com/index.ts
5
+ var _baiduMcp = navigator.modelContext;
6
+ if (!_baiduMcp || typeof _baiduMcp.registerTool !== "function") {
7
+ console.warn("[webmcp-tools] www.baidu.com: navigator.modelContext.registerTool \u672A\u5C31\u7EEA\uFF0C\u8DF3\u8FC7\u6CE8\u5165");
8
+ } else if (!window.__webmcptools_baidu) {
9
+ try {
10
+ _baiduMcp.registerTool({
11
+ name: "baidu_search",
12
+ title: "\u767E\u5EA6\u641C\u7D22",
13
+ description: "\u5728\u767E\u5EA6\u8F93\u5165\u6846\u4E2D\u8F93\u5165\u5173\u952E\u5B57\u5E76\u6267\u884C\u641C\u7D22\u3002",
14
+ inputSchema: {
15
+ type: "object",
16
+ properties: {
17
+ keyword: { type: "string", description: "\u8981\u641C\u7D22\u7684\u5173\u952E\u5B57" }
18
+ },
19
+ required: ["keyword"]
20
+ },
21
+ execute: async ({ keyword }) => {
22
+ const inputEl = document.querySelector("#kw");
23
+ const btnEl = document.querySelector("#su");
24
+ if (!inputEl || !btnEl) {
25
+ return {
26
+ content: [{ type: "text", text: "\u672A\u627E\u5230\u767E\u5EA6\u641C\u7D22\u6846\u6216\u641C\u7D22\u6309\u94AE\uFF0C\u53EF\u80FD\u4E0D\u5728\u9996\u9875\u6216\u9875\u9762\u7ED3\u6784\u5DF2\u53D8\u3002" }]
27
+ };
28
+ }
29
+ inputEl.value = keyword;
30
+ inputEl.dispatchEvent(new Event("input", { bubbles: true }));
31
+ btnEl.click();
32
+ return {
33
+ content: [{ type: "text", text: `\u5DF2\u5728\u767E\u5EA6\u6267\u884C\u641C\u7D22\uFF1A${keyword}` }]
34
+ };
35
+ }
36
+ });
37
+ _baiduMcp.registerTool({
38
+ name: "baidu_get_results",
39
+ title: "\u83B7\u53D6\u767E\u5EA6\u641C\u7D22\u7ED3\u679C",
40
+ description: "\u83B7\u53D6\u5F53\u524D\u767E\u5EA6\u641C\u7D22\u7ED3\u679C\u9875\u9762\u4E2D\u7684\u641C\u7D22\u7ED3\u679C\u5217\u8868\uFF0C\u5305\u542B\u6807\u9898\u548C\u94FE\u63A5\u3002",
41
+ inputSchema: {
42
+ type: "object",
43
+ properties: {
44
+ limit: { type: "string", description: "\u6700\u591A\u8FD4\u56DE\u7684\u7ED3\u679C\u6570\u91CF\uFF0C\u9ED8\u8BA4 10" }
45
+ },
46
+ required: []
47
+ },
48
+ execute: async ({ limit }) => {
49
+ const maxCount = parseInt(limit || "10", 10);
50
+ const results = [];
51
+ const items = document.querySelectorAll(".result.c-container");
52
+ items.forEach((item, idx) => {
53
+ if (idx >= maxCount) return;
54
+ const titleEl = item.querySelector("h3 a");
55
+ const summaryEl = item.querySelector(".content-right_8Zs40, .c-abstract, .c-span9");
56
+ if (titleEl) {
57
+ results.push({
58
+ title: titleEl.textContent?.trim() || "",
59
+ url: titleEl.href || "",
60
+ summary: summaryEl?.textContent?.trim() || ""
61
+ });
62
+ }
63
+ });
64
+ return {
65
+ content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
66
+ };
67
+ }
68
+ });
69
+ window.__webmcptools_baidu = true;
70
+ console.log("[webmcp-tools] www.baidu.com \u5DE5\u5177\u6CE8\u518C\u6210\u529F");
71
+ } catch (e) {
72
+ console.error("[webmcp-tools] www.baidu.com \u5DE5\u5177\u6CE8\u518C\u5931\u8D25:", e.message);
73
+ }
74
+ }
75
+ })();
76
+ })();
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@opentiny/webmcp-cli",
3
+ "version": "0.0.1-alpha.0",
4
+ "type": "module",
5
+ "description": "WebMCP CLI for AI Agents to interact with browser via Puppeteer",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "webmcp-cli": "./dist/bin.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "keywords": [
16
+ "chrome",
17
+ "puppeteer",
18
+ "cli"
19
+ ],
20
+ "license": "MIT",
21
+ "author": "OpenTiny Team",
22
+ "engines": {
23
+ "node": ">=16"
24
+ },
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "dependencies": {
29
+ "@mcp-b/webmcp-polyfill": "^2.2.0",
30
+ "@page-agent/page-controller": "^1.7.1",
31
+ "commander": "^11.1.0",
32
+ "picocolors": "^1.0.0",
33
+ "puppeteer-core": "^22.0.0",
34
+ "@opentiny/next-sdk": "^0.3.3"
35
+ },
36
+ "devDependencies": {
37
+ "@types/node": "^20.0.0",
38
+ "esbuild": "^0.25.0",
39
+ "tsup": "^8.0.2",
40
+ "tsx": "^4.0.0",
41
+ "typescript": "^5.3.3"
42
+ },
43
+ "scripts": {
44
+ "dev": "tsup --watch",
45
+ "build:inject": "node scripts/build-inject.mjs",
46
+ "build:tools": "node scripts/build-inject.mjs",
47
+ "build": "tsup && pnpm run build:inject",
48
+ "link:global": "npm install -g .",
49
+ "start": "node dist/bin.js"
50
+ }
51
+ }