Skip to main content
Glama
RestDB

Codehooks.io MCP Server

by RestDB

deploy_code

Deploys JavaScript files to a Codehooks.io project, creating serverless APIs with built-in CORS and optional instant CRUD backends.

Instructions

Deploy JavaScript code to Codehooks.io project.

MINIMAL WORKING EXAMPLE:

import { app } from 'codehooks-js';

app.get('/hello', (req, res) => {
  res.json({ message: 'Hello, world!' });
});

// MANDATORY: bind to serverless runtime
export default app.init();

INSTANT CRUD BACKEND:

import { app } from 'codehooks-js';

// Creates complete CRUD API for any collection (no schema required)
app.crudlify();

export default app.init();

KEY REQUIREMENTS:

  • Always import from 'codehooks-js'

  • Always end with export default app.init();

  • Use app.get(), app.post(), app.put(), app.delete() for routes

  • For database: const conn = await Datastore.open(); conn.insertOne(collection, data);

  • Use app.crudlify() to create complete CRUD backend with no schema required

  • Package.json will be auto-generated if not provided

DOCUMENTATION:

  • Use 'docs' tool for more information

  • Online ChatGPT prompt: https://codehooks.io/docs/chatgpt-backend-api-prompt

  • Online Workflow API: https://codehooks.io/docs/workflow-api

  • LLM-optimized docs: https://codehooks.io/llms.txt and https://codehooks.io/llms-full.txt

Note: Codehooks.io has CORS built-in by default, so no additional CORS middleware is needed.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filesYesArray of files to deploy
mainNoApplication main file (defaults to 'index')
jsonNoOutput JSON format
projectIdNoProject ID
spaceIdNoSpace IDdev

