Skip to content

Commit b175a96

Browse files
authored
Extend localstack-deployer with AWS SAM support (#18)
1 parent 0e7d3ae commit b175a96

File tree

5 files changed

+277
-30
lines changed

5 files changed

+277
-30
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ A [Model Context Protocol](https://modelcontextprotocol.io/docs/getting-started/
88
This server eliminates custom scripts and manual LocalStack management with direct access to:
99

1010
- Start, stop, restart, and monitor LocalStack for AWS container status with built-in auth.
11-
- Deploy CDK and Terraform projects with automatic configuration detection.
11+
- Deploy CDK, Terraform, and SAM projects with automatic configuration detection.
1212
- Search LocalStack documentation for guides, API references, and configuration details.
1313
- Parse logs, catch errors, and auto-generate IAM policies from violations. (requires active license)
1414
- Inject chaos faults and network effects into LocalStack to test system resilience. (requires active license)
@@ -23,7 +23,7 @@ This server provides your AI with dedicated tools for managing your LocalStack e
2323
| Tool Name | Description | Key Features |
2424
| :-------------------------------------------------------------------------------- | :------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
2525
| [`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 |
26-
| [`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 |
26+
| [`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 |
2727
| [`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 |
2828
| [`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 |
2929
| [`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 |
@@ -42,7 +42,7 @@ For other MCP Clients, refer to the [configuration guide](#configuration).
4242
### Prerequisites
4343

4444
- [LocalStack CLI](https://docs.localstack.cloud/getting-started/installation/#localstack-cli) and Docker installed in your system path
45-
- [`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
45+
- [`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
4646
- 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**)
4747
- [Node.js v22.x](https://nodejs.org/en/download/) or higher installed in your system path
4848

src/core/analytics.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,16 @@ export const TOOL_ARG_ALLOWLIST: Record<string, string[]> = {
1919
"localstack-aws-client": ["command"],
2020
"localstack-chaos-injector": ["action", "rules_count", "latency_ms"],
2121
"localstack-cloud-pods": ["action", "pod_name"],
22-
"localstack-deployer": ["action", "projectType", "directory", "stackName", "templatePath"],
22+
"localstack-deployer": [
23+
"action",
24+
"projectType",
25+
"directory",
26+
"stackName",
27+
"templatePath",
28+
"s3Bucket",
29+
"resolveS3",
30+
"saveParams",
31+
],
2332
"localstack-docs": ["query", "limit"],
2433
"localstack-extensions": ["action", "name", "source"],
2534
"localstack-iam-policy-analyzer": ["action", "mode"],

src/lib/deployment/deployment-utils.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import { parseCdkOutputs, parseTerraformOutputs, validateVariables } from "./deployment-utils";
1+
import fs from "fs";
2+
import os from "os";
3+
import path from "path";
4+
import {
5+
inferProjectType,
6+
parseCdkOutputs,
7+
parseTerraformOutputs,
8+
validateVariables,
9+
} from "./deployment-utils";
210

311
describe("deployment-utils", () => {
412
describe("validateVariables", () => {
@@ -35,4 +43,25 @@ describe("deployment-utils", () => {
3543
expect(result).toContain("No outputs defined");
3644
});
3745
});
46+
47+
describe("inferProjectType", () => {
48+
it("detects SAM projects via samconfig.toml", async () => {
49+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ls-mcp-samcfg-"));
50+
fs.writeFileSync(path.join(dir, "samconfig.toml"), "version = 0.1");
51+
52+
await expect(inferProjectType(dir)).resolves.toBe("sam");
53+
fs.rmSync(dir, { recursive: true, force: true });
54+
});
55+
56+
it("detects SAM projects via template with AWS::Serverless resources", async () => {
57+
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "ls-mcp-samtpl-"));
58+
fs.writeFileSync(
59+
path.join(dir, "template.yaml"),
60+
"Resources:\n MyFunction:\n Type: AWS::Serverless::Function\n"
61+
);
62+
63+
await expect(inferProjectType(dir)).resolves.toBe("sam");
64+
fs.rmSync(dir, { recursive: true, force: true });
65+
});
66+
});
3867
});

src/lib/deployment/deployment-utils.ts

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,24 @@ export interface DependencyCheckResult {
99
errorMessage?: string;
1010
}
1111

12-
export type ProjectType = "cdk" | "terraform" | "cloudformation" | "ambiguous" | "unknown";
12+
export type ProjectType =
13+
| "cdk"
14+
| "terraform"
15+
| "sam"
16+
| "cloudformation"
17+
| "ambiguous"
18+
| "unknown";
1319

1420
/**
1521
* Check if the required deployment tool (cdklocal or tflocal) is available in the system PATH
1622
* @param projectType The type of project requiring either 'cdk' or 'terraform' tooling
1723
* @returns Promise with availability status and tool information
1824
*/
1925
export async function checkDependencies(
20-
projectType: "cdk" | "terraform"
26+
projectType: "cdk" | "terraform" | "sam"
2127
): Promise<DependencyCheckResult> {
22-
const tool = projectType === "cdk" ? "cdklocal" : "tflocal";
28+
const tool =
29+
projectType === "cdk" ? "cdklocal" : projectType === "terraform" ? "tflocal" : "samlocal";
2330

2431
try {
2532
const { stdout, error } = await runCommand(tool, ["--version"], { timeout: 10000 });
@@ -42,15 +49,25 @@ Installation:
4249
npm install -g aws-cdk-local aws-cdk
4350
4451
After installation, make sure the 'cdklocal' command is available in your PATH.`
45-
: `❌ tflocal is not installed or not available in PATH.
52+
: projectType === "terraform"
53+
? `❌ tflocal is not installed or not available in PATH.
4654
4755
Please install terraform-local by following the official documentation:
4856
https://github.com/localstack/terraform-local
4957
5058
Installation:
5159
pip install terraform-local
5260
53-
After installation, make sure the 'tflocal' command is available in your PATH.`;
61+
After installation, make sure the 'tflocal' command is available in your PATH.`
62+
: `❌ samlocal is not installed or not available in PATH.
63+
64+
Please install aws-sam-cli-local by following the official documentation:
65+
https://github.com/localstack/aws-sam-cli-local
66+
67+
Installation:
68+
pip install aws-sam-cli-local
69+
70+
After installation, make sure the 'samlocal' command is available in your PATH.`;
5471

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

87-
const hasCloudFormationTemplates = files.some(
88-
(file) => file.endsWith(".yaml") || file.endsWith(".yml")
89-
);
104+
const hasTemplateYaml = files.includes("template.yaml") || files.includes("template.yml");
105+
const hasSamConfig = files.includes("samconfig.toml");
106+
107+
let hasServerlessResources = false;
108+
if (hasTemplateYaml) {
109+
const samTemplateFile = files.includes("template.yaml") ? "template.yaml" : "template.yml";
110+
try {
111+
const templateContent = await fs.promises.readFile(path.join(directory, samTemplateFile), "utf-8");
112+
hasServerlessResources = /AWS::Serverless::[A-Za-z]+/.test(templateContent);
113+
} catch {
114+
hasServerlessResources = false;
115+
}
116+
}
117+
118+
const hasCloudFormationTemplates = files.some((file) => file.endsWith(".yaml") || file.endsWith(".yml"));
90119

91120
const isCdk = hasCdkJson || hasCdkFiles;
92121
const isTerraform = hasTerraformFiles;
93-
const isCloudFormation = hasCloudFormationTemplates;
122+
const isSam = hasSamConfig || hasServerlessResources;
123+
const isCloudFormation = hasCloudFormationTemplates && !isSam;
94124

95125
if (
96-
[isCdk, isTerraform, isCloudFormation].filter(Boolean).length > 1
126+
[isCdk, isTerraform, isSam, isCloudFormation].filter(Boolean).length > 1
97127
) {
98128
return "ambiguous";
99129
} else if (isCdk) {
100130
return "cdk";
101131
} else if (isTerraform) {
102132
return "terraform";
133+
} else if (isSam) {
134+
return "sam";
103135
} else if (isCloudFormation) {
104136
return "cloudformation";
105137
} else {

0 commit comments

Comments
 (0)