- TypeScript 99.1%
- Makefile 0.8%
- Nix 0.1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
* Declare allowExternalMembers on managed group settings Every pulumi up was resetting the Google Workspace per-group setting ALLOW_EXTERNAL_MEMBERS to false on all managed groups, because the GroupSettings resources never declared allowExternalMembers and the provider (SamuZad/googleworkspace 0.11.1) defaults the field to false. Google then silently purges external-email members from affected groups roughly 1-2 days after each apply, with no audit events. Pin the setting to true for all managed groups. External membership itself remains governed exclusively by config/users.ts entries; this setting only permits it. Part of the #133 incident. * Scope allowExternalMembers per group, derived from membership config Instead of permitting external members on every managed group, derive allowExternalMembers per group: true only for groups whose membership config (config/users.ts) resolves at least one member to a non-@modelcontextprotocol.io email. Email resolution is factored into resolveGoogleMemberEmail and shared with GroupMember creation so the two cannot drift. The field stays declared on every group because the provider defaults it to false on each apply, after which Google silently purges external members (#133 incident). With current config, exactly these groups derive true: maintainers, registry-wg, antitrust, catch-all. A config test pins this set so changes to it are always deliberate. * Make allowExternalMembers an explicit per-role opt-in with config validation Replace the derived per-group allowExternalMembers (computed from membership config) with an explicit opt-in: group owners set allowExternalMembers: true on the role's google config in src/config/roles.ts, and src/google.ts passes it straight through to GroupSettings (defaulting to false). The field stays declared on every group because the provider resets an omitted field to false on each apply, after which Google silently purges external members (#133). Roles opting in, matching current membership: maintainers, registry-maintainers (registry-wg), antitrust, catch-all. A validate-config check replaces the old pinned-set test: it fails with an actionable error whenever a group has a member resolving to a non-@modelcontextprotocol.io email but its role does not opt in, naming the group, the member email, and the exact config line to add. Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
| .github | ||
| scripts | ||
| src | ||
| .gitignore | ||
| .pre-commit-config.yaml | ||
| .prettierignore | ||
| .prettierrc | ||
| devenv.nix | ||
| Makefile | ||
| package-lock.json | ||
| package.json | ||
| Pulumi.prod.yaml | ||
| Pulumi.yaml | ||
| README.md | ||
| tsconfig.json | ||
MCP Access Management
Infrastructure as Code for managing access to MCP community resources using Pulumi.
- Define groups in
src/config/groups.ts - Add users to groups in
src/config/users.ts - Changes are applied via GitHub Actions when merged to the main branch
What This Manages
- GitHub Teams: Automatically syncs team memberships in the MCP GitHub organization
- Google Workspace Groups: Automatically syncs group memberships for @modelcontextprotocol.io email accounts
- Email Groups: Groups with
isEmailGroup: trueaccept emails from anyone (including external users) and notify all members. External posts are moderated for security.
- Email Groups: Groups with
- Google Workspace User Accounts: Provisions @modelcontextprotocol.io accounts for members of roles with
provisionUser: true
Opting in to a Google Workspace account (maintainers)
If you're a maintainer and want an @modelcontextprotocol.io account, open a PR adding the following fields to your entry in src/config/users.ts:
{
github: 'your-github-username',
// ...
firstName: 'Your',
lastName: 'Name',
googleEmailPrefix: 'yourname', // -> yourname@modelcontextprotocol.io
memberOf: [ROLE_IDS.MAINTAINERS /* , ... */],
},
Once merged, Pulumi provisions the account. An admin will share your initial password (retrievable via pulumi stack output --show-secrets newGWSUserPasswords).
Deployment
Production Deployment (Automated)
Note: Production deployment is automatically handled by GitHub Actions. All merges to the main branch trigger an automatic deployment via the configured GitHub Actions workflow.
Manual Deployment
Pre-requisites:
- Pulumi CLI installed
- Google Cloud SDK installed
- Access to GCP project and GCS bucket
- Required credentials and secrets
- Authenticate with GCP:
gcloud auth application-default login - Get the passphrase file
passphrase.prod.txtfrom the maintainers - Preview changes:
make preview - Deploy changes:
make up
Key Management
Required GitHub Secrets (for CI/CD)
The following secrets must be configured in GitHub Actions for automated deployments:
-
GCP_PROD_SERVICE_ACCOUNT_KEY: GCP service account key- Used to authenticate with Google Cloud Storage for Pulumi state (
gs://mcp-access-prod-pulumi-state) - Should be a JSON key file for a service account with Storage Admin permissions
- See "Setting Up GCS Backend" below for setup instructions
- Used to authenticate with Google Cloud Storage for Pulumi state (
-
PULUMI_PROD_PASSPHRASE: Passphrase for encrypting Pulumi state- Used to decrypt encrypted values in Pulumi stack configuration
- Keep this secure - if lost, you cannot decrypt your Pulumi state
Initial Setup
If setting up this infrastructure for the first time:
1. Set Up Service Account
# Create project and enable APIs
gcloud projects create mcp-access-prod
gcloud config set project mcp-access-prod
gcloud services enable storage.googleapis.com
gcloud services enable admin.googleapis.com
gcloud services enable groupssettings.googleapis.com
# Create service account
gcloud iam service-accounts create pulumi-svc \
--display-name="MCP Access Management Service Account" \
--description="Service account for Pulumi state and Google Workspace management"
# Grant storage admin permissions (for Pulumi state)
gcloud projects add-iam-policy-binding mcp-access-prod \
--member="serviceAccount:pulumi-svc@mcp-access-prod.iam.gserviceaccount.com" \
--role="roles/storage.admin"
# Create key
gcloud iam service-accounts keys create sa-key.json \
--iam-account=pulumi-svc@mcp-access-prod.iam.gserviceaccount.com
# Create GCS bucket for Pulumi state
gsutil mb gs://mcp-access-prod-pulumi-state
Then:
- In Google Workspace Admin Console, go to Account → Admin roles
- Select Groups Admin role (or create a custom role with these privileges):
- Read, create, update, and delete groups
- Read and update group members
- Click Assign service accounts
- Add your service account email:
pulumi-svc@mcp-access-prod.iam.gserviceaccount.com
2. Initialize Pulumi Stack
# Login to Pulumi backend (GCS)
pulumi login gs://mcp-access-prod-pulumi-state
# Create production stack
export PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt
pulumi stack init prod
# Configure application secrets in Pulumi
pulumi config set --secret googleworkspace:credentials "$(cat sa-key.json)"
pulumi config set --secret github:token "ghp_your_github_token_here"
3. Configure GitHub Actions Secrets
Add the CI/CD secrets to GitHub Actions (repository settings → Secrets and variables → Actions):
GCP_PROD_SERVICE_ACCOUNT_KEY: Content ofsa-key.jsonPULUMI_PROD_PASSPHRASE: The passphrase you set above