feat: remote MCP server via Streamable HTTP + api_keys table (OPE-91)#284
Conversation
…-91) Phase 1 of MCP dogfooding. Converts the MCP server from stdio-only to dual transport: stdio for local dev, streamable-http for remote. Changes: - server.py: Rewritten with FastMCP, dual transport support - stdio mode: same as before (Claude Desktop config) - streamable-http mode: remote deployment for Claude.ai Connectors - /health endpoint for Railway health checks - /mcp endpoint for MCP protocol (Streamable HTTP) - CLI: python server.py --transport http - Env: MCP_TRANSPORT=streamable-http - config.py: Added TRANSPORT, HOST, PORT config from env vars - requirements.txt: Added uvicorn, bumped mcp>=1.25.0 - Dockerfile: New, for Railway deployment of MCP service - .env.example: Updated with transport config - supabase/migrations/004_api_keys.sql: Creates api_keys table for MCP authentication (ci_xxx format, SHA-256 hashed, RLS) Deployment steps in PR description.
|
@DevanshuNEU is attempting to deploy a commit to the Dev's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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. ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
📝 WalkthroughWalkthroughAdds streamable-HTTP transport to the MCP server (FastMCP/uvicorn), HTTP health endpoint, Dockerfile for container deployment, env/config updates (TRANSPORT/HOST/PORT, server version), dependency bumps, CI workflow additions, and a new supabase migration introducing an api_keys table with RLS policies. Changes
Sequence Diagram(s)sequenceDiagram
participant Client
participant Uvicorn as Uvicorn/HTTP
participant FastMCP as FastMCP
participant Tool as ToolRegistry
Client->>Uvicorn: HTTP POST /mcp (streamable-http)
Uvicorn->>FastMCP: forward MCP request
FastMCP->>Tool: handle call_tool / dispatch
Tool-->>FastMCP: tool response
FastMCP-->>Uvicorn: MCP response
Uvicorn-->>Client: HTTP response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~22 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (4)
mcp-server/server.py (1)
74-78: CLI argument parsing could be improved with argparse.The manual
sys.argvparsing works but is fragile (e.g., no validation, no help text). Consider usingargparsefor robustness, though the current implementation is acceptable for a simple single-flag case.♻️ Optional: Use argparse for CLI
import argparse def main(): parser = argparse.ArgumentParser(description=f"{SERVER_NAME} MCP Server") parser.add_argument( "--transport", choices=["stdio", "http", "streamable-http"], default=TRANSPORT, help="Transport mode (default: from MCP_TRANSPORT env)" ) args = parser.parse_args() transport = "streamable-http" if args.transport == "http" else args.transport # ... rest of main()🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcp-server/server.py` around lines 74 - 78, Replace fragile manual sys.argv parsing with argparse: modify the main entry (where transport is set using sys.argv and variable transport) to use an argparse.ArgumentParser that defines a --transport option with choices ("stdio", "http", "streamable-http") and a default derived from TRANSPORT/env; after parsing, normalize "http" to "streamable-http" (as current logic does) and assign to transport. Ensure the parser includes a helpful description and help text so validation and --help work correctly.supabase/migrations/004_api_keys.sql (2)
13-13: Consider adding a CHECK constraint for thetiercolumn.The
tiercolumn accepts any text value. If only specific tiers are valid (e.g.,'free','pro','enterprise'), a CHECK constraint would prevent invalid data.🛡️ Proposed fix
- tier text DEFAULT 'free', + tier text DEFAULT 'free' CHECK (tier IN ('free', 'pro', 'enterprise')),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@supabase/migrations/004_api_keys.sql` at line 13, Add a CHECK constraint to restrict the tier column to allowed values (e.g., 'free', 'pro', 'enterprise') by updating the CREATE TABLE statement that defines the tier column (or adding an ALTER TABLE ... ADD CONSTRAINT tier_check) so that the column "tier" enforces CHECK (tier IN ('free','pro','enterprise')) to prevent invalid values being inserted.
10-10: Nullableuser_idmay cause RLS policy failures for system/service keys.The
user_idcolumn allows NULL values, but RLS policies useauth.uid() = user_id. For system keys (NULL user_id), these policies will never match, making such keys invisible to all authenticated users via RLS. This may be intentional (service_role bypass), but consider documenting this behavior or adding explicit handling.📝 Suggestion: Add documentation comment
CREATE TABLE IF NOT EXISTS api_keys ( id uuid DEFAULT gen_random_uuid() PRIMARY KEY, - user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE, + -- user_id can be NULL for system/CI keys (accessed only via service_role) + user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@supabase/migrations/004_api_keys.sql` at line 10, The user_id column is nullable which causes RLS policies using auth.uid() = user_id to never match for system/service keys; update the migration to explicitly document this behavior or adjust schema/logic: either add a SQL COMMENT on the user_id column explaining that NULL means a system/service key and therefore will not match RLS policies that compare to auth.uid(), or alter the schema/logical design (e.g., add a separate boolean like is_system_key or make user_id NOT NULL and use a sentinel) and update RLS policies accordingly; reference the user_id column and the auth.uid() checks in the RLS policies when making the change.mcp-server/Dockerfile (1)
15-17: Consider adding a HEALTHCHECK instruction for container orchestration.Since
_get_http_app()exposes/health, adding a Docker HEALTHCHECK would help orchestrators (including Railway) detect container readiness and health.🐳 Proposed addition
EXPOSE 8080 +HEALTHCHECK --interval=30s --timeout=5s --start-period=5s --retries=3 \ + CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:${PORT:-8080}/health')" || exit 1 + CMD ["python", "server.py"]🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcp-server/Dockerfile` around lines 15 - 17, Add a Docker HEALTHCHECK to the Dockerfile to probe the application's /health endpoint exposed by _get_http_app(); update the Dockerfile (near the EXPOSE/CMD block) to run a lightweight HTTP check (e.g., curl or wget) against http://localhost:8080/health with sensible options for --interval (e.g., 30s), --timeout (e.g., 5s) and --retries (e.g., 3) and ensure the check returns exit 0 on healthy responses and non-zero otherwise; this will allow orchestrators to detect readiness and liveness of the server started by CMD ["python","server.py"].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@mcp-server/config.py`:
- Line 21: The PORT environment parsing currently does int(os.getenv("PORT",
"8080")) which will raise an unhandled ValueError for non-numeric values; wrap
the conversion in a try/except (or validate with str.isdigit()/regex) around the
os.getenv("PORT", "8080") result, log or raise a clear error if invalid, and
fall back to the default 8080 (or exit) so that the module-level PORT variable
is always a valid int; update the PORT assignment and any related error
message/logging accordingly (refer to the PORT variable and os.getenv usage).
In `@mcp-server/server.py`:
- Line 40: The code directly accesses the private attribute _mcp_server on the
mcp module (assigned to _server) which is brittle across versions; update
requirements.txt to pin an upper bound (e.g., change mcp>=1.25.0 to
mcp>=1.25.0,<2.0.0), add a clear inline comment next to the assignment of
_server = mcp._mcp_server explaining why the private API is required (to bypass
FastMCP's automatic schema generation and use custom schemas from tools.py), and
add a short TODO to monitor mcp for a public API or open an upstream issue to
request custom input schema registration so this private access can be removed
when available.
In `@supabase/migrations/004_api_keys.sql`:
- Around line 35-38: The UPDATE policy "Users can deactivate own keys" on
api_keys is too permissive (it allows changing sensitive columns like key_hash
and tier) while APIKeyManager.revoke_key() only intends to toggle active (and
maybe last_used_at); restrict updates so users can only modify the active and
last_used_at columns by either (a) replacing the policy with a condition that
ensures no other columns change, (b) adding a trigger that rejects changes to
any column except active and last_used_at, or (c) create a SECURITY DEFINER
function (e.g., revoke_api_key) that performs the allowed update and keep the
UPDATE policy narrow/removed so callers must use that function — reference the
policy name "Users can deactivate own keys", APIKeyManager.revoke_key(), and the
sensitive columns key_hash and tier when making the change.
---
Nitpick comments:
In `@mcp-server/Dockerfile`:
- Around line 15-17: Add a Docker HEALTHCHECK to the Dockerfile to probe the
application's /health endpoint exposed by _get_http_app(); update the Dockerfile
(near the EXPOSE/CMD block) to run a lightweight HTTP check (e.g., curl or wget)
against http://localhost:8080/health with sensible options for --interval (e.g.,
30s), --timeout (e.g., 5s) and --retries (e.g., 3) and ensure the check returns
exit 0 on healthy responses and non-zero otherwise; this will allow
orchestrators to detect readiness and liveness of the server started by CMD
["python","server.py"].
In `@mcp-server/server.py`:
- Around line 74-78: Replace fragile manual sys.argv parsing with argparse:
modify the main entry (where transport is set using sys.argv and variable
transport) to use an argparse.ArgumentParser that defines a --transport option
with choices ("stdio", "http", "streamable-http") and a default derived from
TRANSPORT/env; after parsing, normalize "http" to "streamable-http" (as current
logic does) and assign to transport. Ensure the parser includes a helpful
description and help text so validation and --help work correctly.
In `@supabase/migrations/004_api_keys.sql`:
- Line 13: Add a CHECK constraint to restrict the tier column to allowed values
(e.g., 'free', 'pro', 'enterprise') by updating the CREATE TABLE statement that
defines the tier column (or adding an ALTER TABLE ... ADD CONSTRAINT tier_check)
so that the column "tier" enforces CHECK (tier IN ('free','pro','enterprise'))
to prevent invalid values being inserted.
- Line 10: The user_id column is nullable which causes RLS policies using
auth.uid() = user_id to never match for system/service keys; update the
migration to explicitly document this behavior or adjust schema/logic: either
add a SQL COMMENT on the user_id column explaining that NULL means a
system/service key and therefore will not match RLS policies that compare to
auth.uid(), or alter the schema/logical design (e.g., add a separate boolean
like is_system_key or make user_id NOT NULL and use a sentinel) and update RLS
policies accordingly; reference the user_id column and the auth.uid() checks in
the RLS policies when making the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 870d2e9c-7774-4228-b4c0-1dd5868f6a3f
📒 Files selected for processing (6)
mcp-server/.env.examplemcp-server/Dockerfilemcp-server/config.pymcp-server/requirements.txtmcp-server/server.pysupabase/migrations/004_api_keys.sql
Review fixes: - config.py: PORT parsing wrapped in try/except, falls back to 8080 - server.py: pinned mcp<2.0.0, documented _mcp_server private API access - requirements.txt: mcp>=1.25.0,<2.0.0 upper bound - Dockerfile: added HEALTHCHECK with curl to /health endpoint - 004_api_keys.sql: CHECK constraint on tier column, immutable column trigger (blocks key_hash/tier/name changes for non-service-role), documented NULL user_id = system key behavior CI pipeline: - Added mcp-server/** path filter to change detection - New test-mcp job: Python 3.13, runs pytest on mcp-server/tests/ - Security scan now also triggers on MCP changes
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
.github/workflows/ci.yml (1)
110-137: Job structure is correct; consider adding linting for consistency.The test-mcp job is well-structured and correctly mirrors the pattern of other test jobs. The dependencies are properly installed from requirements.txt which includes pytest and pytest-asyncio.
Optional improvements for consistency with the backend job:
- Add a linting step (e.g., flake8 or ruff)
- Add coverage reporting (
--covflag)♻️ Optional: Add linting step
- name: Install dependencies working-directory: ./mcp-server run: | python -m pip install --upgrade pip + pip install flake8 pip install -r requirements.txt + - name: Lint (flake8) + working-directory: ./mcp-server + run: | + flake8 src/ + - name: Run tests🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 110 - 137, Add a linting step and optional coverage reporting to the test-mcp GitHub Actions job: modify the test-mcp job (job name "test-mcp") to install a linter (e.g., ruff or flake8) in the "Install dependencies" step or as a separate step, then add a new step that runs the linter (e.g., "ruff check ." or "flake8 .") before running tests; also update the "Run tests" step (the pytest invocation) to include coverage reporting (e.g., add the --cov flag such as "pytest tests/ -v --cov") and, if desired, add a step to upload coverage reports so it mirrors the backend job's behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@mcp-server/server.py`:
- Around line 74-88: The current startup logic quietly falls back to stdio for
any transport other than "streamable-http"; change it to validate the chosen
transport (TRANSPORT or CLI override via "--transport") and only allow known
values ("streamable-http" and "stdio"), mapping the "http" alias to
"streamable-http", and otherwise print a clear error including the bad transport
and exit non-zero; update the block that parses sys.argv and the final dispatch
(the branch that currently calls mcp.run(transport="stdio")) to perform this
validation and call sys.exit(1) on unknown transports, while preserving the
existing uvicorn run path that uses _get_http_app(), SERVER_NAME,
SERVER_VERSION, HOST, and PORT.
---
Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 110-137: Add a linting step and optional coverage reporting to the
test-mcp GitHub Actions job: modify the test-mcp job (job name "test-mcp") to
install a linter (e.g., ruff or flake8) in the "Install dependencies" step or as
a separate step, then add a new step that runs the linter (e.g., "ruff check ."
or "flake8 .") before running tests; also update the "Run tests" step (the
pytest invocation) to include coverage reporting (e.g., add the --cov flag such
as "pytest tests/ -v --cov") and, if desired, add a step to upload coverage
reports so it mirrors the backend job's behavior.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fdb9d003-e37c-48cf-92f6-193aaeb6fd99
📒 Files selected for processing (6)
.github/workflows/ci.ymlmcp-server/Dockerfilemcp-server/config.pymcp-server/requirements.txtmcp-server/server.pysupabase/migrations/004_api_keys.sql
🚧 Files skipped from review as they are similar to previous changes (1)
- mcp-server/Dockerfile
- server.py: unknown transport now prints error and exits non-zero instead of silently falling back to stdio - .flake8: new config matching backend (bugs-only, 120 char lines) - ci.yml: MCP job now runs flake8 lint + pytest with --cov
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/ci.yml (1)
20-33:⚠️ Potential issue | 🟠 MajorInclude the Supabase auth migration in this filter.
The new MCP auth surface is not only
mcp-server/**; this PR also introducessupabase/migrations/004_api_keys.sql. As written, a PR that only changes theapi_keysschema or RLS policies will skip bothtest-mcpand the widenedsecurity-scan, which leaves auth regressions untested and unscanned.Suggested fix
mcp: - 'mcp-server/**' + - 'supabase/migrations/**'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/ci.yml around lines 20 - 33, The mcp filter only matches 'mcp-server/**' so changes to the new Supabase migration (supabase/migrations/004_api_keys.sql) are not triggering downstream jobs; update the filter definition used by the dorny/paths-filter step (id: filter) to include the Supabase migration path (for example add 'supabase/migrations/004_api_keys.sql' or broaden to 'supabase/migrations/**') under the mcp filter so PRs that touch the api_keys schema or RLS policies will trigger test-mcp and security-scan.
♻️ Duplicate comments (1)
mcp-server/server.py (1)
74-88:⚠️ Potential issue | 🟠 MajorUnknown transport values still fall through to stdio.
Anything other than
"streamable-http"lands in theelsebranch, soMCP_TRANSPORT=http, mixed-case values, or typos silently start stdio and break the remote deployment path. Normalize and validate the chosen transport before dispatching instead of treating every unknown value as stdio.🔧 Suggested fix
def main(): """Run with configured transport.""" - transport = TRANSPORT + transport = TRANSPORT.strip().lower() # CLI override: --transport http if "--transport" in sys.argv: idx = sys.argv.index("--transport") if idx + 1 < len(sys.argv): - arg = sys.argv[idx + 1] - transport = "streamable-http" if arg in ("http", "streamable-http") else arg + transport = sys.argv[idx + 1].strip().lower() + + transport = {"http": "streamable-http"}.get(transport, transport) + if transport not in {"stdio", "streamable-http"}: + raise SystemExit( + f"Unsupported transport '{transport}'. " + "Expected 'stdio' or 'streamable-http'." + ) if transport == "streamable-http": import uvicorn print(f"Starting {SERVER_NAME} v{SERVER_VERSION} on {HOST}:{PORT}/mcp") uvicorn.run(_get_http_app(), host=HOST, port=PORT) else: - mcp.run(transport="stdio") + mcp.run(transport=transport)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@mcp-server/server.py` around lines 74 - 88, Normalize and validate the transport value from TRANSPORT and CLI args before dispatch: lower-case the chosen transport (use transport = transport.lower()), map accepted aliases ("http" -> "streamable-http") and explicitly handle known transports (e.g., "streamable-http" -> start uvicorn via _get_http_app(), "stdio" -> call mcp.run(transport="stdio")), and if the value is unknown print a clear error and exit non‑zero instead of falling through to stdio; update the sys.argv parsing and dispatch logic that currently uses TRANSPORT, transport, uvicorn.run, _get_http_app, and mcp.run accordingly.
🧹 Nitpick comments (1)
supabase/migrations/004_api_keys.sql (1)
53-70: Consider documenting the absence of DELETE policy.There's no
DELETEpolicy, meaning users cannot hard-delete their API keys—only soft-delete via settingactive = false. This is likely intentional for audit purposes, but consider adding an explicit comment or a deny-all DELETE policy for clarity:-- Users cannot hard-delete keys; deactivation (active=false) is the intended revocation mechanism. -- Service role can hard-delete if needed for GDPR/data-retention compliance.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@supabase/migrations/004_api_keys.sql` around lines 53 - 70, Add documentation and/or an explicit deny-all DELETE policy for the api_keys table to clarify that hard-deletes are disallowed; update the migration near the api_keys RLS block (where policies "Users can view own keys", "Users can create own keys", and "Users can deactivate own keys" are defined) to include a comment like "Users cannot hard-delete keys; deactivation (active=false) is the intended revocation mechanism. Service role may hard-delete for compliance" and optionally add a deny-all DELETE policy for readability/explicitness so future reviewers see DELETE is intentionally restricted.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@mcp-server/config.py`:
- Around line 21-25: The current parsing of _port_raw into PORT only handles
non-numeric values; update the logic that parses _port_raw and assigns PORT to
validate the TCP port range (1–65535). After converting _port_raw to int (in the
existing try/except around PORT), check that PORT is within 1 and 65535 and if
not either set PORT to the sane default 8080 or raise a configuration error
(choose one consistent behavior for the app) and log or surface the problem;
reference the variables/functions _port_raw and PORT so you update that block
only. Ensure non-numeric values keep the existing fallback behavior and
out-of-range numeric values are handled deterministically.
In `@mcp-server/server.py`:
- Around line 65-69: The app returned by _get_http_app() currently returns the
raw mcp.streamable_http_app() with only a /health route, leaving the MCP
endpoint unprotected; modify _get_http_app() to enforce authentication on the
MCP endpoint before returning the app—either add an authentication middleware to
app or wrap/replace the MCP Route with a guarded handler that validates API keys
or Bearer tokens (use your existing auth validator function or token store) and
returns 401/403 on failure; ensure you apply this protection to the
mcp.streamable_http_app() routes (the MCP handler produced by
mcp.streamable_http_app()) while leaving _health publicly accessible.
In `@supabase/migrations/004_api_keys.sql`:
- Line 19: The last_used_at column is never updated; modify verify_key() in
backend/services/rate_limiter.py so that after a successful lookup of api_keys
(the existing db.table("api_keys").select(...).eq(...).execute() result) you
execute an update on that row to set last_used_at to the current timestamp
(e.g., now()/datetime.utcnow() or DB now()) using
db.table("api_keys").update({...}).eq("id", result.data[0]["id"]).execute();
alternatively, if you prefer not to track usage, remove the last_used_at column
from the schema to avoid misleading audit fields.
---
Outside diff comments:
In @.github/workflows/ci.yml:
- Around line 20-33: The mcp filter only matches 'mcp-server/**' so changes to
the new Supabase migration (supabase/migrations/004_api_keys.sql) are not
triggering downstream jobs; update the filter definition used by the
dorny/paths-filter step (id: filter) to include the Supabase migration path (for
example add 'supabase/migrations/004_api_keys.sql' or broaden to
'supabase/migrations/**') under the mcp filter so PRs that touch the api_keys
schema or RLS policies will trigger test-mcp and security-scan.
---
Duplicate comments:
In `@mcp-server/server.py`:
- Around line 74-88: Normalize and validate the transport value from TRANSPORT
and CLI args before dispatch: lower-case the chosen transport (use transport =
transport.lower()), map accepted aliases ("http" -> "streamable-http") and
explicitly handle known transports (e.g., "streamable-http" -> start uvicorn via
_get_http_app(), "stdio" -> call mcp.run(transport="stdio")), and if the value
is unknown print a clear error and exit non‑zero instead of falling through to
stdio; update the sys.argv parsing and dispatch logic that currently uses
TRANSPORT, transport, uvicorn.run, _get_http_app, and mcp.run accordingly.
---
Nitpick comments:
In `@supabase/migrations/004_api_keys.sql`:
- Around line 53-70: Add documentation and/or an explicit deny-all DELETE policy
for the api_keys table to clarify that hard-deletes are disallowed; update the
migration near the api_keys RLS block (where policies "Users can view own keys",
"Users can create own keys", and "Users can deactivate own keys" are defined) to
include a comment like "Users cannot hard-delete keys; deactivation
(active=false) is the intended revocation mechanism. Service role may
hard-delete for compliance" and optionally add a deny-all DELETE policy for
readability/explicitness so future reviewers see DELETE is intentionally
restricted.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 44897365-3d71-442b-8761-f133887c2ae6
📒 Files selected for processing (6)
.github/workflows/ci.ymlmcp-server/Dockerfilemcp-server/config.pymcp-server/requirements.txtmcp-server/server.pysupabase/migrations/004_api_keys.sql
🚧 Files skipped from review as they are similar to previous changes (2)
- mcp-server/requirements.txt
- mcp-server/Dockerfile
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
- config.py: PORT now validated 1-65535, falls back to 8080 if out of range - config.py: added MCP_AUTH_TOKEN env var - server.py: Bearer token middleware on /mcp endpoint when MCP_AUTH_TOKEN set; /health remains public; no auth → 401, wrong token → 401 - auth.py: _validate_api_key now updates last_used_at on successful lookup (fire-and-forget, won't block auth on failure) - 004_api_keys.sql: documented DELETE policy intent (soft-delete via active flag) - ci.yml: supabase/migrations/** added to mcp path filter
What
Converts our MCP server from stdio-only (local) to dual transport, enabling remote deployment as a Claude.ai Custom Connector. This is Phase 1 of MCP dogfooding.
Changes
MCP Server
server.py: Rewritten with FastMCP, supportsstdioandstreamable-httptransportconfig.py: New env vars:MCP_TRANSPORT,MCP_HOST,PORTDockerfile: New, for Railway deployment as separate service/healthendpoint returns 200 (Railway health checks)/mcpendpoint handles Streamable HTTP MCP protocolDatabase
supabase/migrations/004_api_keys.sql: Createsapi_keystable forci_xxxtoken authTransport modes
Summary by CodeRabbit
New Features
Chores
Summary by CodeRabbit
New Features
Chores