marble-headed-mcp 0.1.40 → 0.1.42
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/dist/index.js +35 -48
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -125,22 +125,25 @@ async function readCodexThreadIdFromLog(filePath) {
|
|
|
125
125
|
return null;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
function
|
|
129
|
-
if (selectedEnvironment) {
|
|
130
|
-
return normalizeBaseUrl(ENVIRONMENT_BASE_URLS[selectedEnvironment]);
|
|
131
|
-
}
|
|
128
|
+
function resolveHeadedServerRawBaseUrl() {
|
|
132
129
|
const base = process.env.HEADED_SERVER_BASE_URL || DEFAULT_BASE_URL;
|
|
133
130
|
return normalizeBaseUrl(base);
|
|
134
131
|
}
|
|
135
|
-
function
|
|
136
|
-
const raw =
|
|
132
|
+
function resolveHeadedServerAppBaseUrl() {
|
|
133
|
+
const raw = resolveHeadedServerRawBaseUrl();
|
|
137
134
|
return raw.replace(/\/api\/headed\/?$/, '');
|
|
138
135
|
}
|
|
136
|
+
function resolveBrowserAppBaseUrl() {
|
|
137
|
+
if (selectedEnvironment) {
|
|
138
|
+
return normalizeBaseUrl(ENVIRONMENT_BASE_URLS[selectedEnvironment]);
|
|
139
|
+
}
|
|
140
|
+
return normalizeBaseUrl(ENVIRONMENT_BASE_URLS.localhost);
|
|
141
|
+
}
|
|
139
142
|
function buildUrl(pathname) {
|
|
140
|
-
return `${
|
|
143
|
+
return `${resolveHeadedServerAppBaseUrl()}${pathname}`;
|
|
141
144
|
}
|
|
142
145
|
function buildHeadedUrl(pathname) {
|
|
143
|
-
return `${
|
|
146
|
+
return `${resolveHeadedServerAppBaseUrl()}/api/headed${pathname}`;
|
|
144
147
|
}
|
|
145
148
|
async function postJson(pathname, payload) {
|
|
146
149
|
const response = await fetch(buildUrl(pathname), {
|
|
@@ -184,6 +187,16 @@ async function getHeadedText(pathname) {
|
|
|
184
187
|
const text = await response.text();
|
|
185
188
|
return { status: response.status, ok: response.ok, text };
|
|
186
189
|
}
|
|
190
|
+
function withBrowserAppBaseUrl(payload) {
|
|
191
|
+
const appBaseUrl = resolveBrowserAppBaseUrl();
|
|
192
|
+
if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
|
|
193
|
+
return {
|
|
194
|
+
...payload,
|
|
195
|
+
appBaseUrl,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
return { appBaseUrl };
|
|
199
|
+
}
|
|
187
200
|
async function getJson(pathname) {
|
|
188
201
|
const response = await fetch(buildUrl(pathname));
|
|
189
202
|
const text = await response.text();
|
|
@@ -418,7 +431,7 @@ async function saveImageFromUrl({ url, filename }) {
|
|
|
418
431
|
const TOOLS = [
|
|
419
432
|
{
|
|
420
433
|
name: 'set_environment',
|
|
421
|
-
description: 'Set the
|
|
434
|
+
description: 'Set the in-browser app environment used by headed session actions. localhost -> http://localhost:3000, dev -> https://dev.withmarble.ai, production -> https://withmarble.ai. API calls still go to HEADED_SERVER_BASE_URL (default localhost:3000).',
|
|
422
435
|
inputSchema: {
|
|
423
436
|
type: 'object',
|
|
424
437
|
properties: {
|
|
@@ -469,20 +482,6 @@ const TOOLS = [
|
|
|
469
482
|
additionalProperties: false,
|
|
470
483
|
},
|
|
471
484
|
},
|
|
472
|
-
{
|
|
473
|
-
name: 'navigate_to_url',
|
|
474
|
-
description: 'Navigate a headed session to a URL. Prefer `headed_navigate_to_project` when possible; use this only for validating code in a separate browser tab (e.g., proxy URL access). If the URL already exists (ignoring query parameters), the existing tab will be focused instead of creating a new one.',
|
|
475
|
-
inputSchema: {
|
|
476
|
-
type: 'object',
|
|
477
|
-
properties: {
|
|
478
|
-
browserSession: { type: 'number', description: 'Headed browser session id.' },
|
|
479
|
-
browserSessionId: { type: 'number', description: 'Alias for browserSession.' },
|
|
480
|
-
url: { type: 'string', description: 'URL to navigate to.' },
|
|
481
|
-
},
|
|
482
|
-
required: ['url'],
|
|
483
|
-
additionalProperties: false,
|
|
484
|
-
},
|
|
485
|
-
},
|
|
486
485
|
{
|
|
487
486
|
name: 'start_plan_project',
|
|
488
487
|
description: 'Navigate to a project within a plan. If startProject is true (default), clicks BEGIN SIMULATION; if false, only navigates to the plan project without starting the simulation.',
|
|
@@ -766,7 +765,8 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
766
765
|
};
|
|
767
766
|
}
|
|
768
767
|
selectedEnvironment = environment;
|
|
769
|
-
const
|
|
768
|
+
const browserAppBaseUrl = resolveBrowserAppBaseUrl();
|
|
769
|
+
const headedServerAppBaseUrl = resolveHeadedServerAppBaseUrl();
|
|
770
770
|
return {
|
|
771
771
|
content: [
|
|
772
772
|
{
|
|
@@ -774,45 +774,32 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
774
774
|
text: JSON.stringify({
|
|
775
775
|
ok: true,
|
|
776
776
|
environment,
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
777
|
+
browserAppBaseUrl,
|
|
778
|
+
headedServerAppBaseUrl,
|
|
779
|
+
headedServerHeadedApiBaseUrl: `${headedServerAppBaseUrl}/api/headed`,
|
|
780
780
|
}, null, 2),
|
|
781
781
|
},
|
|
782
782
|
],
|
|
783
783
|
};
|
|
784
784
|
}
|
|
785
785
|
case 'headed_start_session': {
|
|
786
|
-
const result = await postHeadedJson('/start_session', args);
|
|
786
|
+
const result = await postHeadedJson('/start_session', withBrowserAppBaseUrl(args));
|
|
787
787
|
return { content: [{ type: 'text', text: JSON.stringify(result.json || { status: result.status, body: result.text }, null, 2) }] };
|
|
788
788
|
}
|
|
789
789
|
case 'headed_end_session': {
|
|
790
|
-
const result = await postHeadedJson('/end_session', args);
|
|
790
|
+
const result = await postHeadedJson('/end_session', withBrowserAppBaseUrl(args));
|
|
791
791
|
return { content: [{ type: 'text', text: JSON.stringify(result.json || { status: result.status, body: result.text }, null, 2) }] };
|
|
792
792
|
}
|
|
793
793
|
case 'headed_navigate_to_project': {
|
|
794
|
-
const result = await postHeadedJson('/navigate_to_project', args);
|
|
795
|
-
return { content: [{ type: 'text', text: JSON.stringify(result.json || { status: result.status, body: result.text }, null, 2) }] };
|
|
796
|
-
}
|
|
797
|
-
case 'navigate_to_url': {
|
|
798
|
-
const url = typeof args?.url === 'string' ? args.url.trim() : '';
|
|
799
|
-
const browserSessionRaw = args?.browserSession ?? args?.browserSessionId;
|
|
800
|
-
const browserSessionId = typeof browserSessionRaw === 'number' ? browserSessionRaw : Number(browserSessionRaw);
|
|
801
|
-
if (!url) {
|
|
802
|
-
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: 'url is required.' }, null, 2) }] };
|
|
803
|
-
}
|
|
804
|
-
if (!browserSessionId || Number.isNaN(browserSessionId)) {
|
|
805
|
-
return { content: [{ type: 'text', text: JSON.stringify({ ok: false, error: 'browserSession is required.' }, null, 2) }] };
|
|
806
|
-
}
|
|
807
|
-
const result = await postHeadedJson('/navigate_to_url', { browserSessionId, url });
|
|
794
|
+
const result = await postHeadedJson('/navigate_to_project', withBrowserAppBaseUrl(args));
|
|
808
795
|
return { content: [{ type: 'text', text: JSON.stringify(result.json || { status: result.status, body: result.text }, null, 2) }] };
|
|
809
796
|
}
|
|
810
797
|
case 'start_plan_project': {
|
|
811
|
-
const result = await postHeadedJson('/start_plan_project', args);
|
|
798
|
+
const result = await postHeadedJson('/start_plan_project', withBrowserAppBaseUrl(args));
|
|
812
799
|
return { content: [{ type: 'text', text: JSON.stringify(result.json || { status: result.status, body: result.text }, null, 2) }] };
|
|
813
800
|
}
|
|
814
801
|
case 'headed_send_msg': {
|
|
815
|
-
const result = await postHeadedJson('/send_msg_headed', args);
|
|
802
|
+
const result = await postHeadedJson('/send_msg_headed', withBrowserAppBaseUrl(args));
|
|
816
803
|
const payload = (result.json && typeof result.json === 'object') ? result.json : null;
|
|
817
804
|
if (payload?.workflowRunId) {
|
|
818
805
|
const summaryResult = await fetchWorkflowEntries(String(payload.workflowRunId));
|
|
@@ -827,7 +814,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
827
814
|
return { content: [{ type: 'text', text: JSON.stringify(payload || { status: result.status, body: result.text }, null, 2) }] };
|
|
828
815
|
}
|
|
829
816
|
case 'take_screenshot': {
|
|
830
|
-
const result = await postHeadedJson('/take_screenshot', args);
|
|
817
|
+
const result = await postHeadedJson('/take_screenshot', withBrowserAppBaseUrl(args));
|
|
831
818
|
const payload = (result.json && typeof result.json === 'object') ? result.json : null;
|
|
832
819
|
if (payload?.workflowRunId) {
|
|
833
820
|
const summaryResult = await fetchWorkflowEntries(String(payload.workflowRunId));
|
|
@@ -842,14 +829,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
842
829
|
return { content: [{ type: 'text', text: JSON.stringify(payload || { status: result.status, body: result.text }, null, 2) }] };
|
|
843
830
|
}
|
|
844
831
|
case 'take_screenshot': {
|
|
845
|
-
const result = await postHeadedJson('/take_screenshot', args);
|
|
832
|
+
const result = await postHeadedJson('/take_screenshot', withBrowserAppBaseUrl(args));
|
|
846
833
|
return { content: [{ type: 'text', text: JSON.stringify(result.json || { status: result.status, body: result.text }, null, 2) }] };
|
|
847
834
|
}
|
|
848
835
|
case 'screenshots_preview': {
|
|
849
836
|
const payload = args?.screenshotUrls
|
|
850
837
|
? { screenshotUrls: args.screenshotUrls }
|
|
851
838
|
: args?.response || args;
|
|
852
|
-
const result = await postHeadedJson('/preview_screenshots', payload);
|
|
839
|
+
const result = await postHeadedJson('/preview_screenshots', withBrowserAppBaseUrl(payload));
|
|
853
840
|
return { content: [{ type: 'text', text: JSON.stringify({ status: result.status, ok: result.ok, html: result.text }, null, 2) }] };
|
|
854
841
|
}
|
|
855
842
|
case 'screenshots_get_preview': {
|