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
5 changes: 5 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,10 @@ assignees: ''
## Environment

- Version:
- Node.js and npm versions:
- MCP client:
- OS:

## Logs or Diagnostics

<!-- Remove bot tokens, webhook URLs, invite codes, and private guild data. -->
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: Security report
url: https://mikesoft.it
url: https://github.com/TheStreamCode/discord-management-mcp/security/advisories/new
about: Please report sensitive vulnerabilities privately.
15 changes: 11 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,17 @@ Fixes #

## Testing

- [ ] `npm run check` passes
- [ ] Tested mutation guard with a real Discord server
- [ ] Tested backup/restore flow end-to-end
- [ ] `npm run preflight` passes
- [ ] `npm run pack:check` passes when package or release files changed
- [ ] Added or updated regression tests for changed behavior
- [ ] No live Discord mutation was required, or the authorized test guild and result are documented below
- [ ] Backup/restore changes were exercised end-to-end with mocks or an authorized test guild

## Release impact

- [ ] `CHANGELOG.md` updated when user-visible behavior changed
- [ ] Package version remains unchanged, or release metadata is consistent

## Notes

-
-
36 changes: 34 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,22 @@ on:
permissions:
contents: read

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-test:
name: build-and-test
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@v7
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24
cache: npm
Expand All @@ -30,15 +35,42 @@ jobs:
- name: Typecheck
run: npm run typecheck

- name: Lint
run: npm run lint

- name: Test
run: npm test

- name: Build
run: npm run build

- name: Verify npm package
run: npm run pack:check

# Gate on high/critical only. A plain `npm audit --omit=dev` exits non-zero
# for *any* advisory in the tree, which deadlocked the repo: every Dependabot
# PR stayed red because of the vulnerabilities it wasn't fixing, so no PR
# could ever go green and none of them could be merged.
- name: Runtime dependency audit
run: npm audit --omit=dev --audit-level=high

windows-test:
name: windows-test
runs-on: windows-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Setup Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24
cache: npm

- name: Install dependencies
run: npm ci

- name: Check
run: npm run check
49 changes: 49 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: Publish to npm

on:
release:
types:
- published

permissions:
contents: read
id-token: write

concurrency:
group: npm-${{ github.event.release.tag_name }}
cancel-in-progress: false

jobs:
publish:
name: publish
runs-on: ubuntu-latest
timeout-minutes: 15

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Setup Node.js
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
with:
node-version: 24
registry-url: https://registry.npmjs.org/
package-manager-cache: false

- name: Install dependencies
run: npm ci

- name: Verify source, tests, and build
run: npm run preflight

- name: Verify release metadata
run: npm run release:check
env:
RELEASE_TAG: ${{ github.event.release.tag_name }}

- name: Publish with provenance
run: npm publish --access public --provenance
env:
# Needed only to bootstrap the first publication. Remove the secret
# after configuring npm Trusted Publishing for this workflow.
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ coverage/
!.env.example
backups/
*.log

*.tgz
.eslintcache
78 changes: 78 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# AGENTS.md

## Scope

These instructions apply to the entire repository.

Discord Management MCP is a Node.js 24, TypeScript ESM, stdio-only MCP server. It manages real Discord guilds, so correctness and explicit operator intent take priority over convenience.

## Repository Map

- `src/index.ts`: process entrypoint and tool registration.
- `src/config.ts`: environment and `.env.local` parsing.
- `src/discordClient.ts`: Discord client lifecycle.
- `src/safety.ts`: deterministic confirmation and backup guards.
- `src/backup/`: snapshot schema, validation, storage, diff, and restore primitives.
- `src/tools/`: MCP tool definitions grouped by domain.
- `src/__tests__/`: unit and regression tests. Tests must not contact Discord.
- `docs/`: design, configuration, safety, tool, and release documentation.
- `examples/`: explicitly confirmed operator examples; these may mutate a live guild.
- `.github/`: contribution forms, ownership, CI, and release automation.

## Setup and Verification

Use the repository-local toolchain; do not install or change global Node.js tooling.

```bash
npm ci
npm run lint
npm run typecheck
npm test
npm run build
npm run preflight
npm run pack:check
npm audit --omit=dev
```

Run focused tests while iterating, then run `npm run preflight` before handing off code changes. Run `npm run pack:check` whenever package metadata, build output, documentation included in the package, or release automation changes.

## Safety Invariants

