Skip to content

Add HTTP transport and Bearer token auth for Google Cloud Run deployment#11

Open
hemati wants to merge 4 commits into
Arindam200:mainfrom
hemati:main
Open

Add HTTP transport and Bearer token auth for Google Cloud Run deployment#11
hemati wants to merge 4 commits into
Arindam200:mainfrom
hemati:main

Conversation

@hemati

@hemati hemati commented Dec 24, 2025

Copy link
Copy Markdown
Contributor

This pull request adds support for deploying the Reddit MCP server to Google Cloud Run using HTTP transport, including optional Bearer Token authentication for secure access. The changes also improve local development and testing workflows, update dependencies to support HTTP serving, and enhance error handling and logging throughout the codebase.

Deployment and Authentication Enhancements:

  • Added detailed instructions to README.md for deploying to Google Cloud Run, including environment variable configuration, authentication setup, and log monitoring.
  • Introduced Bearer Token authentication middleware for HTTP endpoints, activated via the MCP_BEARER_TOKEN environment variable and implemented using Starlette middleware.
  • Updated the __main__ section in server.py to support both stdio and HTTP transports, with conditional middleware injection for authentication and Uvicorn server startup for HTTP mode.
  • Added a Procfile to specify the web server startup command for deployment platforms.

Dependency and Configuration Updates:

  • Updated pyproject.toml to add fastmcp, uvicorn, and an optional auth dependency group for Starlette-based authentication.
  • Ensured praw.models is explicitly imported for type checking and improved type annotations for comment formatting. [1] [2]

Robustness and Logging Improvements:

  • Improved error handling when replying to posts and comments by raising an error if Reddit returns no response. [1] [2]
  • Fixed a potential unbound variable error when extracting submission IDs.

Summary by CodeRabbit

  • New Features

    • Optional Bearer token authentication for secure HTTP deployments
    • Added HTTP/streamable-HTTP transport mode for running the service
  • Documentation

    • Added a detailed Google Cloud Run deployment guide (includes prerequisites, secure deployment, local testing, and monitoring) — note: deployment section appears duplicated
  • Chores

    • Added Procfile for web deployment
    • Updated and consolidated project dependencies and requirements file

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai

coderabbitai Bot commented Dec 24, 2025

Copy link
Copy Markdown

Warning

Rate limit exceeded

@hemati has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 20 minutes and 48 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 0fe003e and 06f36a0.

📒 Files selected for processing (2)
  • pyproject.toml
  • requirements.txt
📝 Walkthrough

Walkthrough

Adds deployment/run files and README Cloud Run instructions; updates packaging/dependencies. server.py gains environment-driven FastMCP/Uvicorn startup, optional Bearer-token Starlette middleware for HTTP transport, transport selection (stdio vs HTTP), defensive Reddit reply handling, and expanded comment typing. (50 words)

Changes

