@tensakulabs/discord-mcp 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +7 -13
- package/dist/auth.js +49 -18
- package/dist/cli.js +22 -14
- package/package.json +6 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tensaku Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Exposes 6 Discord tools via MCP (Model Context Protocol):
|
|
|
22
22
|
### 1. Install & configure
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
|
-
npx discord-mcp setup
|
|
25
|
+
npx @tensakulabs/discord-mcp setup
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
This will:
|
|
@@ -32,35 +32,29 @@ This will:
|
|
|
32
32
|
|
|
33
33
|
### 2. Token extraction (step shown during setup)
|
|
34
34
|
|
|
35
|
-
Open Discord desktop app →
|
|
36
|
-
|
|
37
|
-
```javascript
|
|
38
|
-
window.webpackChunkdiscord_app.push([[''],{},e=>{m=[];for(let c in e.c)m.push(e.c[c])}]),m.find(m=>m?.exports?.default?.getToken!==void 0).exports.default.getToken()
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
Copy the returned string.
|
|
35
|
+
Open Discord desktop app → Press **Ctrl+Shift+I** (or **Cmd+Option+I** on Mac) → **Network** tab → Send any message in Discord → filter requests by `messages` → click any request → **Headers** tab → find the `Authorization` header → copy its value.
|
|
42
36
|
|
|
43
37
|
### 3. Restart Claude
|
|
44
38
|
|
|
45
|
-
Restart Claude
|
|
39
|
+
Restart Claude Code. You'll see Discord tools available.
|
|
46
40
|
|
|
47
41
|
### Verify it's working
|
|
48
42
|
|
|
49
43
|
```bash
|
|
50
|
-
npx discord-mcp status
|
|
44
|
+
npx @tensakulabs/discord-mcp status
|
|
51
45
|
# ✅ Connected as: yourname#0
|
|
52
46
|
```
|
|
53
47
|
|
|
54
48
|
## Manual MCP config (if auto-config fails)
|
|
55
49
|
|
|
56
|
-
Add to
|
|
50
|
+
Add to `~/.claude/settings.json`:
|
|
57
51
|
|
|
58
52
|
```json
|
|
59
53
|
{
|
|
60
54
|
"mcpServers": {
|
|
61
55
|
"discord": {
|
|
62
56
|
"command": "npx",
|
|
63
|
-
"args": ["-y", "discord-mcp"]
|
|
57
|
+
"args": ["-y", "@tensakulabs/discord-mcp"]
|
|
64
58
|
}
|
|
65
59
|
}
|
|
66
60
|
}
|
|
@@ -89,7 +83,7 @@ Add to OpenClaw's MCP config:
|
|
|
89
83
|
"name": "discord",
|
|
90
84
|
"transport": "stdio",
|
|
91
85
|
"command": "npx",
|
|
92
|
-
"args": ["-y", "discord-mcp"]
|
|
86
|
+
"args": ["-y", "@tensakulabs/discord-mcp"]
|
|
93
87
|
}]
|
|
94
88
|
}
|
|
95
89
|
}
|
package/dist/auth.js
CHANGED
|
@@ -1,12 +1,30 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
|
|
2
|
-
import { homedir } from "os";
|
|
2
|
+
import { homedir, platform } from "os";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
5
|
+
import { execSync } from "child_process";
|
|
5
6
|
const SERVICE = "discord-mcp";
|
|
6
7
|
const ACCOUNT = "user-token";
|
|
7
8
|
const CONFIG_DIR = join(homedir(), ".config", "discord-mcp");
|
|
8
9
|
const TOKEN_FILE = join(CONFIG_DIR, "token.enc");
|
|
9
10
|
const KEY_FILE = join(CONFIG_DIR, "key.bin");
|
|
11
|
+
// macOS: use built-in `security` CLI — no native module compilation required
|
|
12
|
+
function saveMacOSKeychain(token) {
|
|
13
|
+
// Delete existing entry first to avoid "already exists" error
|
|
14
|
+
try {
|
|
15
|
+
execSync(`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`);
|
|
16
|
+
}
|
|
17
|
+
catch { /* not found, ok */ }
|
|
18
|
+
execSync(`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${token}"`);
|
|
19
|
+
}
|
|
20
|
+
function getMacOSKeychain() {
|
|
21
|
+
try {
|
|
22
|
+
return execSync(`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`).toString().trim() || null;
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
10
28
|
let _keytar = null;
|
|
11
29
|
async function getKeytar() {
|
|
12
30
|
if (_keytar !== undefined)
|
|
@@ -20,38 +38,51 @@ async function getKeytar() {
|
|
|
20
38
|
return _keytar;
|
|
21
39
|
}
|
|
22
40
|
export async function saveToken(token) {
|
|
41
|
+
// macOS: security CLI always works — no native module needed
|
|
42
|
+
if (platform() === "darwin") {
|
|
43
|
+
saveMacOSKeychain(token);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
// Other platforms: try keytar
|
|
23
47
|
const keytar = await getKeytar();
|
|
24
48
|
try {
|
|
25
49
|
if (!keytar)
|
|
26
50
|
throw new Error("keytar not available");
|
|
27
51
|
await keytar.setPassword(SERVICE, ACCOUNT, token);
|
|
52
|
+
return;
|
|
28
53
|
}
|
|
29
|
-
catch {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
const iv = randomBytes(16);
|
|
41
|
-
const cipher = createCipheriv("aes-256-cbc", key, iv);
|
|
42
|
-
const enc = Buffer.concat([cipher.update(token, "utf8"), cipher.final()]);
|
|
43
|
-
writeFileSync(TOKEN_FILE, Buffer.concat([iv, enc]), { mode: 0o600 });
|
|
54
|
+
catch { /* fall through */ }
|
|
55
|
+
// Fallback: encrypt to file (for headless/CI environments)
|
|
56
|
+
console.warn("⚠️ Keychain unavailable, using encrypted file fallback.");
|
|
57
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
58
|
+
let key;
|
|
59
|
+
if (existsSync(KEY_FILE)) {
|
|
60
|
+
key = readFileSync(KEY_FILE);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
key = randomBytes(32);
|
|
64
|
+
writeFileSync(KEY_FILE, key, { mode: 0o600 });
|
|
44
65
|
}
|
|
66
|
+
const iv = randomBytes(16);
|
|
67
|
+
const cipher = createCipheriv("aes-256-cbc", key, iv);
|
|
68
|
+
const enc = Buffer.concat([cipher.update(token, "utf8"), cipher.final()]);
|
|
69
|
+
writeFileSync(TOKEN_FILE, Buffer.concat([iv, enc]), { mode: 0o600 });
|
|
45
70
|
}
|
|
46
71
|
export async function getToken() {
|
|
47
|
-
//
|
|
72
|
+
// macOS: try security CLI first
|
|
73
|
+
if (platform() === "darwin") {
|
|
74
|
+
const token = getMacOSKeychain();
|
|
75
|
+
if (token)
|
|
76
|
+
return token;
|
|
77
|
+
}
|
|
78
|
+
// Try keytar
|
|
48
79
|
const keytar = await getKeytar();
|
|
49
80
|
const keychainToken = keytar ? await keytar.getPassword(SERVICE, ACCOUNT).catch(() => null) : null;
|
|
50
81
|
if (keychainToken)
|
|
51
82
|
return keychainToken;
|
|
52
83
|
// Fallback: encrypted file
|
|
53
84
|
if (!existsSync(TOKEN_FILE) || !existsSync(KEY_FILE)) {
|
|
54
|
-
throw new Error("No Discord token found. Run: npx discord-mcp setup");
|
|
85
|
+
throw new Error("No Discord token found. Run: npx @tensakulabs/discord-mcp setup");
|
|
55
86
|
}
|
|
56
87
|
const key = readFileSync(KEY_FILE);
|
|
57
88
|
const raw = readFileSync(TOKEN_FILE);
|
package/dist/cli.js
CHANGED
|
@@ -5,7 +5,7 @@ import { saveToken, getToken } from "./auth.js";
|
|
|
5
5
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
7
|
import { homedir, platform } from "os";
|
|
8
|
-
import { join } from "path";
|
|
8
|
+
import { join, dirname } from "path";
|
|
9
9
|
const program = new Command();
|
|
10
10
|
program
|
|
11
11
|
.name("discord-mcp")
|
|
@@ -24,12 +24,11 @@ Step 1: Extract your Discord token
|
|
|
24
24
|
|
|
25
25
|
1. Open Discord desktop app
|
|
26
26
|
2. Press Ctrl+Shift+I (or Cmd+Option+I on Mac) to open DevTools
|
|
27
|
-
3. Click the "
|
|
28
|
-
4.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
5. Copy the returned string (no quotes needed)
|
|
27
|
+
3. Click the "Network" tab
|
|
28
|
+
4. Switch to any server or channel to trigger a request
|
|
29
|
+
5. Click any request to discord.com/api/...
|
|
30
|
+
6. Scroll to "Request Headers" → find the "authorization" header
|
|
31
|
+
7. Copy the value (starts with MT or OD — no quotes needed)
|
|
33
32
|
|
|
34
33
|
`);
|
|
35
34
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -42,11 +41,9 @@ Step 1: Extract your Discord token
|
|
|
42
41
|
}
|
|
43
42
|
await saveToken(token);
|
|
44
43
|
console.log("✅ Token saved securely to OS keychain (or encrypted file fallback).");
|
|
45
|
-
// Auto-patch
|
|
44
|
+
// Auto-patch Claude Code settings.json
|
|
46
45
|
const configPaths = [
|
|
47
|
-
join(homedir(), "
|
|
48
|
-
join(homedir(), ".config", "Claude", "claude_desktop_config.json"), // Linux
|
|
49
|
-
join(process.env["APPDATA"] ?? "", "Claude", "claude_desktop_config.json"), // Windows
|
|
46
|
+
join(homedir(), ".claude", "settings.json"), // Claude Code (all platforms)
|
|
50
47
|
];
|
|
51
48
|
const configPath = configPaths.find(existsSync);
|
|
52
49
|
// Write launchd plist (macOS only) — ISC-D6
|
|
@@ -59,6 +56,12 @@ Step 1: Extract your Discord token
|
|
|
59
56
|
catch {
|
|
60
57
|
return "/usr/local/bin/npx";
|
|
61
58
|
} })();
|
|
59
|
+
const nodeBinDir = (() => { try {
|
|
60
|
+
return dirname(execSync("which node").toString().trim());
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return "/usr/local/bin";
|
|
64
|
+
} })();
|
|
62
65
|
const logDir = join(homedir(), ".config", "discord-mcp");
|
|
63
66
|
const plist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
64
67
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
@@ -72,6 +75,11 @@ Step 1: Extract your Discord token
|
|
|
72
75
|
<string>@tensakulabs/discord-mcp</string>
|
|
73
76
|
<string>daemon-start</string>
|
|
74
77
|
</array>
|
|
78
|
+
<key>EnvironmentVariables</key>
|
|
79
|
+
<dict>
|
|
80
|
+
<key>PATH</key>
|
|
81
|
+
<string>${nodeBinDir}:/usr/local/bin:/usr/bin:/bin</string>
|
|
82
|
+
</dict>
|
|
75
83
|
<key>RunAtLoad</key>
|
|
76
84
|
<true/>
|
|
77
85
|
<key>KeepAlive</key>
|
|
@@ -101,13 +109,13 @@ Step 1: Extract your Discord token
|
|
|
101
109
|
};
|
|
102
110
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
103
111
|
console.log(`✅ Registered in Claude config: ${configPath}`);
|
|
104
|
-
console.log("\n🎉 Done! Restart Claude to start using Discord tools.");
|
|
112
|
+
console.log("\n🎉 Done! Restart Claude Code to start using Discord tools.");
|
|
105
113
|
}
|
|
106
114
|
else {
|
|
107
115
|
console.log(`
|
|
108
|
-
⚠️ Could not find Claude
|
|
116
|
+
⚠️ Could not find Claude Code config automatically.
|
|
109
117
|
|
|
110
|
-
Add this to your
|
|
118
|
+
Add this to your ~/.claude/settings.json manually:
|
|
111
119
|
|
|
112
120
|
"mcpServers": {
|
|
113
121
|
"discord": {
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tensakulabs/discord-mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Discord selfbot MCP server — read & send messages via Claude",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"bin": {
|
|
7
8
|
"discord-mcp": "./dist/cli.js"
|
|
@@ -29,6 +30,10 @@
|
|
|
29
30
|
"optionalDependencies": {
|
|
30
31
|
"keytar": "^7.9.0"
|
|
31
32
|
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "https://github.com/tensakulabs/discord-mcp"
|
|
36
|
+
},
|
|
32
37
|
"publishConfig": {
|
|
33
38
|
"access": "public"
|
|
34
39
|
},
|