sh-mcp/README.md
Adam Moussa 1bfa2a85c9
ci(deploy): switch deploy trigger from push-to-main to manual workflow_dispatch (#39)
Remove the push-to-main trigger from .github/workflows/deploy.yaml so merges
no longer deploy automatically; deploys now run only via the Actions "Run
workflow" button (workflow_dispatch). No job content, permissions, or
reusable-workflow inputs changed. README and the auth deploy runbook updated
to match.
2026-07-28 16:29:49 +00:00

7.1 KiB

sh-mcp

CI TypeScript Node AWS CDK Slack

Sea Haven MCP platform. A TypeScript monorepo of trust-tiered MCP servers that expose Sea Haven's proprietary integrations as tools, plus the Cognito/Google auth broker and the rebuilt scheduled jobs. This service replaces seahaven-slack-bot and exec-aide, which are deprecated completely; the conversational surface becomes a configurable Slack task agent.

Status: BUILDING. Platform + auth substrate built; nothing deployed to AWS yet. Phase 0b (monorepo + @sh-mcp/shared core), Phase 1 (runnable sh-mcp-ops / sh-mcp-finance over MCP + OpenAPI), and Phase 2a (the Cognito auth substrate CDK stack + pre-token/group-sync Lambdas) are on main. The servers run locally (SH_MCP_ENV=local); SH_MCP_ENV=aws is wired but not yet deployed. The authoritative spec is docs/design.md.

Documentation

The canonical map of Sea Haven's AWS infrastructure lives in Confluence. This project's sh-mcp-auth, sh-mcp-ops, and sh-mcp-finance stacks are represented there as Mermaid subgraphs.

Infrastructure (CDK app)

All AWS infrastructure is defined as code with the AWS CDK (TypeScript, aws-cdk-lib pinned in package.json). The repo root is the CDK app: cdk.json is the app config and points the CDK CLI at the app entry point.

// cdk.json
{
  "app": "tsx infra/bin/app.ts", // entry point (run with tsx, no pre-compile)
  "output": "cdk.out",           // synth output dir (git-ignored)
  "context": { "@aws-cdk/core:newStyleStackSynthesis": true }
}
  • Entry point — infra/bin/app.ts constructs the App and instantiates the stacks. Every stack sets an explicit kebab-case stackName and pins env to account 328440206208 / us-east-1, so synth needs no AWS credentials (shared CMKs are referenced by ARN, not fromLookup).
  • Stacks — infra/lib/. Currently one: ShMcpAuthStack → sh-mcp-auth (the Cognito auth substrate, detailed below). The per-tier sh-mcp-ops / sh-mcp-finance hosting stacks join the same app in Phase 2b. The Lambda handler source the stacks bundle lives in auth/ (and later servers/ / jobs/), not under infra/.
  • Deploy-time context — the app reads two optional -c context inputs: callbackUrls (per-tier OAuth callback URLs; defaults to a placeholder until the conversational surface is chosen) and logsKmsArn (the alias/seahaven-logs CMK for the Lambda log groups; AWS-managed encryption is used if absent).
# from the repo root
npm ci
npx cdk synth                         # synthesize CloudFormation into cdk.out/
npx cdk diff  sh-mcp-auth             # preview changes against the deployed stack
npx cdk deploy sh-mcp-auth \
  -c logsKmsArn=<cmk-arn> \
  -c callbackUrls='["https://…/oauth/callback"]'

CI runs npx cdk synth at the repo root on every PR (the ci-typescript-cdk reusable workflow with run-cdk-synth: true); deploys are triggered manually (Actions → deploy → Run workflow on main, i.e. workflow_dispatch) via the cd-cdk reusable workflow over the per-repo githubdeploy-sh-mcp OIDC role. Nothing is deployed to AWS yet — see status above.

Auth substrate (Phase 2a — infra/ + auth/)

infra/ is the root CDK app; cdk synth builds the sh-mcp-auth stack: a Google-federated Cognito user pool (ESSENTIALS feature plan), per-tier app clients whose AllowedOAuthScopes are the trust-tier boundary (sh-agentforce-ops / -finance / -exec), a suppress-only V2 pre-token Lambda (auth/pre-token-gen), a 5-minute group-sync Lambda (auth/group-sync), and the sync-state + deny-list tables.

Revocation has two layers. Group membership (Google → Cognito, 5-min cadence) is the primary entitlement control, with a fail-closed 30-minute freshness window: if group-sync stalls, the pre-token Lambda drops every caller to base ops:read. The sh-mcp-deny-list table is a hard-kill overlay the pre-token Lambda consults on every mint — a sub listed there is stripped to no tier scopes immediately (TTL-expiring), ahead of the next sync. The deny-list read is fail-open (a DynamoDB blip logs deny_list_read_failed and does not lock everyone out, since group membership + its fail-closed window remain authoritative). The finance app client additionally caps its refresh token at 8h (vs 30d for ops/exec) so a stolen finance refresh token cannot ride past the short access-token TTL for a month.

Deploy is gated on two manual prerequisites (owner: Adam):

  1. Google Cloud OAuth 2.0 web client (Cognito federation) → Secrets Manager sh-mcp/google-oidc ({client_id, client_secret}).
  2. Google Workspace service account w/ domain-wide delegation (Directory groups.readonly) → Secrets Manager sh-mcp/google-directory-sa.

App-client OAuth callback URLs are a placeholder (-c callbackUrls=...) until the conversational surface (Agentforce vs Bolt) is chosen — the substrate is surface-agnostic. The optional alias/seahaven-logs CMK for the Lambda log groups is supplied at deploy via -c logsKmsArn=....

Shape (planned)

  • MCP servers (trust-tiered, remote HTTP, per-server IAM):
    • sh-mcp-ops — read-mostly, agent-facing (WO/PO/site lookups, KB search, Google Maps, Gmail/Calendar, tasks, reminders).
    • sh-mcp-finance — sensitive, read-only, audited (QBO vendor search, payment lookups).
    • sh-mcp-physical — DEFERRED, admin/out-of-band only (Lenel/Yealink/3CX control).
  • Auth — Google Workspace is the single IdP; an Amazon Cognito user pool federated to Google issues scoped, audience-bound JWTs; group → scope mapping via a pre-token Lambda. See design §2.
  • Jobs — rebuilt proactive Lambdas (email classify/digest, KB syncs).
  • Language — TypeScript everywhere (servers, packages, CDK, jobs).

Open decisions

  • Task-agent surface: Agentforce (recommended) vs marketplace Claude app vs custom Bolt assistant (design §12). Drives the model + guardrail story.
  • Endpoint exposure specifics (Slack egress ranges / WAF) — design §9 / §11.

Layout (target)

cdk.json    CDK app config (app → infra/bin/app.ts)
infra/      CDK app: bin/app.ts entry + lib/ stack definitions
packages/   shared + one package per integration
servers/    sh-mcp-ops, sh-mcp-finance  (CDK stacks)
auth/       cognito, pre-token-lambda, group-sync-lambda
jobs/       rebuilt scheduled Lambdas
docs/       design.md  (the canonical plan)

See docs/design.md for the authoritative spec.