Skip to content

Commit d1e2ba6

Browse files
committed
Initial commit
0 parents  commit d1e2ba6

File tree

16 files changed

+3855
-0
lines changed

16 files changed

+3855
-0
lines changed

.github/workflows/ci.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
build:
12+
name: Build and Typecheck
13+
runs-on: ubuntu-latest
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Setup Node.js
19+
uses: actions/setup-node@v4
20+
with:
21+
node-version: '22'
22+
cache: 'npm'
23+
24+
- name: Install dependencies
25+
run: npm ci
26+
27+
- name: Build
28+
run: npm run build

.github/workflows/deploy.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Deploy
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
permissions:
9+
contents: read
10+
11+
env:
12+
PULUMI_VERSION: "3.197.0"
13+
14+
jobs:
15+
deploy-production:
16+
name: Deploy to Production
17+
runs-on: ubuntu-latest
18+
environment: production
19+
concurrency:
20+
group: deploy-production
21+
cancel-in-progress: false
22+
steps:
23+
- name: Checkout code
24+
uses: actions/checkout@v4
25+
26+
- name: Setup Node.js
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: '22'
30+
cache: 'npm'
31+
32+
- name: Install dependencies
33+
run: npm ci
34+
35+
- name: Build
36+
run: npm run build
37+
38+
- name: Setup Pulumi
39+
uses: pulumi/actions@v6
40+
with:
41+
pulumi-version: ${{ env.PULUMI_VERSION }}
42+
43+
- name: Authenticate to Google Cloud
44+
uses: google-github-actions/auth@v2
45+
with:
46+
credentials_json: ${{ secrets.GCP_PROD_SERVICE_ACCOUNT_KEY }}
47+
48+
- name: Deploy to Production
49+
run: make up

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
node_modules/
2+
bin/
3+
*.log
4+
5+
# Pulumi
6+
.pulumi/
7+
Pulumi.*.yaml.bak
8+
sdks
9+
10+
# Secrets
11+
passphrase.prod.txt
12+
sa-key.json

Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
.PHONY: help login preview up
2+
3+
# Default target
4+
help: ## Show this help message
5+
@echo "Available targets:"
6+
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " %-20s %s\n", $$1, $$2}'
7+
8+
# Production stack commands
9+
login: ## Login to Pulumi backend (GCS)
10+
pulumi login gs://mcp-access-prod-pulumi-state
11+
12+
preview: login ## Preview infrastructure changes
13+
PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi preview --stack prod
14+
15+
up: login ## Deploy infrastructure
16+
PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt pulumi up --yes --stack prod

Pulumi.prod.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
encryptionsalt: v1:N7wjHl1hvH8=:v1:VT8UbYOIS0kNADr5:fSnvGX+is6htXDjLS03RDObRnzGEVA==
2+
config:
3+
googleworkspace:customerId: C01dja0mo
4+
googleworkspace:credentials:
5+
secure: v1:Ntr2su0kgwp0oAh3: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
6+
github:owner: modelcontextprotocol
7+
github:token:
8+
secure: v1:RKjKUcq1e0V7kVNf:5PP+vWbnRzgX8MmhF/yp52Fh78cTMBYz798JNc9LiyrubSt4AAZH/y/UA6kErP0FmXfFLRpdDIMmrR3RiNQlCe7nbkB6hf0CsV8mg8U7oB0EkA5wnRlqrZaKBri5l5puy2ZBFWjLhHr6oC714A==

Pulumi.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: mcp-access
2+
runtime: nodejs
3+
description: Infrastructure as Code for MCP access management
4+
packages:
5+
googleworkspace:
6+
source: terraform-provider
7+
version: 0.14.0
8+
parameters:
9+
- hashicorp/googleworkspace

