Skip to main content
Glama

slack-mcp

An AWS-native MCP server that posts to Slack (post_to_slack, post_file_to_slack), reachable via an Amazon Bedrock AgentCore Gateway.

Today's one caller: daily-tech-brief-bedrock's Bedrock Converse API tool-use loop, replacing its vendored, stdio-spawned copy of a Node.js slack-poster MCP server. This is deliberately scoped to AI callers that decide mid-reasoning to invoke a tool — a packaged automation with no LLM in its trigger path (e.g. a website's deploy/signup notifications) has no use for MCP here and should keep calling a plain Slack incoming webhook instead. See the tool logic's origin and the scope decision in the project's own history for the full reasoning.

Architecture

AWS-internal AI caller (Bedrock Converse tool-use loop, SigV4-signed via
IAM — e.g. mcp-proxy-for-aws's aws_iam_streamablehttp_client)
        |
        v
AgentCore Gateway (authorizer_type = AWS_IAM, protocol_type = MCP)
        |
        v
API Gateway HTTP API (route auth = AWS_IAM, AWS_PROXY integration)
        |
        v
Lambda (container image, Python 3.13) -- FastMCP streamable-HTTP server
wrapped for Lambda via Mangum
        |
        v
Slack Web API (chat.postMessage, using a Bot Token from Secrets Manager)

No VPC Link, ALB, or ECS hop, unlike the sibling CoreSample repo's ec2-audit-mcp (which runs on Fargate) — API Gateway integrates with a Lambda directly, and this tool's actual workload (one outbound HTTPS POST to Slack) doesn't need a always-on container.

Related MCP server: Slack Notify MCP

Repository layout

server/
  handler.py       Lambda entrypoint: FastMCP app (post_to_slack,
                    post_file_to_slack tools) wrapped for Lambda via Mangum
  slack_tools.py    Pure Slack-posting logic, ported from
                    daily-tech-brief-bedrock's vendored slack_mcp_server/index.js
  Dockerfile
  requirements.txt
terraform/
  lambda.tf           ECR repo, Lambda (container image), IAM execution role
  secrets.tf          Looks up the existing daily-tech-brief-bedrock Slack
                       bot token secret (reused, not duplicated)
  api_gateway.tf       HTTP API, AWS_PROXY integration, AWS_IAM route auth
  agentcore_gateway.tf AgentCore Gateway + target
  deploy_policy.tf     Dedicated deploy IAM user + managed policy, shared
                        by CI's OIDC role (see "Deploy identity" below)
  versions.tf / variables.tf / outputs.tf
tests/               pytest unit tests (mocked Slack API calls, no network)
.github/workflows/test.yml     CI gate: ruff/mypy/pytest + terraform fmt/validate
.github/workflows/deploy.yml   Auto-triggered on push to main

Current status

Live and deployed. Full CI/CD path proven end-to-end: feature branch → PR → passing test CI → merge to main → auto-triggered deploy.yml via GitHub OIDC → terraform apply → image build/push → Lambda update.

  • Lambda: slack-mcp (container image, Python 3.13)

  • API Gateway HTTP API: https://8gr00zm4d9.execute-api.us-west-2.amazonaws.com/

  • AgentCore Gateway: arn:aws:bedrock-agentcore:us-west-2:293528978619:gateway/slack-mcp-cp2plvgahi, target status READY

See CLAUDE.md for the required PR workflow and the deploy-identity/RBAC setup, and the project's vault note for the architecture decisions this was built against (validated directly against CoreSample's deployed-and-verified AgentCore Gateway pattern, not guessed from docs).

Local verification

pip install -r server/requirements.txt -r requirements-dev.txt
ruff check server tests
mypy server
pytest

cd terraform && terraform fmt -check -recursive . && terraform init -backend=false && terraform validate

One-time setup (already done for this stack; kept for reference/re-bootstrap)

  1. Bootstrap the Terraform state bucket (slack-mcp-tfstate-<account-id>), same out-of-band process as CoreSample/daily-tech-brief-bedrock.

  2. No token setup needed — this stack reads the existing daily-tech-brief-bedrock/slack-bot-token Secrets Manager secret rather than provisioning its own.

  3. Bootstrap the deploy identities by hand (deliberately outside Terraform for the OIDC role — see CLAUDE.md "Deploy identity / RBAC"):

    • Create the slack-mcp-deploy IAM user.

    • Create the slack-mcp-github-deploy IAM role with a trust policy scoped to this repo via GitHub's OIDC provider (repository_id condition + wildcard sub match, not a literal repo-name string — see CLAUDE.md for why).

    • Set the AWS_DEPLOY_ROLE_ARN GitHub Actions repo secret to that role's ARN.

  4. terraform init && terraform apply (as the slack-mcp-deploy user) to create the ECR repo and everything else, including aws_iam_policy.deploy and its attachment to both identities from step 3, then build and push the Lambda image (docker build -f server/Dockerfile -t <ecr-repo>:latest . && docker push ...), then terraform apply again so the Lambda's image_uri resolves. From then on, every merge to main re-runs this automatically via .github/workflows/deploy.yml.

  5. Grant the calling project's execution role bedrock-agentcore:InvokeGateway on this stack's agentcore_gateway_arn output.

Related MCP Connectors

Related MCP Servers