mcp-graph-me-tool
mcp-graph-me-tool
A minimal Streamable HTTP
MCP server exposing one tool, graph_me, which calls Microsoft Graph's GET /me with the caller's
bearer token and returns the signed-in user's profile.
It's the backend half of a Microsoft Entra ID On-Behalf-Of (OBO) token exchange demo: a gateway
(e.g. agentgateway) sits in front of this server, validates the caller's
Entra token, exchanges it for a Graph-scoped token via Entra's own token endpoint, and forwards the
request here with the exchanged token substituted for Authorization. This server does not perform
any exchange or validation itself - it only relays whatever bearer token it's handed to Graph.
What it does
sequenceDiagram
participant Client as MCP Client
participant AGW as Gateway (OBO exchange)
participant Tool as mcp-graph-me-tool
participant Graph as Microsoft Graph
Client->>AGW: tools/call graph_me + user's Entra token
AGW->>AGW: exchange for a Graph-scoped token
AGW->>Tool: tools/call graph_me + exchanged token
Tool->>Graph: GET /v1.0/me + exchanged token
Graph-->>Tool: profile
Tool-->>AGW: tool result
AGW-->>Client: tool resultgraph_me- no arguments. Reads theAuthorizationheader off the incoming HTTP request and callshttps://graph.microsoft.com/v1.0/mewith it. Returns the profile JSON on success, or{"error": "Graph API returned <status>", "detail": "<Graph's own error body>"}on failure (including when noAuthorizationheader is present at all).GET /healthz- plain200 okliveness/readiness check.
Each HTTP request gets a fresh McpServer instance built from that request's own Authorization
header (see buildServer() in server.js) - there is no session or connection state
held between requests.
Running locally
npm install
npm start
# listening on :8080 (override with PORT)curl localhost:8080/healthz
# okDevelopment
npm test # node --check server.js (syntax check)Wiring into agentgateway
Deploy this image behind a plain EnterpriseAgentgatewayBackend/HTTPRoute pointing at port 8080,
protocol: StreamableHTTP, path: /mcp, then apply an oauthTokenExchange policy (grantType: JwtBearer) on that route to perform the Entra OBO exchange before requests reach this server. See
docs.solo.io's Entra OBO guide
for the full walkthrough.
License
Apache License 2.0 - see LICENSE.