Cohort / File(s) Summary
Deployment / Packaging
Procfile, requirements.txt, pyproject.toml
Adds Procfile with web: python server.py; introduces dependencies mcp[cli]>=1.21.0, praw>=7.8.1, uvicorn>=0.32.1, fastmcp>=2.14.1; optional auth extras include starlette>=0.27.0.
Documentation
README.md
Adds a full Google Cloud Run deployment guide (prereqs, quick/source deploy, secure deploy with Bearer token, MCP client config, local testing, monitoring). The deployment section is duplicated.
Server runtime & auth
server.py
Reads FastMCP host/port/stateless from env; selects transport via MCP_TRANSPORT (stdio vs http/streamable-http); adds optional BearerToken middleware when MCP_BEARER_TOKEN present (uses Starlette if available, logs/warns otherwise); starts Uvicorn for HTTP transport.
Runtime robustness & types
server.py
_format_comment signature broadened to accept `praw.models.Comment

Sequence Diagram(s)

sequenceDiagram
  participant Client as HTTP Client
  participant Uvicorn as Uvicorn/ASGI
  participant Middleware as BearerTokenMiddleware
  participant Server as FastMCP App (server.py)
  participant Reddit as Reddit API (praw)

  Client->>Uvicorn: HTTP request (POST /events or stream)
  Uvicorn->>Middleware: pass request
  alt MCP_BEARER_TOKEN set
    Middleware->>Client: validate Authorization: Bearer
    Middleware-->>Uvicorn: allow or 401
  end
  Uvicorn->>Server: dispatch event to handler
  Server->>Server: process event, require_write_access checks
  Server->>Reddit: create reply / fetch submission
  Reddit-->>Server: reply object (or None)
  alt reply is None
    Server->>Server: raise RuntimeError / log error
  else
    Server->>Client: return success / event response
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

A rabbit codes at dawn, so spry,
I add a token, watch requests fly,
FastMCP hums, Uvicorn leaps,
Reddit whispers secrets it keeps,
Deploy with joy — hop to the sky! 🐇☁️

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main changes: adding HTTP transport capability and Bearer token authentication specifically for Google Cloud Run deployment, which are the core objectives of this PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
server.py (1)

155-208: Consider constant-time comparison for Bearer token validation.

The Bearer token authentication middleware is well-structured with proper error responses (401 for missing/invalid format, 403 for wrong token). However, the token comparison at line 192 uses standard string comparison, which may be vulnerable to timing attacks.

🔎 Proposed fix using secrets.compare_digest

Add import at the top of the file:

import secrets

Then update the token comparison:

                 # Extract and validate token
                 token = auth_header[7:]  # Remove "Bearer " prefix
-                if token != self.bearer_token:
+                if not secrets.compare_digest(token, self.bearer_token):
                     return JSONResponse(
                         status_code=403,
                         content={"error": "Invalid bearer token"}
                     )

secrets.compare_digest performs constant-time comparison, making timing attacks significantly harder.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5c56363 and afe37a2.

📒 Files selected for processing (5)
  • Procfile
  • README.md
  • pyproject.toml
  • requirements.txt
  • server.py
🧰 Additional context used
🪛 Gitleaks (8.30.0)
README.md

[high] 291-296: Discovered a potential authorization token provided in a curl command header, which could compromise the curl accessed resource.

(curl-auth-header)

🪛 LanguageTool
README.md

[grammar] ~262-~262: Ensure spelling is correct
Context: ...} } } } ``` ### Local Testing **Stdio mode (default, for local MCP clients):*...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 Ruff (0.14.10)
server.py

140-140: Possible binding to all interfaces

(S104)


1432-1432: Abstract raise to an inner function

(TRY301)


1432-1432: Avoid specifying long messages outside the exception class

(TRY003)


1537-1537: Abstract raise to an inner function

(TRY301)


1537-1537: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (9)
README.md (1)

173-342: Well-documented Cloud Run deployment guide.

The deployment instructions are comprehensive and cover:

  • Prerequisites and authentication setup
  • Basic and secure (Bearer token) deployment options
  • MCP client configuration examples
  • Local testing for both stdio and HTTP modes
  • Monitoring and operational commands

The documentation structure is clear and provides actionable commands.

Procfile (1)

1-1: LGTM! Simple and correct.

The Procfile correctly defines the web process for Heroku-style deployments. The server.py main block will handle transport selection based on the MCP_TRANSPORT environment variable.

server.py (7)

9-9: Good addition for type checking.

Explicitly importing praw.models improves type annotations and IDE support, especially for the updated _format_comment signature.


138-152: Environment-driven configuration is well-designed.

The FastMCP configuration correctly reads from environment variables:

  • HOST defaults to 0.0.0.0 (appropriate for Cloud Run containers)
  • PORT defaults to 8080 (Cloud Run standard)
  • MCP_STATELESS enables stateless HTTP mode for serverless deployments

The static analysis warning about binding to all interfaces (0.0.0.0) is a false positive here—Cloud Run containers require this to accept traffic.


332-332: Improved type annotation for flexibility.

Updating the type hint to accept both praw.models.Comment and praw.models.Message improves type safety and correctly reflects that the function can handle both types of objects.


