@citerocket/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 +21 -0
- package/README.md +133 -0
- package/dist/index.js +126 -0
- package/manifest.json +588 -0
- package/package.json +42 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CiteRocket
|
|
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
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Reddit MCP: the Reddit API for Claude, Cursor and any MCP client
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@citerocket/reddit-mcp)
|
|
4
|
+
[](./LICENSE)
|
|
5
|
+
|
|
6
|
+
The official **[CiteRocket](https://www.citerocket.com)** MCP server, the fastest way
|
|
7
|
+
to use the **Reddit API** from an AI assistant. Give Claude, Cursor, or any
|
|
8
|
+
[Model Context Protocol](https://modelcontextprotocol.io) client direct access to
|
|
9
|
+
Reddit data: **search Reddit posts and comments, pull a subreddit's top, read full
|
|
10
|
+
comment trees, look up users and their karma, search communities, media and users,
|
|
11
|
+
and run shadowban checks**, all over one clean, fast, camelCase JSON API.
|
|
12
|
+
|
|
13
|
+
**Tools stay current automatically.** When CiteRocket ships a new endpoint, the new
|
|
14
|
+
tool shows up on your next restart, with no reinstall and no config change.
|
|
15
|
+
|
|
16
|
+
→ **[Get an API key at citerocket.com](https://app.citerocket.com)** · **[API docs](https://www.citerocket.com/docs)** · **[Rate limits](https://www.citerocket.com/docs/rate-limits)**
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Install
|
|
21
|
+
|
|
22
|
+
Add it to your MCP client config (Claude Desktop, Cursor, Windsurf, etc.):
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"citerocket": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "@citerocket/reddit-mcp@latest"],
|
|
30
|
+
"env": {
|
|
31
|
+
"CITEROCKET_API_KEY": "cite_live_..."
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Get your `CITEROCKET_API_KEY` from the [CiteRocket dashboard](https://app.citerocket.com).
|
|
39
|
+
That's all it needs.
|
|
40
|
+
|
|
41
|
+
Or via the Claude Code CLI:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
claude mcp add citerocket -e CITEROCKET_API_KEY=cite_live_... -- npx -y @citerocket/reddit-mcp@latest
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## What you can do
|
|
50
|
+
|
|
51
|
+
Once installed, just ask your assistant naturally:
|
|
52
|
+
|
|
53
|
+
> "Find the top posts in r/programming this week"
|
|
54
|
+
> "Search Reddit for posts about the new iPhone, sorted by top"
|
|
55
|
+
> "What's u/spez's karma and account age?"
|
|
56
|
+
> "Is u/some_account shadowbanned or suspended?"
|
|
57
|
+
> "Get the full comment tree for this post: https://reddit.com/r/..."
|
|
58
|
+
> "Search r/startups comments that mention 'pricing'"
|
|
59
|
+
> "Show me the rules and moderators of r/webdev"
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Tools
|
|
64
|
+
|
|
65
|
+
All tools are read-only. Query parameters are `snake_case`; responses are
|
|
66
|
+
camelCase JSON.
|
|
67
|
+
|
|
68
|
+
| Tool | What it does |
|
|
69
|
+
|------|--------------|
|
|
70
|
+
| `get_posts` | Fetch posts from a subreddit |
|
|
71
|
+
| `get_search` | Search posts across Reddit |
|
|
72
|
+
| `get_comments` | A post's full comment tree |
|
|
73
|
+
| `get_post_by_id` | Fetch one post by id |
|
|
74
|
+
| `get_sub_by_name_top` | A subreddit's top posts |
|
|
75
|
+
| `get_sub_by_name_info` | Subreddit metadata, rules, moderators |
|
|
76
|
+
| `get_user_by_name` | User profile and karma |
|
|
77
|
+
| `get_user_by_name_comments` | A user's recent comments |
|
|
78
|
+
| `get_user_by_name_status` | Account status / shadowban check |
|
|
79
|
+
| `get_search_communities` | Search communities |
|
|
80
|
+
| `get_search_comments` | Search comments |
|
|
81
|
+
| `get_search_media` | Search media |
|
|
82
|
+
| `get_search_users` | Search users |
|
|
83
|
+
| `get_cite_rocket_overview` | Your credit, usage, and billing snapshot |
|
|
84
|
+
|
|
85
|
+
The live set is whatever the server pulls from the manifest at startup, so this
|
|
86
|
+
table tracks what's shipped today, not a hardcoded ceiling.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## How billing works
|
|
91
|
+
|
|
92
|
+
Every tool call is a normal CiteRocket API call authenticated with your
|
|
93
|
+
`CITEROCKET_API_KEY`, metered exactly like direct API usage, no separate MCP
|
|
94
|
+
billing. Standard reads cost 1 credit; `get_cite_rocket_overview` is free.
|
|
95
|
+
Per-plan QPS ceilings apply, see the [rate limits](https://www.citerocket.com/docs/rate-limits).
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Configuration
|
|
100
|
+
|
|
101
|
+
| Env var | Required | Purpose |
|
|
102
|
+
|---------|----------|---------|
|
|
103
|
+
| `CITEROCKET_API_KEY` | yes | Your API key, sent as `Authorization: Bearer` on every call. |
|
|
104
|
+
|
|
105
|
+
If CiteRocket is briefly unreachable at startup, the server falls back to the tool
|
|
106
|
+
set bundled in the package so your existing tools keep working.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Development
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
npm install
|
|
114
|
+
npm run build:manifest # regenerate the bundled tool manifest from the OpenAPI spec
|
|
115
|
+
npm run build # compile TypeScript to dist/
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Links
|
|
121
|
+
|
|
122
|
+
- 🌐 **Website:** [citerocket.com](https://www.citerocket.com)
|
|
123
|
+
- 📚 **API docs:** [citerocket.com/docs](https://www.citerocket.com/docs)
|
|
124
|
+
- 🔑 **Get an API key:** [app.citerocket.com](https://app.citerocket.com)
|
|
125
|
+
- 📈 **Status:** [citerocket.com/status](https://www.citerocket.com/status)
|
|
126
|
+
- ✉️ **Support:** [support@citerocket.com](mailto:support@citerocket.com)
|
|
127
|
+
|
|
128
|
+
CiteRocket is an independent third-party API for developers and researchers. Not
|
|
129
|
+
affiliated with, endorsed by, or sponsored by Reddit, Inc.
|
|
130
|
+
|
|
131
|
+
## License
|
|
132
|
+
|
|
133
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CiteRocket MCP server — thin, manifest-driven runtime.
|
|
4
|
+
*
|
|
5
|
+
* Holds ZERO hardcoded endpoints. On startup it loads the tool manifest
|
|
6
|
+
* (fetched from api.citerocket.com/mcp/manifest, with the bundled manifest.json
|
|
7
|
+
* as an offline fallback) and registers every tool dynamically. A single
|
|
8
|
+
* generic handler proxies each call to api.citerocket.com.
|
|
9
|
+
*
|
|
10
|
+
* This is what lets new endpoints reach every user WITHOUT a reinstall: add the
|
|
11
|
+
* endpoint to the API's OpenAPI spec, rebuild + deploy the API (which serves the
|
|
12
|
+
* updated manifest), and every already-installed MCP picks up the new tools on
|
|
13
|
+
* its next startup. No `npm update`, no config change.
|
|
14
|
+
*
|
|
15
|
+
* Auth model:
|
|
16
|
+
* CITEROCKET_API_KEY — required. Sent as `Authorization: Bearer` on every
|
|
17
|
+
* call. This is the only credential; the current tool surface is read-only.
|
|
18
|
+
*/
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import path from "node:path";
|
|
22
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
23
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
24
|
+
import { ListToolsRequestSchema, CallToolRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
25
|
+
// ── Config ────────────────────────────────────────────────────────────────
|
|
26
|
+
const API_KEY = process.env.CITEROCKET_API_KEY || process.env.CITEROCKET_KEY;
|
|
27
|
+
const MANIFEST_URL = process.env.CITEROCKET_MANIFEST_URL ||
|
|
28
|
+
"https://api.citerocket.com/mcp/manifest";
|
|
29
|
+
if (!API_KEY) {
|
|
30
|
+
console.error("[reddit-mcp] Missing CITEROCKET_API_KEY. Set it in your MCP config:\n" +
|
|
31
|
+
' "env": { "CITEROCKET_API_KEY": "cite_live_..." }\n' +
|
|
32
|
+
"Get a key at https://app.citerocket.com");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
// ── Manifest loading: hosted URL, bundled fallback ──────────────────────────
|
|
36
|
+
async function loadManifest() {
|
|
37
|
+
try {
|
|
38
|
+
const res = await fetch(MANIFEST_URL, { signal: AbortSignal.timeout(8000) });
|
|
39
|
+
if (res.ok)
|
|
40
|
+
return (await res.json());
|
|
41
|
+
console.error(`[reddit-mcp] manifest fetch ${res.status}; using bundled copy`);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
console.error(`[reddit-mcp] manifest fetch failed (${err.message}); using bundled copy`);
|
|
45
|
+
}
|
|
46
|
+
// Offline fallback: the manifest bundled in the npm tarball. If both the live
|
|
47
|
+
// fetch and the bundle are unavailable, fail loudly — since tool calls hit the
|
|
48
|
+
// same host, an unreachable manifest means the API itself is unreachable.
|
|
49
|
+
try {
|
|
50
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
51
|
+
const bundled = path.resolve(here, "../manifest.json");
|
|
52
|
+
return JSON.parse(readFileSync(bundled, "utf8"));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
throw new Error(`Could not load the tool manifest from ${MANIFEST_URL}, and no bundled ` +
|
|
56
|
+
`fallback was found. Check your network and that api.citerocket.com is reachable.`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// ── The generic call handler ────────────────────────────────────────────────
|
|
60
|
+
async function callEndpoint(manifest, tool, args) {
|
|
61
|
+
const query = {};
|
|
62
|
+
const body = {};
|
|
63
|
+
let urlPath = tool.path;
|
|
64
|
+
for (const [field, where] of Object.entries(tool.placement)) {
|
|
65
|
+
const value = args[field];
|
|
66
|
+
if (value === undefined || value === null || value === "")
|
|
67
|
+
continue;
|
|
68
|
+
if (where === "query")
|
|
69
|
+
query[field] = String(value);
|
|
70
|
+
else if (where === "path")
|
|
71
|
+
urlPath = urlPath.replace(`{${field}}`, encodeURIComponent(String(value)));
|
|
72
|
+
else
|
|
73
|
+
body[field] = value;
|
|
74
|
+
}
|
|
75
|
+
const qs = Object.keys(query).length ? "?" + new URLSearchParams(query) : "";
|
|
76
|
+
const url = `${manifest.server}${urlPath}${qs}`;
|
|
77
|
+
const res = await fetch(url, {
|
|
78
|
+
method: tool.method,
|
|
79
|
+
headers: {
|
|
80
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
81
|
+
"Content-Type": "application/json",
|
|
82
|
+
},
|
|
83
|
+
body: tool.method !== "GET" ? JSON.stringify(body) : undefined,
|
|
84
|
+
});
|
|
85
|
+
const text = await res.text();
|
|
86
|
+
return { isError: !res.ok, content: [{ type: "text", text }] };
|
|
87
|
+
}
|
|
88
|
+
// ── Boot ────────────────────────────────────────────────────────────────────
|
|
89
|
+
async function main() {
|
|
90
|
+
const manifest = await loadManifest();
|
|
91
|
+
const byName = new Map(manifest.tools.map((t) => [t.name, t]));
|
|
92
|
+
const server = new Server({ name: "citerocket", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
93
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
94
|
+
tools: manifest.tools.map((t) => ({
|
|
95
|
+
name: t.name,
|
|
96
|
+
description: t.description,
|
|
97
|
+
inputSchema: t.inputSchema,
|
|
98
|
+
...(t.annotations ? { annotations: t.annotations } : {}),
|
|
99
|
+
})),
|
|
100
|
+
}));
|
|
101
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
102
|
+
const tool = byName.get(req.params.name);
|
|
103
|
+
if (!tool) {
|
|
104
|
+
return {
|
|
105
|
+
isError: true,
|
|
106
|
+
content: [{ type: "text", text: `Unknown tool: ${req.params.name}` }],
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
const args = (req.params.arguments || {});
|
|
110
|
+
try {
|
|
111
|
+
return await callEndpoint(manifest, tool, args);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
return {
|
|
115
|
+
isError: true,
|
|
116
|
+
content: [{ type: "text", text: `Error: ${err.message}` }],
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
await server.connect(new StdioServerTransport());
|
|
121
|
+
console.error(`[reddit-mcp] ready — ${manifest.tools.length} tools (manifest ${manifest.version})`);
|
|
122
|
+
}
|
|
123
|
+
main().catch((err) => {
|
|
124
|
+
console.error("[reddit-mcp] fatal:", err);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
});
|
package/manifest.json
ADDED
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "2026-09-12T12:44:46.936Z",
|
|
3
|
+
"server": "https://api.citerocket.com",
|
|
4
|
+
"tools": [
|
|
5
|
+
{
|
|
6
|
+
"name": "get_posts",
|
|
7
|
+
"description": "Fetch posts from a subreddit",
|
|
8
|
+
"method": "GET",
|
|
9
|
+
"path": "/api/reddit/posts",
|
|
10
|
+
"annotations": {
|
|
11
|
+
"readOnlyHint": true
|
|
12
|
+
},
|
|
13
|
+
"placement": {
|
|
14
|
+
"subreddit": "query",
|
|
15
|
+
"sort": "query",
|
|
16
|
+
"t": "query",
|
|
17
|
+
"limit": "query",
|
|
18
|
+
"after": "query"
|
|
19
|
+
},
|
|
20
|
+
"inputSchema": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"properties": {
|
|
23
|
+
"subreddit": {
|
|
24
|
+
"type": "string",
|
|
25
|
+
"description": "Subreddit name (no r/ prefix)"
|
|
26
|
+
},
|
|
27
|
+
"sort": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"enum": [
|
|
30
|
+
"new",
|
|
31
|
+
"hot",
|
|
32
|
+
"top",
|
|
33
|
+
"rising",
|
|
34
|
+
"controversial",
|
|
35
|
+
"best"
|
|
36
|
+
],
|
|
37
|
+
"default": "new",
|
|
38
|
+
"description": "Sort tab"
|
|
39
|
+
},
|
|
40
|
+
"t": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"enum": [
|
|
43
|
+
"hour",
|
|
44
|
+
"day",
|
|
45
|
+
"week",
|
|
46
|
+
"month",
|
|
47
|
+
"year",
|
|
48
|
+
"all"
|
|
49
|
+
],
|
|
50
|
+
"description": "Timeframe for sort=top/controversial"
|
|
51
|
+
},
|
|
52
|
+
"limit": {
|
|
53
|
+
"type": "integer",
|
|
54
|
+
"default": 25,
|
|
55
|
+
"description": "Items to return, 1-100"
|
|
56
|
+
},
|
|
57
|
+
"after": {
|
|
58
|
+
"type": "string",
|
|
59
|
+
"description": "Pagination cursor from a previous response"
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"required": [
|
|
63
|
+
"subreddit"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "get_search",
|
|
69
|
+
"description": "Search posts across Reddit",
|
|
70
|
+
"method": "GET",
|
|
71
|
+
"path": "/api/reddit/search",
|
|
72
|
+
"annotations": {
|
|
73
|
+
"readOnlyHint": true
|
|
74
|
+
},
|
|
75
|
+
"placement": {
|
|
76
|
+
"q": "query",
|
|
77
|
+
"subreddit": "query",
|
|
78
|
+
"sort": "query",
|
|
79
|
+
"t": "query",
|
|
80
|
+
"nsfw": "query",
|
|
81
|
+
"limit": "query",
|
|
82
|
+
"after": "query"
|
|
83
|
+
},
|
|
84
|
+
"inputSchema": {
|
|
85
|
+
"type": "object",
|
|
86
|
+
"properties": {
|
|
87
|
+
"q": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "Search query"
|
|
90
|
+
},
|
|
91
|
+
"subreddit": {
|
|
92
|
+
"type": "string",
|
|
93
|
+
"description": "Restrict to a subreddit"
|
|
94
|
+
},
|
|
95
|
+
"sort": {
|
|
96
|
+
"type": "string",
|
|
97
|
+
"enum": [
|
|
98
|
+
"relevance",
|
|
99
|
+
"new",
|
|
100
|
+
"hot",
|
|
101
|
+
"top",
|
|
102
|
+
"comments"
|
|
103
|
+
],
|
|
104
|
+
"description": "Sort order"
|
|
105
|
+
},
|
|
106
|
+
"t": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"enum": [
|
|
109
|
+
"hour",
|
|
110
|
+
"day",
|
|
111
|
+
"week",
|
|
112
|
+
"month",
|
|
113
|
+
"year",
|
|
114
|
+
"all"
|
|
115
|
+
],
|
|
116
|
+
"description": "Timeframe"
|
|
117
|
+
},
|
|
118
|
+
"nsfw": {
|
|
119
|
+
"type": "boolean",
|
|
120
|
+
"description": "true to include NSFW results"
|
|
121
|
+
},
|
|
122
|
+
"limit": {
|
|
123
|
+
"type": "integer",
|
|
124
|
+
"default": 25,
|
|
125
|
+
"description": "Items to return, 1-100"
|
|
126
|
+
},
|
|
127
|
+
"after": {
|
|
128
|
+
"type": "string",
|
|
129
|
+
"description": "Pagination cursor from a previous response"
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
"required": [
|
|
133
|
+
"q"
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "get_sub_by_name_top",
|
|
139
|
+
"description": "A subreddit's top posts",
|
|
140
|
+
"method": "GET",
|
|
141
|
+
"path": "/api/reddit/sub/{name}/top",
|
|
142
|
+
"annotations": {
|
|
143
|
+
"readOnlyHint": true
|
|
144
|
+
},
|
|
145
|
+
"placement": {
|
|
146
|
+
"name": "path",
|
|
147
|
+
"t": "query",
|
|
148
|
+
"limit": "query",
|
|
149
|
+
"after": "query"
|
|
150
|
+
},
|
|
151
|
+
"inputSchema": {
|
|
152
|
+
"type": "object",
|
|
153
|
+
"properties": {
|
|
154
|
+
"name": {
|
|
155
|
+
"type": "string",
|
|
156
|
+
"description": "Subreddit name (no r/ prefix)"
|
|
157
|
+
},
|
|
158
|
+
"t": {
|
|
159
|
+
"type": "string",
|
|
160
|
+
"enum": [
|
|
161
|
+
"day",
|
|
162
|
+
"week",
|
|
163
|
+
"month",
|
|
164
|
+
"year",
|
|
165
|
+
"all"
|
|
166
|
+
],
|
|
167
|
+
"default": "week",
|
|
168
|
+
"description": "Timeframe"
|
|
169
|
+
},
|
|
170
|
+
"limit": {
|
|
171
|
+
"type": "integer",
|
|
172
|
+
"default": 25,
|
|
173
|
+
"description": "Items to return, 1-100"
|
|
174
|
+
},
|
|
175
|
+
"after": {
|
|
176
|
+
"type": "string",
|
|
177
|
+
"description": "Pagination cursor from a previous response"
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
"required": [
|
|
181
|
+
"name"
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"name": "get_sub_by_name_info",
|
|
187
|
+
"description": "Subreddit metadata, rules, moderators",
|
|
188
|
+
"method": "GET",
|
|
189
|
+
"path": "/api/reddit/sub/{name}/info",
|
|
190
|
+
"annotations": {
|
|
191
|
+
"readOnlyHint": true
|
|
192
|
+
},
|
|
193
|
+
"placement": {
|
|
194
|
+
"name": "path"
|
|
195
|
+
},
|
|
196
|
+
"inputSchema": {
|
|
197
|
+
"type": "object",
|
|
198
|
+
"properties": {
|
|
199
|
+
"name": {
|
|
200
|
+
"type": "string",
|
|
201
|
+
"description": "Subreddit name (no r/ prefix)"
|
|
202
|
+
}
|
|
203
|
+
},
|
|
204
|
+
"required": [
|
|
205
|
+
"name"
|
|
206
|
+
]
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"name": "get_comments",
|
|
211
|
+
"description": "A post's full comment tree",
|
|
212
|
+
"method": "GET",
|
|
213
|
+
"path": "/api/reddit/comments",
|
|
214
|
+
"annotations": {
|
|
215
|
+
"readOnlyHint": true
|
|
216
|
+
},
|
|
217
|
+
"placement": {
|
|
218
|
+
"permalink": "query"
|
|
219
|
+
},
|
|
220
|
+
"inputSchema": {
|
|
221
|
+
"type": "object",
|
|
222
|
+
"properties": {
|
|
223
|
+
"permalink": {
|
|
224
|
+
"type": "string",
|
|
225
|
+
"description": "Post permalink, e.g. /r/X/comments/abc/title/"
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
"required": [
|
|
229
|
+
"permalink"
|
|
230
|
+
]
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
"name": "get_post_by_id",
|
|
235
|
+
"description": "Fetch one post by id",
|
|
236
|
+
"method": "GET",
|
|
237
|
+
"path": "/api/reddit/post/{id}",
|
|
238
|
+
"annotations": {
|
|
239
|
+
"readOnlyHint": true
|
|
240
|
+
},
|
|
241
|
+
"placement": {
|
|
242
|
+
"id": "path"
|
|
243
|
+
},
|
|
244
|
+
"inputSchema": {
|
|
245
|
+
"type": "object",
|
|
246
|
+
"properties": {
|
|
247
|
+
"id": {
|
|
248
|
+
"type": "string",
|
|
249
|
+
"description": "Reddit post id, e.g. 1sgjld3"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
"required": [
|
|
253
|
+
"id"
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
"name": "get_user_by_name",
|
|
259
|
+
"description": "User profile and karma",
|
|
260
|
+
"method": "GET",
|
|
261
|
+
"path": "/api/reddit/user/{name}",
|
|
262
|
+
"annotations": {
|
|
263
|
+
"readOnlyHint": true
|
|
264
|
+
},
|
|
265
|
+
"placement": {
|
|
266
|
+
"name": "path"
|
|
267
|
+
},
|
|
268
|
+
"inputSchema": {
|
|
269
|
+
"type": "object",
|
|
270
|
+
"properties": {
|
|
271
|
+
"name": {
|
|
272
|
+
"type": "string",
|
|
273
|
+
"description": "Reddit username (no u/ prefix)"
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
"required": [
|
|
277
|
+
"name"
|
|
278
|
+
]
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"name": "get_user_by_name_comments",
|
|
283
|
+
"description": "A user's recent comments",
|
|
284
|
+
"method": "GET",
|
|
285
|
+
"path": "/api/reddit/user/{name}/comments",
|
|
286
|
+
"annotations": {
|
|
287
|
+
"readOnlyHint": true
|
|
288
|
+
},
|
|
289
|
+
"placement": {
|
|
290
|
+
"name": "path",
|
|
291
|
+
"sort": "query",
|
|
292
|
+
"limit": "query",
|
|
293
|
+
"after": "query"
|
|
294
|
+
},
|
|
295
|
+
"inputSchema": {
|
|
296
|
+
"type": "object",
|
|
297
|
+
"properties": {
|
|
298
|
+
"name": {
|
|
299
|
+
"type": "string",
|
|
300
|
+
"description": "Reddit username"
|
|
301
|
+
},
|
|
302
|
+
"sort": {
|
|
303
|
+
"type": "string",
|
|
304
|
+
"enum": [
|
|
305
|
+
"new",
|
|
306
|
+
"top",
|
|
307
|
+
"controversial"
|
|
308
|
+
],
|
|
309
|
+
"default": "new",
|
|
310
|
+
"description": "Sort order"
|
|
311
|
+
},
|
|
312
|
+
"limit": {
|
|
313
|
+
"type": "integer",
|
|
314
|
+
"default": 25,
|
|
315
|
+
"description": "Items to return, 1-100"
|
|
316
|
+
},
|
|
317
|
+
"after": {
|
|
318
|
+
"type": "string",
|
|
319
|
+
"description": "Pagination cursor from a previous response"
|
|
320
|
+
}
|
|
321
|
+
},
|
|
322
|
+
"required": [
|
|
323
|
+
"name"
|
|
324
|
+
]
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
{
|
|
328
|
+
"name": "get_user_by_name_status",
|
|
329
|
+
"description": "Account status / shadowban check",
|
|
330
|
+
"method": "GET",
|
|
331
|
+
"path": "/api/reddit/user/{name}/status",
|
|
332
|
+
"annotations": {
|
|
333
|
+
"readOnlyHint": true
|
|
334
|
+
},
|
|
335
|
+
"placement": {
|
|
336
|
+
"name": "path"
|
|
337
|
+
},
|
|
338
|
+
"inputSchema": {
|
|
339
|
+
"type": "object",
|
|
340
|
+
"properties": {
|
|
341
|
+
"name": {
|
|
342
|
+
"type": "string",
|
|
343
|
+
"description": "Reddit username (no u/ prefix)"
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"required": [
|
|
347
|
+
"name"
|
|
348
|
+
]
|
|
349
|
+
}
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
"name": "get_search_communities",
|
|
353
|
+
"description": "Search communities",
|
|
354
|
+
"method": "GET",
|
|
355
|
+
"path": "/api/reddit/search/communities",
|
|
356
|
+
"annotations": {
|
|
357
|
+
"readOnlyHint": true
|
|
358
|
+
},
|
|
359
|
+
"placement": {
|
|
360
|
+
"q": "query",
|
|
361
|
+
"nsfw": "query",
|
|
362
|
+
"limit": "query",
|
|
363
|
+
"after": "query"
|
|
364
|
+
},
|
|
365
|
+
"inputSchema": {
|
|
366
|
+
"type": "object",
|
|
367
|
+
"properties": {
|
|
368
|
+
"q": {
|
|
369
|
+
"type": "string",
|
|
370
|
+
"description": "Search query"
|
|
371
|
+
},
|
|
372
|
+
"nsfw": {
|
|
373
|
+
"type": "boolean",
|
|
374
|
+
"description": "true to include NSFW results"
|
|
375
|
+
},
|
|
376
|
+
"limit": {
|
|
377
|
+
"type": "integer",
|
|
378
|
+
"default": 25,
|
|
379
|
+
"description": "Items to return, 1-100"
|
|
380
|
+
},
|
|
381
|
+
"after": {
|
|
382
|
+
"type": "string",
|
|
383
|
+
"description": "Pagination cursor from a previous response"
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
"required": [
|
|
387
|
+
"q"
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"name": "get_search_comments",
|
|
393
|
+
"description": "Search comments",
|
|
394
|
+
"method": "GET",
|
|
395
|
+
"path": "/api/reddit/search/comments",
|
|
396
|
+
"annotations": {
|
|
397
|
+
"readOnlyHint": true
|
|
398
|
+
},
|
|
399
|
+
"placement": {
|
|
400
|
+
"q": "query",
|
|
401
|
+
"sort": "query",
|
|
402
|
+
"t": "query",
|
|
403
|
+
"nsfw": "query",
|
|
404
|
+
"limit": "query",
|
|
405
|
+
"after": "query"
|
|
406
|
+
},
|
|
407
|
+
"inputSchema": {
|
|
408
|
+
"type": "object",
|
|
409
|
+
"properties": {
|
|
410
|
+
"q": {
|
|
411
|
+
"type": "string",
|
|
412
|
+
"description": "Search query"
|
|
413
|
+
},
|
|
414
|
+
"sort": {
|
|
415
|
+
"type": "string",
|
|
416
|
+
"enum": [
|
|
417
|
+
"relevance",
|
|
418
|
+
"new",
|
|
419
|
+
"top"
|
|
420
|
+
],
|
|
421
|
+
"default": "relevance",
|
|
422
|
+
"description": "Sort order"
|
|
423
|
+
},
|
|
424
|
+
"t": {
|
|
425
|
+
"type": "string",
|
|
426
|
+
"enum": [
|
|
427
|
+
"hour",
|
|
428
|
+
"day",
|
|
429
|
+
"week",
|
|
430
|
+
"month",
|
|
431
|
+
"year",
|
|
432
|
+
"all"
|
|
433
|
+
],
|
|
434
|
+
"description": "Timeframe"
|
|
435
|
+
},
|
|
436
|
+
"nsfw": {
|
|
437
|
+
"type": "boolean",
|
|
438
|
+
"description": "true to include NSFW results"
|
|
439
|
+
},
|
|
440
|
+
"limit": {
|
|
441
|
+
"type": "integer",
|
|
442
|
+
"default": 25,
|
|
443
|
+
"description": "Items to return, 1-100"
|
|
444
|
+
},
|
|
445
|
+
"after": {
|
|
446
|
+
"type": "string",
|
|
447
|
+
"description": "Pagination cursor from a previous response"
|
|
448
|
+
}
|
|
449
|
+
},
|
|
450
|
+
"required": [
|
|
451
|
+
"q"
|
|
452
|
+
]
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
"name": "get_search_media",
|
|
457
|
+
"description": "Search media",
|
|
458
|
+
"method": "GET",
|
|
459
|
+
"path": "/api/reddit/search/media",
|
|
460
|
+
"annotations": {
|
|
461
|
+
"readOnlyHint": true
|
|
462
|
+
},
|
|
463
|
+
"placement": {
|
|
464
|
+
"q": "query",
|
|
465
|
+
"kind": "query",
|
|
466
|
+
"sort": "query",
|
|
467
|
+
"t": "query",
|
|
468
|
+
"nsfw": "query",
|
|
469
|
+
"limit": "query",
|
|
470
|
+
"after": "query"
|
|
471
|
+
},
|
|
472
|
+
"inputSchema": {
|
|
473
|
+
"type": "object",
|
|
474
|
+
"properties": {
|
|
475
|
+
"q": {
|
|
476
|
+
"type": "string",
|
|
477
|
+
"description": "Search query"
|
|
478
|
+
},
|
|
479
|
+
"kind": {
|
|
480
|
+
"type": "string",
|
|
481
|
+
"enum": [
|
|
482
|
+
"image",
|
|
483
|
+
"video",
|
|
484
|
+
"gallery",
|
|
485
|
+
"all"
|
|
486
|
+
],
|
|
487
|
+
"default": "all",
|
|
488
|
+
"description": "Media kind"
|
|
489
|
+
},
|
|
490
|
+
"sort": {
|
|
491
|
+
"type": "string",
|
|
492
|
+
"enum": [
|
|
493
|
+
"relevance",
|
|
494
|
+
"new",
|
|
495
|
+
"hot",
|
|
496
|
+
"top",
|
|
497
|
+
"comments"
|
|
498
|
+
],
|
|
499
|
+
"default": "relevance",
|
|
500
|
+
"description": "Sort order"
|
|
501
|
+
},
|
|
502
|
+
"t": {
|
|
503
|
+
"type": "string",
|
|
504
|
+
"enum": [
|
|
505
|
+
"hour",
|
|
506
|
+
"day",
|
|
507
|
+
"week",
|
|
508
|
+
"month",
|
|
509
|
+
"year",
|
|
510
|
+
"all"
|
|
511
|
+
],
|
|
512
|
+
"description": "Timeframe"
|
|
513
|
+
},
|
|
514
|
+
"nsfw": {
|
|
515
|
+
"type": "boolean",
|
|
516
|
+
"description": "true to include NSFW results"
|
|
517
|
+
},
|
|
518
|
+
"limit": {
|
|
519
|
+
"type": "integer",
|
|
520
|
+
"default": 25,
|
|
521
|
+
"description": "Items to return, 1-100"
|
|
522
|
+
},
|
|
523
|
+
"after": {
|
|
524
|
+
"type": "string",
|
|
525
|
+
"description": "Pagination cursor from a previous response"
|
|
526
|
+
}
|
|
527
|
+
},
|
|
528
|
+
"required": [
|
|
529
|
+
"q"
|
|
530
|
+
]
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
{
|
|
534
|
+
"name": "get_search_users",
|
|
535
|
+
"description": "Search users",
|
|
536
|
+
"method": "GET",
|
|
537
|
+
"path": "/api/reddit/search/users",
|
|
538
|
+
"annotations": {
|
|
539
|
+
"readOnlyHint": true
|
|
540
|
+
},
|
|
541
|
+
"placement": {
|
|
542
|
+
"q": "query",
|
|
543
|
+
"nsfw": "query",
|
|
544
|
+
"limit": "query",
|
|
545
|
+
"after": "query"
|
|
546
|
+
},
|
|
547
|
+
"inputSchema": {
|
|
548
|
+
"type": "object",
|
|
549
|
+
"properties": {
|
|
550
|
+
"q": {
|
|
551
|
+
"type": "string",
|
|
552
|
+
"description": "Search query"
|
|
553
|
+
},
|
|
554
|
+
"nsfw": {
|
|
555
|
+
"type": "boolean",
|
|
556
|
+
"description": "true to include NSFW results"
|
|
557
|
+
},
|
|
558
|
+
"limit": {
|
|
559
|
+
"type": "integer",
|
|
560
|
+
"default": 25,
|
|
561
|
+
"description": "Items to return, 1-100"
|
|
562
|
+
},
|
|
563
|
+
"after": {
|
|
564
|
+
"type": "string",
|
|
565
|
+
"description": "Pagination cursor from a previous response"
|
|
566
|
+
}
|
|
567
|
+
},
|
|
568
|
+
"required": [
|
|
569
|
+
"q"
|
|
570
|
+
]
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
{
|
|
574
|
+
"name": "get_cite_rocket_overview",
|
|
575
|
+
"description": "Return member identity, plan access, spendable credits, lifetime usage and billing history in one free request",
|
|
576
|
+
"method": "GET",
|
|
577
|
+
"path": "/citerocket/overview",
|
|
578
|
+
"annotations": {
|
|
579
|
+
"readOnlyHint": true
|
|
580
|
+
},
|
|
581
|
+
"placement": {},
|
|
582
|
+
"inputSchema": {
|
|
583
|
+
"type": "object",
|
|
584
|
+
"properties": {}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
]
|
|
588
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@citerocket/reddit-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official Reddit API MCP server by CiteRocket — search Reddit posts & comments, subreddit top, comment trees, user karma, communities, media, and shadowban checks inside Claude, Cursor, Windsurf, and any MCP client.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"reddit-mcp": "dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"manifest.json",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build:manifest": "node scripts/build-manifest.mjs",
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"prepublishOnly": "npm run build:manifest && npm run build"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"mcp",
|
|
22
|
+
"model-context-protocol",
|
|
23
|
+
"reddit",
|
|
24
|
+
"reddit-api",
|
|
25
|
+
"claude",
|
|
26
|
+
"cursor",
|
|
27
|
+
"citerocket"
|
|
28
|
+
],
|
|
29
|
+
"homepage": "https://www.citerocket.com",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/citerocket-hq/reddit-mcp.git"
|
|
33
|
+
},
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^22.0.0",
|
|
40
|
+
"typescript": "^5.5.0"
|
|
41
|
+
}
|
|
42
|
+
}
|