JavaScript Code Execution - Troubleshooting
Common issues, error messages, and solutions for the code_execution tool.
Table of Contents
- Configuration Issues
- Syntax Errors
- Runtime Errors
- Timeout Issues
- Tool Call Errors
- Stored Script Errors
- Serialization Errors
- Performance Issues
- Debugging Tips
Configuration Issues
Error: "code_execution is disabled in configuration"
Symptom:
Error: code_execution is disabled in configuration. Set 'enable_code_execution: true' in config file.
Cause: The code_execution feature is switched off in this configuration ("enable_code_execution": false — it ships on by default since v0.66.0, but a config file written by an earlier release carries an explicit false). While it is disabled the tool is not listed in tools/list, so an MCP client will normally not see it at all; this error appears when a call reaches the handler by name anyway (the REST API or the CLI). An MCP client that calls the name from a stale tool list gets an unknown-tool error instead.
Solution:
- Edit your configuration file (
~/.mcpproxy/mcp_config.json) - Add or update:
"enable_code_execution": true - The flag is hot-reloaded: the running proxy picks up the change, advertises the tool, and sends
notifications/tools/list_changedto connected sessions. No restart is needed; clients that do not honorlist_changedneed to reconnect to see the tool.
Example Configuration:
{
"enable_code_execution": true,
"code_execution_timeout_ms": 120000,
"code_execution_max_tool_calls": 0,
"code_execution_pool_size": 10,
"code_execution_max_parallel": 8,
"mcpServers": [...]
}
Error: "code_execution tool not found in tools list"
Symptom: LLM agent lists available tools but code_execution is missing.
Cause: Feature is not enabled — a disabled code_execution is deliberately absent from tools/list — or the client is holding a tool list from before the flag was enabled.
Solution:
- Verify configuration has
"enable_code_execution": true - The change is hot-reloaded and announced with
notifications/tools/list_changed; if the client does not honor that notification, reconnect it - List tools again
Verification:
# Check if code_execution tool is registered
mcpproxy call tool --tool-name=retrieve_tools --json_args='{"query":"code execution"}'
Error: "timeout must be between 1 and 600000 milliseconds"
Symptom:
{
"ok": false,
"error": {
"message": "timeout_ms must be between 1 and 600000 milliseconds"
}
}
Cause: Invalid timeout_ms value in request options.
Solution: Use a timeout between 1ms and 600000ms (10 minutes):
{
"code": "...",
"options": {
"timeout_ms": 120000 // 2 minutes (valid)
}
}
Error: "code_execution_max_parallel: must be between 1 and 32"
Symptom: mcpproxy refuses to load the configuration file:
config validation failed: code_execution_max_parallel: must be between 1 and 32 (or 0 for default)
Cause: code_execution_max_parallel is outside the supported range.
Solution: Use a value between 1 and 32 (or omit the key / set 0 for the
default of 8):
{
"code_execution_max_parallel": 8
}
The same range applies to the per-batch override —
call_tools(requests, {max_parallel: 40}) returns a single INVALID_ARGS
envelope instead of dispatching.
Syntax Errors
Error: "SyntaxError: Unexpected token"
Symptom:
{
"ok": false,
"error": {
"code": "SYNTAX_ERROR",
"message": "SyntaxError: Unexpected token '{'",
"stack": ""
}
}
Common Causes:
- Missing closing brackets/braces
- Invalid JavaScript syntax
Solutions:
Problem: Missing brackets
// Bad
const x = { value: 1, missing: 2
// Good
const x = { value: 1, missing: 2 };
Problem: Incomplete expressions
// Bad
const msg = `Hello, ${
// Good
const msg = `Hello, ${name}!`;
Error: "SyntaxError: Unexpected end of input"
Symptom: Code execution fails with "end of input" error.
Cause: Incomplete JavaScript expression or statement.
Solution: Ensure all blocks are properly closed:
// Bad
var x = function() {
return 42;
// Missing closing brace
// Good
var x = function() {
return 42;
};
Runtime Errors
Error: "TypeError: Cannot read property 'X' of undefined/null"
Symptom:
{
"ok": false,
"error": {
"code": "RUNTIME_ERROR",
"message": "TypeError: Cannot read property 'name' of undefined",
"stack": "..."
}
}
Cause: Accessing properties on undefined or null values.
Solution: Always check values before accessing properties:
// Bad
var name = input.user.name; // Crashes if input.user is undefined
// Good
var name = input.user ? input.user.name : 'Unknown';
// Better
var name = 'Unknown';
if (input && input.user && input.user.name) {
name = input.user.name;
}
For Tool Calls:
// Bad
var user = call_tool('github', 'get_user', {username: input.username});
var name = user.result.name; // Crashes if user.ok is false
// Good
var user = call_tool('github', 'get_user', {username: input.username});
if (!user.ok) {
return {error: user.error.message};
}
var name = user.result.name;
Error: "ReferenceError: X is not defined"
Symptom:
{
"ok": false,
"error": {
"code": "RUNTIME_ERROR",
"message": "ReferenceError: myVariable is not defined",
"stack": "..."
}
}
Cause: Using variables or functions that don't exist.
Common Mistakes:
Problem: Undefined variables
// Bad
return result; // 'result' was never declared
// Good
var result = 42;
return result;
Problem: Using unavailable functions
// Bad
var data = require('fs').readFileSync('file.txt'); // require() not available
// Bad
setTimeout(function() { doWork(); }, 1000); // setTimeout() not available
// Good
var data = call_tool('filesystem', 'read_file', {path: 'file.txt'});
Error: "RangeError: Maximum call stack size exceeded"
Symptom: Execution fails with stack overflow.
Cause: Infinite recursion or very deep recursion.
Solution: Check for infinite loops or recursive calls:
// Bad
function factorial(n) {
return n * factorial(n - 1); // No base case!
}
// Good
function factorial(n) {
if (n <= 1) return 1; // Base case
return n * factorial(n - 1);
}
// Better (iterative)
function factorial(n) {
var result = 1;
for (var i = 2; i <= n; i++) {
result *= i;
}
return result;
}
Timeout Issues
Error: "JavaScript execution timed out"
Symptom:
{
"ok": false,
"error": {
"code": "TIMEOUT",
"message": "JavaScript execution timed out",
"stack": ""
}
}
Common Causes:
- Infinite loops
- Too many tool calls
- Slow upstream servers
- Heavy computation
Solutions:
Problem: Infinite loop
// Bad
while (true) {
// This will timeout
}
// Bad
for (var i = 0; i < 1000000000; i++) {
// This takes too long
}
// Good
for (var i = 0; i < input.items.length; i++) {
// Bounded loop
}
Problem: Insufficient timeout for workload
// Bad: Default 2-minute timeout for 100 tool calls
{
"code": "for(var i=0;i<100;i++){call_tool(...)}",
"options": {"timeout_ms": 120000} // Might not be enough
}
// Good: Increase timeout for heavy workloads
{
"code": "for(var i=0;i<100;i++){call_tool(...)}",
"options": {"timeout_ms": 300000} // 5 minutes
}
Problem: Slow upstream tools
// Solution: Reduce number of calls or increase timeout
{
"code": "...",
"options": {
"timeout_ms": 300000, // Increase timeout
"max_tool_calls": 50 // Limit calls to prevent runaway
}
}
Tool Call Errors
Error: "Exceeded maximum tool calls limit"
Symptom:
{
"ok": false,
"error": {
"code": "MAX_TOOL_CALLS_EXCEEDED",
"message": "Exceeded maximum tool calls limit (10)",
"stack": ""
}
}
Cause: Code called call_tool() more times than max_tool_calls allows.
Every element of a call_tools() batch counts as one call too, checked in input
order — tail elements over the limit come back as per-slot
MAX_TOOL_CALLS_EXCEEDED errors and are never dispatched.
Solution:
Option 1: Increase limit
{
"code": "for(var i=0;i<20;i++){call_tool(...)}",
"options": {"max_tool_calls": 25} // Set higher than needed
}
Option 2: Reduce tool calls
// Bad: Call tool for every item
for (var i = 0; i < 1000; i++) {
call_tool('api', 'process', {id: items[i]});
}
// Good: Batch items if tool supports it
var batchSize = 100;
for (var i = 0; i < items.length; i += batchSize) {
var batch = items.slice(i, i + batchSize);
call_tool('api', 'process_batch', {items: batch});
}
Error: "Server 'X' is not in the allowed servers list"
Symptom:
{
"ok": false,
"error": {
"code": "SERVER_NOT_ALLOWED",
"message": "Server 'gitlab' is not in the allowed servers list",
"stack": ""
}
}
Cause: Attempted to call a server not in allowed_servers option.
Solution:
Option 1: Add server to allowed list
{
"code": "call_tool('gitlab', 'get_user', {username: 'test'})",
"options": {
"allowed_servers": ["github", "gitlab"] // Add gitlab
}
}
Option 2: Remove restriction (allow all servers)
{
"code": "call_tool('gitlab', 'get_user', {username: 'test'})",
"options": {
"allowed_servers": [] // Empty array = all servers allowed
}
}
Error: "server not found: X"
Symptom: call_tool() returns error saying server doesn't exist.
Cause: Server name is incorrect or server is not configured.
Solution:
- Check server name: Verify spelling and case
// Bad
call_tool('GitHub', 'get_user', {}); // Wrong case
// Good
call_tool('github', 'get_user', {}); // Correct name
- List available servers:
mcpproxy call tool --tool-name=upstream_servers --json_args='{"operation":"list"}'
- Add server if missing:
mcpproxy call tool --tool-name=upstream_servers \
--json_args='{"operation":"add","name":"github","url":"https://api.github.com/mcp","protocol":"http","enabled":true}'
Error: "call_tools: element N: ..." (INVALID_ARGS)
Symptom: call_tools() returns a single envelope instead of an array of slots:
{
"ok": false,
"error": {
"code": "INVALID_ARGS",
"message": "call_tools: element 3: must be an object with server and tool"
}
}
Cause: The batch itself is malformed, so nothing was dispatched and no budget
was consumed. Triggers: requests is not an array, an element is not an object
with non-empty server/tool strings, a supplied args is not an object, the
array has a sparse hole, options is not an object, max_parallel is not an
integer in 1-32, or the batch exceeds 100 elements.
Solution: Fix the element the message names, then check the result shape before mapping over it:
var slots = call_tools(requests, {max_parallel: 8});
if (!Array.isArray(slots)) {
// whole batch rejected — slots is {ok:false, error:{...}}
({error: slots.error.message});
} else {
({results: slots});
}
For more than 100 items, chunk the array and issue one call_tools() per chunk.
Error: "upstream server X is busy: its concurrency limit (N) is saturated (queue_full)"
Symptom: A call_tools() batch returns one success and many failed slots
mentioning a concurrency limit:
[
{"ok": true, "result": {...}},
{"ok": false, "error": {
"code": "UPSTREAM_ERROR",
"message": "upstream server \"fragile-db\" is busy: its concurrency limit (1) is saturated (queue_full) — please retry shortly"
}}
]
Cause: The target server has a per-server concurrency limit
(max_concurrent_requests) with no queue_size. Batching never bypasses
those limits: calls over the cap are shed immediately, which is the server's
configured policy — one shed error per overflow element.
Solution: Give the server queue headroom, or lower the batch concurrency to match its cap:
{
"mcpServers": [
{ "name": "fragile-db", "command": "db-mcp", "max_concurrent_requests": 1, "queue_size": 20 }
]
}
// Or match the cap from the script
call_tools(requests, {max_parallel: 1});
Queued calls wait up to queue_timeout, and that wall-clock wait happens inside
the script's timeout_ms budget — size queue_size and timeout_ms together.
Stored Script Errors
These apply to invocations that name a stored script
(script: "<name>", --script <name>) instead of sending code inline. One
command answers most of them:
mcpproxy code scripts list # names, paths, statuses, and the directory that was read
Error: "Provide exactly one of 'code' or 'script'"
Symptom:
Provide exactly one of 'code' (inline source) or 'script' (the name of a script stored in the 'scripts' directory next to mcpproxy's config file) — not both, not neither.
Over REST the same rule is an HTTP 400 before dispatch:
{"ok": false, "error": {"code": "INVALID_REQUEST", "message": "Provide exactly one of 'code' (inline source) or 'script' (the name of a stored script)"}}
Cause: The request carried both code and script, or neither. JSON Schema
cannot express "exactly one of", so neither field is schema-required and the
rule is enforced by the tool.
Solution: Send one source. On the CLI, --code, --file and --script are
mutually exclusive (--code, --file and --script are mutually exclusive, exit
code 2).
Error: "stored script X not found"
Symptom:
Cannot execute stored script: stored script "fetch-pr" not found in /Users/me/.mcpproxy/scripts. Available scripts (3): daily-report, fetch-prs, triage
Or, with an empty/absent directory:
Cannot execute stored script: stored script "fetch-pr" not found: no stored scripts in /Users/me/.mcpproxy/scripts (create fetch-pr.js or fetch-pr.ts there)
Or, when the caller is an agent token rather than an administrator — the listing, the count and the directory are withheld, and the message is the same whether the directory is empty or full:
Cannot execute stored script: stored script "fetch-pr" not found (the stored-script listing is available to administrators only; an agent-token caller must already know the script name)
Cause: No <name>.js / <name>.ts in the scripts directory. Usually a typo
(names are case-sensitive), a file that is not a script (uppercase or other
extension: .JS, .mjs, .jsx are ignored), or the wrong directory — the
scripts directory follows the active config file, not --data-dir.
Solution: For an administrator this error is the discovery mechanism — it lists the first 20 available names alphabetically plus the total, so the name set is recovered from the failed call. An agent token gets no listing: give the agent the script names out of band (or in its custom instructions) and check them against the administrator's view. For the full picture, including where the daemon looked:
mcpproxy code scripts list
mcpproxy code scripts list --config /etc/mcpproxy/mcp_config.json # a non-default config
If the directory in the message is not the one you authored in, start the daemon
with the config file you meant (mcpproxy serve --config …) — with
~/.mcpproxy/mcp_config.json the scripts live in ~/.mcpproxy/scripts/.
Case-insensitive filesystems (the default macOS and Windows volumes; on
Linux a Docker Desktop bind mount from a macOS or Windows host, vfat, an ext4
casefold directory): the on-disk spelling still decides, for every caller.
FETCH-PR.JS or Fetch-pr.js is not the script fetch-pr even where the
filesystem would open it under that name — the daemon verifies the stored
spelling before running anything, so the administrator's listing, the
administrator's call and an agent-token call all agree. Every platform —
Linux, the BSDs, macOS/darwin and Windows — answers an agent-token call
ONLY from an exact-name index of the directory that matches its CURRENT
state — built at daemon start, validated once per call, refreshed in the
background when the directory changes — so no call lists the directory,
whatever name is asked for; a differently-cased name and one that is not
stored at all cost exactly the same, and the refusal body is unchanged.
Every step of one call's own check — the stat, the candidate probe, the
open and the re-check after it — is bound to a single directory descriptor
(or, on Windows, handle) retained for that call, never a fresh resolution
of the path per step, so a symlink, bind mount or reparse point retargeted
mid-call cannot make two of those steps disagree about which directory they
are looking at. A call landing while that refresh is
scheduled or in flight is refused exactly as one against a directory never
seen before, never served from what the index held a moment ago — a rename
cannot have a scoped caller's own probe fold onto whatever now occupies the
old name. Even once refreshed, the index only authorizes a hit once its
directory timestamp is provably SETTLED (old enough — about two seconds —
that a write could not still be landing on the same coarse tick): a script
you have just added or renamed is callable by agent tokens only after the
index has both refreshed AND settled — retry a call refused in that
window, up to about two seconds — while administrators see the change at
once; mcpproxy never creates the directory itself, mkdir -p it. macOS
adds one extra, belt-and-suspenders check on top: after the open, it
re-reads the opened descriptor's own stored spelling (F_GETPATH) and
refuses on any mismatch. Windows performs the probe, the open and the
background listing all relative to the SAME retained directory handle
(NtCreateFile), so the post-open check only needs to confirm the opened
handle's own name (GetFinalPathNameByHandle) rather than re-walking a
path that a retargeted reparse point could have redirected.
Error: "invalid script name"
Symptom:
Cannot execute stored script: invalid script name "../../etc/passwd": character "." is not allowed (names are 1-64 characters of A-Z, a-z, 0-9, '-' or '_' — a name, never a path)
Cause: script is a name, never a path. Separators, .., dots,
extensions, non-ASCII characters and names longer than 64 characters are
rejected before the filesystem is touched at all.
Solution: Pass the base name only — fetch-prs, not fetch-prs.js,
./fetch-prs.js, or /abs/path/fetch-prs.js.
Error: "stored script X is ambiguous"
Symptom:
Cannot execute stored script: stored script "triage" is ambiguous: /Users/me/.mcpproxy/scripts/triage.js and /Users/me/.mcpproxy/scripts/triage.ts both exist — remove one
Cause: Both extensions exist for one name — often a leftover after converting a script from JavaScript to TypeScript. Ambiguity is never resolved silently.
Solution: Delete (or rename) one of the two files. mcpproxy code scripts list flags such names with status ambiguous before you hit them at runtime.
Error: "stored script X is oversized / empty / unreadable / non-regular"
Symptom:
Cannot execute stored script: stored script "big-report" (/Users/me/.mcpproxy/scripts/big-report.js) is oversized: scripts are limited to 262144 bytes
Cause:
| Reason | Meaning |
|---|---|
oversized | The file exceeds the 256 KB stored-script bound (inline code has no such bound; this one exists purely to bound the daemon-side read) |
empty | Zero bytes — commonly a half-finished redirect (> script.js) |
unreadable | Permissions or an I/O error; the detail carries the OS error |
non-regular | The path is a symlink, directory, or device — scripts must be regular files |
Solution: Split an oversized workflow into several scripts (or move bulk
data into input), finish the write, fix permissions, or replace the symlink
with the real file. Copy, do not link:
cp /shared/workflows/report.js ~/.mcpproxy/scripts/report.js
The scripts directory itself may be a symlink — it is operator-controlled; only the script file may not be.
Error: "stored script X is a .ts file but language Y was requested"
Symptom:
Cannot execute stored script: stored script "daily-report" is a .ts file (typescript) but language "javascript" was requested — omit 'language' or set it to "typescript"
Cause: The extension is authoritative for a stored script, and the explicit
language contradicted it.
Solution: Omit language entirely — the extension decides. (The CLI already
forwards --language only when you set it explicitly, so its javascript
default cannot trigger this.)
Issue: An edited script still runs the old content
Cause: Almost always the file was not replaced where the daemon looks, or the edit went to a different scripts directory. There is no cache and no watcher: every invocation opens and reads the file once, so a completed replacement is visible to the very next call — no restart, nothing to flush.
Solution: Confirm the path with mcpproxy code scripts list (it always
prints the directory it read), then edit by atomic replace so no invocation
can observe a half-written file:
tmp=$(mktemp ~/.mcpproxy/scripts/.report.XXXXXX)
cp new-report.js "$tmp" && mv "$tmp" ~/.mcpproxy/scripts/report.js
Editing in place while an invocation is reading is the one unsupported case: that run gets whatever the read returned (validated, but unspecified).
Issue: No way to upload or edit a script through the API
Cause: Working as designed. v1 has no write path for stored scripts — no MCP tool, no REST endpoint, no CLI verb creates, updates, or deletes them. Code running in the sandbox has no filesystem access either.
Solution: Author scripts with your normal filesystem tooling (editor, scp,
configuration management). GET /api/v1/code/scripts and mcpproxy code scripts list are read-only, administrator-only views of the result (an
agent token is refused with
403).
Serialization Errors
Error: "Result contains non-JSON-serializable values"
Symptom:
{
"ok": false,
"error": {
"code": "SERIALIZATION_ERROR",
"message": "Result contains non-JSON-serializable values (functions, circular references, etc.)",
"stack": ""
}
}
Cause: JavaScript return value contains functions, circular references, or other non-JSON types.
Solutions:
Problem: Returning functions
// Bad
return {
calculate: function() { return 42; }
};
// Good
return {
result: 42
};
Problem: Returning undefined
// Bad
return undefined; // Not JSON-serializable
// Good
return null; // JSON-serializable
Problem: Circular references
// Bad
var obj = {value: 42};
obj.self = obj; // Circular reference
return obj;
// Good
return {value: 42};
Problem: Special objects (Date, RegExp)
// Bad
return {
created: new Date() // Date object not JSON-serializable
};
// Good
return {
created: new Date().toISOString() // String is JSON-serializable
};
Performance Issues
Issue: Slow execution times
Symptom: Code takes longer than expected to execute.
Diagnosis:
- Check number of tool calls
- Measure upstream tool latency
- Look for inefficient loops
- Check for excessive data processing
Solutions:
Reduce tool calls:
// Bad: N tool calls
for (var i = 0; i < items.length; i++) {
call_tool('api', 'get', {id: items[i]});
}
// Good: 1 batch tool call
call_tool('api', 'get_batch', {ids: items});
Run independent calls in parallel (when the tool has no bulk variant):
// Bad: N sequential calls — latency is the sum
for (var i = 0; i < items.length; i++) {
call_tool('api', 'get', {id: items[i]});
}
// Good: one batch — latency is about the slowest call
var slots = call_tools(items.map(function (id) {
return {server: 'api', tool: 'get', args: {id: id}};
}), {max_parallel: 8});
Only batch calls that do not depend on each other. Raise
code_execution_max_parallel (or options.max_parallel, max 32) if upstreams
can take the pressure — and check the target server's max_concurrent_requests /
queue_size first (see the queue_full entry above).
Cache repeated calls:
// Bad: Call same tool multiple times
for (var i = 0; i < items.length; i++) {
var config = call_tool('api', 'get_config', {}); // Repeated call
process(items[i], config);
}
// Good: Call once, reuse result
var config = call_tool('api', 'get_config', {});
if (!config.ok) return config;
for (var i = 0; i < items.length; i++) {
process(items[i], config.result);
}
Optimize loops:
// Bad: Inefficient nested loops
for (var i = 0; i < arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] === arr2[j]) {
results.push(arr1[i]);
}
}
}
// Good: Use object for O(1) lookup
var set = {};
for (var i = 0; i < arr2.length; i++) {
set[arr2[i]] = true;
}
for (var i = 0; i < arr1.length; i++) {
if (set[arr1[i]]) {
results.push(arr1[i]);
}
}
Issue: Pool exhaustion (all VMs busy)
Symptom: Requests take longer to start, or you see "waiting for VM" logs.
Cause: More concurrent executions than pool size allows.
Solution: Increase pool size in configuration:
{
"code_execution_pool_size": 20 // Increase from default 10
}
Trade-offs:
- Larger pool = more concurrency, more memory usage
- Smaller pool = less concurrency, less memory usage
Recommendation: Monitor pool usage and adjust based on load.
Debugging Tips
Enable Debug Logging
CLI:
mcpproxy code exec --code="..." --log-level=debug
Server: Edit config to set log level:
{
"log_level": "debug"
}
What you'll see:
- Tool call details (server, tool name, arguments)
- Execution timing
- Pool acquisition/release
- Detailed error messages
Use console.log() for Debugging
var user = call_tool('github', 'get_user', {username: input.username});
console.log('User response:', JSON.stringify(user)); // Logs to server logs
if (!user.ok) {
console.log('Error occurred:', user.error);
return {error: user.error.message};
}
console.log('User name:', user.result.name);
return {name: user.result.name};
Where to find logs: ~/.mcpproxy/logs/main.log (or platform-specific log directory)
Test Code Incrementally
Start simple and build up:
// Step 1: Verify input access
return input;
// Step 2: Test tool call
var res = call_tool('github', 'get_user', {username: 'octocat'});
return res;
// Step 3: Add error handling
var res = call_tool('github', 'get_user', {username: 'octocat'});
if (!res.ok) return {error: res.error.message};
return res.result;
// Step 4: Add data transformation
var res = call_tool('github', 'get_user', {username: 'octocat'});
if (!res.ok) return {error: res.error.message};
return {
name: res.result.name,
repos: res.result.public_repos
};
Validate JSON Serialization
Test that your return value is JSON-serializable:
var result = {/* your data */};
// This will throw if result is not serializable
var json = JSON.stringify(result);
// If it succeeds, return it
return result;
Use Error Boundaries
Wrap risky operations in try-catch or use checks:
// Check before accessing
if (res && res.ok && res.result && res.result.name) {
return {name: res.result.name};
} else {
return {error: 'Invalid response structure'};
}
// For loops, check each iteration
for (var i = 0; i < items.length; i++) {
if (!items[i]) {
console.log('Skipping null item at index', i);
continue;
}
// Process items[i]
}
Reproduce Issues Locally
Use the CLI to reproduce issues quickly:
# Save problematic code to file
cat > /tmp/debug.js << 'EOF'
var user = call_tool('github', 'get_user', {username: input.username});
console.log('Response:', JSON.stringify(user));
return user;
EOF
# Run with debug logging
mcpproxy code exec \
--file=/tmp/debug.js \
--input='{"username":"octocat"}' \
--log-level=debug
Getting Help
If you're still stuck after trying these solutions:
- Check the examples: examples.md has 10+ working patterns
- Review API reference: api-reference.md has complete schema
- Read the overview: overview.md explains architecture
- Check server logs:
~/.mcpproxy/logs/main.logfor detailed error messages - File an issue: GitHub Issues
What to Include in Bug Reports
**Environment**:
- MCPProxy version: (run `mcpproxy --version`)
- OS: (macOS/Linux/Windows)
- Configuration: (relevant config fields)
**Code**:
```javascript
// Your JavaScript code here
Input:
{
"input": {...}
}
Expected: What you expected to happen
Actual: What actually happened (include full error message)
Logs: Relevant lines from ~/.mcpproxy/logs/main.log
---
## Next Steps
- **Examples**: See [examples.md](examples.md) for working code samples
- **API Reference**: See [api-reference.md](api-reference.md) for complete schema
- **Overview**: See [overview.md](overview.md) for architecture and best practices