Repository navigation
feat: add optional Reddit OAuth credentials and surface real HTTP errors - #6
Merged
Merged
Conversation
Reddit now answers most unauthenticated programmatic requests with
HTTP 403 ("You've been blocked by network security"), and redd reports
every transport failure as HttpError(0), so users only saw
"HTTP error (0). Reddit may be temporarily unavailable".
- Optional REDDIT_CLIENT_ID / REDDIT_CLIENT_SECRET (and REDDIT_USER_AGENT):
when set, redd's HTTP transport is replaced by an adapter that obtains
an app-only token (client_credentials grant), refreshes it on expiry or
401, and sends requests to oauth.reddit.com with a bearer token.
Anonymous access stays the default; setting only one variable is a
usage error.
- Recover the real cause behind redd's HttpError(0): HTTP status plus a
short body summary, 404 -> not found, network errors, non-JSON bodies,
and OAuth token failures. Tool errors now explain 401/403/429/5xx, and
403 points to the OAuth credentials.
- Disable the FastMCP startup banner on the stdio transport.
- Remove the emoji from the CLI description; --help crashed on Windows
cp1252 consoles.
- Read __version__ from package metadata (it was stuck at 0.1.0).
- README: optional credentials, 403 explanation, banner note.
This was referenced Oct 24, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #3
Reddit now answers most unauthenticated programmatic requests with HTTP 403 and an HTML page that says "You've been blocked by network security". I confirmed this from a residential connection, including with browser-like headers. This PR covers all four points in the issue.
1. Optional Reddit OAuth app credentials
New, optional environment variables:
REDDIT_CLIENT_ID/REDDIT_CLIENT_SECRETREDDIT_USER_AGENTpython:reddit-no-auth-mcp-server:v<version> (+repo URL).When both credentials are set,
RedditOAuthHttpAdapter(new) takes the place of redd's HTTP transport insideAsyncRedd. It:POST https://www.reddit.com/api/v1/access_token(grant_type=client_credentials, HTTP Basic client auth);expires_in, or after a 401 (the request is retried once);www.reddit.comURLs that redd builds tohttps://oauth.reddit.comand sendsAuthorization: bearer <token>.redd keeps building the URLs and parsing the responses, so tool output does not change. Anonymous access remains the default. Setting only one of the two credentials is rejected at startup with a clean usage error (exit code 2).
Shippable without a redd release. redd 0.2.x has no public hook for a custom transport, so the adapter is installed on
AsyncRedd._http. That attribute is private, but it is the single place all requests go through. A guard raises aConfigurationErrorif a future redd removes it, and the OAuth tests run through the realAsyncRedd, so a breaking redd change would fail CI. A publichttp=/transport hook in redd would let this drop the private attribute later, but nothing here needs one.2. The real HTTP status and a useful message instead of
HTTP error (0)The
0comes from redd:AsyncRedd._getcatches every exception and re-raisesHttpError(0, url, str(exc)).ReddRedditAdapternow inspects__cause__and raises the matching domain exception:httpx.HTTPStatusErrorbecomesHttpError(<real status>, url, <short body summary>). HTML block pages are cut down to their first sentence, and JSON errors use theirmessage.NotFoundError.NetworkError.ParseError.AuthenticationError.McpErrorMapperturns these into actionable messages. The live result on a blocked network:401, 429, and 5xx get their own messages, and bad credentials produce
Reddit OAuth authentication failed. Reddit rejected the OAuth token request (HTTP 401: Unauthorized). Check REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET.3. FastMCP banner on stdio
The stdio transport now calls
mcp.run(transport="stdio", show_banner=False). With fastmcp 3.1 the banner goes to stderr, not stdout, so it doesn't actually corrupt the JSON-RPC stream. It is still noise, and its box-drawing art can trip up clients and Windows consoles. The HTTP transport keeps the default, andFASTMCP_SHOW_SERVER_BANNER=false(now in the README) hides it there.4.
--helpcrash on Windows cp1252Removed the emoji from the argparse description, and a test now asserts that the help text is ASCII.
Also
__version__is read from package metadata. It was hard-coded to0.1.0, so--versionand the default User-Agent were wrong.httpxis now a direct dependency. It was already installed through fastmcp.envexample), what a 403 means, and the banner note. The package description is updated to match.Verification
tests/test_reddit_oauth.py,httpx.MockTransport, through the realAsyncRedd):grant_type=client_credentialsbody, and User-Agent;oauth.reddit.com/<same path>withbearer <token>and nothing else is contacted;access_token, raisesAuthenticationError;reddit_get_subreddit_postswithfastmcp.Client):mainreturnsHTTP error (0). Reddit may be temporarily unavailable...;mainprints it).PYTHONIOENCODING=cp1252 reddit-no-auth-mcp-server --helpworks. Onmainit raisesUnicodeEncodeError: 'charmap' codec can't encode character '\U0001f916'.ruff check,ruff format --check, andpytest(81 passed) are clean.mypy srcshows only the existingasdictignore-code error, which fix: return JSON objects from list tools so outputSchema matches the payload #5 fixes.Not verified: a successful call with valid credentials against
oauth.reddit.com, since I had no Reddit app credentials. Specifically untested: that the OAuth host serves redd's.json-suffixed paths (/r/<sub>/hot.json,/user/<name>/.json,/search.json,/<permalink>.json) the same waywwwdoes.