dev-mcps/dev-server-mcp/services.example.json

169 lines
5.7 KiB
JSON

{
"_comment": [
"Operator-owned. An MCP caller selects a service id and nothing else: commands, arguments,",
"directories and environment all come from here.",
"",
"workspaceMode 'shared' serves one fixed tree in the workspace mount, with its dependencies",
"installed ahead of time by the operator. 'execution' serves the tree the current execution",
"wrote, in a throwaway copy of it, and may take an allocated ${port}.",
"",
"Two flags are not optional in a service definition, both learned the hard way:",
" --host 0.0.0.0 a dev server left to its default binds IPv6 loopback only, so a health",
" check on 127.0.0.1 declares a perfectly live server dead, and no other",
" container can reach it.",
" --strictPort without it a dev server whose port is busy moves to another one and says",
" so only in its log, leaving the preview at an address nobody looks at."
],
"_comment_java": [
"./mvnw and not mvn: the wrapper pins the Maven version the project is built with, so the",
"image carries no Maven of its own to be used by mistake.",
"",
"The proxy is passed as system properties because a JVM ignores HTTP_PROXY entirely - the",
"worker sets those variables, and Maven is the one toolchain that cannot read them.",
"",
"A first build downloads the whole dependency tree into this execution's own ~/.m2, which is",
"why the timeouts here are the largest in the file. Past the MCP client's own 120 s request",
"timeout, use workspaceMode 'shared' with a prepared repository instead."
],
"_comment_python": [
"python3 -m uvicorn and not the uvicorn script: a --user install puts its console scripts in",
"$HOME/.local/bin, which is not on the sanitised PATH, while the module itself is found",
"because the per-execution HOME puts its user site on sys.path.",
"",
"--break-system-packages reads worse than it is: Debian marks its own python as externally",
"managed, and this flag only lifts that refusal. Combined with --user, nothing outside this",
"execution's HOME is written."
],
"services": {
"web": {
"command": "npm",
"args": [
"run",
"dev",
"--",
"--host",
"0.0.0.0",
"--port",
"5173",
"--strictPort"
],
"cwd": ".",
"workspaceMode": "shared",
"publicUrl": "http://dev-server-worker:5173",
"healthUrl": "http://127.0.0.1:5173/",
"startupTimeoutMs": 20000,
"shutdownTimeoutMs": 5000,
"env": {
"PORT": "5173"
}
},
"execution-web": {
"command": "npm",
"args": [
"run",
"dev",
"--",
"--host",
"0.0.0.0",
"--port",
"${port}",
"--strictPort"
],
"cwd": ".",
"workspaceMode": "execution",
"agentInstructions": "This service runs npm ci and then npm run dev. Before starting, create a valid package.json with a dev script and the matching package-lock.json. The dev server must honour PORT and bind to 0.0.0.0. Navigate only to the publicUrl returned by a successful start_service.",
"install": {
"command": "npm",
"args": [
"ci",
"--ignore-scripts",
"--no-audit",
"--no-fund"
],
"timeoutMs": 90000
},
"publicUrl": "http://dev-server-worker:${port}",
"healthUrl": "http://127.0.0.1:${port}/",
"startupTimeoutMs": 60000,
"shutdownTimeoutMs": 5000,
"env": {
"PORT": "${port}"
}
},
"execution-node": {
"command": "node",
"args": ["server.js", "${port}"],
"cwd": ".",
"workspaceMode": "execution",
"agentInstructions": "Use this for a dependency-free page in an empty workspace. Create server.js in the workspace root; it must serve the page, listen on 0.0.0.0, and use process.env.PORT. No package.json or lockfile is required. Navigate only to the publicUrl returned by a successful start_service.",
"publicUrl": "http://dev-server-worker:${port}",
"healthUrl": "http://127.0.0.1:${port}/",
"startupTimeoutMs": 20000,
"shutdownTimeoutMs": 5000,
"env": {
"PORT": "${port}"
}
},
"execution-api": {
"command": "./mvnw",
"args": [
"-B",
"-q",
"-Dhttps.proxyHost=egress-proxy",
"-Dhttps.proxyPort=3128",
"spring-boot:run",
"-Dspring-boot.run.arguments=--server.port=${port} --server.address=0.0.0.0"
],
"cwd": ".",
"workspaceMode": "execution",
"install": {
"command": "./mvnw",
"args": [
"-B",
"-q",
"-Dhttps.proxyHost=egress-proxy",
"-Dhttps.proxyPort=3128",
"dependency:go-offline"
],
"timeoutMs": 600000
},
"publicUrl": "http://dev-server-worker:${port}",
"healthUrl": "http://127.0.0.1:${port}/actuator/health",
"startupTimeoutMs": 120000,
"shutdownTimeoutMs": 15000
},
"execution-python": {
"command": "python3",
"args": [
"-m",
"uvicorn",
"main:app",
"--host",
"0.0.0.0",
"--port",
"${port}"
],
"cwd": ".",
"workspaceMode": "execution",
"install": {
"command": "python3",
"args": [
"-m",
"pip",
"install",
"--user",
"--break-system-packages",
"--no-input",
"-r",
"requirements.txt"
],
"timeoutMs": 180000
},
"publicUrl": "http://dev-server-worker:${port}",
"healthUrl": "http://127.0.0.1:${port}/",
"startupTimeoutMs": 60000,
"shutdownTimeoutMs": 5000
}
}
}