- Never print, return, commit, or place in fixtures a real bot token, webhook token, invite secret, authorization header, `.env.local`, or backup payload.
- Never run an example or perform a live Discord mutation unless the user explicitly asks for that live action and identifies the intended guild.
- Every mutating MCP tool must require `confirm: true` and a non-empty audit reason.
- Delete and other high-impact tools must retain their backup guard or explicit `allowWithoutBackup: true` acknowledgement.
- Guild-targeted destructive actions must verify that the backup belongs to the target guild.
- Core backup sections such as roles and channels must fail closed when they cannot be captured. Optional sections may emit structured warnings.
- Keep message-content and guild-member privileged intents opt-in.
- Keep webhook tokens out of tool output and recursively remove secret fields from snapshots.
- Cross-guild restore must remain explicit, conservative, and safe when IDs or permission targets cannot be mapped.
- Restore apply must create a pre-restore backup before the first Discord mutation and must report skipped or lossy operations truthfully.
- MCP annotations must describe actual behavior: read-only tools are read-only, additive tools are non-destructive, and updates/deletes are marked destructive where appropriate.

## Code Conventions

- Use strict TypeScript and ESM imports with `.js` extensions for local modules.
- Prefer focused modules and typed helpers over broad casts. When an SDK boundary requires a cast, keep it narrow and validate the input first.
- Define bounded Zod input schemas for every tool. Use Discord API limits where known.
- Return both readable MCP text and structured content. Error responses must be actionable and must not expose secrets.
- Treat backup JSON as untrusted local input: validate it before planning or applying changes.
- Preserve stable identity across renames and reorders. Do not derive matching solely from mutable names or positions.
- Add regression tests for safety guards, snapshot validation, identity matching, restore mapping, and error paths.
- Keep comments focused on non-obvious safety or protocol decisions.

## Generated and Sensitive Files

- Do not edit or commit `dist/`; it is generated by `npm run build` and included at npm pack time.
- Do not commit `.env*` except `.env.example`, `backups/`, `coverage/`, logs, `node_modules/`, or generated package tarballs.
- Do not inspect or echo `.env.local` during routine review. Verify only that Git ignores it.
- Preserve unrelated working-tree changes and never rewrite user work to clean the repository.

## GitHub and Releases

- Use focused commits and pull requests. Prefer Conventional Commit subjects such as `fix:`, `feat:`, `docs:`, `test:`, and `chore:`.
- Do not commit, push, create tags/releases, change repository settings, or publish to npm unless the user explicitly authorizes that external action.
- Keep the required `build-and-test` status context stable unless branch protection is updated in the same authorized operation.
- Pin third-party GitHub Actions to full commit SHAs and retain a version comment.
- For a release, update `package.json` and `package-lock.json`, `CHANGELOG.md`, and `CITATION.cff`; then run `npm run release:check -- vX.Y.Z`, `npm run preflight`, and `npm run pack:check`.
- npm publication should use the `publish.yml` workflow with OIDC trusted publishing and provenance. A one-time `NPM_TOKEN` is allowed only to bootstrap the first publication and should be removed afterward.
19 changes: 18 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@

All notable changes to this project are documented in this file.

## 0.1.0
## Unreleased

## 0.1.0 - 2026-08-01

### Added

- Initial release: safe-by-default Discord management MCP server with JSON guild backups, restore planning, and guarded mutations.
- Snapshots strip secret fields (tokens, secrets, authorization) so backup files never contain bot or webhook credentials.
- Destructive operations are gated and require explicit intent, with restore planning to preview changes before applying them.
- Repository-specific `AGENTS.md`, TypeScript linting, Windows CI coverage, npm package verification, and an npm publication workflow with provenance.
- Regression tests for restore identity, role ordering, cross-guild permission mapping, required snapshot sections, and malformed backup data.

### Changed

- Restore matching now prefers immutable Discord IDs and uses unambiguous semantic matching across guilds, avoiding duplicate resources after renames or reorders.
- Role and channel restore now applies supported positions, parents, and safely mapped permission overwrites.
- Runtime and development dependencies were refreshed, and GitHub Actions are pinned to immutable commits.

### Security

