browser-devtools-mcp 0.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.
- package/LICENSE +21 -0
- package/README.md +652 -0
- package/dist/browser.js +67 -0
- package/dist/browser.js.map +1 -0
- package/dist/config.js +11 -0
- package/dist/config.js.map +1 -0
- package/dist/context.js +210 -0
- package/dist/context.js.map +1 -0
- package/dist/index.js +296 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.js +97 -0
- package/dist/logger.js.map +1 -0
- package/dist/server-info.js +33 -0
- package/dist/server-info.js.map +1 -0
- package/dist/server.js +131 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/content/get-as-html.js +164 -0
- package/dist/tools/content/get-as-html.js.map +1 -0
- package/dist/tools/content/get-as-text.js +76 -0
- package/dist/tools/content/get-as-text.js.map +1 -0
- package/dist/tools/content/index.js +16 -0
- package/dist/tools/content/index.js.map +1 -0
- package/dist/tools/content/save-as-pdf.js +146 -0
- package/dist/tools/content/save-as-pdf.js.map +1 -0
- package/dist/tools/content/take-aria-snapshot.js +49 -0
- package/dist/tools/content/take-aria-snapshot.js.map +1 -0
- package/dist/tools/content/take-screenshot.js +113 -0
- package/dist/tools/content/take-screenshot.js.map +1 -0
- package/dist/tools/index.js +29 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/interaction/click.js +29 -0
- package/dist/tools/interaction/click.js.map +1 -0
- package/dist/tools/interaction/drag.js +41 -0
- package/dist/tools/interaction/drag.js.map +1 -0
- package/dist/tools/interaction/evaluate.js +33 -0
- package/dist/tools/interaction/evaluate.js.map +1 -0
- package/dist/tools/interaction/fill.js +28 -0
- package/dist/tools/interaction/fill.js.map +1 -0
- package/dist/tools/interaction/hover.js +29 -0
- package/dist/tools/interaction/hover.js.map +1 -0
- package/dist/tools/interaction/index.js +20 -0
- package/dist/tools/interaction/index.js.map +1 -0
- package/dist/tools/interaction/press-key.js +36 -0
- package/dist/tools/interaction/press-key.js.map +1 -0
- package/dist/tools/interaction/select.js +30 -0
- package/dist/tools/interaction/select.js.map +1 -0
- package/dist/tools/monitoring/get-console-messages.js +151 -0
- package/dist/tools/monitoring/get-console-messages.js.map +1 -0
- package/dist/tools/monitoring/get-http-requests.js +216 -0
- package/dist/tools/monitoring/get-http-requests.js.map +1 -0
- package/dist/tools/monitoring/index.js +7 -0
- package/dist/tools/monitoring/index.js.map +1 -0
- package/dist/tools/navigation/go-back.js +76 -0
- package/dist/tools/navigation/go-back.js.map +1 -0
- package/dist/tools/navigation/go-forward.js +76 -0
- package/dist/tools/navigation/go-forward.js.map +1 -0
- package/dist/tools/navigation/go-to.js +80 -0
- package/dist/tools/navigation/go-to.js.map +1 -0
- package/dist/tools/navigation/index.js +8 -0
- package/dist/tools/navigation/index.js.map +1 -0
- package/dist/tools/tool-executor.js +57 -0
- package/dist/tools/tool-executor.js.map +1 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/types.js +55 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.js +47 -0
- package/dist/utils.js.map +1 -0
- package/package.json +73 -0
package/dist/browser.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BrowserType = void 0;
|
|
4
|
+
exports.getBrowser = getBrowser;
|
|
5
|
+
exports.newBrowserContext = newBrowserContext;
|
|
6
|
+
exports.newPage = newPage;
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
const playwright_1 = require("playwright");
|
|
9
|
+
var BrowserType;
|
|
10
|
+
(function (BrowserType) {
|
|
11
|
+
BrowserType["CHROMIUM"] = "chromium";
|
|
12
|
+
BrowserType["FIREFOX"] = "firefox";
|
|
13
|
+
BrowserType["WEBKIT"] = "webkit";
|
|
14
|
+
})(BrowserType || (exports.BrowserType = BrowserType = {}));
|
|
15
|
+
const browsers = new Map();
|
|
16
|
+
function _createBrowserOptions(browserType) {
|
|
17
|
+
return {
|
|
18
|
+
browserType,
|
|
19
|
+
executablePath: config_1.BROWSER_EXECUTABLE_PATH,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async function _createBrowser(browserOptions = {}) {
|
|
23
|
+
// Use the appropriate browser engine
|
|
24
|
+
let browserInstance;
|
|
25
|
+
switch (browserOptions.browserType) {
|
|
26
|
+
case BrowserType.FIREFOX:
|
|
27
|
+
browserInstance = playwright_1.firefox;
|
|
28
|
+
break;
|
|
29
|
+
case BrowserType.WEBKIT:
|
|
30
|
+
browserInstance = playwright_1.webkit;
|
|
31
|
+
break;
|
|
32
|
+
case BrowserType.CHROMIUM:
|
|
33
|
+
default:
|
|
34
|
+
browserInstance = playwright_1.chromium;
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
return browserInstance.launch({
|
|
38
|
+
executablePath: browserOptions.executablePath,
|
|
39
|
+
handleSIGINT: false,
|
|
40
|
+
handleSIGTERM: false,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
async function getBrowser(browserType = BrowserType.CHROMIUM) {
|
|
44
|
+
let browserInstance = browsers.get(browserType);
|
|
45
|
+
if (browserInstance && !browserInstance.isConnected()) {
|
|
46
|
+
try {
|
|
47
|
+
await browserInstance.close().catch(() => { });
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
// Ignore errors when closing disconnected browser
|
|
51
|
+
}
|
|
52
|
+
// Reset browser and page references
|
|
53
|
+
browserInstance = undefined;
|
|
54
|
+
}
|
|
55
|
+
if (!browserInstance) {
|
|
56
|
+
browserInstance = await _createBrowser(_createBrowserOptions(browserType));
|
|
57
|
+
browsers.set(browserType, browserInstance);
|
|
58
|
+
}
|
|
59
|
+
return browserInstance;
|
|
60
|
+
}
|
|
61
|
+
async function newBrowserContext(browser, browserContextOptions = {}) {
|
|
62
|
+
return await browser.newContext();
|
|
63
|
+
}
|
|
64
|
+
async function newPage(browserContext, pageOptions = {}) {
|
|
65
|
+
return await browserContext.newPage();
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":";;;AAoDA,gCAoBC;AAED,8CAKC;AAED,0BAKC;AAtFD,qCAAmD;AAEnD,2CAAuD;AAEvD,IAAY,WAIX;AAJD,WAAY,WAAW;IACnB,oCAAqB,CAAA;IACrB,kCAAmB,CAAA;IACnB,gCAAiB,CAAA;AACrB,CAAC,EAJW,WAAW,2BAAX,WAAW,QAItB;AAWD,MAAM,QAAQ,GAA8B,IAAI,GAAG,EAAE,CAAC;AAEtD,SAAS,qBAAqB,CAAC,WAAwB;IACnD,OAAO;QACH,WAAW;QACX,cAAc,EAAE,gCAAuB;KAC1C,CAAC;AACN,CAAC;AAED,KAAK,UAAU,cAAc,CACzB,iBAAiC,EAAE;IAEnC,qCAAqC;IACrC,IAAI,eAAe,CAAC;IACpB,QAAQ,cAAc,CAAC,WAAW,EAAE,CAAC;QACjC,KAAK,WAAW,CAAC,OAAO;YACpB,eAAe,GAAG,oBAAO,CAAC;YAC1B,MAAM;QACV,KAAK,WAAW,CAAC,MAAM;YACnB,eAAe,GAAG,mBAAM,CAAC;YACzB,MAAM;QACV,KAAK,WAAW,CAAC,QAAQ,CAAC;QAC1B;YACI,eAAe,GAAG,qBAAQ,CAAC;YAC3B,MAAM;IACd,CAAC;IACD,OAAO,eAAe,CAAC,MAAM,CAAC;QAC1B,cAAc,EAAE,cAAc,CAAC,cAAc;QAC7C,YAAY,EAAE,KAAK;QACnB,aAAa,EAAE,KAAK;KACvB,CAAC,CAAC;AACP,CAAC;AAEM,KAAK,UAAU,UAAU,CAC5B,cAA2B,WAAW,CAAC,QAAQ;IAE/C,IAAI,eAAe,GAAwB,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACrE,IAAI,eAAe,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC;QACpD,IAAI,CAAC;YACD,MAAM,eAAe,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,GAAS,EAAE,GAAE,CAAC,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAChB,kDAAkD;QACtD,CAAC;QACD,oCAAoC;QACpC,eAAe,GAAG,SAAS,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,eAAe,EAAE,CAAC;QACnB,eAAe,GAAG,MAAM,cAAc,CAClC,qBAAqB,CAAC,WAAW,CAAC,CACrC,CAAC;QACF,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,eAAe,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,eAAe,CAAC;AAC3B,CAAC;AAEM,KAAK,UAAU,iBAAiB,CACnC,OAAgB,EAChB,wBAA+C,EAAE;IAEjD,OAAO,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;AACtC,CAAC;AAEM,KAAK,UAAU,OAAO,CACzB,cAA8B,EAC9B,cAA2B,EAAE;IAE7B,OAAO,MAAM,cAAc,CAAC,OAAO,EAAE,CAAC;AAC1C,CAAC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BROWSER_EXECUTABLE_PATH = exports.HTTP_REQUESTS_BUFFER_SIZE = exports.CONSOLE_MESSAGES_BUFFER_SIZE = exports.SESSION_CLOSE_ON_SOCKET_CLOSE = exports.SESSION_IDLE_CHECK_SECONDS = exports.SESSION_IDLE_SECONDS = exports.PORT = void 0;
|
|
4
|
+
exports.PORT = Number(process.env.PORT) || 3000;
|
|
5
|
+
exports.SESSION_IDLE_SECONDS = Number(process.env.SESSION_IDLE_SECONDS) || 300;
|
|
6
|
+
exports.SESSION_IDLE_CHECK_SECONDS = Number(process.env.SESSION_IDLE_CHECK_SECONDS) || 30;
|
|
7
|
+
exports.SESSION_CLOSE_ON_SOCKET_CLOSE = process.env.SESSION_CLOSE_ON_SOCKET_CLOSE === 'true';
|
|
8
|
+
exports.CONSOLE_MESSAGES_BUFFER_SIZE = Number(process.env.CONSOLE_MESSAGES_BUFFER_SIZE) || 1_000;
|
|
9
|
+
exports.HTTP_REQUESTS_BUFFER_SIZE = Number(process.env.HTTP_REQUESTS_BUFFER_SIZE) || 1_000;
|
|
10
|
+
exports.BROWSER_EXECUTABLE_PATH = process.env.BROWSER_EXECUTABLE_PATH;
|
|
11
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";;;AAAa,QAAA,IAAI,GAAW,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AAChD,QAAA,oBAAoB,GAC7B,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,IAAI,GAAG,CAAC;AACvC,QAAA,0BAA0B,GACnC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,CAAC,IAAI,EAAE,CAAC;AAC5C,QAAA,6BAA6B,GACtC,OAAO,CAAC,GAAG,CAAC,6BAA6B,KAAK,MAAM,CAAC;AAC5C,QAAA,4BAA4B,GACrC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,KAAK,CAAC;AACjD,QAAA,yBAAyB,GAClC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,IAAI,KAAK,CAAC;AAC9C,QAAA,uBAAuB,GAChC,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.McpSessionContext = void 0;
|
|
37
|
+
const config_1 = require("./config");
|
|
38
|
+
const logger = __importStar(require("./logger"));
|
|
39
|
+
const types_1 = require("./types");
|
|
40
|
+
class McpSessionContext {
|
|
41
|
+
consoleMessages = [];
|
|
42
|
+
httpRequests = [];
|
|
43
|
+
sessionIdProvider;
|
|
44
|
+
closed = false;
|
|
45
|
+
browser;
|
|
46
|
+
browserContext;
|
|
47
|
+
page;
|
|
48
|
+
constructor(sessionIdProvider, browser, browserContext, page) {
|
|
49
|
+
this.sessionIdProvider = sessionIdProvider;
|
|
50
|
+
this.browser = browser;
|
|
51
|
+
this.browserContext = browserContext;
|
|
52
|
+
this.page = page;
|
|
53
|
+
this._init();
|
|
54
|
+
}
|
|
55
|
+
_init() {
|
|
56
|
+
const me = this;
|
|
57
|
+
let consoleMessageSequenceNumber = 0;
|
|
58
|
+
this.page.on('console', (msg) => {
|
|
59
|
+
me.consoleMessages.push(me._toConsoleMessage(msg, ++consoleMessageSequenceNumber));
|
|
60
|
+
if (me.consoleMessages.length > config_1.CONSOLE_MESSAGES_BUFFER_SIZE) {
|
|
61
|
+
me.consoleMessages.splice(0, me.consoleMessages.length - config_1.CONSOLE_MESSAGES_BUFFER_SIZE);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
this.page.on('pageerror', (err) => {
|
|
65
|
+
me.consoleMessages.push(me._errorToConsoleMessage(err, ++consoleMessageSequenceNumber));
|
|
66
|
+
if (me.consoleMessages.length > config_1.CONSOLE_MESSAGES_BUFFER_SIZE) {
|
|
67
|
+
me.consoleMessages.splice(0, me.consoleMessages.length - config_1.CONSOLE_MESSAGES_BUFFER_SIZE);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
let httpRequestSequenceNumber = 0;
|
|
71
|
+
this.page.on('requestfinished', async (req) => {
|
|
72
|
+
me.httpRequests.push(await me._toHttpRequest(req, ++httpRequestSequenceNumber));
|
|
73
|
+
if (me.httpRequests.length > config_1.HTTP_REQUESTS_BUFFER_SIZE) {
|
|
74
|
+
me.httpRequests.splice(0, me.httpRequests.length - config_1.HTTP_REQUESTS_BUFFER_SIZE);
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
this.page.on('requestfailed', async (req) => {
|
|
78
|
+
me.httpRequests.push(await me._toHttpRequest(req, ++httpRequestSequenceNumber));
|
|
79
|
+
if (me.httpRequests.length > config_1.HTTP_REQUESTS_BUFFER_SIZE) {
|
|
80
|
+
me.httpRequests.splice(0, me.httpRequests.length - config_1.HTTP_REQUESTS_BUFFER_SIZE);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
_toConsoleMessageLevelName(type) {
|
|
85
|
+
switch (type) {
|
|
86
|
+
case 'assert':
|
|
87
|
+
case 'error':
|
|
88
|
+
return types_1.ConsoleMessageLevelName.ERROR;
|
|
89
|
+
case 'warning':
|
|
90
|
+
return types_1.ConsoleMessageLevelName.WARNING;
|
|
91
|
+
case 'count':
|
|
92
|
+
case 'dir':
|
|
93
|
+
case 'dirxml':
|
|
94
|
+
case 'info':
|
|
95
|
+
case 'log':
|
|
96
|
+
case 'table':
|
|
97
|
+
case 'time':
|
|
98
|
+
case 'timeEnd':
|
|
99
|
+
return types_1.ConsoleMessageLevelName.INFO;
|
|
100
|
+
case 'clear':
|
|
101
|
+
case 'debug':
|
|
102
|
+
case 'endGroup':
|
|
103
|
+
case 'profile':
|
|
104
|
+
case 'profileEnd':
|
|
105
|
+
case 'startGroup':
|
|
106
|
+
case 'startGroupCollapsed':
|
|
107
|
+
case 'trace':
|
|
108
|
+
return types_1.ConsoleMessageLevelName.DEBUG;
|
|
109
|
+
default:
|
|
110
|
+
return types_1.ConsoleMessageLevelName.INFO;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
_toConsoleMessage(message, sequenceNumber) {
|
|
114
|
+
const timestamp = Date.now();
|
|
115
|
+
const levelName = this._toConsoleMessageLevelName(message.type());
|
|
116
|
+
const levelCode = types_1.ConsoleMessageLevel[levelName].code;
|
|
117
|
+
return {
|
|
118
|
+
type: message.type(),
|
|
119
|
+
text: message.text(),
|
|
120
|
+
level: {
|
|
121
|
+
name: levelName,
|
|
122
|
+
code: levelCode,
|
|
123
|
+
},
|
|
124
|
+
location: {
|
|
125
|
+
url: message.location().url,
|
|
126
|
+
lineNumber: message.location().lineNumber,
|
|
127
|
+
columnNumber: message.location().columnNumber,
|
|
128
|
+
},
|
|
129
|
+
timestamp,
|
|
130
|
+
sequenceNumber,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
_errorToConsoleMessage(error, sequenceNumber) {
|
|
134
|
+
const timestamp = Date.now();
|
|
135
|
+
if (error instanceof Error) {
|
|
136
|
+
return {
|
|
137
|
+
type: 'error',
|
|
138
|
+
text: error.message,
|
|
139
|
+
level: {
|
|
140
|
+
name: types_1.ConsoleMessageLevelName.ERROR,
|
|
141
|
+
code: types_1.ConsoleMessageLevelCode.ERROR,
|
|
142
|
+
},
|
|
143
|
+
timestamp,
|
|
144
|
+
sequenceNumber,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
type: 'error',
|
|
149
|
+
text: String(error),
|
|
150
|
+
level: {
|
|
151
|
+
name: types_1.ConsoleMessageLevelName.ERROR,
|
|
152
|
+
code: types_1.ConsoleMessageLevelCode.ERROR,
|
|
153
|
+
},
|
|
154
|
+
timestamp,
|
|
155
|
+
sequenceNumber,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
async _toHttpRequest(req, sequenceNumber) {
|
|
159
|
+
const res = await req.response();
|
|
160
|
+
return {
|
|
161
|
+
url: req.url(),
|
|
162
|
+
method: req.method(),
|
|
163
|
+
headers: req.headers(),
|
|
164
|
+
body: req.postData() || undefined,
|
|
165
|
+
resourceType: req.resourceType(),
|
|
166
|
+
failure: req.failure()?.errorText,
|
|
167
|
+
duration: req.timing().responseEnd,
|
|
168
|
+
response: res
|
|
169
|
+
? {
|
|
170
|
+
status: res.status(),
|
|
171
|
+
statusText: res.statusText(),
|
|
172
|
+
headers: res.headers(),
|
|
173
|
+
body: (await res.body()).toString(),
|
|
174
|
+
}
|
|
175
|
+
: undefined,
|
|
176
|
+
ok: res ? res.ok() : false,
|
|
177
|
+
timestamp: Math.floor(req.timing().startTime),
|
|
178
|
+
sequenceNumber,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
sessionId() {
|
|
182
|
+
return this.sessionIdProvider();
|
|
183
|
+
}
|
|
184
|
+
getConsoleMessages() {
|
|
185
|
+
return this.consoleMessages;
|
|
186
|
+
}
|
|
187
|
+
getHttpRequests() {
|
|
188
|
+
return this.httpRequests;
|
|
189
|
+
}
|
|
190
|
+
async close() {
|
|
191
|
+
if (this.closed) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
// Page(s) owned by browser context are already closed by the browser context itself
|
|
195
|
+
try {
|
|
196
|
+
logger.debug(`Closing browser context of the MCP session with id ${this.sessionIdProvider()} ...`);
|
|
197
|
+
await this.browserContext.close();
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
logger.debug(`Error occurred while closing browser context of the MCP session with id ${this.sessionIdProvider()} ...`, err);
|
|
201
|
+
}
|
|
202
|
+
this.consoleMessages.length = 0;
|
|
203
|
+
this.httpRequests.length = 0;
|
|
204
|
+
// We are not closing browser here as it is shared between sessions, so it should be closed on MCP server close/shutdown
|
|
205
|
+
this.closed = true;
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
exports.McpSessionContext = McpSessionContext;
|
|
210
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
36
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
37
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
38
|
+
};
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
const config = __importStar(require("./config"));
|
|
41
|
+
const logger = __importStar(require("./logger"));
|
|
42
|
+
const server_1 = require("./server");
|
|
43
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
44
|
+
const mcp_1 = require("@hono/mcp");
|
|
45
|
+
const node_server_1 = require("@hono/node-server");
|
|
46
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
47
|
+
const commander_1 = require("commander");
|
|
48
|
+
const hono_1 = require("hono");
|
|
49
|
+
const cors_1 = require("hono/cors");
|
|
50
|
+
const MCP_TEMPLATE = {
|
|
51
|
+
jsonrpc: '2.0',
|
|
52
|
+
error: {
|
|
53
|
+
code: 0,
|
|
54
|
+
message: 'N/A',
|
|
55
|
+
},
|
|
56
|
+
id: null,
|
|
57
|
+
};
|
|
58
|
+
const MCP_ERRORS = {
|
|
59
|
+
get sessionNotFound() {
|
|
60
|
+
return _buildMCPErrorResponse(-32001, 'Session Not Found');
|
|
61
|
+
},
|
|
62
|
+
get unauthorized() {
|
|
63
|
+
return _buildMCPErrorResponse(-32001, 'Unauthorized');
|
|
64
|
+
},
|
|
65
|
+
get internalServerError() {
|
|
66
|
+
return _buildMCPErrorResponse(-32603, 'Internal Server Error');
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
const sessions = new Map();
|
|
70
|
+
function _buildMCPErrorResponse(code, message) {
|
|
71
|
+
const result = { ...MCP_TEMPLATE };
|
|
72
|
+
result.error.code = code;
|
|
73
|
+
result.error.message = message;
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
function _parsePort(value) {
|
|
77
|
+
const n = Number(value);
|
|
78
|
+
if (!Number.isInteger(n) || n < 1 || n > 65535) {
|
|
79
|
+
throw new commander_1.InvalidOptionArgumentError('port must be an integer between 1 and 65535');
|
|
80
|
+
}
|
|
81
|
+
return n;
|
|
82
|
+
}
|
|
83
|
+
function _getOptions() {
|
|
84
|
+
const program = new commander_1.Command()
|
|
85
|
+
.addOption(new commander_1.Option('--transport <type>', 'transport type')
|
|
86
|
+
.choices(['stdio', 'streamable-http'])
|
|
87
|
+
.default('stdio'))
|
|
88
|
+
.addOption(new commander_1.Option('--port <number>', 'port for Streamable HTTP transport')
|
|
89
|
+
.argParser(_parsePort)
|
|
90
|
+
.default(config.PORT))
|
|
91
|
+
.allowUnknownOption()
|
|
92
|
+
.parse(process.argv);
|
|
93
|
+
return program.opts();
|
|
94
|
+
}
|
|
95
|
+
function _getConfig() {
|
|
96
|
+
return {};
|
|
97
|
+
}
|
|
98
|
+
async function _startStdioServer() {
|
|
99
|
+
await (0, server_1.createSession)(_getConfig(), new stdio_js_1.StdioServerTransport());
|
|
100
|
+
}
|
|
101
|
+
async function _createMCPServerSession(ctx) {
|
|
102
|
+
let session;
|
|
103
|
+
// Get MCP server config
|
|
104
|
+
const serverConfig = _getConfig();
|
|
105
|
+
// Create new instances of MCP Server and Transport for each incoming request
|
|
106
|
+
const transport = new mcp_1.StreamableHTTPTransport({
|
|
107
|
+
// Change to `false` if you want to enable SSE in responses.
|
|
108
|
+
enableJsonResponse: true,
|
|
109
|
+
sessionIdGenerator: () => crypto_1.default.randomUUID(),
|
|
110
|
+
onsessioninitialized: async (sessionId) => {
|
|
111
|
+
sessions.set(sessionId, session);
|
|
112
|
+
session.initialized = true;
|
|
113
|
+
logger.debug(`MCP session initialized with id ${sessionId}`);
|
|
114
|
+
},
|
|
115
|
+
onsessionclosed: async (sessionId) => {
|
|
116
|
+
logger.debug(`Closing MCP session closed with id ${sessionId} ...`);
|
|
117
|
+
await transport.close();
|
|
118
|
+
logger.debug(`MCP session closed with id ${sessionId}`);
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
// Create MCP session with MCP server
|
|
122
|
+
session = await (0, server_1.createSession)(serverConfig, transport);
|
|
123
|
+
// Register hook to close the associated MCP session on socket close
|
|
124
|
+
const socket = ctx.env.incoming.socket;
|
|
125
|
+
if (!socket._mcpRegistered) {
|
|
126
|
+
socket._mcpRegistered = true;
|
|
127
|
+
socket.on('close', async () => {
|
|
128
|
+
logger.debug(`Socket, which is for MCP session with id ${transport.sessionId}, has been closed`);
|
|
129
|
+
if (config.SESSION_CLOSE_ON_SOCKET_CLOSE) {
|
|
130
|
+
await transport.close();
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
// Register MCP session close hook to gracefully close it
|
|
135
|
+
_registerMCPSessionClose(transport, session.server);
|
|
136
|
+
logger.debug(`Created MCP server session with id ${transport.sessionId}`);
|
|
137
|
+
return session;
|
|
138
|
+
}
|
|
139
|
+
async function _getMCPServerSession(sessionId) {
|
|
140
|
+
return sessions.get(sessionId);
|
|
141
|
+
}
|
|
142
|
+
async function _getOrCreateMCPServerSession(ctx) {
|
|
143
|
+
const sessionId = ctx.req.header('mcp-session-id');
|
|
144
|
+
if (sessionId) {
|
|
145
|
+
const session = sessions.get(sessionId);
|
|
146
|
+
if (session) {
|
|
147
|
+
logger.debug(`Reusing MCP session with id ${sessionId}`);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
logger.debug(`No MCP session could be found with id ${sessionId}`);
|
|
151
|
+
}
|
|
152
|
+
return session;
|
|
153
|
+
}
|
|
154
|
+
return await _createMCPServerSession(ctx);
|
|
155
|
+
}
|
|
156
|
+
function _registerMCPSessionClose(transport, mcpServer) {
|
|
157
|
+
let closed = false;
|
|
158
|
+
transport.onclose = async () => {
|
|
159
|
+
logger.debug(`Closing MCP session with id ${transport.sessionId} ...`);
|
|
160
|
+
if (closed) {
|
|
161
|
+
logger.debug(`MCP session with id ${transport.sessionId} has already been closed`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
closed = true;
|
|
165
|
+
try {
|
|
166
|
+
await mcpServer.close();
|
|
167
|
+
logger.debug('Closed MCP server');
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
logger.error('Error occurred while closing MCP server', err);
|
|
171
|
+
}
|
|
172
|
+
if (transport.sessionId) {
|
|
173
|
+
const session = sessions.get(transport.sessionId);
|
|
174
|
+
if (session) {
|
|
175
|
+
session.closed = true;
|
|
176
|
+
try {
|
|
177
|
+
await session.context.close();
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
logger.error('Error occurred while closing MCP session context', err);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
sessions.delete(transport.sessionId);
|
|
184
|
+
}
|
|
185
|
+
logger.debug(`Closing MCP session with id ${transport.sessionId} ...`);
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function _scheduleIdleSessionCheck() {
|
|
189
|
+
const sessionCheck = () => {
|
|
190
|
+
const currentTime = Date.now();
|
|
191
|
+
for (const [sessionId, session] of sessions) {
|
|
192
|
+
logger.debug(`Checking whether session with id ${sessionId} is idle or not ...`);
|
|
193
|
+
if (currentTime - session.lastActiveAt >
|
|
194
|
+
config.SESSION_IDLE_SECONDS * 1000) {
|
|
195
|
+
logger.debug(`Session with id ${sessionId} is idle, so it will be closing ...`);
|
|
196
|
+
session.transport
|
|
197
|
+
.close()
|
|
198
|
+
.then(() => {
|
|
199
|
+
logger.debug(`Session with id ${sessionId} was idle, so it has been closed`);
|
|
200
|
+
})
|
|
201
|
+
.catch((err) => {
|
|
202
|
+
logger.error(`Unable to delete idle session with id ${sessionId}`, err);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
setInterval(sessionCheck, config.SESSION_IDLE_CHECK_SECONDS * 1000);
|
|
208
|
+
}
|
|
209
|
+
const app = new hono_1.Hono();
|
|
210
|
+
async function _startStreamableHTTPServer(port) {
|
|
211
|
+
// Global CORS
|
|
212
|
+
app.use('*', (0, cors_1.cors)({
|
|
213
|
+
origin: '*',
|
|
214
|
+
allowMethods: ['GET', 'POST', 'OPTIONS'],
|
|
215
|
+
allowHeaders: [
|
|
216
|
+
'Content-Type',
|
|
217
|
+
'Authorization',
|
|
218
|
+
'MCP-Protocol-Version',
|
|
219
|
+
],
|
|
220
|
+
}));
|
|
221
|
+
// MCP Health
|
|
222
|
+
app.get('/health', (ctx) => ctx.json({ status: 'ok' }));
|
|
223
|
+
// MCP Ping
|
|
224
|
+
app.get('/ping', (ctx) => ctx.json({ status: 'ok', message: 'pong' }));
|
|
225
|
+
// MCP Get info
|
|
226
|
+
app.get('/mcp', (ctx) => ctx.json({
|
|
227
|
+
status: 'ok',
|
|
228
|
+
protocol: 'model-context-protocol',
|
|
229
|
+
version: '1.0',
|
|
230
|
+
}));
|
|
231
|
+
// MCP Post message
|
|
232
|
+
app.post('/mcp', async (ctx) => {
|
|
233
|
+
try {
|
|
234
|
+
const mcpSession = await _getOrCreateMCPServerSession(ctx);
|
|
235
|
+
if (!mcpSession) {
|
|
236
|
+
return ctx.json(MCP_ERRORS.sessionNotFound, 400);
|
|
237
|
+
}
|
|
238
|
+
mcpSession.lastActiveAt = Date.now();
|
|
239
|
+
return await mcpSession.transport.handleRequest(ctx);
|
|
240
|
+
}
|
|
241
|
+
catch (err) {
|
|
242
|
+
logger.error('Error occurred while handling MCP request', err);
|
|
243
|
+
return ctx.json(MCP_ERRORS.internalServerError, 500);
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
// MCP Delete session
|
|
247
|
+
app.delete('/mcp', async (ctx) => {
|
|
248
|
+
try {
|
|
249
|
+
const sessionId = ctx.req.header('mcp-session-id');
|
|
250
|
+
if (!sessionId) {
|
|
251
|
+
return ctx.json(MCP_ERRORS.sessionNotFound, 400);
|
|
252
|
+
}
|
|
253
|
+
const mcpSession = await _getMCPServerSession(sessionId);
|
|
254
|
+
if (!mcpSession) {
|
|
255
|
+
return ctx.json(MCP_ERRORS.sessionNotFound, 400);
|
|
256
|
+
}
|
|
257
|
+
await mcpSession.transport.close();
|
|
258
|
+
return ctx.json({ ok: true }, 200);
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
logger.error('Error occurred while deleting MCP session', err);
|
|
262
|
+
return ctx.json(MCP_ERRORS.internalServerError, 500);
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
// 404
|
|
266
|
+
app.notFound((ctx) => ctx.json({ error: 'Not Found', status: 404 }, 404));
|
|
267
|
+
// Listener for Node
|
|
268
|
+
(0, node_server_1.serve)({
|
|
269
|
+
fetch: app.fetch,
|
|
270
|
+
port,
|
|
271
|
+
}, () => logger.info(`Listening on port ${port}`));
|
|
272
|
+
// Schedule background task to check (and remove) idle sessions
|
|
273
|
+
_scheduleIdleSessionCheck();
|
|
274
|
+
}
|
|
275
|
+
async function main() {
|
|
276
|
+
const options = _getOptions();
|
|
277
|
+
if (options.transport === 'stdio') {
|
|
278
|
+
logger.disable();
|
|
279
|
+
await _startStdioServer();
|
|
280
|
+
}
|
|
281
|
+
else if (options.transport === 'streamable-http') {
|
|
282
|
+
logger.info('Starting MCP server...');
|
|
283
|
+
await _startStreamableHTTPServer(options.port);
|
|
284
|
+
logger.info('Started MCP Server');
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
logger.error(`Invalid transport: ${options.transport}`);
|
|
288
|
+
process.exit(1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
main().catch((err) => {
|
|
292
|
+
logger.enable();
|
|
293
|
+
logger.error('MCP server error', err);
|
|
294
|
+
process.exit(1);
|
|
295
|
+
});
|
|
296
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|