Skip to main content
Glama
README.md
# MCP Remote Server — HTTP-Streamable / Resumable (FastMCP)

A production-style **remote MCP (Model Context Protocol) server** built with **FastMCP**, exposing tools over a **multi-user, HTTP-streamable (resumable)** transport and deployed to the cloud via CI/CD. It integrates **Gmail, Google Calendar, OpenAI, Salesforce, and a ChromaDB RAG layer** behind a clean service layer, with **JWT-based Salesforce auth**.

> Part of the **SunnyLab** build series — the step that took a local, single-user MCP server to a **resumable, multi-user remote server on cloud**. That transition is the whole point of this repo: identity moves from "whoever runs the process" to a parameter on the connection, credentials move from files on disk to secrets injected at runtime, and a dropped connection no longer loses the session. Sanitized public showcase: all secrets, keys, and infra identifiers were removed; configure your own `.env` / CI secrets.

![Stage 2 of the series — Admin, Sales, and Finance clients converging over resumable Streamable HTTP onto one remote MCP server on GCP, backed by a RAG vector store and reaching Email, CRM, Calendar, and AI analysis.](assets/architecture-hero.png)


> **SSE → Streamable HTTP.** The transport was migrated off SSE: SSE holds one long-lived unidirectional stream, so a dropped connection loses the session and every client needs its own. Streamable HTTP (JSON-RPC 2.0) survives reconnects and serves many users on one endpoint — which is what made the multi-user story possible at all. The `MCP_MODE=sse` env value is a legacy name for "remote mode"; the wire protocol underneath is Streamable HTTP.

## What it demonstrates
- **Remote MCP over HTTP-streamable, resumable transport** — multi-user, not local stdio; clients reconnect without losing session state
- **Per-request user identity** — `?user_id=…&client_type=…` on the MCP URL selects that user's Gmail mailbox and Salesforce identity (`admin` / `sales` / `finance`), each initialized independently
- **Runtime secret materialization** — Base64 credentials and PEM keys arrive as env vars and are written to disk at startup; nothing sensitive is ever committed
- **Enterprise integrations** — Gmail, Google Calendar, OpenAI, Salesforce (JWT Bearer), ChromaDB for RAG-backed helpdesk answers
- **Built-in observability** — logging middleware over every tool call, a log-receiver API on a second port, and a lightweight dashboard
- **Cloud-native delivery** — Docker, Cloud Build, GitHub Actions (all secrets via `${{ secrets.* }}`; project/VM are placeholders), plus a log-retention cron

## Architecture
```
MCP clients (multi-user)
   Claude Desktop · Cursor · ADK web · LangGraph
        │  HTTP-streamable / resumable MCP
        │  /mcp?user_id=admin&client_type=…
        ▼
FastMCP remote server  (:8000)  ── LoggingMiddleware ──► log API (:8001) ──► dashboard
   ├─ per-user config resolution (Gmail token · SFDC identity)
   ├─ tools: gmail · calendar · openai · salesforce · helpdesk(RAG) · logging
   └─ service layer  ──►  Gmail · Calendar · OpenAI · Salesforce (JWT) · ChromaDB
        │
        ▼
  deployed on a cloud VM (Docker), CI/CD via GitHub Actions
```
See [`mcp_server/`](mcp_server/) for tools and services.

Drawn against the concrete tool groups and the enterprise APIs each one reaches:

![Multiple PC clients connecting over Streamable HTTP to a remote MCP server on a cloud VM, which registers tool groups for email, CRM, data analysis, calendar, and helpdesk against the corresponding enterprise APIs and a vector database.](assets/remote-mcp-architecture.png)

## Tech stack
Python · MCP / FastMCP · HTTP-streamable resumable transport · Gmail & Google Calendar · OpenAI · Salesforce (JWT) · ChromaDB (RAG) · Docker · Google Cloud Build · GitHub Actions

## Project structure
```
mcp_server/
  server.py             # FastMCP entrypoint (:8000, log API :8001)
  config.py             # env config, multi-user map, runtime credential materialization
  tools/                # gmail · calendar · openai · salesforce · helpdesk · logging
  services/             # integration clients + service_manager
  logging_middleware.py, log_receiver.py
generate_token.py       # Gmail OAuth token helper (no secrets committed)
retention_cron.py       # log retention job
dashboard.py            # lightweight dashboard
assets/                 # architecture diagram
tests/                  # per-service smoke tests + server test
.github/workflows/      # CI/CD (secrets via ${{ secrets.* }}, placeholders for project/VM)
Dockerfile · docker-compose.yml · cloudbuild.yaml
.env.example            # required env vars (no real keys)
```

## Setup
```bash
cp .env.example .env      # OPENAI_API_KEY, Gmail creds/tokens, Salesforce JWT, ChromaDB paths
pip install -r requirements.txt

# remote (HTTP-streamable) mode — MCP on :8000, log API on :8001
MCP_MODE=sse python mcp_server/server.py
```
Set `MCP_MODE=stdio` to run it locally for a desktop MCP client instead.

Verify the integrations before connecting a client:
```bash
python -m tests.test_mcp_server
```

Or with Docker:
```bash
docker compose up --build      # publishes 8000 (MCP); the log API stays internal to the container
```

### Connecting a client
Point your MCP client at the server and identify the user on the URL:
```
http://<host>:8000/mcp?user_id=admin&client_type=claude
```
Supported `user_id` values are `admin`, `sales`, and `finance`; each resolves to its own Gmail token and Salesforce identity. First-time Gmail authorization is done with `generate_token.py`, and the resulting token is supplied as a Base64 env var — never as a committed file.

## The SunnyLab build series
| # | Repo | What it adds |
|---|------|--------------|
| 1 | [ai_mcp_fastmcp](https://github.com/sunnylabtv-crypto/ai_mcp_fastmcp) | Local MCP server (stdio), single user — Gmail · OpenAI · Salesforce as tools |
| **2** | **ai_mcp_fastmcp_remote-public** ← *you are here* | **Remote, HTTP-streamable resumable transport — multi-user, deployed to cloud** |
| 3 | [ai_mcp_multi_agent-public](https://github.com/sunnylabtv-crypto/ai_mcp_multi_agent-public) | Orchestrator + 6 domain agents over the same tool layer |
| 4 | [ai_mcp_langgraph-public](https://github.com/sunnylabtv-crypto/ai_mcp_langgraph-public) | Same capabilities, orchestrated by an explicit LangGraph state machine |
| 5 | [ai_web_orchestrator_adk-public](https://github.com/sunnylabtv-crypto/ai_web_orchestrator_adk-public) | Google ADK (Gemini) web/mobile front door onto the MCP server |
| 6 | [ai_mcp_multi_agent_oosdk-public](https://github.com/sunnylabtv-crypto/ai_mcp_multi_agent_oosdk-public) | **Flagship** — ontology-driven policy engine, order-to-cash end to end |

## Note
Public **portfolio showcase**. Credential files (deploy keys, the Salesforce private key, OAuth tokens), `.env`, and infrastructure identifiers were removed before publishing. The code loads all secrets from environment variables or mounted files at runtime — none are committed.

## License
[MIT](LICENSE) — free to use, modify, and distribute with attribution. Provided as is, without warranty.
The third-party services it integrates with (OpenAI, Google, Salesforce) are governed by their own terms; the diagrams and screenshots under `assets/` are the author's own work.

---
**SunnyLab** — building agentic AI in public · Medium [@sunnylabtv](https://medium.com/@sunnylabtv) · YouTube [@sunnylabtv](https://www.youtube.com/@sunnylabtv)