Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ A [Model Context Protocol](https://modelcontextprotocol.io/docs/getting-started/
This server eliminates custom scripts and manual LocalStack management with direct access to:

- Start, stop, restart, and monitor LocalStack for AWS container status with built-in auth.
- Deploy CDK and Terraform projects with automatic configuration detection.
- Deploy CDK, Terraform, and SAM projects with automatic configuration detection.
- Search LocalStack documentation for guides, API references, and configuration details.
- Parse logs, catch errors, and auto-generate IAM policies from violations. (requires active license)
- Inject chaos faults and network effects into LocalStack to test system resilience. (requires active license)
Expand All @@ -23,7 +23,7 @@ This server provides your AI with dedicated tools for managing your LocalStack e
| Tool Name | Description | Key Features |
| :-------------------------------------------------------------------------------- | :------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [`localstack-management`](./src/tools/localstack-management.ts) | Manages LocalStack runtime operations for AWS and Snowflake stacks | - Execute start, stop, restart, and status checks<br/>- Integrate LocalStack authentication tokens<br/>- Inject custom environment variables<br/>- Verify real-time status and perform health monitoring |
| [`localstack-deployer`](./src/tools/localstack-deployer.ts) | Handles infrastructure deployment to LocalStack for AWS environments | - Automatically run CDK and Terraform tooling to deploy infrastructure locally<br/>- Enable parameterized deployments with variable support<br/>- Process and present deployment results<br/>- Requires you to have [`cdklocal`](https://github.com/localstack/aws-cdk-local) or [`tflocal`](https://github.com/localstack/terraform-local) installed in your system path |
| [`localstack-deployer`](./src/tools/localstack-deployer.ts) | Handles infrastructure deployment to LocalStack for AWS environments | - Automatically run CDK, Terraform, and SAM tooling to deploy infrastructure locally<br/>- Enable parameterized deployments with variable support<br/>- Process and present deployment results<br/>- Requires you to have [`cdklocal`](https://github.com/localstack/aws-cdk-local), [`tflocal`](https://github.com/localstack/terraform-local), or [`samlocal`](https://github.com/localstack/aws-sam-cli-local) installed in your system path |
| [`localstack-logs-analysis`](./src/tools/localstack-logs-analysis.ts) | Analyzes LocalStack for AWS logs for troubleshooting and insights | - Offer multiple analysis options including summaries, errors, requests, and raw data<br/>- Filter by specific services and operations<br/>- Generate API call metrics and failure breakdowns<br/>- Group errors intelligently and identify patterns |
| [`localstack-iam-policy-analyzer`](./src/tools/localstack-iam-policy-analyzer.ts) | Handles IAM policy management and violation remediation | - Set IAM enforcement levels including `enforced`, `soft`, and `disabled` modes<br/>- Search logs for permission-related violations<br/>- Generate IAM policies automatically from detected access failures<br/>- Requires a valid LocalStack Auth Token |
| [`localstack-chaos-injector`](./src/tools/localstack-chaos-injector.ts) | Injects and manages chaos experiment faults for system resilience testing | - Inject, add, remove, and clear service fault rules<br/>- Configure network latency effects<br/>- Comprehensive fault targeting by service, region, and operation<br/>- Built-in workflow guidance for chaos experiments<br/>- Requires a valid LocalStack Auth Token |
Expand All @@ -42,7 +42,7 @@ For other MCP Clients, refer to the [configuration guide](#configuration).
### Prerequisites

- [LocalStack CLI](https://docs.localstack.cloud/getting-started/installation/#localstack-cli) and Docker installed in your system path
- [`cdklocal`](https://github.com/localstack/aws-cdk-local) or [`tflocal`](https://github.com/localstack/terraform-local) installed in your system path for running infrastructure deployment tooling
- [`cdklocal`](https://github.com/localstack/aws-cdk-local), [`tflocal`](https://github.com/localstack/terraform-local), or [`samlocal`](https://github.com/localstack/aws-sam-cli-local) installed in your system path for running infrastructure deployment tooling
- A [valid LocalStack Auth Token](https://docs.localstack.cloud/aws/getting-started/auth-token/) to enable Pro services, IAM Policy Analyzer, Cloud Pods, Chaos Injector, and Extensions tools (**optional**)
- [Node.js v22.x](https://nodejs.org/en/download/) installed in your system path

Expand Down
11 changes: 10 additions & 1 deletion src/core/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,16 @@ export const TOOL_ARG_ALLOWLIST: Record<string, string[]> = {
"localstack-aws-client": ["command"],
"localstack-chaos-injector": ["action", "rules_count", "latency_ms"],
"localstack-cloud-pods": ["action", "pod_name"],
"localstack-deployer": ["action", "projectType", "directory", "stackName", "templatePath"],
"localstack-deployer": [
"action",
"projectType",
"directory",
"stackName",
"templatePath",
"s3Bucket",
"resolveS3",
"saveParams",
],
"localstack-docs": ["query", "limit"],
"localstack-extensions": ["action", "name", "source"],
"localstack-iam-policy-analyzer": ["action", "mode"],
Expand Down
31 changes: 30 additions & 1 deletion src/lib/deployment/deployment-utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { parseCdkOutputs, parseTerraformOutputs, validateVariables } from "./deployment-utils";
import fs from "fs";
import os from "os";
import path from "path";
import {
inferProjectType,
parseCdkOutputs,
parseTerraformOutputs,
validateVariables,
} from "./deployment-utils";

describe("deployment-utils", () => {
describe("validateVariables", () => {
Expand Down Expand Up @@ -35,4 +43,25 @@ describe("deployment-utils", () => {
expect(result).toContain("No outputs defined");
});
});

describe("inferProjectType", () => {
it("detects SAM projects via samconfig.toml", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ls-mcp-samcfg-"));
fs.writeFileSync(path.join(dir, "samconfig.toml"), "version = 0.1");

await expect(inferProjectType(dir)).resolves.toBe("sam");
fs.rmSync(dir, { recursive: true, force: true });
});

it("detects SAM projects via template with AWS::Serverless resources", async () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ls-mcp-samtpl-"));
fs.writeFileSync(
path.join(dir, "template.yaml"),
"Resources:\n MyFunction:\n Type: AWS::Serverless::Function\n"
);

await expect(inferProjectType(dir)).resolves.toBe("sam");
fs.rmSync(dir, { recursive: true, force: true });
});
});
});
52 changes: 42 additions & 10 deletions src/lib/deployment/deployment-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,24 @@ export interface DependencyCheckResult {
errorMessage?: string;
}

export type ProjectType = "cdk" | "terraform" | "cloudformation" | "ambiguous" | "unknown";
export type ProjectType =
| "cdk"
| "terraform"
| "sam"
| "cloudformation"
| "ambiguous"
| "unknown";

/**
* Check if the required deployment tool (cdklocal or tflocal) is available in the system PATH
* @param projectType The type of project requiring either 'cdk' or 'terraform' tooling
* @returns Promise with availability status and tool information
*/
export async function checkDependencies(
projectType: "cdk" | "terraform"
projectType: "cdk" | "terraform" | "sam"
): Promise<DependencyCheckResult> {
const tool = projectType === "cdk" ? "cdklocal" : "tflocal";
const tool =
projectType === "cdk" ? "cdklocal" : projectType === "terraform" ? "tflocal" : "samlocal";

try {
const { stdout, error } = await runCommand(tool, ["--version"], { timeout: 10000 });
Expand All @@ -42,15 +49,25 @@ Installation:
npm install -g aws-cdk-local aws-cdk

After installation, make sure the 'cdklocal' command is available in your PATH.`
: `❌ tflocal is not installed or not available in PATH.
: projectType === "terraform"
? `❌ tflocal is not installed or not available in PATH.

Please install terraform-local by following the official documentation:
https://github.com/localstack/terraform-local

Installation:
pip install terraform-local

After installation, make sure the 'tflocal' command is available in your PATH.`;
After installation, make sure the 'tflocal' command is available in your PATH.`
: `❌ samlocal is not installed or not available in PATH.

Please install aws-sam-cli-local by following the official documentation:
https://github.com/localstack/aws-sam-cli-local

Installation:
pip install aws-sam-cli-local

After installation, make sure the 'samlocal' command is available in your PATH.`;

return {
isAvailable: false,
Expand Down Expand Up @@ -84,22 +101,37 @@ export async function inferProjectType(directory: string): Promise<ProjectType>
(file) => file.endsWith(".tf") || file.endsWith(".tf.json")
);

const hasCloudFormationTemplates = files.some(
(file) => file.endsWith(".yaml") || file.endsWith(".yml")
);
const hasTemplateYaml = files.includes("template.yaml") || files.includes("template.yml");
const hasSamConfig = files.includes("samconfig.toml");

let hasServerlessResources = false;
if (hasTemplateYaml) {
const samTemplateFile = files.includes("template.yaml") ? "template.yaml" : "template.yml";
try {
const templateContent = await fs.promises.readFile(path.join(directory, samTemplateFile), "utf-8");
hasServerlessResources = /AWS::Serverless::[A-Za-z]+/.test(templateContent);
} catch {
hasServerlessResources = false;
}
}

const hasCloudFormationTemplates = files.some((file) => file.endsWith(".yaml") || file.endsWith(".yml"));

const isCdk = hasCdkJson || hasCdkFiles;
const isTerraform = hasTerraformFiles;
const isCloudFormation = hasCloudFormationTemplates;
const isSam = hasSamConfig || hasServerlessResources;
const isCloudFormation = hasCloudFormationTemplates && !isSam;

if (
[isCdk, isTerraform, isCloudFormation].filter(Boolean).length > 1
[isCdk, isTerraform, isSam, isCloudFormation].filter(Boolean).length > 1
) {
return "ambiguous";
} else if (isCdk) {
return "cdk";
} else if (isTerraform) {
return "terraform";
} else if (isSam) {
return "sam";
} else if (isCloudFormation) {
return "cloudformation";
} else {
Expand Down
Loading
Loading