Reading public lists via RSS, posts and comments via .json without keys,
and also direct access to the Reddit API
via OAuth2 without PRAW. Port of the MCP server
Arindam200/reddit-mcp to shell scripts
following the pattern of yandex-metrika / yandex-search-api.
Choosing the reading method
For public reading by user subscriptions, including RSS monitoring,
take the list from config/subscriptions.txt: one subreddit name
per line, without r/. Subreddits explicitly specified in the request take priority
over the saved list. Do not look for subscriptions in .env or the account and do not connect
a browser session to obtain this list. If the file is missing or empty,
ask the user to clarify the subreddits.
If the user has not specified a method, for public reading first use
the available built-in URL reading tool (fetch, WebFetch, open or equivalent).
Open a specific address; search results by themselves do not replace the content:
- Post and comments: use the address with
.json; for a regular link add.jsonto the post path before the query parameters, for examplehttps://www.reddit.com/r/Python/comments/abc123/title/.json?limit=100&raw_json=1. - List of posts: if the tool supports XML/Atom, open the RSS feed,
for example
https://www.reddit.com/r/Python/top.rss?t=day&limit=25.
For this method do not run auth_check.sh and do not request application keys.
The subscription list is stored separately from .env; the presence or validity of keys
is not a condition for public reading.
During repeated monitoring, request fresh data if the tool allows it;
otherwise indicate the freshness limitation.
If the tool is absent, does not support the format, did not return the required content, or
the task requires a script and a local cache, use the commands below. For reading without keys pass
REDDIT_RSS_MODE=1. The failure of one method does not prove the unavailability of another.
The web tool may return truncated text instead of the original JSON or RSS.
Do not present such a response as a complete file and do not promise all comments: account for truncation,
the parameter limit and the elements more. The local cache is described below only for scripts;
when reading with the web tool, do not report that a file was saved if it was not saved.
Configuring scripts
Application keys are not needed for monitoring posts. Enable RSS explicitly:
REDDIT_RSS_MODE=1 sh scripts/subreddit_top.sh --subreddit singularity --time day --limit 25
REDDIT_RSS_MODE=1 can be saved to config/.env. When passed via the environment,
the script does not read .env. For a list of config/subscriptions.txt , pass each
subreddit explicitly via --subreddit: the scripts do not load the subscription list themselves.
For RSS there is a standard User-Agent; it can be replaced
via REDDIT_USER_AGENT.
For full access via the API, register script-app at
https://www.reddit.com/prefs/apps and fill in config/.env:
REDDIT_CLIENT_ID,REDDIT_CLIENT_SECRETREDDIT_USER_AGENT(required by Reddit rules)
Detailed instructions: config/README.md.
For write/me additionally:
REDDIT_USERNAME,REDDIT_PASSWORD— owner of the script-app (without 2FA)REDDIT_ENABLE_WRITE=1+--confirmon every write command
Script behavior
- Cache-first — token, users, subreddits, listings are cached by a deterministic key.
- Context window hygiene — stdout ≤ 30 lines, full JSON in
cache/listings/<hash>.json. - Mode selection —
REDDIT_RSS_MODE=1enables RSS. Without keys, supported read commands also use RSS. With keys, user mode is selected ifREDDIT_USERNAME+REDDIT_PASSWORDis present, otherwise app-only. If authorization fails, reading posts automatically switches to RSS in the current run; settings on disk are not changed. - Double write protection — two levels:
- Without
REDDIT_ENABLE_WRITE=1в.envwrite scripts fail immediately with a clear error (no dry-run — this is an environment-level "gate"). - С
REDDIT_ENABLE_WRITE=1, but without--confirm— dry-run: they print what they would do, but do not send the request. - Only with
REDDIT_ENABLE_WRITE=1и--confirmdoes the command actually go to Reddit.
- Without
- Rate-limit from headers — we read
x-ratelimit-remaining,x-ratelimit-reset,Retry-After. On 429, one retry if the wait is ≤ 60s.
Using scripts
Access check
-
If a script is selected, run the required read command immediately. If you need to check access separately:
sh scripts/auth_check.shSuccess:
OK: RSS feed works,OK: app-only token worksorOK: user token works. For RSS, do not request the file with keys and do not require app registration. -
If a write operation is needed:
- Make sure that
.envcontainsREDDIT_USERNAME+REDDIT_PASSWORD+REDDIT_ENABLE_WRITE=1(withoutREDDIT_ENABLE_WRITE=1the command immediately fails with an error — this is intentional) - First run the command without
--confirm— you will see a dry-run - Only after user review — add
--confirm
- Make sure that
-
Subreddit/user name can be passed with or without a prefix:
r/python≡python,u/spez≡spez.
RSS capabilities
RSS supports subreddit_top.sh, search.sh, user_posts.sh и auth_check.sh.
Search, sorting, period, and count parameters are passed to the public feed.
submission.sh in the same mode reads https://www.reddit.com/comments/{id}.json
without a token. You can pass a regular post link, a link with .json or an ID.
--include-comments for top loads posts and comments via the same public JSON.
The remaining commands require the API.
The title, link, date, author, subreddit, and text available in the feed are saved.
The JSON has the usual structure Listing and the flag source: "rss".
score и num_comments are equal to null, in the brief output — ?: RSS does not provide these numbers.
Do not judge a post's popularity by them. The text is limited to the content of the feed itself.
The public .json is saved as an array [Listing поста, Listing комментариев],
each with source: "public-json"; scores and other fields are taken from the Reddit response.
The full received text and nested replies are available in the cache; a brief summary is displayed on screen.
Do not promise all comments: the response is limited to --limit-comments /
--comments-per-post and may contain more. The skill does not expand more
with additional requests; submission.sh reports if it found it in the tree.
Automatic fallback triggers when token issuance fails (HTTP 400/401/403 or OAuth authorization error), API 403, or a repeated API 401 after token refresh. Network errors, 429, and 5xx do not mean the key is broken and do not enable RSS. If RSS or public JSON is also unavailable, the command returns an explicit error. If comment loading fails, the already retrieved list of posts remains in cache.
Scripts
Auth & identity
| Script | Endpoint | Mode | Description |
|---|---|---|---|
auth_check.sh |
GET /r/all/new?limit=1 or .rss |
any | API or RSS check |
me.sh |
GET /api/v1/me |
user only | Personal profile (karma, name) |
Read
| Script | Endpoint | Description |
|---|---|---|
user_info.sh --username U |
/user/{u}/about |
User profile |
user_posts.sh --username U |
/user/{u}/submitted |
User posts |
user_comments.sh --username U |
/user/{u}/comments |
User comments |
subreddit_info.sh --subreddit S |
/r/{s}/about |
Subreddit metadata |
subreddit_stats.sh --subreddit S |
/r/{s}/about + /about/rules + /about/moderators |
Extended metrics + rules + moderators |
subreddit_popular.sh |
/subreddits/popular |
Popular subreddits (Reddit "trending") |
subreddit_top.sh --subreddit S |
/r/{s}/top (+ /comments/{id} per-post with --include-comments) |
Top subreddit posts; optionally with comments for each |
search.sh --query "..." |
/search or /r/{s}/search |
Reddit search (opt. --subreddit) |
submission.sh --id I or --url U |
/comments/{id} or /comments/{id}.json |
Post + comments; works without keys |
Common read flags: --limit N, --no-cache, --time T (where applicable), --sort S (where applicable).
Write (dangerous — double safety)
| Script | Endpoint | Description |
|---|---|---|
post_create.sh --subreddit S --title T (--content C | --url U) |
POST /api/submit |
Publish a post |
comment_reply.sh --parent-id ID --content C |
POST /api/comment |
Reply to a post (t3_*) or comment (t1_*) |
subreddit_subscribe.sh --subreddit S [--unsubscribe] |
POST /api/subscribe |
Subscribe / unsubscribe |
All write commands require --confirm и REDDIT_ENABLE_WRITE=1 в .env.
Behavior:
REDDIT_ENABLE_WRITEnot set → failure with an error (envelope level).REDDIT_ENABLE_WRITE=1, but without--confirm→ dry-run (printing, no network).- Both conditions met → real POST.
Scripts cache
cache/
├── token.json # OAuth access token + expires_at
├── users/<username>.json # /user/{u}/about
├── subreddits/<sub>.json # /r/{sub}/about
├── subreddits/<sub>.rules.json
├── subreddits/<sub>.moderators.json
├── listings/<hash>.json # листинги (search, top, posts, comments, popular)
├── top_with_comments/<hash>/ # копии постов с комментариями в подпапках api/ и rss/
└── me.json # /api/v1/me
Public read cache keys are separated from the API. If updating a post or list fails, the previous
file is preserved. For fresh publications during repeated monitoring, pass --no-cache.
Cache search: grep -r "term" cache/ or rg "term" cache/.
Examples
# 1) Profile of a user
sh scripts/user_info.sh --username spez
# 2) Top posts in r/Python this week
sh scripts/subreddit_top.sh --subreddit python --time week --limit 25
# 3) Search "machine learning" in r/learnprogramming, sorted by new
sh scripts/search.sh --query "machine learning" --subreddit learnprogramming \
--sort new --time month --limit 20
# 4) Пост и комментарии через публичный JSON без ключей
REDDIT_RSS_MODE=1 sh scripts/submission.sh \
--url "https://www.reddit.com/r/Python/comments/abc123/some_title/" \
--limit-comments 50
# 5) DRY-RUN of a comment reply (requires REDDIT_ENABLE_WRITE=1; without --confirm only prints)
REDDIT_ENABLE_WRITE=1 sh scripts/comment_reply.sh \
--parent-id t3_abc123 --content "Looks great!"
# 6) Real reply (after dry-run review)
REDDIT_ENABLE_WRITE=1 sh scripts/comment_reply.sh \
--parent-id t3_abc123 --content "Looks great!" --confirm
# 7) Топ с комментариями (один дополнительный API или JSON запрос на пост)
sh scripts/subreddit_top.sh --subreddit Python --time week --limit 5 \
--include-comments --comments-per-post 25
Rate limits
Reddit OAuth: ~60 req/min for app-only, ~600/10min for user-mode (depends on account history). The skill reads Reddit-specific headers x-ratelimit-* and the standard Retry-After. On 429 it retries once if the wait is ≤ 60s, otherwise fails with a clear error.
Tests
sh scripts/tests/run.sh
No-network, they check:
- parsing submission URL → id
- determinism of cache_key
- correctness of automatic auth mode selection
- that write commands without
REDDIT_ENABLE_WRITEor without--confirmsend nothing - Atom parsing, public JSON, reading without keys, migration from the API, and cache separation
Differences from upstream
The original reddit-mcp uses PRAW + Python and is hardwired as an MCP server. Here public reading starts with the agent's available web tool; shell scripts use curl and a cache in the skill directory. The agent performs analysis of posts and discussions based on the retrieved data.