README.md

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# MCP Access Management
2+
3+
Infrastructure as Code for managing access to MCP community resources using Pulumi.
4+
5+
- Define groups in [`src/config/groups.ts`](src/config/groups.ts)
6+
- Add users to groups in [`src/config/users.ts`](src/config/users.ts)
7+
- Changes are applied via GitHub Actions when merged to the main branch
8+
9+
## What This Manages
10+
11+
- **GitHub Teams**: Automatically syncs team memberships in the MCP GitHub organization
12+
- **Google Workspace Groups**: Automatically syncs group memberships for @modelcontextprotocol.io email accounts
13+
14+
## Deployment
15+
16+
### Production Deployment (Automated)
17+
18+
**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](.github/workflows/deploy.yml).
19+
20+
### Manual Deployment
21+
22+
Pre-requisites:
23+
- [Pulumi CLI installed](https://www.pulumi.com/docs/iac/download-install/)
24+
- [Google Cloud SDK installed](https://cloud.google.com/sdk/docs/install)
25+
- Access to GCP project and GCS bucket
26+
- Required credentials and secrets
27+
28+
1. Authenticate with GCP: `gcloud auth application-default login`
29+
2. Get the passphrase file `passphrase.prod.txt` from the maintainers
30+
3. Preview changes: `make preview`
31+
4. Deploy changes: `make up`
32+
33+
## Key Management
34+
35+
### Required GitHub Secrets (for CI/CD)
36+
37+
The following secrets must be configured in GitHub Actions for automated deployments:
38+
39+
- **`GCP_PROD_SERVICE_ACCOUNT_KEY`**: GCP service account key
40+
- Used to authenticate with Google Cloud Storage for Pulumi state (`gs://mcp-access-prod-pulumi-state`)
41+
- Should be a JSON key file for a service account with Storage Admin permissions
42+
- See "Setting Up GCS Backend" below for setup instructions
43+
44+
- **`PULUMI_PROD_PASSPHRASE`**: Passphrase for encrypting Pulumi state
45+
- Used to decrypt encrypted values in Pulumi stack configuration
46+
- Keep this secure - if lost, you cannot decrypt your Pulumi state
47+
48+
## Initial Setup
49+
50+
If setting up this infrastructure for the first time:
51+
52+
### 1. Set Up Service Account
53+
54+
```bash
55+
# Create project and enable APIs
56+
gcloud projects create mcp-access-prod
57+
gcloud config set project mcp-access-prod
58+
gcloud services enable storage.googleapis.com
59+
gcloud services enable admin.googleapis.com
60+
gcloud services enable groupssettings.googleapis.com
61+
62+
# Create service account
63+
gcloud iam service-accounts create pulumi-svc \
64+
--display-name="MCP Access Management Service Account" \
65+
--description="Service account for Pulumi state and Google Workspace management"
66+
67+
# Grant storage admin permissions (for Pulumi state)
68+
gcloud projects add-iam-policy-binding mcp-access-prod \
69+
--member="serviceAccount:[email protected]" \
70+
--role="roles/storage.admin"
71+
72+
# Create key
73+
gcloud iam service-accounts keys create sa-key.json \
74+
75+
76+
# Create GCS bucket for Pulumi state
77+
gsutil mb gs://mcp-access-prod-pulumi-state
78+
```
79+
80+
Then:
81+
1. In Google Workspace Admin Console, go to **Account****Admin roles**
82+
2. Select **Groups Admin** role (or create a custom role with these privileges):
83+
- Read, create, update, and delete groups
84+
- Read and update group members
85+
3. Click **Assign service accounts**
86+
4. Add your service account email: `[email protected]`
87+
88+
### 2. Initialize Pulumi Stack
89+
90+
```bash
91+
# Login to Pulumi backend (GCS)
92+
pulumi login gs://mcp-access-prod-pulumi-state
93+
94+
# Create production stack
95+
export PULUMI_CONFIG_PASSPHRASE_FILE=passphrase.prod.txt
96+
pulumi stack init prod
97+
98+
# Configure application secrets in Pulumi
99+
pulumi config set --secret googleworkspace:credentials "$(cat sa-key.json)"
100+
pulumi config set --secret github:token "ghp_your_github_token_here"
101+
```
102+
103+
### 3. Configure GitHub Actions Secrets
104+
105+
Add the CI/CD secrets to GitHub Actions (repository settings → Secrets and variables → Actions):
106+
- `GCP_PROD_SERVICE_ACCOUNT_KEY`: Content of `sa-key.json`
107+
- `PULUMI_PROD_PASSPHRASE`: The passphrase you set above

0 commit comments

Comments
 (0)