UNPKG

app-builder-mcp-server

Version:

MCP server for Adobe App Builder CLI commands

950 lines (947 loc) 27.6 kB
#!/usr/bin/env node import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { exec } from "child_process"; import { promisify } from "util"; const execAsync = promisify(exec); // Parse command line arguments const args = process.argv.slice(2); let projectPath = null; // Look for --projectPath or -p argument for (let i = 0; i < args.length; i++) { if ((args[i] === '--projectPath' || args[i] === '-p') && i + 1 < args.length) { projectPath = args[i + 1]; console.log(`Using project path from command line: ${projectPath}`); break; } } // Throw error if no project path is provided if (!projectPath) { console.error("Error: No project path provided. Please use --projectPath or -p to specify the project path."); process.exit(1); } // Helper function for executing Adobe App Builder CLI commands async function executeAioCommand(command) { try { // Set the working directory to the specified path const options = { cwd: projectPath }; const { stdout, stderr } = await execAsync(`aio ${command}`, options); if (stderr) { console.error(`Command stderr: ${stderr}`); } return stdout; } catch (error) { console.error(`Error executing command: ${error}`); throw error; } } // Create server instance const server = new McpServer({ name: "App Builder MCP Server", version: "1.0.0", }); // Register Adobe App Builder CLI tools server.tool("app-init", "Initialize / Create a new Adobe App Builder application", { path: z.string().optional().describe("Path where the app will be initialized"), }, async ({ path }) => { const command = `app init -y --no-login --standalone-app --no-install`; try { const result = await executeAioCommand(command); return { content: [ { type: "text", text: `Successfully initialized app:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to initialize app: ${error}`, }, ], }; } }); server.tool("app-build", "Build an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app build"); return { content: [ { type: "text", text: `Successfully built app:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to build app: ${error}`, }, ], }; } }); server.tool("app-deploy", "Deploy an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app deploy"); return { content: [ { type: "text", text: `Successfully deployed app:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to deploy app: ${error}`, }, ], }; } }); server.tool("app-undeploy", "Undeploy an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app undeploy"); return { content: [ { type: "text", text: `Successfully undeployed app:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to undeploy app: ${error}`, }, ], }; } }); server.tool("app-info", "Get information about an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app info"); return { content: [ { type: "text", text: `App information:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get app information: ${error}`, }, ], }; } }); // Additional app commands server.tool("app-run", "Run an Adobe App Builder application locally", {}, async () => { try { const result = await executeAioCommand("app run"); return { content: [ { type: "text", text: `Running app locally:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to run app locally: ${error}`, }, ], }; } }); server.tool("app-test", "Run tests for an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app test"); return { content: [ { type: "text", text: `Test results:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to run tests: ${error}`, }, ], }; } }); server.tool("app-add-action", "Add an action to an Adobe App Builder application", { actionName: z.string().describe("Name of the action to add"), }, async ({ actionName }) => { try { const result = await executeAioCommand(`app add action ${actionName}`); return { content: [ { type: "text", text: `Added action ${actionName}:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to add action: ${error}`, }, ], }; } }); server.tool("app-add-web-assets", "Add web assets to an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app add web-assets"); return { content: [ { type: "text", text: `Added web assets:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to add web assets: ${error}`, }, ], }; } }); server.tool("app-logs", "Get logs for an Adobe App Builder application", {}, async () => { try { const result = await executeAioCommand("app logs"); return { content: [ { type: "text", text: `App logs:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get app logs: ${error}`, }, ], }; } }); server.tool("app-get-url", "Get the URL for an Adobe App Builder application action", { action: z.string().optional().describe("Name of the action to get the URL for"), }, async ({ action }) => { try { const result = await executeAioCommand(`app get-url ${action || ""}`); return { content: [ { type: "text", text: `App URL:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get app URL: ${error}`, }, ], }; } }); // Adobe App Builder commands server.tool("runtime-list", "List Adobe App Builder entities", {}, async () => { try { const result = await executeAioCommand("runtime list"); return { content: [ { type: "text", text: `Adobe App Builder entities:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder entities: ${error}`, }, ], }; } }); server.tool("runtime-namespace-list", "List Adobe App Builder namespaces", {}, async () => { try { const result = await executeAioCommand("runtime namespace list"); return { content: [ { type: "text", text: `Adobe App Builder namespaces:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder namespaces: ${error}`, }, ], }; } }); // Add more Adobe App Builder commands (aio rt) server.tool("rt-action-list", "List Adobe App Builder actions", { packageName: z.string().optional().describe("Package name to list actions from"), }, async ({ packageName }) => { try { const result = await executeAioCommand(`rt action list ${packageName || ""}`); return { content: [ { type: "text", text: `Adobe App Builder actions:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder actions: ${error}`, }, ], }; } }); server.tool("rt-action-create", "Create an Adobe App Builder action", { actionName: z.string().describe("Name of the action to create"), actionPath: z.string().optional().describe("Path to the action code"), }, async ({ actionName, actionPath }) => { try { const result = await executeAioCommand(`rt action create ${actionName} ${actionPath || ""}`); return { content: [ { type: "text", text: `Created Adobe App Builder action:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to create Adobe App Builder action: ${error}`, }, ], }; } }); server.tool("rt-action-update", "Update an Adobe App Builder action", { actionName: z.string().describe("Name of the action to update"), actionPath: z.string().optional().describe("Path to the updated action code"), }, async ({ actionName, actionPath }) => { try { const result = await executeAioCommand(`rt action update ${actionName} ${actionPath || ""}`); return { content: [ { type: "text", text: `Updated Adobe App Builder action:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to update Adobe App Builder action: ${error}`, }, ], }; } }); server.tool("rt-action-delete", "Delete an Adobe App Builder action", { actionName: z.string().describe("Name of the action to delete"), }, async ({ actionName }) => { try { const result = await executeAioCommand(`rt action delete ${actionName}`); return { content: [ { type: "text", text: `Deleted Adobe App Builder action:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to delete Adobe App Builder action: ${error}`, }, ], }; } }); server.tool("rt-action-invoke", "Invoke an Adobe App Builder action", { actionName: z.string().describe("Name of the action to invoke"), }, async ({ actionName }) => { try { const result = await executeAioCommand(`rt action invoke ${actionName}`); return { content: [ { type: "text", text: `Invoked Adobe App Builder action:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to invoke Adobe App Builder action: ${error}`, }, ], }; } }); server.tool("rt-action-get", "Get details of an Adobe App Builder action", { actionName: z.string().describe("Name of the action to get details for"), }, async ({ actionName }) => { try { const result = await executeAioCommand(`rt action get ${actionName}`); return { content: [ { type: "text", text: `Adobe App Builder action details:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get Adobe App Builder action details: ${error}`, }, ], }; } }); server.tool("rt-package-list", "List Adobe App Builder packages", { namespace: z.string().optional().describe("Namespace to list packages from"), }, async ({ namespace }) => { try { const result = await executeAioCommand(`rt package list ${namespace || ""}`); return { content: [ { type: "text", text: `Adobe App Builder packages:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder packages: ${error}`, }, ], }; } }); server.tool("rt-package-create", "Create an Adobe App Builder package", { packageName: z.string().describe("Name of the package to create"), }, async ({ packageName }) => { try { const result = await executeAioCommand(`rt package create ${packageName}`); return { content: [ { type: "text", text: `Created Adobe App Builder package:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to create Adobe App Builder package: ${error}`, }, ], }; } }); server.tool("rt-package-update", "Update an Adobe App Builder package", { packageName: z.string().describe("Name of the package to update"), }, async ({ packageName }) => { try { const result = await executeAioCommand(`rt package update ${packageName}`); return { content: [ { type: "text", text: `Updated Adobe App Builder package:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to update Adobe App Builder package: ${error}`, }, ], }; } }); server.tool("rt-package-delete", "Delete an Adobe App Builder package", { packageName: z.string().describe("Name of the package to delete"), }, async ({ packageName }) => { try { const result = await executeAioCommand(`rt package delete ${packageName}`); return { content: [ { type: "text", text: `Deleted Adobe App Builder package:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to delete Adobe App Builder package: ${error}`, }, ], }; } }); server.tool("rt-package-get", "Get details of an Adobe App Builder package", { packageName: z.string().describe("Name of the package to get details for"), }, async ({ packageName }) => { try { const result = await executeAioCommand(`rt package get ${packageName}`); return { content: [ { type: "text", text: `Adobe App Builder package details:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get Adobe App Builder package details: ${error}`, }, ], }; } }); server.tool("rt-activation-list", "List Adobe App Builder activations", { actionName: z.string().optional().describe("Action name to list activations for"), }, async ({ actionName }) => { try { const result = await executeAioCommand(`rt activation list ${actionName || ""}`); return { content: [ { type: "text", text: `Adobe App Builder activations:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder activations: ${error}`, }, ], }; } }); server.tool("rt-activation-get", "Get details of an Adobe App Builder activation", { activationId: z.string().optional().describe("ID of the activation to get details for"), }, async ({ activationId }) => { try { const result = await executeAioCommand(`rt activation get ${activationId || ""}`); return { content: [ { type: "text", text: `Adobe App Builder activation details:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get Adobe App Builder activation details: ${error}`, }, ], }; } }); server.tool("rt-activation-logs", "Get logs of an Adobe App Builder activation", { activationId: z.string().optional().describe("ID of the activation to get logs for"), }, async ({ activationId }) => { try { const result = await executeAioCommand(`rt activation logs ${activationId || ""}`); return { content: [ { type: "text", text: `Adobe App Builder activation logs:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get Adobe App Builder activation logs: ${error}`, }, ], }; } }); server.tool("rt-activation-result", "Get result of an Adobe App Builder activation", { activationId: z.string().optional().describe("ID of the activation to get result for"), }, async ({ activationId }) => { try { const result = await executeAioCommand(`rt activation result ${activationId || ""}`); return { content: [ { type: "text", text: `Adobe App Builder activation result:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get Adobe App Builder activation result: ${error}`, }, ], }; } }); server.tool("rt-deploy", "Deploy Adobe App Builder entities", {}, async () => { try { const result = await executeAioCommand("rt deploy"); return { content: [ { type: "text", text: `Deployed Adobe App Builder entities:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to deploy Adobe App Builder entities: ${error}`, }, ], }; } }); server.tool("rt-trigger-list", "List Adobe App Builder triggers", {}, async () => { try { const result = await executeAioCommand("rt trigger list"); return { content: [ { type: "text", text: `Adobe App Builder triggers:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder triggers: ${error}`, }, ], }; } }); server.tool("rt-rule-list", "List Adobe App Builder rules", {}, async () => { try { const result = await executeAioCommand("rt rule list"); return { content: [ { type: "text", text: `Adobe App Builder rules:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to list Adobe App Builder rules: ${error}`, }, ], }; } }); // Info command server.tool("info", "Get Adobe App Builder CLI information", {}, async () => { try { const result = await executeAioCommand("info"); return { content: [ { type: "text", text: `Adobe App Builder CLI information:\n\n${result}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to get information: ${error}`, }, ], }; } }); // Internal login command for Adobe internal developers server.tool("internal-login", "Allows Adobe internal developers to create credentials for a sandbox environment", {}, async () => { try { const result = await execAsync("npx aio-internal-login", { cwd: projectPath }); return { content: [ { type: "text", text: `Adobe internal login successful:\n\n${result.stdout}`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to perform internal login: ${error}`, }, ], }; } }); // Initialize a hello world action server.tool("init-hello-world-action", "Initializes a basic Hello World action with all necessary files", { actionName: z.string().optional().describe("Name of the action (defaults to 'hello')"), }, async ({ actionName = "hello" }) => { try { // Create actions directory if it doesn't exist await execAsync(`mkdir -p actions/${actionName}`, { cwd: projectPath }); // Create index.js with hello world action const actionCode = ` function main(params) { return { statusCode: 200, headers: { 'Content-Type': 'application/json' }, body: { message: 'Hello, world!' } } } exports.main = main `; await execAsync(`cat > actions/${actionName}/index.js << 'EOL'${actionCode}EOL`, { cwd: projectPath }); // Create app.config.yaml const appConfig = ` application: name: ${actionName}-app actions: actions web: web-src runtimeManifest: packages: ${actionName}-package: license: Apache-2.0 actions: ${actionName}: function: actions/${actionName}/index.js web: 'yes' runtime: 'nodejs:16' inputs: LOG_LEVEL: debug annotations: require-adobe-auth: false `; await execAsync(`cat > app.config.yaml << 'EOL'${appConfig}EOL`, { cwd: projectPath }); // Create package.json const packageJson = `{ "name": "${actionName}-action", "version": "1.0.0", "description": "Adobe App Builder ${actionName} Action", "main": "index.js", "scripts": { "test": "echo \\"Error: no test specified\\" && exit 1" }, "dependencies": { "@adobe/aio-sdk": "^3.0.0" }, "engines": { "node": ">=14.0.0" } }`; await execAsync(`cat > package.json << 'EOL'\n${packageJson}\nEOL`, { cwd: projectPath, shell: '/bin/bash' }); return { content: [ { type: "text", text: `Successfully initialized Hello World action "${actionName}" with the following files using the specified configuration: - actions/${actionName}/index.js - app.config.yaml - package.json You can now build and deploy your action with: - mcp_app_builder_app_build - mcp_app_builder_app_deploy`, }, ], }; } catch (error) { return { content: [ { type: "text", text: `Failed to initialize Hello World action: ${error}`, }, ], }; } }); // Start the server async function main() { const transport = new StdioServerTransport(); await server.connect(transport); console.error("App Builder MCP Server running on stdio"); } main().catch((error) => { console.error("Fatal error in main():", error); process.exit(1); });