Skip to main content
Glama
day0ops

mcp-graph-me-tool

by day0ops
README.md
# mcp-graph-me-tool

A minimal [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#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](https://agentgateway.dev)) 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

```mermaid
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 result
```

- **`graph_me`** - no arguments. Reads the `Authorization` header off the incoming HTTP request and
  calls `https://graph.microsoft.com/v1.0/me` with it. Returns the profile JSON on success, or
  `{"error": "Graph API returned <status>", "detail": "<Graph's own error body>"}` on failure
  (including when no `Authorization` header is present at all).
- **`GET /healthz`** - plain `200 ok` liveness/readiness check.

Each HTTP request gets a fresh `McpServer` instance built from that request's own `Authorization`
header (see `buildServer()` in [`server.js`](server.js)) - there is no session or connection state
held between requests.

## Running locally

```bash
npm install
npm start
# listening on :8080 (override with PORT)
```

```bash
curl localhost:8080/healthz
# ok
```

## Development

```bash
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](https://docs.solo.io/agentgateway/latest/mcp/token-exchange/obo/obo-entra/)
for the full walkthrough.

## License

Apache License 2.0 - see [LICENSE](LICENSE).