Skip to content

Commit c1688e1

Browse files
chore: mcp code tool explicit error message when missing a run function
1 parent 0b9eb86 commit c1688e1

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
@@ -38,6 +38,7 @@
3838
"express": "^5.1.0",
3939
"jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz",
4040
"qs": "^6.14.0",
41+
"typescript": "5.8.3",
4142
"yargs": "^17.7.2",
4243
"zod": "^3.25.20",
4344
"zod-to-json-schema": "^3.24.5",
@@ -64,8 +65,7 @@
6465
"ts-morph": "^19.0.0",
6566
"ts-node": "^10.5.0",
6667
"tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz",
67-
"tsconfig-paths": "^4.0.0",
68-
"typescript": "5.8.3"
68+
"tsconfig-paths": "^4.0.0"
6969
},
7070
"imports": {
7171
"cas-parser-node-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 { CasParser } from 'cas-parser-node';
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 CasParser({
1057
...opts,
1158
});

0 commit comments

Comments
 (0)