Skip to main content
Glama
suryanandan1

Gmail-SAP-MCP-Assistant

by suryanandan1

Gmail + SAP MCP Assistant

A Streamlit application that lets you read and manage Gmail, browse SAP Business Partner / Sales / Billing / Product data, and ask an AI assistant natural-language questions about your inbox (and SAP records) — all through a single Model Context Protocol (MCP) server.

                              Streamlit UI (app.py)
                                       │
                       ┌───────────────┴───────────────┐
                       ▼                               ▼
           Gmail / SAP / Admin tabs                  Ai tab
           (direct button click)              EmailAssistant (ai_agent.py)
                       │                       → Mistral LLM decides which
                       │                         tool(s) to call, if any
                       │                                │
                       └───────────────┬────────────────┘
                                       ▼
                     MCPClient (mcp_client.py) — one persistent
                     background event loop for every call, either path
                                        │
                                        │  Streamable HTTP transport
                                        ▼
                        FastMCP server (server.py) — dispatches
                              the tool call by name
                                        │
                       ┌────────────────┴────────────────┐
                       ▼                                 ▼
                GmailService                        SAPService
              (gmail_service.py)                  (sap_service.py)
                       │                                  │
                       ▼                                  ▼
                  Gmail API                          SAP OData API
                (OAuth credentials)                  (API key, sandbox)

The UI never talks to Gmail or SAP directly — every action, whether it's a button click or something the AI assistant decided to do, goes through the same MCPClient → FastMCP server → service layer path. This keeps a single, auditable boundary between the app and the two external systems.

Request flow

There are two ways a request enters the system, and they converge at MCPClient.

1. Direct UI action (Gmail / SAP / Admin tabs)

  1. You click a button (e.g. "Search" in the Gmail tab). app.py calls a method directly on the shared MCPClient instance, e.g. mcp_client.gmail_search_messages(query, max_results).

  2. MCPClient schedules that coroutine on its dedicated background event loop and blocks until it completes (_loop.run(...) in mcp_client.py) — this is what keeps the MCP session safe across Streamlit's rerun-per-interaction model.

  3. The FastMCP server (server.py) receives the tool call over Streamable HTTP and dispatches it to the matching function, e.g. gmail_search_messages().

  4. That function calls into GmailService (gmail_service.py) or SAPService (sap_service.py), which makes the real network call — the Gmail API (OAuth) or the SAP OData API (API key) — and returns parsed, plain-dict results.

  5. The result travels back up: MCP server → MCPClient._unwrap()app.py, which stores it in st.session_state and renders it.

Errors at any layer (MCPToolError, MCPConnectionError, or anything unexpected) are caught centrally by run_action() in app.py and shown as an st.error, so a failed call never crashes the UI.

2. AI Assistant question (Ai tab)

This is the same pipeline with a decision loop in front of it:

  1. Your question (plus chat history) goes to EmailAssistant.ask() in ai_agent.py, which builds a system prompt via prompts.py (injected with today's/tomorrow's dates) and sends it to Mistral along with the TOOLS schema.

  2. Mistral decides whether it needs a tool. If so, ai_agent.py runs the call through the same MCPClient instance used by the manual tabs — EmailAssistant never talks to Gmail/SAP itself — and feeds the JSON result back into the conversation.

  3. Steps 1–2 repeat (search, then maybe read a specific message, then maybe another search) up to MISTRAL_MAX_STEPS times (default 12).

  4. Once Mistral has enough information, it stops calling tools and returns a final natural-language answer, which app.py renders in the chat — with the full tool-call trace available in a collapsible "Tool calls used" expander for debugging.

The agent's tool list is deliberately narrow (read-only Gmail/SAP lookups), so no matter what you ask it, it cannot send, delete, or modify anything. Only the manual flows in the Gmail tab can do that, and each of those requires an explicit confirmation step before the destructive action fires.

3. App startup (once per process)

get_mcp_client() in app.py is wrapped in @st.cache_resource, so it runs exactly once: it creates the MCPClient, calls .connect(), which starts the background thread + event loop and opens the Streamable HTTP session to the FastMCP server. That session stays alive for the life of the Streamlit process — it is not recreated on every rerun.

Features

Gmail (via the "Gmail" tab)

  • List / search messages using Gmail's native search syntax

  • Read a full message (body, headers, attachments)

  • Send email, create drafts, move messages to Trash (each gated behind an explicit confirmation step in the UI)

  • Mark messages read/unread, list labels, fetch attachment bytes

SAP (via the "SAP" tab)

  • Check configuration / connectivity to the SAP OData sandbox

  • List and search Business Partners, view a single partner

  • List email addresses on file

  • (Read-only by default — see SAP writes below)

AI Assistant (via the "Ai" tab)

A Mistral-powered agent (ai_agent.py / EmailAssistant) that answers natural-language questions such as:

  • "Summarize today's important emails"

  • "Find emails containing attachments"

  • "Do I have any interviews scheduled tomorrow?"

  • "Summarize emails from the last 7 days"

The agent is intentionally read-only: it can only call gmail_search_messages, gmail_read_message, and gmail_list_messages (plus the read-only SAP lookups described in prompts.py). It has no tool for sending, replying to, or deleting anything, and the system prompt explicitly instructs it to say so if asked — every fact in its answers must trace back to an actual tool result, never an invented one.

