run-mcp-local — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited run-mcp-local (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Two-container stack: mcp-server (FastAPI on :8000) and redis (on :6379), orchestrated by futuresearch-mcp/deploy/docker-compose.yaml with local overrides.
CRITICAL: Always check for stale processes on port 8000 before starting.
A leftover futuresearch-mcp --no-auth or similar process on the host will shadow the Docker container's port binding. All requests hit the stale process instead of the container — this can look like auth routes are broken, sheets tools are missing, etc.
# Check for anything on port 8000
lsof -i :8000
# Kill if needed
lsof -ti :8000 | xargs kill -9Also check Docker is running:
docker info --format '{{.ServerVersion}}' || colima startcd futuresearch-mcp/deploy
REDIS_PASSWORD=testpass \
MCP_SERVER_URL=http://localhost:8000 \
docker compose \
-f docker-compose.yaml \
-f docker-compose.local.yaml \
up -d --buildVerify: curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/health should return 200.
Pass these alongside REDIS_PASSWORD and MCP_SERVER_URL:
| Env var | Default | Purpose |
|---|---|---|
ENABLE_SHEETS_TOOLS | false | Register Google Sheets tools |
TRUST_PROXY_HEADERS | false | Trust X-Forwarded-For (required behind tunnel) |
EXTRA_ALLOWED_HOSTS | (empty) | Extra hostnames for DNS rebinding allowlist |
These are templated in docker-compose.local.yaml as ${VAR:-default} — the container must be recreated (not just restarted) for env var changes to take effect.
The .env file at futuresearch-mcp/deploy/.env contains production secrets (Supabase, API keys, upload secret). It is already present and should NOT be committed or overwritten.
REDIS_PASSWORD is intentionally NOT in .env — always pass it as an env var (testpass for local dev).
The .env file is gitignored and won't exist in worktrees. Symlink it:
ln -s /Users/rafaelpoyiadzi/Documents/git/futuresearch-python/futuresearch-mcp/deploy/.env \
<worktree-path>/futuresearch-mcp/deploy/.envRequired when testing with Claude.ai or Claude Desktop, which can't reach localhost.
pkill -f cloudflared 2>/dev/null
rm -f /tmp/cf-tunnel.log
lsof -ti :8000 | xargs kill -9 2>/dev/nullcloudflared tunnel --url http://localhost:8000 2>/tmp/cf-tunnel.log &
sleep 6
grep -oE 'https://[a-z0-9-]+\.trycloudflare\.com' /tmp/cf-tunnel.log | head -1This prints a URL like https://something-something.trycloudflare.com.
The server must know its public URL for OAuth redirects to work:
cd futuresearch-mcp/deploy
REDIS_PASSWORD=testpass \
MCP_SERVER_URL=https://something-something.trycloudflare.com \
TRUST_PROXY_HEADERS=true \
ENABLE_SHEETS_TOOLS=true \
docker compose \
-f docker-compose.yaml \
-f docker-compose.local.yaml \
up -d --buildKey: MCP_SERVER_URL must match the tunnel URL exactly, and TRUST_PROXY_HEADERS=true is required so the server trusts the forwarded headers from Cloudflare.
# Through the tunnel (what Claude.ai sees)
curl -s https://<tunnel-url>/.well-known/oauth-authorization-server | python3 -m json.tool | head -5
# Locally
curl -s http://localhost:8000/.well-known/oauth-authorization-server | python3 -m json.tool | head -5Both should return JSON with issuer, authorization_endpoint, etc. If local returns 404 but tunnel works (or vice versa), check for stale processes on port 8000.
Claude.ai / Claude Desktop: Use the tunnel URL as the MCP server URL in the client config.
Claude Code: Add a project-scoped MCP server (writes to .claude/settings.local.json in the current dir, not the global config):
claude mcp add futuresearch --scope project --transport http <TUNNEL_URL>/mcpThen restart Claude Code. Remove with claude mcp remove futuresearch --scope project.
# All logs
docker logs deploy-mcp-server-1 -f
# Filter for errors
docker logs deploy-mcp-server-1 2>&1 | grep -iE "error|warn|401|500"
# Check User-Agent strings (for widget/client detection work)
docker logs deploy-mcp-server-1 2>&1 | grep "User-Agent"cd futuresearch-mcp/deploy
REDIS_PASSWORD=testpass MCP_SERVER_URL=http://localhost:8000 \
docker compose -f docker-compose.yaml -f docker-compose.local.yaml downKill the tunnel: pkill -f cloudflared or kill %1 if it was backgrounded.
Run the server directly with uv run — no Docker needed. Useful for quick local testing with the MCP Inspector.
WARNING: If you leave this running and later start the Docker stack, the local process will shadow Docker's port 8000. Always kill it first: lsof -ti :8000 | xargs kill -9
docker run -d --name test-redis -p 6379:6379 redis:7-alpine)FUTURESEARCH_API_KEY (or legacy FUTURESEARCH_API_KEY) in ~/.claude/secrets/remote.envcd futuresearch-mcp
ALLOW_NO_AUTH=1 \
UPLOAD_SECRET=$(python -c "import secrets; print(secrets.token_urlsafe(32))") \
EXTRA_ALLOWED_HOSTS="host.docker.internal,localhost" \
bash scripts/run-no-auth.shnpx @modelcontextprotocol/inspectorMCP_PROXY_AUTH_TOKEN)http://localhost:8000/mcpNote: Direct mode won't work (CORS). Auth mode won't work (Inspector v0.21.0 doesn't handle the OAuth flow). Use Via Proxy with no-auth.
uv run python scripts/mcp_call.py list
uv run python scripts/mcp_call.py call futuresearch_balance
uv run python scripts/mcp_call.py call futuresearch_agent '{"params": {"task": "...", "data": [...]}}'Note: mcp_call.py only works against --no-auth servers. It doesn't do OAuth, so authenticated servers will show a subset of tools or fail.
| Problem | Solution | |
|---|---|---|
required variable REDIS_PASSWORD is missing | Pass REDIS_PASSWORD=testpass as env var | |
required variable MCP_SERVER_URL is missing | Pass MCP_SERVER_URL=http://localhost:8000 (or tunnel URL) | |
| OAuth 401 when connecting via tunnel | MCP_SERVER_URL doesn't match the tunnel URL, or TRUST_PROXY_HEADERS=true is missing | |
| OAuth discovery returns 404 | Check `lsof -i :8000` — a stale local process is likely shadowing Docker. Kill it and restart containers with down/up (not just restart) | |
| Port 8000 already in use | `lsof -ti :8000 | xargs kill -9` then restart |
| Redis connection refused | Check redis container is healthy: `docker ps | grep redis` |
| cloudflared output is empty | It writes to stderr: use 2>/tmp/cf-tunnel.log redirect | |
| Container doesn't pick up code changes | Add --build to the docker compose up command | |
| Container doesn't pick up env var changes | Must recreate: docker compose ... down && docker compose ... up -d | |
.env not found in worktree | Symlink from main repo: ln -s <main>/futuresearch-mcp/deploy/.env <worktree>/futuresearch-mcp/deploy/.env | |
| Sheets tools not showing in tool list | Pass ENABLE_SHEETS_TOOLS=true and recreate the container | |
mcp_call.py shows fewer tools than expected | It connects without auth — authenticated servers may filter tools | |
| Docker daemon not running | colima start (may need colima stop && colima start if socket is stale) |
| File | Purpose |
|---|---|
futuresearch-mcp/deploy/docker-compose.yaml | Base compose (server + redis) |
futuresearch-mcp/deploy/docker-compose.local.yaml | Local overrides (ports, env passthrough) |
futuresearch-mcp/deploy/.env | Production secrets (DO NOT commit changes) |
futuresearch-mcp/deploy/Dockerfile | Server container build |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.