Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Infrastructure as Code for managing access to MCP community resources using Pulu
- **Google Workspace Groups**: Automatically syncs group memberships for @modelcontextprotocol.io email accounts
- **Email Groups**: Groups with `isEmailGroup: true` accept emails from anyone (including external users) and notify all members. External posts are moderated for security.
- **Google Workspace User Accounts**: Provisions @modelcontextprotocol.io accounts for members of roles with `provisionUser: true` (directly, or via a role nested under one through `github.parent` — e.g. SDK teams under `sdk-maintainers`, working groups under `working-groups`)
- **Discord**: Syncs the Discord roles declared in [`src/config/roles.ts`](src/config/roles.ts) to the members' Discord IDs in `users.ts`, and manages the settings of the channels declared in [`src/config/channels.ts`](src/config/channels.ts), including thread-only forum/media channels. See [Discord channels](#discord-channels) below.
- **Cloudflare Access (security-room)**: Syncs the Cloudflare Zero Trust Access policy that decides who can sign in to `securityroom.modelcontextprotocol.io` from the roles declared in [`src/config/accessPolicies.ts`](src/config/accessPolicies.ts). See [Cloudflare Access (security-room)](#cloudflare-access-security-room) below.
- **npm & PyPI Package Publishing Access** (declared, not applied): Expected registry access is declared in [`src/config/packageAccess.ts`](src/config/packageAccess.ts) and drift against the live npm registry is detected by CI — but changes are applied manually by a maintainer. See [npm & PyPI Package Publishing Access](#npm--pypi-package-publishing-access) below for why and how.

Expand Down Expand Up @@ -61,6 +62,31 @@ The PR's `pulumi preview` comment shows the repository create. Once merged, the
- The `repository` key of a managed entry is also the Pulumi resource name. Renaming it in place archives the old repository and creates a new one. To rename, do three things in order: rename the repository on GitHub, rename the resources in state with `pulumi state rename` (`repository-<old>` to `repository-<new>`, and `repo-<old>` to `repo-<new>`), then change the key.
- A repository archived by hand in GitHub stays archived (`archived` is ignored on refresh); un-archiving is a manual org-owner action.

## Discord channels

Channels listed in [`src/config/channels.ts`](src/config/channels.ts) are managed by the `DiscordChannel` resource in [`src/discord.ts`](src/discord.ts), using the same `discord:botToken`/`discord:guildId` stack config as the role sync (the bot needs the **Manage Channels** permission in the guild, plus **View Channel** on any private channel you adopt; creating `forum`/`media` channels requires the guild's Community feature). Each entry is either an **existing channel adopted by its ID** or a **new channel created on deploy**:

```ts
// Adopt an existing channel by ID: the declared settings are enforced in place,
// anything not declared (here, the name) is left as it is on Discord
{ id: '1234567890123456789', type: 'text', rateLimitPerUser: 5 },

// Create a thread-only forum channel
{
name: 'sdk-help',
type: 'forum',
requireTag: true,
availableTags: [{ name: 'typescript' }, { name: 'python' }, { name: 'answered', moderated: true }],
defaultSortOrder: 'latest_activity',
},
```

- **Thread-only channels are a channel type, not a setting.** Discord has no "require threads" switch; thread-only behaviour exists only as `forum` and `media` channels, and the API cannot convert a text channel into one. To make an existing channel thread-only, declare a new `forum`/`media` channel (without `id`) and retire the old channel by hand. Declaring `type: 'forum'` on the `id` of a text channel fails the deploy with an error saying so.
- **Channels are never deleted.** Removing an entry only drops the resource from Pulumi state; the channel and its history stay on Discord. Changing an entry's `id` or `type` likewise adopts/creates the new channel and leaves the old one alone.
- Only declared settings are managed. `name` is required when creating a channel and optional when adopting one by `id`; declare it only if you want it enforced. Validation (`npm run check`) rejects a missing name on a new channel, names outside 1-100 characters, topics over Discord's limit (1024 for text, 4096 for forum/media), malformed snowflakes, duplicate entries, more than 20 tags, `requireTag` with no tags to pick from, and forum/media settings on text channels (`defaultForumLayout` is forum-only). It prints a `WARNING:` without failing for names with uppercase letters or spaces (Discord normalizes those, so the declared name would never match) and for `requireTag` on an adopted channel that declares no `availableTags` (it relies on the tags already on Discord; the deploy fails if there are none).
- `position` is applied on creation only. Discord renumbers positions whenever channels move, so it is not checked or re-applied afterwards; reorder channels in Discord.
- Settings changed by hand in Discord show up as drift on refresh and are reverted by the next deploy (`make up` runs `pulumi up --refresh`). Channel creates and updates carry `X-Audit-Log-Reason: modelcontextprotocol/access deploy`, so the guild's audit log shows where a change came from.

## Cloudflare Access (security-room)

[securityroom.modelcontextprotocol.io](https://securityroom.modelcontextprotocol.io) is protected by Cloudflare Zero Trust Access with GitHub as the identity provider. The reusable Access policy `Maintainers` that grants sign-in is managed from this repo by [`src/cloudflare.ts`](src/cloudflare.ts), driven by [`src/config/accessPolicies.ts`](src/config/accessPolicies.ts):
Expand Down
Loading
Loading