- Backup reads now validate the complete snapshot structure before restore planning or application.
- Core role/channel capture fails closed, backup paths use restrictive modes where supported, and fixable dependency advisories were removed.
10 changes: 6 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ Maintainer: [Michael Gasperini](https://mikesoft.it) / [TheStreamCode](https://g
## Local Development

```bash
npm install
npm ci
npm run lint
npm run typecheck
npm test
npm run build
npm run pack:check
```

Use Node.js `>=24`. Do not commit `node_modules/`, `dist/`, `.env.local`, backups, or logs.
Expand All @@ -28,10 +30,10 @@ Use Node.js `>=24`. Do not commit `node_modules/`, `dist/`, `.env.local`, backup

- New tools have clear names and descriptions.
- Inputs use Zod validation with useful bounds.
- Mutating tools use confirmation guards.
- Destructive tools use backup guards.
- Mutating tools use confirmation guards and accurate MCP annotations.
- Delete and other high-impact destructive tools use backup guards.
- Error responses include actionable next steps.
- Tests cover safety-critical behavior.
- `npm run typecheck`, `npm test`, and `npm run build` pass.
- `npm run preflight` and `npm run pack:check` pass.

All changes should be submitted through pull requests. Direct pushes to the protected default branch are reserved for the maintainer bypass path.
28 changes: 21 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# Discord Management MCP

![Discord Management MCP hero](./discord-management-mcp.png)
[![CI](https://github.com/TheStreamCode/discord-management-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/TheStreamCode/discord-management-mcp/actions/workflows/ci.yml)

![Discord Management MCP hero](https://raw.githubusercontent.com/TheStreamCode/discord-management-mcp/main/discord-management-mcp.png)

Safe-by-default Discord management server for the Model Context Protocol (MCP). It lets MCP clients inspect and manage Discord guilds through a local stdio server, with JSON backups, restore planning, and explicit guardrails for risky operations.

Expand All @@ -11,10 +13,10 @@ Created by [Michael Gasperini](https://mikesoft.it). Repository: [TheStreamCode/
- **Local stdio MCP server**: no public HTTP listener, no hosted service, no proxy.
- **Discord-first tooling**: guild, channel, role, member, AutoMod, scheduled event, invite, webhook, emoji, sticker, and application-command tools.
- **Safe mutations**: write operations require `confirm: true` and a non-empty `reason`.
- **Destructive-operation guards**: destructive tools require a valid backup ID or an explicit `allowWithoutBackup: true`.
- **High-impact operation guards**: delete and other high-impact tools require a valid backup ID or an explicit `allowWithoutBackup: true`.
- **Guild-matched backups**: destructive guards reject backups from a different Discord guild.
- **Readable JSON backups**: snapshots are stored locally and can be diffed or used for conservative restore planning.
- **Conservative restore apply**: role/channel create and update operations only by default; deletes are opt-in.
- **Conservative restore apply**: role/channel fields, ordering, parents, and safely mappable permission overwrites; deletes are opt-in.
- **Optional message reading**: `Message Content` is disabled by default and must be explicitly enabled.

## Requirements
Expand All @@ -39,14 +41,20 @@ ENABLE_GUILD_MEMBERS=false

Use the token from **Discord Developer Portal > Application > Bot > Token**. Do not use the Application ID or Public Key.

Install, build, and run:
Install from source, build, and run:

```bash
npm install
npm ci
npm run build
npm start
```

Published npm releases can also be run without cloning the repository:

```bash
npx --yes discord-management-mcp
```

## Discord Intents

Default gateway intents avoid privileged intents so a new bot can start with minimal setup.
Expand Down Expand Up @@ -82,6 +90,10 @@ If installed as a package, the binary entry is:
discord-management-mcp
```

For an npm-based MCP client configuration, use `npx` as the command and
`["--yes", "discord-management-mcp"]` as the arguments. Environment variables,
including `DISCORD_TOKEN`, should be supplied through the client's secure environment configuration.

## Safety Model

Read-only tools do not require confirmation.
Expand All @@ -95,7 +107,7 @@ Mutating tools require:
}
```

Destructive tools also require either:
Delete and other high-impact destructive tools also require either:

```json
{
Expand Down Expand Up @@ -129,7 +141,7 @@ Recommended workflow:

Restore is best-effort. Discord cannot restore original IDs after recreation, message history, audit-log history, invite codes, webhook tokens, managed integration-owned roles, or every community/discovery setting.

`discord_backup_restore_apply` is intentionally conservative: it creates a pre-restore backup automatically, applies role/channel create and update operations, and skips deletes unless `includeDeletes: true` is set.
`discord_backup_restore_apply` is intentionally conservative: it creates a pre-restore backup automatically, applies supported role/channel fields and permission overwrites, and skips deletes unless `includeDeletes: true` is set. When a cross-guild permission target cannot be mapped safely, existing overwrites are preserved and the skipped mapping is reported.

## Tool Coverage

Expand All @@ -153,6 +165,8 @@ npm run typecheck
npm test
npm run build
npm run check
npm run preflight
npm run pack:check
npm audit --omit=dev
```

Expand Down
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Security fixes target the latest `main` branch until tagged releases are introdu

Do not open a public issue for secrets, bypasses, or exploitable behavior.

Report privately to [Michael Gasperini](https://mikesoft.it) or the repository maintainer. Include:
Report privately through [GitHub private vulnerability reporting](https://github.com/TheStreamCode/discord-management-mcp/security/advisories/new). If GitHub reporting is unavailable, contact [Michael Gasperini](https://mikesoft.it). Include:

- Impacted version or commit
- Reproduction steps
Expand Down
Loading