Administration tab

Live MCP connection status, the list of tools the server currently exposes, and the last-fetched Gmail/SAP configuration — useful for verifying the server is reachable and correctly configured.

Project layout

File

Responsibility

app.py

Streamlit UI — tabs for AI, Gmail, SAP, and Admin

mcp_client.py

Streamlit-safe MCP client (single persistent background event loop; see the module docstring for why)

ai_agent.py

Agent loop: sends the user's question + tool results to Mistral until it produces a final answer

prompts.py

System prompt: tool permissions, date context, Gmail search syntax reference, answer-style guidance

server.py

FastMCP server exposing Gmail and SAP operations as MCP tools

gmail_service.py

Gmail API wrapper: OAuth flow, message parsing, send/draft/delete/label operations

sap_service.py

SAP OData wrapper: Business Partner, Sales Order, Billing Document, Product reads (writes implemented but disabled by default)

requirements.txt

Python dependencies

Prerequisites

  • Python 3.10+

  • A Google Cloud project with the Gmail API enabled and an OAuth Desktop app client (credentials.json)

  • Access to an SAP OData sandbox (e.g. the SAP Business Accelerator Hub) with an API key, if you want the SAP tab/tools to work

  • A Mistral API key, if you want the AI Assistant tab to work

Setup

  1. Install dependencies

    python -m venv .venv
    source .venv/bin/activate   # Windows: .venv\Scripts\activate
    pip install -r requirements.txt
  2. Gmail OAuth credentials

    Download your OAuth client's credentials.json from Google Cloud Console and place it at credentials/credentials.json (or point GMAIL_CREDENTIALS_FILE at a different path). The first time the server calls a Gmail tool, it opens a browser window for you to authorize; the resulting token is written to credentials/token.json.

  3. Environment variables

    Create a .env file in the project root:

    # --- MCP server ---
    MCP_SERVER_HOST=127.0.0.1
    MCP_SERVER_PORT=8000
    LOG_LEVEL=INFO
    
    # --- MCP client (Streamlit side) ---
    MCP_SERVER_URL=http://127.0.0.1:8000/mcp
    MCP_CONNECT_TIMEOUT_SECONDS=20
    MCP_CALL_TIMEOUT_SECONDS=60
    
    # --- Gmail ---
    GMAIL_CREDENTIALS_FILE=credentials/credentials.json
    GMAIL_TOKEN_FILE=credentials/token.json
    
    # --- SAP ---
    SAP_MODE=sandbox
    SAP_BASE_URL=https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata/sap/API_BUSINESS_PARTNER
    SAP_API_KEY=your-sap-api-key
    SAP_VERIFY_SSL=true
    SAP_WRITE_ENABLED=false
    SAP_TIMEOUT_SECONDS=30
    
    # --- AI Assistant ---
    MISTRAL_API_KEY=your-mistral-api-key
    MISTRAL_MODEL=mistral-large-latest
    MISTRAL_MAX_STEPS=12

    Every variable has a sane default except the credentials/API keys themselves — see the top of each *_service.py / *_client.py file for the exact fallback values.

  4. Run the MCP server

    python server.py

    This starts the FastMCP server on MCP_SERVER_HOST:MCP_SERVER_PORT using the Streamable HTTP transport.

  5. Run the Streamlit app (in a second terminal)

    streamlit run app.py

    Open the URL Streamlit prints (typically http://localhost:8501).

SAP writes

SAPService already implements create_business_partner and update_business_partner against SAP's OData write endpoints, but the corresponding MCP tools are commented out in server.py and the calls are hard-gated behind SAP_WRITE_ENABLED=true in sap_service.py. To enable them:

  1. Set SAP_WRITE_ENABLED=true in .env.

  2. Uncomment the sap_create_business_partner / sap_update_business_partner tool definitions in server.py.

  3. Restart the MCP server.

Until then, all SAP access is read-only regardless of the flag.

Safety notes

  • The AI Assistant can only read Gmail — it has no send/delete/modify tool, enforced both in ai_agent.py's TOOLS list and in the system prompt in prompts.py.

  • Sending email, creating drafts, and deleting/trashing messages in the Gmail tab each require an explicit confirmation checkbox or a "search → open → confirm" flow before the destructive action fires.

  • SAP writes are off by default (SAP_WRITE_ENABLED=false) and the tools that would perform them aren't even registered on the MCP server unless you opt in.

Troubleshooting

  • "Could not connect to the MCP server" — make sure server.py is running and MCP_SERVER_URL in your .env matches its host/port.

  • Gmail OAuth errors mentioning a stale/invalid token — delete the file at GMAIL_TOKEN_FILE and retry; the app will re-run the OAuth flow.

  • SAP requests failing with HTTP errors — some SAP sandbox tenants don't have every OData service (e.g. API_SALES_ORDER_SRV, API_BILLING_DOCUMENT_SRV) activated by default; check the error body against your API catalog.

  • "AI assistant is not available"MISTRAL_API_KEY is missing or empty in .env.

-
license - not tested
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • MCP server exposing the Backtest360 engine API as tools for AI agents.

  • MCP server for Gainium — manage trading bots, deals, and balances via AI assistants

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/suryanandan1/Gmail-SAP-Connection-With-MCP-Agent'

If you have feedback or need assistance with the MCP directory API, please join our Discord server