Implementation Reference

  • Zod validation schema for the deploy_code tool input parameters. Defines: 'files' (array of {path, content}), optional 'main', 'json', 'projectId', 'spaceId'.
    const deployCodeSchema = z.object({
        files: z.array(z.object({
            path: z.string(),
            content: z.string()
        })),
        main: z.string().optional(),
        json: z.boolean().optional(),
        projectId: z.string().optional(),
        spaceId: z.string().optional()
    });
  • src/index.ts:236-262 (registration)
    Tool registration entry in the tools array. Maps name 'deploy_code' to its description, schema, and inputSchema for tool listing.
    {
        name: "deploy_code",
        description: "Deploy JavaScript code to Codehooks.io project. \n\nMINIMAL WORKING EXAMPLE:\n```javascript\nimport { app } from 'codehooks-js';\n\napp.get('/hello', (req, res) => {\n  res.json({ message: 'Hello, world!' });\n});\n\n// MANDATORY: bind to serverless runtime\nexport default app.init();\n```\n\nINSTANT CRUD BACKEND:\n```javascript\nimport { app } from 'codehooks-js';\n\n// Creates complete CRUD API for any collection (no schema required)\napp.crudlify();\n\nexport default app.init();\n```\n\nKEY REQUIREMENTS:\n- Always import from 'codehooks-js'\n- Always end with `export default app.init();`\n- Use app.get(), app.post(), app.put(), app.delete() for routes\n- For database: `const conn = await Datastore.open(); conn.insertOne(collection, data);`\n- Use app.crudlify() to create complete CRUD backend with no schema required\n- Package.json will be auto-generated if not provided\n\nDOCUMENTATION:\n- Use 'docs' tool for more information \n- Online ChatGPT prompt: https://codehooks.io/docs/chatgpt-backend-api-prompt\n- Online Workflow API: https://codehooks.io/docs/workflow-api\n- LLM-optimized docs: https://codehooks.io/llms.txt and https://codehooks.io/llms-full.txt\n\nNote: Codehooks.io has CORS built-in by default, so no additional CORS middleware is needed.",
        schema: deployCodeSchema,
        inputSchema: {
            type: "object",
            properties: {
                files: {
                    type: "array",
                    items: {
                        type: "object",
                        properties: {
                            path: { type: "string", description: "File path relative to project root (e.g. 'index.js', 'src/utils.js')" },
                            content: { type: "string", description: "File content" }
                        },
                        required: ["path", "content"]
                    },
                    description: "Array of files to deploy"
                },
                main: { type: "string", description: "Application main file (defaults to 'index')" },
                json: { type: "boolean", description: "Output JSON format" },
                projectId: { type: "string", description: "Project ID" },
                spaceId: { type: "string", description: "Space ID", default: "dev" }
            },
            required: ["files"]
        }
    },
  • Full handler implementation for the deploy_code tool. Writes files to temp directory, runs npm install, executes 'coho deploy' CLI command, and returns deployment result.
    case "deploy_code": {
        const {
            files,
            main = "index",
            json = false,
            projectId,
            spaceId
        } = args as DeployCodeArgs;
    
        // Check if package.json is provided, if not create a default one
        const hasPackageJson = files.some(file => file.path === 'package.json');
        let filesToDeploy = [...files];
    
        if (!hasPackageJson) {
            console.error('No package.json provided, creating default one');
            const defaultPackageJson = {
                name: projectId || config.projectId || "codehooks-project",
                version: "1.0.0",
                description: "Codehooks project",
                type: "module",
                main: `${main}.js`,
                scripts: {
                    test: "echo \"Error: no test specified\" && exit 1"
                },
                author: "",
                license: "ISC",
                dependencies: {
                    "codehooks-js": "latest"
                }
            };
    
            filesToDeploy.push({
                path: 'package.json',
                content: JSON.stringify(defaultPackageJson, null, 2)
            });
        }
    
        console.error(`Deploying ${filesToDeploy.length} files`);
        const tmpDir = await fs.mkdtemp('/tmp/codehooks-deploy-');
        console.error('Created temporary directory:', tmpDir);
    
        try {
            // Write all files to the temporary directory with proper formatting
            for (const file of filesToDeploy) {
                const filePath = path.join(tmpDir, file.path);
                // Ensure directory exists
                await fs.mkdir(path.dirname(filePath), { recursive: true });
                console.error(`Writing file: ${filePath}`);
    
                if (file.path === 'package.json') {
                    // Create a properly structured package.json
                    const defaultPackage = {
                        name: projectId || config.projectId || "codehooks-project",
                        version: "1.0.0",
                        description: "Codehooks project",
                        main: `${main}.js`,
                        scripts: {
                            test: "echo \"Error: no test specified\" && exit 1"
                        },
                        author: "",
                        license: "ISC",
                        dependencies: {
                            "codehooks-js": "latest"
                        }
                    };
    
                    // Merge with any existing package.json content
                    let packageJson;
                    try {
                        packageJson = JSON.parse(file.content);
                        packageJson = { ...defaultPackage, ...packageJson };
                    } catch (e) {
                        console.error('Invalid package.json content, using default');
                        packageJson = defaultPackage;
                    }
    
                    // Write package.json with proper formatting
                    await fs.writeFile(filePath, JSON.stringify(packageJson, null, 2));
                } else {
                    await fs.writeFile(filePath, file.content);
                }
            }
    
            // Log directory contents
            console.error('Directory contents before npm install:');
            const { stdout: lsOutput } = await execFile('ls', ['-la'], { cwd: tmpDir });
            console.error(lsOutput);
    
            // Install dependencies
            try {
                console.error('Installing dependencies...');
                const { stdout: npmStdout, stderr: npmStderr } = await execFile('npm', ['install'], { cwd: tmpDir });
                if (npmStderr) console.error('npm install stderr:', npmStderr);
                console.error('npm install stdout:', npmStdout);
    
                // Log directory contents after npm install
                console.error('Directory contents after npm install:');
                const { stdout: lsOutput2 } = await execFile('ls', ['-la'], { cwd: tmpDir });
                console.error(lsOutput2);
            } catch (error: any) {
                console.error('npm install error:', error);
                throw new McpError(ErrorCode.InvalidRequest, `Failed to install dependencies: ${error.message}`);
            }
    
            // Change working directory to tmpDir
            const originalCwd = process.cwd();
            try {
                process.chdir(tmpDir);
                console.error('Changed working directory to:', tmpDir);
    
                // Log file contents before deployment
                console.error('File contents before deployment:');
                for (const file of filesToDeploy) {
                    console.error(`\n=== ${file.path} ===`);
                    const content = await fs.readFile(path.join(tmpDir, file.path), 'utf8');
                    console.error(content);
                }
    
                // Construct deploy command arguments
                const deployArgs = [
                    'deploy',
                    '--projectname', projectId || config.projectId,
                    '--space', spaceId || config.space,
                    '--main', main,
                    '--admintoken', config.adminToken
                ];
    
                if (json) deployArgs.push('--json');
    
                console.error('Executing deploy command...');
                const { stdout, stderr } = await execFile('coho', deployArgs);
                console.error('Deploy stdout:', stdout);
                if (stderr) console.error('Deploy stderr:', stderr);
    
                // Only clean up on success
                await fs.rm(tmpDir, { recursive: true, force: true });
                console.error('Cleaned up temporary directory:', tmpDir);
    
                return {
                    content: [
                        {
                            type: "text",
                            text: stdout || stderr || "Deployment successful"
                        }
                    ],
                    isError: false
                };
            } finally {
                // Restore original working directory
                process.chdir(originalCwd);
                console.error('Restored working directory to:', originalCwd);
            }
        } catch (error: any) {
            console.error(`Deployment failed. Temporary directory ${tmpDir} preserved for inspection.`);
            console.error('Error:', error);
            throw error;
        }
    }
  • Helper function executeCohoCommand() used by the deploy_code handler (and all other tools) to run 'coho' CLI commands via execFile with admin token injection and timeout.
    async function executeCohoCommand(args: string[]): Promise<string> {
        const safeArgs = ['coho', ...args, '--admintoken', '***'];
        console.error(`Executing command: ${safeArgs.join(' ')}`);
        try {
            const { stdout, stderr } = await execFile('coho', [...args, '--admintoken', config.adminToken], {
                timeout: 120000 // 2 minutes timeout for CLI operations
            });
            if (stderr) {
                // Sanitize stderr before logging to avoid token exposure
                const safeSterr = stderr.replace(new RegExp(config.adminToken, 'g'), '***');
                console.error(`Command output to stderr:`, safeSterr);
            }
            console.error(`Command successful`);
            const result = stdout || stderr;
            // Sanitize result to ensure admin token is not exposed
            return result ? result.replace(new RegExp(config.adminToken, 'g'), '***') : result;
        } catch (error: any) {
            // Comprehensive sanitization of all error properties to avoid admin token exposure
            const sanitizeText = (text: string): string => text ? text.replace(new RegExp(config.adminToken, 'g'), '***') : text;
    
            const sanitizedMessage = sanitizeText(error?.message || 'Unknown error');
            const sanitizedCmd = sanitizeText(error?.cmd || '');
            const sanitizedStdout = sanitizeText(error?.stdout || '');
            const sanitizedStderr = sanitizeText(error?.stderr || '');
    
            // Log sanitized error details
            console.error(`Command failed: ${sanitizedMessage}`);
            if (sanitizedCmd) console.error(`Command: ${sanitizedCmd}`);
            if (sanitizedStdout) console.error(`Stdout: ${sanitizedStdout}`);
            if (sanitizedStderr) console.error(`Stderr: ${sanitizedStderr}`);
    
            // Return sanitized error message
            const errorDetails = [sanitizedMessage, sanitizedStderr].filter(Boolean).join(' - ');
            throw new McpError(ErrorCode.InvalidRequest, `Command failed: ${errorDetails}`);
        }
    }
  • src/index.ts:184-184 (registration)
    TypeScript type inference for DeployCodeArgs, derived from the deployCodeSchema.
    type QueryCollectionArgs = z.infer<typeof queryCollectionSchema>;
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description bears full responsibility. It mentions auto-generation of package.json and built-in CORS, but does not disclose potential side effects like overwriting existing code or permission requirements. This is adequate but not comprehensive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is relatively long but well-structured with clear sections, code examples, and links. The first sentence states the purpose. Every part adds value, though some details could be condensed. Justified 4.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Considering the tool's complexity (deploying code files) and the absence of output schema or annotations, the description provides comprehensive context: examples, requirements, and documentation links. It covers what the agent needs to invoke the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with each parameter described. The description adds value through examples and requirements (e.g., 'index.js' path, 'dev' space default), but does not significantly extend beyond the schema's own descriptions. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description explicitly states 'Deploy JavaScript code to Codehooks.io project.' This is a specific verb-resource pair, and the examples further clarify. No sibling tool duplicates this purpose.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides key requirements, minimal working examples, and instructions. It implicitly guides when to use this tool (to deploy code). However, it does not explicitly state when not to use it or list alternatives, though no close siblings exist.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/RestDB/codehooks-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server