@unclick/reddit-mcp 0.1.0

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 ADDED
@@ -0,0 +1,15 @@
1
+ Apache License 2.0
2
+
3
+ Copyright (c) 2026 UnClick / malamutemayhem
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Reddit MCP by UnClick
2
+
3
+ Search, read, and post across Reddit: posts, comments, subreddits, and users.
4
+
5
+ > By UnClick. 180+ tools plus persistent agent memory in one install: https://unclick.world
6
+
7
+ ## Install
8
+
9
+ Installs straight from GitHub, no npm account needed.
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "reddit": {
15
+ "command": "npx",
16
+ "args": ["-y", "https://github.com/malamutemayhem/unclick/releases/download/standalone-mcps-latest/reddit.tgz"]
17
+ }
18
+ }
19
+ }
20
+ ```
21
+
22
+ ## Tools
23
+
24
+ - `reddit_read`
25
+ - `reddit_post`
26
+ - `reddit_comment`
27
+ - `reddit_search`
28
+ - `reddit_user`
29
+ - `reddit_vote`
30
+ - `reddit_subscribe`
31
+
32
+ ## Want the rest?
33
+
34
+ This is one connector. [UnClick](https://unclick.world) bundles 180+ tools plus
35
+ persistent cross-session agent memory in a single install.
36
+
37
+ ## License
38
+
39
+ Apache-2.0
package/dist/index.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ // Reddit MCP. Standalone MCP server by UnClick.
3
+ // By UnClick. 180+ tools plus persistent agent memory in one install: https://unclick.world
4
+ //
5
+ // Generated from the UnClick connector by scripts/generate-standalone-mcp.mjs.
6
+ // Edit the connector in the UnClick monorepo, not here.
7
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
8
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
9
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
10
+ import { redditRead, redditPost, redditComment, redditSearch, redditUser, redditVote, redditSubscribe, } from "./reddit-tool.js";
11
+ const TOOLS = [
12
+ {
13
+ name: "reddit_read",
14
+ description: "Read posts from a Reddit subreddit.",
15
+ inputSchema: {
16
+ type: "object",
17
+ additionalProperties: false,
18
+ properties: {
19
+ access_token: { type: "string" },
20
+ subreddit: { type: "string" },
21
+ sort: { type: "string", enum: ["hot", "new", "top", "rising"], description: "hot, new, top, rising" },
22
+ limit: { type: "number" },
23
+ after: { type: "string" },
24
+ t: { type: "string", enum: ["hour", "day", "week", "month", "year", "all"], description: "hour, day, week, month, year, all" },
25
+ },
26
+ required: ["access_token", "subreddit"],
27
+ },
28
+ },
29
+ {
30
+ name: "reddit_post",
31
+ description: "Create a Reddit post.",
32
+ inputSchema: {
33
+ type: "object",
34
+ additionalProperties: false,
35
+ properties: {
36
+ access_token: { type: "string" },
37
+ subreddit: { type: "string" },
38
+ title: { type: "string" },
39
+ kind: { type: "string", enum: ["self", "link"], description: "self, link" },
40
+ text: { type: "string" },
41
+ url: { type: "string" },
42
+ nsfw: { type: "boolean" },
43
+ spoiler: { type: "boolean" },
44
+ },
45
+ required: ["access_token", "subreddit", "title", "kind"],
46
+ },
47
+ },
48
+ {
49
+ name: "reddit_comment",
50
+ description: "Post a comment on Reddit.",
51
+ inputSchema: {
52
+ type: "object",
53
+ additionalProperties: false,
54
+ properties: {
55
+ access_token: { type: "string" },
56
+ parent_id: { type: "string" },
57
+ text: { type: "string" },
58
+ },
59
+ required: ["access_token", "parent_id", "text"],
60
+ },
61
+ },
62
+ {
63
+ name: "reddit_search",
64
+ description: "Search Reddit posts.",
65
+ inputSchema: {
66
+ type: "object",
67
+ additionalProperties: false,
68
+ properties: {
69
+ access_token: { type: "string" },
70
+ q: { type: "string" },
71
+ subreddit: { type: "string" },
72
+ sort: { type: "string" },
73
+ limit: { type: "number" },
74
+ },
75
+ required: ["access_token", "q"],
76
+ },
77
+ },
78
+ {
79
+ name: "reddit_user",
80
+ description: "Get a Reddit user profile and posts.",
81
+ inputSchema: {
82
+ type: "object",
83
+ additionalProperties: false,
84
+ properties: {
85
+ access_token: { type: "string" },
86
+ username: { type: "string" },
87
+ type: { type: "string", description: "overview, submitted, comments" },
88
+ limit: { type: "number" },
89
+ },
90
+ required: ["access_token", "username"],
91
+ },
92
+ },
93
+ {
94
+ name: "reddit_vote",
95
+ description: "Vote on a Reddit post or comment.",
96
+ inputSchema: {
97
+ type: "object",
98
+ additionalProperties: false,
99
+ properties: {
100
+ access_token: { type: "string" },
101
+ id: { type: "string" },
102
+ dir: { type: "number", description: "1=upvote, 0=neutral, -1=downvote" },
103
+ },
104
+ required: ["access_token", "id", "dir"],
105
+ },
106
+ },
107
+ {
108
+ name: "reddit_subscribe",
109
+ description: "Subscribe to or unsubscribe from a Reddit subreddit.",
110
+ inputSchema: {
111
+ type: "object",
112
+ additionalProperties: false,
113
+ properties: {
114
+ access_token: { type: "string" },
115
+ sr: { type: "string" },
116
+ action: { type: "string", enum: ["sub", "unsub"], description: "sub or unsub" },
117
+ },
118
+ required: ["access_token", "sr", "action"],
119
+ },
120
+ }
121
+ ];
122
+ const HANDLERS = {
123
+ reddit_read: (args) => redditRead(args),
124
+ reddit_post: (args) => redditPost(args),
125
+ reddit_comment: (args) => redditComment(args),
126
+ reddit_search: (args) => redditSearch(args),
127
+ reddit_user: (args) => redditUser(args),
128
+ reddit_vote: (args) => redditVote(args),
129
+ reddit_subscribe: (args) => redditSubscribe(args),
130
+ };
131
+ const server = new Server({ name: "io.github.malamutemayhem/reddit", version: "0.1.0" }, { capabilities: { tools: {} } });
132
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
133
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
134
+ const handler = HANDLERS[req.params.name];
135
+ if (!handler) {
136
+ return { content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }], isError: true };
137
+ }
138
+ try {
139
+ const result = await handler((req.params.arguments ?? {}));
140
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
141
+ }
142
+ catch (err) {
143
+ const message = err instanceof Error ? err.message : String(err);
144
+ return { content: [{ type: "text", text: message }], isError: true };
145
+ }
146
+ });
147
+ async function main() {
148
+ const transport = new StdioServerTransport();
149
+ await server.connect(transport);
150
+ }
151
+ main().catch((err) => {
152
+ process.stderr.write(`[reddit-mcp] fatal: ${err instanceof Error ? err.message : String(err)}\n`);
153
+ process.exit(1);
154
+ });
@@ -0,0 +1,347 @@
1
+ // Reddit API MCP Tool
2
+ // Connects to Reddit via OAuth2 bearer tokens (oauth.reddit.com).
3
+ // No external dependencies - uses global fetch (Node 18+).
4
+ // Rate limit: Reddit allows 60 requests/minute for OAuth clients.
5
+ const REDDIT_BASE = "https://oauth.reddit.com";
6
+ const USER_AGENT = "UnClick-MCP/1.0 by unclick.dev";
7
+ // Per-process rate limit tracking (headers from Reddit responses)
8
+ let _remaining = 60;
9
+ let _resetAt = Date.now() + 60_000;
10
+ // ── Internal fetch helper ────────────────────────────────────────────────────
11
+ async function rFetch(method, path, accessToken, body) {
12
+ // Guard: if we have no remaining quota and reset hasn't passed, bail early
13
+ if (_remaining <= 0 && Date.now() < _resetAt) {
14
+ const waitMs = _resetAt - Date.now();
15
+ return {
16
+ error: "rate_limited",
17
+ message: `Reddit rate limit reached. Resets in ${Math.ceil(waitMs / 1000)}s.`,
18
+ retry_after_ms: waitMs,
19
+ };
20
+ }
21
+ const headers = {
22
+ Authorization: `Bearer ${accessToken}`,
23
+ "User-Agent": USER_AGENT,
24
+ };
25
+ let url = `${REDDIT_BASE}${path}`;
26
+ let fetchBody;
27
+ if (method === "GET" && body) {
28
+ const qs = new URLSearchParams(Object.fromEntries(Object.entries(body).map(([k, v]) => [k, String(v)]))).toString();
29
+ url = `${url}?${qs}`;
30
+ }
31
+ else if (method === "POST" && body) {
32
+ headers["Content-Type"] = "application/x-www-form-urlencoded";
33
+ fetchBody = new URLSearchParams(Object.fromEntries(Object.entries(body).map(([k, v]) => [k, String(v)]))).toString();
34
+ }
35
+ const res = await fetch(url, { method, headers, body: fetchBody });
36
+ // Update rate limit state from response headers
37
+ const rem = res.headers.get("x-ratelimit-remaining");
38
+ const rst = res.headers.get("x-ratelimit-reset");
39
+ if (rem !== null)
40
+ _remaining = parseFloat(rem);
41
+ if (rst !== null)
42
+ _resetAt = Date.now() + parseFloat(rst) * 1_000;
43
+ if (res.status === 429) {
44
+ const retryAfter = res.headers.get("retry-after");
45
+ return {
46
+ error: "rate_limited",
47
+ message: "Reddit API rate limit exceeded.",
48
+ retry_after_seconds: retryAfter ? Number(retryAfter) : 60,
49
+ };
50
+ }
51
+ if (res.status === 401) {
52
+ return {
53
+ error: "unauthorized",
54
+ message: "Invalid or expired access token. Re-authenticate via Reddit OAuth2.",
55
+ };
56
+ }
57
+ if (res.status === 403) {
58
+ return {
59
+ error: "forbidden",
60
+ message: "Access denied. Check token scopes or subreddit permissions.",
61
+ };
62
+ }
63
+ if (res.status === 404) {
64
+ return { error: "not_found", message: `Resource not found: ${path}` };
65
+ }
66
+ if (!res.ok) {
67
+ const text = await res.text().catch(() => "");
68
+ return { error: `http_${res.status}`, message: text || res.statusText };
69
+ }
70
+ const json = await res.json();
71
+ // Reddit wraps API errors in { error: ..., message: ... }
72
+ if (json && typeof json === "object" && "error" in json) {
73
+ return { error: json["error"], message: json["message"] };
74
+ }
75
+ return json;
76
+ }
77
+ // ── Shape helpers ────────────────────────────────────────────────────────────
78
+ function shapePosts(listing) {
79
+ if (!listing ||
80
+ typeof listing !== "object" ||
81
+ !("data" in listing))
82
+ return [];
83
+ const data = listing["data"];
84
+ const children = Array.isArray(data?.["children"]) ? data["children"] : [];
85
+ return children.map((child) => {
86
+ const d = (child["data"] ?? {});
87
+ return {
88
+ id: d["id"],
89
+ name: d["name"],
90
+ title: d["title"],
91
+ author: d["author"],
92
+ subreddit: d["subreddit"],
93
+ score: d["score"],
94
+ upvote_ratio: d["upvote_ratio"],
95
+ num_comments: d["num_comments"],
96
+ url: d["url"],
97
+ permalink: d["permalink"] ? `https://reddit.com${d["permalink"]}` : null,
98
+ selftext: d["selftext"] ?? null,
99
+ is_self: d["is_self"],
100
+ created_utc: d["created_utc"],
101
+ nsfw: d["over_18"],
102
+ spoiler: d["spoiler"],
103
+ flair: d["link_flair_text"] ?? null,
104
+ };
105
+ });
106
+ }
107
+ function shapeComments(listing) {
108
+ if (!listing ||
109
+ typeof listing !== "object" ||
110
+ !("data" in listing))
111
+ return [];
112
+ const data = listing["data"];
113
+ const children = Array.isArray(data?.["children"]) ? data["children"] : [];
114
+ return children
115
+ .filter((c) => {
116
+ const kind = c["kind"];
117
+ return kind === "t1";
118
+ })
119
+ .map((child) => {
120
+ const d = (child["data"] ?? {});
121
+ return {
122
+ id: d["id"],
123
+ name: d["name"],
124
+ author: d["author"],
125
+ body: d["body"],
126
+ score: d["score"],
127
+ created_utc: d["created_utc"],
128
+ permalink: d["permalink"] ? `https://reddit.com${d["permalink"]}` : null,
129
+ parent_id: d["parent_id"],
130
+ subreddit: d["subreddit"],
131
+ };
132
+ });
133
+ }
134
+ export async function redditRead(args) {
135
+ const sub = args.subreddit.replace(/^r\//i, "");
136
+ const sort = args.sort ?? "hot";
137
+ const limit = Math.min(100, Math.max(1, Number(args.limit ?? 25)));
138
+ const params = { limit };
139
+ if (args.after)
140
+ params["after"] = args.after;
141
+ if (sort === "top" && args.t)
142
+ params["t"] = args.t;
143
+ const result = await rFetch("GET", `/r/${sub}/${sort}.json`, args.access_token, params);
144
+ if (result && typeof result === "object" && "error" in result)
145
+ return result;
146
+ const posts = shapePosts(result);
147
+ const data = result?.["data"];
148
+ return {
149
+ subreddit: sub,
150
+ sort,
151
+ count: posts.length,
152
+ after: data?.["after"] ?? null,
153
+ before: data?.["before"] ?? null,
154
+ posts,
155
+ };
156
+ }
157
+ export async function redditPost(args) {
158
+ const sub = args.subreddit.replace(/^r\//i, "");
159
+ if (!args.title?.trim())
160
+ return { error: "validation", message: "title is required." };
161
+ if (args.kind === "self" && !args.text)
162
+ return { error: "validation", message: "text is required for self posts." };
163
+ if (args.kind === "link" && !args.url)
164
+ return { error: "validation", message: "url is required for link posts." };
165
+ const body = {
166
+ sr: sub,
167
+ title: args.title,
168
+ kind: args.kind,
169
+ api_type: "json",
170
+ resubmit: true,
171
+ nsfw: args.nsfw ?? false,
172
+ spoiler: args.spoiler ?? false,
173
+ };
174
+ if (args.kind === "self")
175
+ body["text"] = args.text;
176
+ if (args.kind === "link")
177
+ body["url"] = args.url;
178
+ if (args.flair_id)
179
+ body["flair_id"] = args.flair_id;
180
+ if (args.flair_text)
181
+ body["flair_text"] = args.flair_text;
182
+ const result = await rFetch("POST", "/api/submit", args.access_token, body);
183
+ if (result && typeof result === "object" && "error" in result)
184
+ return result;
185
+ // Reddit wraps submit response in json.data
186
+ const json = result?.["json"];
187
+ const errors = json?.["errors"];
188
+ if (errors && errors.length > 0) {
189
+ return { error: "submit_error", errors };
190
+ }
191
+ const postData = json?.["data"];
192
+ return {
193
+ success: true,
194
+ id: postData?.["id"],
195
+ name: postData?.["name"],
196
+ url: postData?.["url"],
197
+ };
198
+ }
199
+ export async function redditComment(args) {
200
+ if (!args.parent_id?.trim())
201
+ return { error: "validation", message: "parent_id is required (e.g. t3_abc123 or t1_def456)." };
202
+ if (!args.text?.trim())
203
+ return { error: "validation", message: "text is required." };
204
+ const body = {
205
+ parent: args.parent_id,
206
+ text: args.text,
207
+ api_type: "json",
208
+ };
209
+ const result = await rFetch("POST", "/api/comment", args.access_token, body);
210
+ if (result && typeof result === "object" && "error" in result)
211
+ return result;
212
+ const json = result?.["json"];
213
+ const errors = json?.["errors"];
214
+ if (errors && errors.length > 0) {
215
+ return { error: "comment_error", errors };
216
+ }
217
+ const things = json?.["data"]?.["things"];
218
+ const first = things?.[0];
219
+ const d = (first?.["data"] ?? {});
220
+ return {
221
+ success: true,
222
+ id: d["id"],
223
+ name: d["name"],
224
+ author: d["author"],
225
+ body: d["body"],
226
+ created_utc: d["created_utc"],
227
+ permalink: d["permalink"] ? `https://reddit.com${d["permalink"]}` : null,
228
+ };
229
+ }
230
+ export async function redditSearch(args) {
231
+ if (!args.query?.trim())
232
+ return { error: "validation", message: "query is required." };
233
+ const limit = Math.min(100, Math.max(1, Number(args.limit ?? 25)));
234
+ const params = {
235
+ q: args.query,
236
+ sort: args.sort ?? "relevance",
237
+ limit,
238
+ type: "link",
239
+ };
240
+ if (args.t)
241
+ params["t"] = args.t;
242
+ if (args.after)
243
+ params["after"] = args.after;
244
+ if (args.subreddit)
245
+ params["restrict_sr"] = true;
246
+ const sub = args.subreddit?.replace(/^r\//i, "");
247
+ const path = sub ? `/r/${sub}/search.json` : "/search.json";
248
+ const result = await rFetch("GET", path, args.access_token, params);
249
+ if (result && typeof result === "object" && "error" in result)
250
+ return result;
251
+ const posts = shapePosts(result);
252
+ const data = result?.["data"];
253
+ return {
254
+ query: args.query,
255
+ subreddit: sub ?? null,
256
+ sort: args.sort ?? "relevance",
257
+ count: posts.length,
258
+ after: data?.["after"] ?? null,
259
+ results: posts,
260
+ };
261
+ }
262
+ export async function redditUser(args) {
263
+ const username = args.username.replace(/^u\//i, "");
264
+ if (!username)
265
+ return { error: "validation", message: "username is required." };
266
+ const limit = Math.min(100, Math.max(1, Number(args.limit ?? 10)));
267
+ const [aboutResult, ...activityResults] = await Promise.all([
268
+ rFetch("GET", `/user/${username}/about.json`, args.access_token),
269
+ args.include_posts !== false
270
+ ? rFetch("GET", `/user/${username}/submitted.json`, args.access_token, { limit })
271
+ : Promise.resolve(null),
272
+ args.include_comments !== false
273
+ ? rFetch("GET", `/user/${username}/comments.json`, args.access_token, { limit })
274
+ : Promise.resolve(null),
275
+ ]);
276
+ if (aboutResult && typeof aboutResult === "object" && "error" in aboutResult) {
277
+ return aboutResult;
278
+ }
279
+ const userData = (aboutResult?.["data"] ?? {});
280
+ const profile = {
281
+ id: userData["id"],
282
+ name: userData["name"],
283
+ created_utc: userData["created_utc"],
284
+ link_karma: userData["link_karma"],
285
+ comment_karma: userData["comment_karma"],
286
+ is_verified: userData["verified"],
287
+ is_mod: userData["is_mod"],
288
+ icon_img: userData["icon_img"],
289
+ snoovatar_img: userData["snoovatar_img"],
290
+ subreddit: userData["subreddit"]
291
+ ? {
292
+ display_name: userData["subreddit"]?.["display_name"],
293
+ public_description: userData["subreddit"]?.["public_description"],
294
+ subscribers: userData["subreddit"]?.["subscribers"],
295
+ }
296
+ : null,
297
+ };
298
+ const [postsResult, commentsResult] = activityResults;
299
+ const result = { profile };
300
+ if (postsResult && !(typeof postsResult === "object" && "error" in postsResult)) {
301
+ result["recent_posts"] = shapePosts(postsResult);
302
+ }
303
+ if (commentsResult && !(typeof commentsResult === "object" && "error" in commentsResult)) {
304
+ result["recent_comments"] = shapeComments(commentsResult);
305
+ }
306
+ return result;
307
+ }
308
+ export async function redditVote(args) {
309
+ if (!args.id?.trim())
310
+ return { error: "validation", message: "id (fullname) is required, e.g. t3_abc123." };
311
+ const dir = Number(args.dir);
312
+ if (dir !== 1 && dir !== 0 && dir !== -1) {
313
+ return { error: "validation", message: "dir must be 1 (upvote), 0 (remove vote), or -1 (downvote)." };
314
+ }
315
+ const result = await rFetch("POST", "/api/vote", args.access_token, {
316
+ id: args.id,
317
+ dir,
318
+ });
319
+ if (result && typeof result === "object" && "error" in result)
320
+ return result;
321
+ return {
322
+ success: true,
323
+ id: args.id,
324
+ dir,
325
+ action: dir === 1 ? "upvoted" : dir === -1 ? "downvoted" : "vote_removed",
326
+ };
327
+ }
328
+ export async function redditSubscribe(args) {
329
+ const sub = args.subreddit.replace(/^r\//i, "");
330
+ if (!sub)
331
+ return { error: "validation", message: "subreddit is required." };
332
+ if (args.action !== "sub" && args.action !== "unsub") {
333
+ return { error: "validation", message: "action must be 'sub' or 'unsub'." };
334
+ }
335
+ // Fetch subreddit info to get the fullname (sr_name param is also accepted)
336
+ const result = await rFetch("POST", "/api/subscribe", args.access_token, {
337
+ action: args.action,
338
+ sr_name: sub,
339
+ });
340
+ if (result && typeof result === "object" && "error" in result)
341
+ return result;
342
+ return {
343
+ success: true,
344
+ subreddit: sub,
345
+ action: args.action === "sub" ? "subscribed" : "unsubscribed",
346
+ };
347
+ }
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@unclick/reddit-mcp",
3
+ "version": "0.1.0",
4
+ "mcpName": "io.github.malamutemayhem/reddit",
5
+ "description": "Search, read, and post across Reddit: posts, comments, subreddits, and users. By UnClick (https://unclick.world).",
6
+ "keywords": [
7
+ "mcp",
8
+ "model-context-protocol",
9
+ "unclick",
10
+ "reddit",
11
+ "social",
12
+ "forums",
13
+ "subreddit"
14
+ ],
15
+ "author": "UnClick (https://unclick.world)",
16
+ "type": "module",
17
+ "bin": {
18
+ "reddit-mcp": "./dist/index.js"
19
+ },
20
+ "main": "./dist/index.js",
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "server.json"
25
+ ],
26
+ "scripts": {
27
+ "build": "tsc",
28
+ "start": "node dist/index.js",
29
+ "prepublishOnly": "npm run build"
30
+ },
31
+ "dependencies": {
32
+ "@modelcontextprotocol/sdk": "^1.15.1"
33
+ },
34
+ "devDependencies": {
35
+ "typescript": "^5.6.0",
36
+ "@types/node": "^22.0.0"
37
+ },
38
+ "license": "Apache-2.0",
39
+ "repository": {
40
+ "type": "git",
41
+ "url": "https://github.com/malamutemayhem/unclick.git",
42
+ "directory": "packages/standalone/reddit-mcp"
43
+ },
44
+ "homepage": "https://unclick.world"
45
+ }
package/server.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
3
+ "name": "io.github.malamutemayhem/reddit",
4
+ "title": "Reddit MCP by UnClick",
5
+ "description": "Search, read, and post across Reddit: posts, comments, subreddits, and users. By UnClick.",
6
+ "version": "0.1.0",
7
+ "websiteUrl": "https://unclick.world",
8
+ "icons": [
9
+ {
10
+ "src": "https://unclick.world/favicon.png",
11
+ "mimeType": "image/png",
12
+ "sizes": [
13
+ "512x512"
14
+ ]
15
+ }
16
+ ],
17
+ "repository": {
18
+ "url": "https://github.com/malamutemayhem/unclick.git",
19
+ "source": "github",
20
+ "subfolder": "packages/standalone/reddit-mcp"
21
+ },
22
+ "packages": [
23
+ {
24
+ "registryType": "npm",
25
+ "identifier": "@unclick/reddit-mcp",
26
+ "version": "0.1.0",
27
+ "runtimeHint": "npx",
28
+ "transport": {
29
+ "type": "stdio"
30
+ }
31
+ }
32
+ ]
33
+ }