Skip to content

Commit 1bc0f3e

Browse files
chore: mcp code tool explicit error message when missing a run function
1 parent ee2d35b commit 1bc0f3e

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

packages/mcp-server/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"express": "^5.1.0",
4040
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz",
4141
"qs": "^6.14.0",
42+
"typescript": "5.8.3",
4243
"yargs": "^17.7.2",
4344
"zod": "^3.25.20",
4445
"zod-to-json-schema": "^3.24.5",
@@ -65,8 +66,7 @@
6566
"ts-morph": "^19.0.0",
6667
"ts-node": "^10.5.0",
6768
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz",
68-
"tsconfig-paths": "^4.0.0",
69-
"typescript": "5.8.3"
69+
"tsconfig-paths": "^4.0.0"
7070
},
7171
"imports": {
7272
"@beeper/desktop-mcp": ".",

packages/mcp-server/src/code-tool-worker.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,58 @@
11
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
22

33
import util from 'node:util';
4+
5+
import ts from 'typescript';
6+
47
import { WorkerInput, WorkerSuccess, WorkerError } from './code-tool-types';
58
import { BeeperDesktop } from '@beeper/desktop-api';
69

10+
function getRunFunctionNode(
11+
code: string,
12+
): ts.FunctionDeclaration | ts.FunctionExpression | ts.ArrowFunction | null {
13+
const sourceFile = ts.createSourceFile('code.ts', code, ts.ScriptTarget.Latest, true);
14+
15+
for (const statement of sourceFile.statements) {
16+
// Check for top-level function declarations
17+
if (ts.isFunctionDeclaration(statement)) {
18+
if (statement.name?.text === 'run') {
19+
return statement;
20+
}
21+
}
22+
23+
// Check for variable declarations: const run = () => {} or const run = function() {}
24+
if (ts.isVariableStatement(statement)) {
25+
for (const declaration of statement.declarationList.declarations) {
26+
if (ts.isIdentifier(declaration.name) && declaration.name.text === 'run') {
27+
// Check if it's initialized with a function
28+
if (
29+
declaration.initializer &&
30+
(ts.isFunctionExpression(declaration.initializer) || ts.isArrowFunction(declaration.initializer))
31+
) {
32+
return declaration.initializer;
33+
}
34+
}
35+
}
36+
}
37+
}
38+
39+
return null;
40+
}
41+
742
const fetch = async (req: Request): Promise<Response> => {
843
const { opts, code } = (await req.json()) as WorkerInput;
44+
45+
const runFunctionNode = getRunFunctionNode(code);
46+
if (!runFunctionNode) {
47+
return Response.json(
48+
{
49+
message:
50+
'The code is missing a top-level `run` function. Write code within this template:\n\n```\nasync function run(client) {\n // Fill this out\n}\n```',
51+
} satisfies WorkerError,
52+
{ status: 400, statusText: 'Code execution error' },
53+
);
54+
}
55+
956
const client = new BeeperDesktop({
1057
...opts,
1158
});

0 commit comments

Comments
 (0)