app-builder-mcp-server
Version:
MCP server for Adobe App Builder CLI commands
950 lines (947 loc) • 27.6 kB
JavaScript
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);
});