Skip to main content
Glama
franciscomartinezfc

procurement-mailer-mcp

procurement-mailer-mcp

A Model Context Protocol server that lets an SAP Joule agent read and send email from a scoped Microsoft Exchange mailbox. The agent never talks to Microsoft directly โ€” this server sits in the middle, translating MCP tool calls into Microsoft Graph requests against a single mailbox.

๐Ÿ“– Full setup runbook: https://franciscomartinezfc.github.io/procurement-mailer-mcp/

Architecture

  SAP Joule Agent  โ”€โ”€โ–ถ  procurement-mailer-mcp  โ”€โ”€โ–ถ  Exchange / MS Graph
   (BTP / Joule)         (this repo, on CF)          (single scoped mailbox)

Invocation flows left-to-right; data flows back right-to-left. Three stages:

Stage

What it does

1 ยท Joule

Plans the request, picks an MCP tool, calls the server over Streamable HTTP through a BTP destination.

2 ยท MCP (this repo)

Node.js + TypeScript server on Cloud Foundry. Exposes four tools and maps them onto Graph calls through the graph-mail destination (an Entra app identity).

3 ยท Graph

Microsoft Graph over Exchange Online, restricted by an application access policy to just the demo mailbox.

Transport

The server is stateless: every POST /mcp builds a fresh McpServer + StreamableHTTPServerTransport pair (sessionIdGenerator: undefined). GET and DELETE on /mcp โ€” the session channels of Streamable HTTP โ€” return 405.

Graph access

There is no MSAL or token juggling in code. @sap-cloud-sdk/http-client's executeHttpRequest resolves the graph-mail BTP destination, performs the OAuth client-credentials exchange, and prefixes /v1.0 on every call. The Entra credentials (tenant ID, client ID, client secret) live in that destination, not in environment variables.

Related MCP server: outlook-mcp

Project layout

src/
โ”œโ”€โ”€ index.ts          # Express app + Streamable HTTP transport (POST /mcp)
โ”œโ”€โ”€ server.ts         # Builds the McpServer, registers `ping`, wires in mail tools
โ”œโ”€โ”€ tools/
โ”‚   โ””โ”€โ”€ mail.ts       # The three mail tools: list_messages, read_message, send_mail
โ””โ”€โ”€ graph/
    โ””โ”€โ”€ client.ts     # graphGet / graphPost via the `graph-mail` destination

manifest.yml          # Cloud Foundry app + service bindings (dest, conn, xsuaa)
index.html            # The setup runbook (published to GitHub Pages)
assets/               # Runbook images

Tools

Tool

Description

Key inputs

ping

Health check โ€” returns pong @ <timestamp>.

note?

list_messages

Recent emails from the mailbox: id, subject, sender, received time, read state.

top (1โ€“25, default 10), unreadOnly

read_message

Full body of one email by id.

messageId

send_mail

Send an email from the mailbox.

to, subject, body, contentType (Text/HTML)

Requirements

  • Node.js 22.x (see engines in package.json)

  • For deployment: a SAP BTP subaccount with Cloud Foundry, and the graph-mail destination configured (Entra credentials). See the runbook for the full Microsoft-side and BTP setup.

Run locally

npm install

# Dev โ€” tsx watch, hot reload, port 3000 (or $PORT)
npm run dev

# Or build to dist/ and run the compiled server
npm run build
npm start

The server listens on http://localhost:3000/mcp.

Validate with the MCP Inspector

Use a real MCP client โ€” not curl, which can't complete the Streamable HTTP handshake.

npx @modelcontextprotocol/inspector
# Transport: Streamable HTTP   URL: http://localhost:3000/mcp
# Connect โ†’ List Tools (expect 4) โ†’ call `ping` โ†’ expect "pong @ <timestamp>"

ping works locally with no extra setup. The three mail tools resolve the graph-mail destination, which only exists on BTP โ€” test those against the deployed route, or feed the SAP Cloud SDK a destinations env var when starting the server locally.

Deploy to Cloud Foundry

The app expects three bound services (see manifest.yml): a destination, connectivity, and xsuaa instance.

cf api <CF_API_ENDPOINT>          # e.g. https://api.cf.us10-001.hana.ondemand.com
cf login --sso
cf target -o "<ORG>" -s <SPACE>

# One-time: create the backing services manifest.yml binds
cf create-service destination lite  procurement-mailer-dest
cf create-service connectivity lite procurement-mailer-conn
cf create-service xsuaa application procurement-mailer-uaa

npm run build
cf push

# After re-binding or changing a service: RESTAGE, never restart
cf restage procurement-mailer-mcp

Restage, never restart. Service bindings are only injected into VCAP_SERVICES on cf restage. cf restart reuses the old droplet and the env stays empty.

Configuration

Setting

Where

Notes

MAILBOX

manifest.yml env / src/graph/client.ts default

The mailbox every call targets.

PORT

injected by Cloud Foundry

Defaults to 3000 locally.

Entra credentials

graph-mail BTP destination

Tenant ID, client ID, client secret โ€” not env vars.

License

ISC

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables sending emails through Microsoft Outlook using the Microsoft Graph API. Provides the missing send-email capability for Agent Builder's Outlook connector with support for both delegated and app-only authentication flows.
    MIT
  • A
    license
    B
    quality
    C
    maintenance
    Enables AI assistants to manage Microsoft Outlook email and calendar through the Microsoft Graph API, including reading, sending, searching emails, and handling calendar events.
    43
    86 npm
    27
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to interact with Microsoft 365 Outlook Mail, allowing email operations via natural language.
    12 npm
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables to manage your Outlook mailbox via Microsoft Graph (write access) with delegated permissions, providing MCP tools to create, modify, and send emails, folders, categories, rules, and automatic replies.
    -