$ show makenotion/notion-mcp-server
This is an MCP (Model Context Protocol) server that auto-generates AI-agent-friendly tools from the Notion REST API OpenAPI specification. It runs as a CLI tool (stdio transport) or an HTTP server (Streamable HTTP transport), exposing 24 tools covering users, search, blocks, pages, comments, data sources, and databases — including dedicated markdown read/write endpoints. The architecture follows a clean three-layer design: an OpenAPI-to-MCP converter (`parser.ts`) that transforms each operation into a tool with JSON Schema input/output; an MCP proxy (`proxy.ts`) that handles tool listing/calling and deserializes double-encoded JSON parameters (a known MCP client issue); and an HTTP client (`http-client.ts`) that executes the actual API calls using axios and openapi-client-axios. Notable engineering highlights include per-operation `Notion-Version` header sourcing from the spec (so each endpoint can pin its required API version), a per-request token passthrough mechanism for multi-tenant deployments, and comprehensive test coverage with snapshot tests locking the tool surface. The repo is well-structured TypeScript with clear separation of concerns, though the README signals that this local MCP server may be sunset in favor of a newer remote MCP offering.
The LLM identified 4 files worth highlighting for reuse:
The `deserializeParams` and `deserializeValue` functions recursively walk MCP tool arguments and decode JSON-encoded strings back into structured values, handling double-serialization, nested objects/arrays, and array elements that are individually stringified. This solves a common MCP client bug where LLMs pass JSON-encoded strings instead of objects. Includes max depth protection (3 levels) and preserves non-JSON strings. The pattern is reusable in any MCP server that receives parameters from LLM clients.
Implements per-request Notion token resolution for the HTTP transport, enabling a single server deployment to serve multiple Notion integrations. Provides `resolveNotionToken` which checks the dedicated `Notion-Token` header first, then falls back to `Authorization` only when server gateway auth is disabled (prefix detection prevents Notion tokens from colliding with gateway secrets). Includes `redactToken` for safe logging and `isNotionToken` for shape validation. Clean, isolated design reusable as an auth middleware for any multi-tenant API gateway.
The `buildDefaultHeaders` method sources header parameters from each OpenAPI operation's spec (e.g., `Notion-Version` with different defaults per endpoint) rather than hardcoding global headers. This allows the page-markdown endpoints to use `2026-03-11` while the rest of the API stays on `2025-09-03`, all without configuration. Explicitly-configured headers in `HttpClientConfig` take precedence. This pattern is reusable for any OpenAPI-based client that needs per-operation header management.
A utility for starting Express apps on OS-assigned ephemeral ports (`port 0`) for integration tests. Awaits the `listening` event to avoid request-before-bind races (eliminates `socket hang up` flakiness), uses `127.0.0.1` to force IPv4 and avoid `localhost`→`::1` mismatches, and provides a clean shutdown function. This is a reusable pattern for any Node.js project needing reliable HTTP integration tests.