@deadragdoll/tellymcp 0.0.12 → 0.0.13
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/README-ru.md +19 -0
- package/README.md +19 -0
- package/TOOLS.md +206 -3
- package/dist/cli.js +109 -1
- package/dist/services/features/telegram-mcp/browser.service.js +38 -1
- package/dist/services/features/telegram-mcp/mcp-server.service.js +12 -0
- package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +14 -0
- package/dist/services/features/telegram-mcp/src/app/config/env.js +13 -0
- package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +147 -2
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserClickTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserDomTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserFillTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserInjectScriptTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListAttachedInstancesTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserListTabsTool.js +33 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserPressTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStartTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStatusTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserRecordingStopTool.js +28 -0
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
- package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +485 -1
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/browserRecordingBundle.js +502 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachRegistry.js +79 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/firefoxAttachServer.js +559 -0
- package/dist/services/features/telegram-mcp/src/features/browser-attach/model/types.js +2 -0
- package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +28 -0
- package/docs/STANDALONE-ru.md +42 -6
- package/docs/STANDALONE.md +42 -6
- package/package.json +6 -3
- package/packages/chrome-attach-extension/dist/background.js +1326 -0
- package/packages/chrome-attach-extension/dist/icon.svg +6 -0
- package/packages/chrome-attach-extension/dist/manifest.json +36 -0
- package/packages/chrome-attach-extension/dist/options.html +312 -0
- package/packages/chrome-attach-extension/dist/options.js +593 -0
- package/packages/chrome-attach-extension/dist/popup.html +93 -0
- package/packages/chrome-attach-extension/dist/popup.js +79 -0
- package/packages/chrome-attach-extension/dist/recorder-content.js +83 -0
- package/packages/chrome-attach-extension/dist/recorder-page.js +266 -0
- package/packages/firefox-attach-extension/README.md +13 -0
- package/packages/firefox-attach-extension/dist/background.js +1242 -0
- package/packages/firefox-attach-extension/dist/icon.svg +6 -0
- package/packages/firefox-attach-extension/dist/manifest.json +56 -0
- package/packages/firefox-attach-extension/dist/options.html +312 -0
- package/packages/firefox-attach-extension/dist/options.js +527 -0
- package/packages/firefox-attach-extension/dist/popup.html +93 -0
- package/packages/firefox-attach-extension/dist/popup.js +64 -0
- package/packages/firefox-attach-extension/dist/recorder-content.js +77 -0
- package/packages/firefox-attach-extension/dist/recorder-page.js +302 -0
package/README-ru.md
CHANGED
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
- позволяет одной консоли агента ставить задачу другой консоли
|
|
30
30
|
- хранит structured xchange records в `.mcp-xchange`
|
|
31
31
|
- поддерживает browser automation через Playwright
|
|
32
|
+
- умеет attach к уже открытому Firefox или Chrome через bundled local extensions
|
|
33
|
+
- умеет писать structured browser bundles в `.mcp-xchange/web/...` с HTML, network и console артефактами
|
|
34
|
+
- умеет инжектить helper scripts в attached tabs или Playwright pages через `browser_inject_script`
|
|
32
35
|
- отдаёт Telegram Mini App / Live View с gateway
|
|
33
36
|
- поддерживает polling и webhook на gateway
|
|
34
37
|
- поставляет встроенный Codex plugin со skills под типовые workflow
|
|
@@ -76,9 +79,13 @@ Gateway
|
|
|
76
79
|
- `browser_open`
|
|
77
80
|
- `browser_click`
|
|
78
81
|
- `browser_fill`
|
|
82
|
+
- `browser_inject_script`
|
|
79
83
|
- `browser_press`
|
|
80
84
|
- `browser_wait_for`
|
|
81
85
|
- `browser_screenshot`
|
|
86
|
+
- `browser_recording_start`
|
|
87
|
+
- `browser_recording_stop`
|
|
88
|
+
- `browser_recording_status`
|
|
82
89
|
|
|
83
90
|
Синхронизация инструкций:
|
|
84
91
|
|
|
@@ -105,6 +112,18 @@ npm install -g @deadragdoll/tellymcp
|
|
|
105
112
|
tellymcp browser install
|
|
106
113
|
```
|
|
107
114
|
|
|
115
|
+
Если нужны attach extensions для существующего Firefox/Chrome:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
tellymcp extension firefox
|
|
119
|
+
tellymcp extension chrome
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Команда выгружает готовые unpacked bundles в текущий каталог:
|
|
123
|
+
|
|
124
|
+
- `./tellymcp-firefox-attach`
|
|
125
|
+
- `./tellymcp-chrome-attach`
|
|
126
|
+
|
|
108
127
|
Если используешь Codex:
|
|
109
128
|
|
|
110
129
|
```bash
|
package/README.md
CHANGED
|
@@ -29,6 +29,9 @@ The current model is gateway-first:
|
|
|
29
29
|
- lets one agent ask another agent to do work and return files or notes
|
|
30
30
|
- stores structured xchange records in `.mcp-xchange`
|
|
31
31
|
- supports browser automation with Playwright
|
|
32
|
+
- can attach to an already running Firefox or Chrome tab through bundled local extensions
|
|
33
|
+
- records browser sessions into structured `.mcp-xchange/web/...` bundles with HTML, network and console artifacts
|
|
34
|
+
- can inject helper scripts into attached tabs or Playwright pages through `browser_inject_script`
|
|
32
35
|
- serves the Telegram Mini App / Live View from the gateway
|
|
33
36
|
- supports Telegram polling or webhook mode on the gateway
|
|
34
37
|
- ships a bundled Codex workflow plugin for better agent behavior
|
|
@@ -76,9 +79,13 @@ Browser:
|
|
|
76
79
|
- `browser_open`
|
|
77
80
|
- `browser_click`
|
|
78
81
|
- `browser_fill`
|
|
82
|
+
- `browser_inject_script`
|
|
79
83
|
- `browser_press`
|
|
80
84
|
- `browser_wait_for`
|
|
81
85
|
- `browser_screenshot`
|
|
86
|
+
- `browser_recording_start`
|
|
87
|
+
- `browser_recording_stop`
|
|
88
|
+
- `browser_recording_status`
|
|
82
89
|
|
|
83
90
|
Tools sync:
|
|
84
91
|
|
|
@@ -105,6 +112,18 @@ Optional browser runtime:
|
|
|
105
112
|
tellymcp browser install
|
|
106
113
|
```
|
|
107
114
|
|
|
115
|
+
Optional attached-browser extensions:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
tellymcp extension firefox
|
|
119
|
+
tellymcp extension chrome
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
This exports unpacked extension bundles into the current directory:
|
|
123
|
+
|
|
124
|
+
- `./tellymcp-firefox-attach`
|
|
125
|
+
- `./tellymcp-chrome-attach`
|
|
126
|
+
|
|
108
127
|
Optional Codex workflow plugin:
|
|
109
128
|
|
|
110
129
|
```bash
|
package/TOOLS.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Tools
|
|
2
2
|
|
|
3
|
-
Version: `2026-
|
|
3
|
+
Version: `2026-06-06.1`
|
|
4
4
|
|
|
5
5
|
Gateway/client runtime compatibility:
|
|
6
6
|
|
|
@@ -16,10 +16,16 @@ This MCP server currently exposes the following tools.
|
|
|
16
16
|
|
|
17
17
|
Browser tools:
|
|
18
18
|
|
|
19
|
+
- `browser_list_attached_instances`
|
|
20
|
+
- `browser_list_tabs`
|
|
21
|
+
- `browser_recording_start`
|
|
22
|
+
- `browser_recording_stop`
|
|
23
|
+
- `browser_recording_status`
|
|
19
24
|
- `browser_open`
|
|
20
25
|
- `browser_reload`
|
|
21
26
|
- `browser_click`
|
|
22
27
|
- `browser_fill`
|
|
28
|
+
- `browser_inject_script`
|
|
23
29
|
- `browser_press`
|
|
24
30
|
- `browser_wait_for`
|
|
25
31
|
- `browser_wait_for_url`
|
|
@@ -34,7 +40,17 @@ Browser tools:
|
|
|
34
40
|
|
|
35
41
|
Browser runtime rule:
|
|
36
42
|
|
|
37
|
-
- Browser tools
|
|
43
|
+
- Browser tools now have two backends:
|
|
44
|
+
- attached browser tab backend for a real user Firefox or Chrome session
|
|
45
|
+
- isolated Playwright Chromium backend
|
|
46
|
+
- `browser_open` is only for the isolated Playwright backend.
|
|
47
|
+
- `browser_list_attached_instances` and `browser_list_tabs` are for the attached browser backend.
|
|
48
|
+
- if the local attach extension is connected and a tab was selected from the browser control panel, `browser_click`, `browser_fill`, `browser_inject_script`, `browser_press`, `browser_dom`, and `browser_screenshot` use that attached browser tab for the current session without requiring `browser_open`
|
|
49
|
+
- `browser_recording_start`, `browser_recording_stop`, and `browser_recording_status` are also for the attached browser backend
|
|
50
|
+
- browser recordings are written under `.mcp-xchange/web/{tab-title-slug}-{timestamp}/`
|
|
51
|
+
- each recording bundle contains `session.json`, `timeline.ndjson`, `pages/`, `network/`, and `console/`
|
|
52
|
+
- inside `network/`, use `index.ndjson` as the thin search index and `requests/{seq}-{request_id}/` as the per-request artifact bundle
|
|
53
|
+
- otherwise those tools use the Playwright backend after `browser_open`
|
|
38
54
|
- If browser tools fail because the Playwright browser runtime is missing, install it with `tellymcp browser install`.
|
|
39
55
|
- Do not stop at the installation error itself. Install the browser runtime first, then retry the browser tool.
|
|
40
56
|
|
|
@@ -758,7 +774,8 @@ Output:
|
|
|
758
774
|
Notes:
|
|
759
775
|
|
|
760
776
|
- each session gets its own isolated browser context and page
|
|
761
|
-
- call this first
|
|
777
|
+
- call this first only when you want the isolated Playwright backend
|
|
778
|
+
- do not call this just to work with an already selected Firefox attached tab
|
|
762
779
|
- `url` may be an absolute URL, or a relative path when `BROWSER_ADDRESS` is configured
|
|
763
780
|
- in headed mode the browser window is started maximized by default
|
|
764
781
|
- in headed mode a fresh browser context is created without a fixed viewport unless you explicitly pass `width` and `height`
|
|
@@ -766,6 +783,148 @@ Notes:
|
|
|
766
783
|
- if you pass viewport size, pass both `width` and `height` together
|
|
767
784
|
- use explicit `width` and `height` when the task depends on a specific responsive breakpoint or working area
|
|
768
785
|
|
|
786
|
+
## `browser_list_attached_instances`
|
|
787
|
+
|
|
788
|
+
Purpose:
|
|
789
|
+
|
|
790
|
+
- list browser instances currently connected through the local attach extension bridge
|
|
791
|
+
|
|
792
|
+
Input:
|
|
793
|
+
|
|
794
|
+
- `session_id?`
|
|
795
|
+
|
|
796
|
+
Output:
|
|
797
|
+
|
|
798
|
+
- `session_id?`
|
|
799
|
+
- `total`
|
|
800
|
+
- `instances[]`
|
|
801
|
+
- `instance_id`
|
|
802
|
+
- `browser`
|
|
803
|
+
- `extension_version`
|
|
804
|
+
- `profile_name?`
|
|
805
|
+
- `connected_at`
|
|
806
|
+
- `last_seen_at`
|
|
807
|
+
- `capabilities[]`
|
|
808
|
+
- `tab_count`
|
|
809
|
+
- `active_tab?`
|
|
810
|
+
|
|
811
|
+
## `browser_list_tabs`
|
|
812
|
+
|
|
813
|
+
Purpose:
|
|
814
|
+
|
|
815
|
+
- list tabs from an attached browser instance
|
|
816
|
+
|
|
817
|
+
Input:
|
|
818
|
+
|
|
819
|
+
- `session_id?`
|
|
820
|
+
- `instance_id?`
|
|
821
|
+
|
|
822
|
+
Output:
|
|
823
|
+
|
|
824
|
+
- `session_id?`
|
|
825
|
+
- `instance_id`
|
|
826
|
+
- `total`
|
|
827
|
+
- `tabs[]`
|
|
828
|
+
- `tab_id`
|
|
829
|
+
- `window_id?`
|
|
830
|
+
- `active`
|
|
831
|
+
- `selected?`
|
|
832
|
+
- `title`
|
|
833
|
+
- `url`
|
|
834
|
+
- `status?`
|
|
835
|
+
|
|
836
|
+
Notes:
|
|
837
|
+
|
|
838
|
+
- if only one attached browser instance is connected, `instance_id` can be omitted
|
|
839
|
+
- current tab selection for the attach backend is done from the browser extension control panel
|
|
840
|
+
- `active=true` means the tab is active in its browser window; there may be more than one such tab across multiple windows
|
|
841
|
+
- for the tab currently selected for this MCP session, prefer `selected=true`
|
|
842
|
+
|
|
843
|
+
## `browser_recording_start`
|
|
844
|
+
|
|
845
|
+
Purpose:
|
|
846
|
+
|
|
847
|
+
- start a structured browser recording bundle for the attached browser tab currently selected for this MCP session
|
|
848
|
+
|
|
849
|
+
Input:
|
|
850
|
+
|
|
851
|
+
- `session_id?`
|
|
852
|
+
- `instance_id?`
|
|
853
|
+
|
|
854
|
+
Output:
|
|
855
|
+
|
|
856
|
+
- `session_id`
|
|
857
|
+
- `backend`
|
|
858
|
+
- `started`
|
|
859
|
+
- `recording_id`
|
|
860
|
+
- `instance_id`
|
|
861
|
+
- `tab_id`
|
|
862
|
+
- `tab_title?`
|
|
863
|
+
- `tab_url?`
|
|
864
|
+
- `bundle_dir_name`
|
|
865
|
+
- `bundle_relative_path`
|
|
866
|
+
- `bundle_path`
|
|
867
|
+
- `started_at`
|
|
868
|
+
|
|
869
|
+
Notes:
|
|
870
|
+
|
|
871
|
+
- this works only with the attached browser backend, not Playwright
|
|
872
|
+
- select the target tab first from the browser extension control panel
|
|
873
|
+
- the bundle is created under `.mcp-xchange/web/{tab-title-slug}-{timestamp}/`
|
|
874
|
+
- the recording captures page snapshots, console events, request metadata, headers, cookies snapshots, and available request/response bodies
|
|
875
|
+
- for network analysis, read `network/index.ndjson` first, then open the matching `network/requests/{seq}-{request_id}/meta.json`
|
|
876
|
+
- use `request.json`, `response.json`, and optional body files only when deeper detail is needed
|
|
877
|
+
|
|
878
|
+
## `browser_recording_stop`
|
|
879
|
+
|
|
880
|
+
Purpose:
|
|
881
|
+
|
|
882
|
+
- stop the active structured browser recording for this MCP session
|
|
883
|
+
|
|
884
|
+
Input:
|
|
885
|
+
|
|
886
|
+
- `session_id?`
|
|
887
|
+
|
|
888
|
+
Output:
|
|
889
|
+
|
|
890
|
+
- `session_id`
|
|
891
|
+
- `stopped`
|
|
892
|
+
- `recording_id?`
|
|
893
|
+
- `bundle_dir_name?`
|
|
894
|
+
- `bundle_relative_path?`
|
|
895
|
+
- `bundle_path?`
|
|
896
|
+
- `stopped_at?`
|
|
897
|
+
|
|
898
|
+
## `browser_recording_status`
|
|
899
|
+
|
|
900
|
+
Purpose:
|
|
901
|
+
|
|
902
|
+
- inspect whether a structured browser recording is active and where its bundle is being written
|
|
903
|
+
|
|
904
|
+
Input:
|
|
905
|
+
|
|
906
|
+
- `session_id?`
|
|
907
|
+
|
|
908
|
+
Output:
|
|
909
|
+
|
|
910
|
+
- `session_id`
|
|
911
|
+
- `active`
|
|
912
|
+
- `recording?`
|
|
913
|
+
- `backend`
|
|
914
|
+
- `recording_id`
|
|
915
|
+
- `instance_id`
|
|
916
|
+
- `tab_id`
|
|
917
|
+
- `tab_title?`
|
|
918
|
+
- `tab_url?`
|
|
919
|
+
- `bundle_dir_name`
|
|
920
|
+
- `bundle_relative_path`
|
|
921
|
+
- `bundle_path`
|
|
922
|
+
- `started_at`
|
|
923
|
+
- `stopped_at?`
|
|
924
|
+
- `status`
|
|
925
|
+
- `event_count`
|
|
926
|
+
- `last_event_at?`
|
|
927
|
+
|
|
769
928
|
## `browser_console`
|
|
770
929
|
|
|
771
930
|
Purpose:
|
|
@@ -806,6 +965,8 @@ Output:
|
|
|
806
965
|
Purpose:
|
|
807
966
|
|
|
808
967
|
- click an element in the current session page
|
|
968
|
+
- if the session has a selected attached browser tab, click there
|
|
969
|
+
- otherwise click in the isolated Playwright page
|
|
809
970
|
|
|
810
971
|
Input:
|
|
811
972
|
|
|
@@ -831,6 +992,8 @@ Output:
|
|
|
831
992
|
Purpose:
|
|
832
993
|
|
|
833
994
|
- fill an input or textarea in the current session page
|
|
995
|
+
- if the session has a selected attached browser tab, fill there
|
|
996
|
+
- otherwise fill in the isolated Playwright page
|
|
834
997
|
|
|
835
998
|
Input:
|
|
836
999
|
|
|
@@ -858,6 +1021,8 @@ Output:
|
|
|
858
1021
|
Purpose:
|
|
859
1022
|
|
|
860
1023
|
- send a key press to the page or a targeted element
|
|
1024
|
+
- if the session has a selected attached browser tab, press there
|
|
1025
|
+
- otherwise press in the isolated Playwright page
|
|
861
1026
|
|
|
862
1027
|
Input:
|
|
863
1028
|
|
|
@@ -880,6 +1045,38 @@ Output:
|
|
|
880
1045
|
- `url`
|
|
881
1046
|
- `title?`
|
|
882
1047
|
|
|
1048
|
+
## `browser_inject_script`
|
|
1049
|
+
|
|
1050
|
+
Purpose:
|
|
1051
|
+
|
|
1052
|
+
- inject JavaScript into the current session browser target
|
|
1053
|
+
- if the session has a selected attached browser tab, inject into that real browser tab
|
|
1054
|
+
- otherwise inject into the isolated Playwright page
|
|
1055
|
+
- the script is wrapped so `window[namespace]` exists; default namespace is `TELLY`
|
|
1056
|
+
|
|
1057
|
+
Input:
|
|
1058
|
+
|
|
1059
|
+
- `session_id?`
|
|
1060
|
+
- `source?`
|
|
1061
|
+
- `file_path?`
|
|
1062
|
+
- `namespace?`
|
|
1063
|
+
|
|
1064
|
+
Rules:
|
|
1065
|
+
|
|
1066
|
+
- provide either `source` or `file_path`
|
|
1067
|
+
- prefer `file_path` for local reusable scripts and larger payloads
|
|
1068
|
+
- injected scripts can use both `window.TELLY` and local `TELLY` when `namespace` is left at the default
|
|
1069
|
+
|
|
1070
|
+
Output:
|
|
1071
|
+
|
|
1072
|
+
- `session_id`
|
|
1073
|
+
- `injected`
|
|
1074
|
+
- `namespace`
|
|
1075
|
+
- `source_type`
|
|
1076
|
+
- `bytes`
|
|
1077
|
+
- `url`
|
|
1078
|
+
- `title?`
|
|
1079
|
+
|
|
883
1080
|
## `browser_wait_for`
|
|
884
1081
|
|
|
885
1082
|
Purpose:
|
|
@@ -921,6 +1118,7 @@ Browser target rules for `browser_click`, `browser_fill`, `browser_press`, `brow
|
|
|
921
1118
|
- `div[data-testid="save"]`
|
|
922
1119
|
- use `text` only when there is no reliable selector
|
|
923
1120
|
- do not mix ambiguous hashed CSS classes with fuzzy text guessing when a stable selector exists
|
|
1121
|
+
- for the attached browser backend, prefer `selector` first; `ai_tag` and `text` still work, but the attach executor is intentionally lighter than full Playwright
|
|
924
1122
|
|
|
925
1123
|
## `browser_wait_for_url`
|
|
926
1124
|
|
|
@@ -1002,6 +1200,8 @@ Output:
|
|
|
1002
1200
|
Purpose:
|
|
1003
1201
|
|
|
1004
1202
|
- inspect a DOM element in the session browser tab
|
|
1203
|
+
- if the session has a selected attached browser tab, inspect that real browser tab
|
|
1204
|
+
- otherwise inspect the isolated Playwright page
|
|
1005
1205
|
|
|
1006
1206
|
Input:
|
|
1007
1207
|
|
|
@@ -1050,6 +1250,8 @@ Output:
|
|
|
1050
1250
|
Purpose:
|
|
1051
1251
|
|
|
1052
1252
|
- capture a screenshot from the session browser tab
|
|
1253
|
+
- if the session has a selected attached browser tab, capture from that real browser tab
|
|
1254
|
+
- otherwise capture from the isolated Playwright page
|
|
1053
1255
|
|
|
1054
1256
|
Input:
|
|
1055
1257
|
|
|
@@ -1076,6 +1278,7 @@ Notes:
|
|
|
1076
1278
|
- they are tracked separately from Telegram-uploaded files
|
|
1077
1279
|
- they appear under Telegram `Browser -> Screenshots`
|
|
1078
1280
|
- if `send_to_telegram=true`, the saved screenshot is also sent into the bound Telegram chat for that session
|
|
1281
|
+
- for the attached browser backend, the screenshot comes from the selected tab in the user browser session
|
|
1079
1282
|
|
|
1080
1283
|
## `browser_close`
|
|
1081
1284
|
|
package/dist/cli.js
CHANGED
|
@@ -72,6 +72,8 @@ function printHelp() {
|
|
|
72
72
|
" tellymcp doctor [--env <file>]",
|
|
73
73
|
" tellymcp system-prune [--env <file>] --yes",
|
|
74
74
|
" tellymcp browser install",
|
|
75
|
+
" tellymcp extension firefox",
|
|
76
|
+
" tellymcp extension chrome",
|
|
75
77
|
" tellymcp codex-plugin install",
|
|
76
78
|
" tellymcp codex-plugin status",
|
|
77
79
|
" tellymcp mcp [--url <url>] [--bearer <token>] [--format claude|legacy]",
|
|
@@ -87,6 +89,8 @@ function printHelp() {
|
|
|
87
89
|
" tellymcp doctor --env .env.client",
|
|
88
90
|
" tellymcp system-prune --env .env.gateway --yes",
|
|
89
91
|
" tellymcp browser install",
|
|
92
|
+
" tellymcp extension firefox",
|
|
93
|
+
" tellymcp extension chrome ./tellymcp-chrome-attach",
|
|
90
94
|
" tellymcp codex-plugin install",
|
|
91
95
|
" tellymcp codex-plugin status",
|
|
92
96
|
" tellymcp mcp --help",
|
|
@@ -245,6 +249,27 @@ function printBrowserHelp() {
|
|
|
245
249
|
" Avoids generic npx warnings about missing local project dependencies.",
|
|
246
250
|
]);
|
|
247
251
|
}
|
|
252
|
+
function printExtensionHelp() {
|
|
253
|
+
printBanner("extension helper", "Export bundled browser attach extensions into a local directory");
|
|
254
|
+
printSection("Usage", [
|
|
255
|
+
" tellymcp extension firefox [output-directory]",
|
|
256
|
+
" tellymcp extension ff [output-directory]",
|
|
257
|
+
" tellymcp extension chrome [output-directory]",
|
|
258
|
+
" tellymcp extension <firefox|ff|chrome> --out-dir <directory>",
|
|
259
|
+
" tellymcp extension <firefox|ff|chrome> --force",
|
|
260
|
+
]);
|
|
261
|
+
printSection("What this command does", [
|
|
262
|
+
" Copies the packaged unpacked extension bundle out of the installed tellymcp package.",
|
|
263
|
+
" By default exports into the current directory.",
|
|
264
|
+
" Creates a browser-specific folder you can load into Firefox or Chrome.",
|
|
265
|
+
]);
|
|
266
|
+
printSection("Examples", [
|
|
267
|
+
" tellymcp extension firefox",
|
|
268
|
+
" tellymcp extension chrome",
|
|
269
|
+
" tellymcp extension firefox ./tellymcp-firefox-attach",
|
|
270
|
+
" tellymcp extension chrome --out-dir ./browser-addon",
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
248
273
|
function printCodexPluginHelp() {
|
|
249
274
|
printBanner("codex plugin", "Install or inspect the bundled Codex workflow plugin");
|
|
250
275
|
printSection("Usage", [
|
|
@@ -684,6 +709,39 @@ async function runDoctor(args) {
|
|
|
684
709
|
function hasFlag(args, flagName) {
|
|
685
710
|
return args.includes(flagName);
|
|
686
711
|
}
|
|
712
|
+
function normalizeExtensionFlavor(rawValue) {
|
|
713
|
+
if (rawValue === "firefox" || rawValue === "ff") {
|
|
714
|
+
return "firefox";
|
|
715
|
+
}
|
|
716
|
+
if (rawValue === "chrome") {
|
|
717
|
+
return "chrome";
|
|
718
|
+
}
|
|
719
|
+
return null;
|
|
720
|
+
}
|
|
721
|
+
function getBundledExtensionDir(flavor) {
|
|
722
|
+
return node_path_1.default.join(packageRoot, "packages", flavor === "firefox" ? "firefox-attach-extension" : "chrome-attach-extension", "dist");
|
|
723
|
+
}
|
|
724
|
+
function getDefaultExtensionTargetDir(flavor) {
|
|
725
|
+
return node_path_1.default.resolve(process.cwd(), flavor === "firefox" ? "tellymcp-firefox-attach" : "tellymcp-chrome-attach");
|
|
726
|
+
}
|
|
727
|
+
function resolveExtensionTargetDir(args, flavor) {
|
|
728
|
+
const explicitOutDir = readFlagValue(args, "--out-dir");
|
|
729
|
+
if (explicitOutDir) {
|
|
730
|
+
return node_path_1.default.resolve(process.cwd(), explicitOutDir);
|
|
731
|
+
}
|
|
732
|
+
const positionalOutDir = args.find((value, index) => {
|
|
733
|
+
if (index === 0 || !value) {
|
|
734
|
+
return false;
|
|
735
|
+
}
|
|
736
|
+
if (value === "--force") {
|
|
737
|
+
return false;
|
|
738
|
+
}
|
|
739
|
+
return !value.startsWith("--out-dir=");
|
|
740
|
+
});
|
|
741
|
+
return positionalOutDir
|
|
742
|
+
? node_path_1.default.resolve(process.cwd(), positionalOutDir)
|
|
743
|
+
: getDefaultExtensionTargetDir(flavor);
|
|
744
|
+
}
|
|
687
745
|
async function runSystemPrune(args) {
|
|
688
746
|
const confirmed = hasFlag(args, "--yes");
|
|
689
747
|
if (!confirmed) {
|
|
@@ -821,6 +879,52 @@ function runBrowserCommand(args) {
|
|
|
821
879
|
process.exit(code ?? 0);
|
|
822
880
|
});
|
|
823
881
|
}
|
|
882
|
+
function runExtensionCommand(args) {
|
|
883
|
+
const [rawFlavor] = args;
|
|
884
|
+
if (!rawFlavor || rawFlavor === "--help" || rawFlavor === "-h") {
|
|
885
|
+
printExtensionHelp();
|
|
886
|
+
return;
|
|
887
|
+
}
|
|
888
|
+
const flavor = normalizeExtensionFlavor(rawFlavor);
|
|
889
|
+
if (!flavor) {
|
|
890
|
+
fail("Supported extension targets: firefox, ff, chrome");
|
|
891
|
+
}
|
|
892
|
+
const sourceDir = getBundledExtensionDir(flavor);
|
|
893
|
+
const sourceManifestPath = node_path_1.default.join(sourceDir, "manifest.json");
|
|
894
|
+
if (!(0, node_fs_1.existsSync)(sourceManifestPath)) {
|
|
895
|
+
fail(`Missing bundled ${flavor} extension. Reinstall or republish tellymcp with packaged extension bundles.`);
|
|
896
|
+
}
|
|
897
|
+
const targetDir = resolveExtensionTargetDir(args, flavor);
|
|
898
|
+
const force = hasFlag(args, "--force");
|
|
899
|
+
if ((0, node_fs_1.existsSync)(targetDir)) {
|
|
900
|
+
if (!force) {
|
|
901
|
+
fail(`Refusing to overwrite existing directory: ${targetDir}. Re-run with --force.`);
|
|
902
|
+
}
|
|
903
|
+
(0, node_fs_1.rmSync)(targetDir, { recursive: true, force: true });
|
|
904
|
+
}
|
|
905
|
+
(0, node_fs_1.mkdirSync)(node_path_1.default.dirname(targetDir), { recursive: true });
|
|
906
|
+
(0, node_fs_1.cpSync)(sourceDir, targetDir, { recursive: true });
|
|
907
|
+
printBanner(`extension ${flavor}`, "Bundled attach extension exported");
|
|
908
|
+
printSection("result", [
|
|
909
|
+
` source: ${sourceDir}`,
|
|
910
|
+
` target: ${targetDir}`,
|
|
911
|
+
` manifest: ${node_path_1.default.join(targetDir, "manifest.json")}`,
|
|
912
|
+
]);
|
|
913
|
+
if (flavor === "firefox") {
|
|
914
|
+
printSection("next", [
|
|
915
|
+
" 1. Open about:debugging#/runtime/this-firefox",
|
|
916
|
+
" 2. Click 'Load Temporary Add-on'",
|
|
917
|
+
` 3. Choose ${node_path_1.default.join(targetDir, "manifest.json")}`,
|
|
918
|
+
]);
|
|
919
|
+
return;
|
|
920
|
+
}
|
|
921
|
+
printSection("next", [
|
|
922
|
+
" 1. Open chrome://extensions",
|
|
923
|
+
" 2. Enable Developer mode",
|
|
924
|
+
" 3. Click 'Load unpacked'",
|
|
925
|
+
` 4. Choose ${targetDir}`,
|
|
926
|
+
]);
|
|
927
|
+
}
|
|
824
928
|
function runCodexPluginCommand(args) {
|
|
825
929
|
const [subcommand] = args;
|
|
826
930
|
if (!subcommand || subcommand === "--help" || subcommand === "-h") {
|
|
@@ -942,7 +1046,7 @@ async function runRuntime(args) {
|
|
|
942
1046
|
async function main(argv) {
|
|
943
1047
|
const [rawCommand, firstArg, secondArg] = argv;
|
|
944
1048
|
const command = rawCommand === "init" || rawCommand === "run" || rawCommand === "help" || rawCommand === "mcp" || rawCommand === "doctor" || rawCommand === "browser" || rawCommand === "system-prune"
|
|
945
|
-
|| rawCommand === "codex-plugin"
|
|
1049
|
+
|| rawCommand === "codex-plugin" || rawCommand === "extension"
|
|
946
1050
|
? rawCommand
|
|
947
1051
|
: "help";
|
|
948
1052
|
if (command === "help" || !rawCommand || rawCommand === "--help" || rawCommand === "-h") {
|
|
@@ -965,6 +1069,10 @@ async function main(argv) {
|
|
|
965
1069
|
runBrowserCommand(argv.slice(1));
|
|
966
1070
|
return;
|
|
967
1071
|
}
|
|
1072
|
+
if (command === "extension") {
|
|
1073
|
+
runExtensionCommand(argv.slice(1));
|
|
1074
|
+
return;
|
|
1075
|
+
}
|
|
968
1076
|
if (command === "codex-plugin") {
|
|
969
1077
|
runCodexPluginCommand(argv.slice(1));
|
|
970
1078
|
return;
|
|
@@ -21,6 +21,36 @@ const TelegramMcpBrowserService = {
|
|
|
21
21
|
return this.getBrowserService().getConsole(ctx.params);
|
|
22
22
|
},
|
|
23
23
|
},
|
|
24
|
+
listAttachedInstancesRemote: {
|
|
25
|
+
params: { $$strict: false },
|
|
26
|
+
async handler(ctx) {
|
|
27
|
+
return this.getBrowserService().listAttachedInstances(ctx.params);
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
listTabsRemote: {
|
|
31
|
+
params: { $$strict: false },
|
|
32
|
+
async handler(ctx) {
|
|
33
|
+
return this.getBrowserService().listTabs(ctx.params);
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
startRecordingRemote: {
|
|
37
|
+
params: { $$strict: false },
|
|
38
|
+
async handler(ctx) {
|
|
39
|
+
return this.getBrowserService().startRecording(ctx.params);
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
stopRecordingRemote: {
|
|
43
|
+
params: { $$strict: false },
|
|
44
|
+
async handler(ctx) {
|
|
45
|
+
return this.getBrowserService().stopRecording(ctx.params);
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
getRecordingStatusRemote: {
|
|
49
|
+
params: { $$strict: false },
|
|
50
|
+
async handler(ctx) {
|
|
51
|
+
return this.getBrowserService().getRecordingStatus(ctx.params);
|
|
52
|
+
},
|
|
53
|
+
},
|
|
24
54
|
clickRemote: {
|
|
25
55
|
params: { $$strict: false },
|
|
26
56
|
async handler(ctx) {
|
|
@@ -33,6 +63,12 @@ const TelegramMcpBrowserService = {
|
|
|
33
63
|
return this.getBrowserService().fill(ctx.params);
|
|
34
64
|
},
|
|
35
65
|
},
|
|
66
|
+
injectScriptRemote: {
|
|
67
|
+
params: { $$strict: false },
|
|
68
|
+
async handler(ctx) {
|
|
69
|
+
return this.getBrowserService().injectScript(ctx.params);
|
|
70
|
+
},
|
|
71
|
+
},
|
|
36
72
|
pressRemote: {
|
|
37
73
|
params: { $$strict: false },
|
|
38
74
|
async handler(ctx) {
|
|
@@ -119,7 +155,8 @@ const TelegramMcpBrowserService = {
|
|
|
119
155
|
}
|
|
120
156
|
const runtime = await runtimeService.waitUntilReady();
|
|
121
157
|
this.logger.info("Starting telegram_mcp browser service");
|
|
122
|
-
|
|
158
|
+
const firefoxAttachServer = runtime.firefoxAttachServer;
|
|
159
|
+
this.browserService = new browserService_1.BrowserService(runtime.config, runtime.sessionStore, runtime.maintenanceStore, runtime.stateStore, runtime.stateStore, runtime.objectStore, runtime.telegramTransport, runtime.logger, runtime.projectIdentityResolver, new remoteConsoleActionClient_1.RemoteConsoleActionClient((actionName, params) => this.broker.call(actionName, params, { meta: { internal_call: true } })), firefoxAttachServer);
|
|
123
160
|
this.logger.info("telegram_mcp browser service is ready");
|
|
124
161
|
},
|
|
125
162
|
async stopped() {
|
|
@@ -18,9 +18,15 @@ const browserConsoleTool_1 = require("./src/features/browser/model/browserConsol
|
|
|
18
18
|
const browserDomTool_1 = require("./src/features/browser/model/browserDomTool");
|
|
19
19
|
const browserErrorsTool_1 = require("./src/features/browser/model/browserErrorsTool");
|
|
20
20
|
const browserFillTool_1 = require("./src/features/browser/model/browserFillTool");
|
|
21
|
+
const browserInjectScriptTool_1 = require("./src/features/browser/model/browserInjectScriptTool");
|
|
22
|
+
const browserListAttachedInstancesTool_1 = require("./src/features/browser/model/browserListAttachedInstancesTool");
|
|
23
|
+
const browserListTabsTool_1 = require("./src/features/browser/model/browserListTabsTool");
|
|
21
24
|
const browserNetworkFailuresTool_1 = require("./src/features/browser/model/browserNetworkFailuresTool");
|
|
22
25
|
const browserOpenTool_1 = require("./src/features/browser/model/browserOpenTool");
|
|
23
26
|
const browserPressTool_1 = require("./src/features/browser/model/browserPressTool");
|
|
27
|
+
const browserRecordingStartTool_1 = require("./src/features/browser/model/browserRecordingStartTool");
|
|
28
|
+
const browserRecordingStatusTool_1 = require("./src/features/browser/model/browserRecordingStatusTool");
|
|
29
|
+
const browserRecordingStopTool_1 = require("./src/features/browser/model/browserRecordingStopTool");
|
|
24
30
|
const browserReloadTool_1 = require("./src/features/browser/model/browserReloadTool");
|
|
25
31
|
const browserScreenshotTool_1 = require("./src/features/browser/model/browserScreenshotTool");
|
|
26
32
|
const browserWaitForTool_1 = require("./src/features/browser/model/browserWaitForTool");
|
|
@@ -76,10 +82,16 @@ const TelegramMcpMcpServerService = {
|
|
|
76
82
|
new notifyTelegramTool_1.NotifyTelegramTool(notifyService.getNotifyService()),
|
|
77
83
|
new sendFileToTelegramTool_1.SendFileToTelegramTool(notifyService.getNotifyService()),
|
|
78
84
|
new askUserTelegram_1.AskUserTelegramTool(approvalService.getApprovalOrchestrator()),
|
|
85
|
+
new browserListAttachedInstancesTool_1.BrowserListAttachedInstancesTool(browserService.getBrowserService()),
|
|
86
|
+
new browserListTabsTool_1.BrowserListTabsTool(browserService.getBrowserService()),
|
|
87
|
+
new browserRecordingStartTool_1.BrowserRecordingStartTool(browserService.getBrowserService()),
|
|
88
|
+
new browserRecordingStopTool_1.BrowserRecordingStopTool(browserService.getBrowserService()),
|
|
89
|
+
new browserRecordingStatusTool_1.BrowserRecordingStatusTool(browserService.getBrowserService()),
|
|
79
90
|
new browserOpenTool_1.BrowserOpenTool(browserService.getBrowserService()),
|
|
80
91
|
new browserReloadTool_1.BrowserReloadTool(browserService.getBrowserService()),
|
|
81
92
|
new browserClickTool_1.BrowserClickTool(browserService.getBrowserService()),
|
|
82
93
|
new browserFillTool_1.BrowserFillTool(browserService.getBrowserService()),
|
|
94
|
+
new browserInjectScriptTool_1.BrowserInjectScriptTool(browserService.getBrowserService()),
|
|
83
95
|
new browserPressTool_1.BrowserPressTool(browserService.getBrowserService()),
|
|
84
96
|
new browserWaitForTool_1.BrowserWaitForTool(browserService.getBrowserService()),
|
|
85
97
|
new browserWaitForUrlTool_1.BrowserWaitForUrlTool(browserService.getBrowserService()),
|
|
@@ -12,6 +12,7 @@ const transport_1 = require("../../shared/integrations/telegram/transport");
|
|
|
12
12
|
const minioExchangeStore_1 = require("../../shared/integrations/object-storage/minioExchangeStore");
|
|
13
13
|
const gatewayHttpService_1 = require("../../features/distributed-gateway/model/gatewayHttpService");
|
|
14
14
|
const gatewayClientAccess_1 = require("../../features/distributed-client/model/gatewayClientAccess");
|
|
15
|
+
const firefoxAttachServer_1 = require("../../features/browser-attach/model/firefoxAttachServer");
|
|
15
16
|
const client_2 = require("../../shared/integrations/terminal/client");
|
|
16
17
|
const ptyRegistry_1 = require("../../shared/integrations/terminal/ptyRegistry");
|
|
17
18
|
async function createAppRuntime(input) {
|
|
@@ -63,6 +64,15 @@ async function createAppRuntime(input) {
|
|
|
63
64
|
nudgeDebounceSeconds: config.terminal.nudgeDebounceSeconds,
|
|
64
65
|
nudgeCooldownSeconds: config.terminal.nudgeCooldownSeconds,
|
|
65
66
|
},
|
|
67
|
+
browser: {
|
|
68
|
+
enabled: config.browser.enabled,
|
|
69
|
+
headless: config.browser.headless,
|
|
70
|
+
devtools: config.browser.devtools,
|
|
71
|
+
attachEnabled: config.browser.attach.enabled,
|
|
72
|
+
attachHost: config.browser.attach.host,
|
|
73
|
+
attachPort: config.browser.attach.port,
|
|
74
|
+
attachPath: config.browser.attach.path,
|
|
75
|
+
},
|
|
66
76
|
telegram: {
|
|
67
77
|
webhookEnabled: config.telegram.webhook.enabled,
|
|
68
78
|
webhookPath: config.telegram.webhook.path,
|
|
@@ -200,6 +210,8 @@ async function createAppRuntime(input) {
|
|
|
200
210
|
await telegramTransport.sendStartupNotifications();
|
|
201
211
|
logger.info("Startup Telegram notifications completed");
|
|
202
212
|
const gatewayHttpService = new gatewayHttpService_1.GatewayHttpService(config, input.callBroker);
|
|
213
|
+
const firefoxAttachServer = new firefoxAttachServer_1.FirefoxAttachServer(config, logger, stateStore, stateStore);
|
|
214
|
+
await firefoxAttachServer.start();
|
|
203
215
|
return {
|
|
204
216
|
callBroker: input.callBroker,
|
|
205
217
|
config,
|
|
@@ -217,8 +229,10 @@ async function createAppRuntime(input) {
|
|
|
217
229
|
projectIdentityResolver,
|
|
218
230
|
webAppLaunchRegistry,
|
|
219
231
|
gatewayHttpService,
|
|
232
|
+
firefoxAttachServer,
|
|
220
233
|
shutdown: async () => {
|
|
221
234
|
logger.info("Shutdown started");
|
|
235
|
+
await firefoxAttachServer.stop();
|
|
222
236
|
await telegramTransport.stop();
|
|
223
237
|
(0, ptyRegistry_1.stopAllPtyTargets)();
|
|
224
238
|
redis.disconnect();
|