1431-1432: Good defensive check for API response.

Adding validation that reply is not None prevents potential issues if the Reddit API fails silently. The explicit error message helps with debugging.


1536-1537: Good defensive check for API response.

Consistent with the pattern in reply_to_post, this defensive check ensures the Reddit API returned a valid response.


1906-1908: Good fix for potential UnboundLocalError.

Initializing clean_submission_id before the try block ensures it's defined if _extract_reddit_id raises an exception, preventing an UnboundLocalError when the exception handler references it at line 2038.


2402-2434: Well-structured entry point with proper transport selection.

The __main__ block correctly handles three modes:

  1. HTTP with Bearer token authentication (manual uvicorn with middleware)
  2. HTTP without authentication (standard mcp.run)
  3. Stdio mode (backward-compatible default)

The conditional logic is clear, and logging messages help with debugging deployment issues.

Comment thread pyproject.toml Outdated
Comment thread requirements.txt Outdated
…erver.py with detailed docstrings for better clarity
@hemati hemati changed the title Added Google Cloud Run Deploy Instructions Add HTTP transport and Bearer token auth for Google Cloud Run deployment Dec 24, 2025

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
server.py (1)

184-231: Consider using constant-time comparison for bearer token validation.

The bearer token comparison at line 225 uses a standard equality check, which may be vulnerable to timing attacks. For security-sensitive token validation, consider using a constant-time comparison function.

🔎 Proposed fix using secrets.compare_digest

Add import at the top of the file:

+import secrets
 import functools
 import logging

Then update the token comparison:

                 # Extract and validate token
                 token = auth_header[7:]  # Remove "Bearer " prefix
-                if token != self.bearer_token:
+                if not secrets.compare_digest(token, self.bearer_token):
                     return JSONResponse(
                         status_code=403,
                         content={"error": "Invalid bearer token"}
                     )
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between afe37a2 and 0fe003e.

📒 Files selected for processing (3)
  • pyproject.toml
  • requirements.txt
  • server.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • requirements.txt
🧰 Additional context used
🪛 Ruff (0.14.10)
server.py

158-158: Possible binding to all interfaces

(S104)


1465-1465: Abstract raise to an inner function

(TRY301)


1465-1465: Avoid specifying long messages outside the exception class

(TRY003)


1570-1570: Abstract raise to an inner function

(TRY301)


1570-1570: Avoid specifying long messages outside the exception class

(TRY003)

🔇 Additional comments (7)
server.py (7)

9-9: LGTM!

Explicit import of praw.models improves type checking and makes type annotations clearer.


28-32: LGTM!

The docstring additions improve code documentation and follow Python best practices.

Also applies to: 128-140


156-170: LGTM! Configuration appropriate for Cloud Run deployment.

The environment-based configuration is well-structured. Binding to 0.0.0.0 (flagged by static analysis) is intentional and necessary for Cloud Run deployments to accept external traffic. The stateless HTTP mode is appropriate for serverless environments.


365-365: LGTM!

The type annotation improvement makes the function's accepted types explicit and enhances type safety.


1464-1465: LGTM! Good defensive programming.

The checks for None replies add robustness by ensuring Reddit API calls succeeded before proceeding. This prevents silent failures and provides clear error messages.

Also applies to: 1569-1570


1939-1941: LGTM! Good fix for potential UnboundLocalError.

Initializing clean_submission_id before the try block ensures the variable is always bound when referenced in the exception handler, preventing potential errors.


2436-2467: LGTM! Well-structured transport selection and server startup.

The implementation properly handles both HTTP and stdio transports, with backward compatibility maintained through the stdio default. The conditional middleware injection for Bearer token authentication is correctly implemented, and logging provides good visibility into the server's configuration.

Comment thread pyproject.toml Outdated
@hemati

hemati commented Dec 24, 2025

Copy link
Copy Markdown
Contributor Author

@Arindam200 this is a larger PR, but it adds an important new feature: using the MCP over HTTP.
I also included a short guide on how to deploy it on Google Cloud.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant