From c61dd4a230399605303d5165ec3576f5b8ca2187 Mon Sep 17 00:00:00 2001 From: Kenneth Sinder Date: Wed, 4 Mar 2026 14:29:45 -0800 Subject: [PATCH 1/2] fix: prevent sensitive auth tokens from being logged in cleartext - start-server.ts: Remove auto-generation of auth tokens that were logged in cleartext. Now requires explicit --auth-token or AUTH_TOKEN env var (or --disable-auth) for HTTP transport. - http-client.ts: Remove response data from error logs to prevent potential sensitive data exposure. - proxy.ts: Log only error messages and status codes instead of full error objects, which could contain request headers with auth tokens. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/start-server.ts | 15 ++++++++------- src/openapi-mcp-server/client/http-client.ts | 1 - src/openapi-mcp-server/mcp/proxy.ts | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/scripts/start-server.ts b/scripts/start-server.ts index 0f8b7c1..5995118 100644 --- a/scripts/start-server.ts +++ b/scripts/start-server.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from 'url' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js' -import { randomUUID, randomBytes } from 'node:crypto' +import { randomUUID } from 'node:crypto' import express from 'express' import { initProxy, ValidationError } from '../src/init-server' @@ -42,7 +42,7 @@ Usage: notion-mcp-server [options] Options: --transport Transport type: 'stdio' or 'http' (default: stdio) --port Port for HTTP server when using Streamable HTTP transport (default: 3000) - --auth-token Bearer token for HTTP transport authentication (optional) + --auth-token Bearer token for HTTP transport authentication (required unless --disable-auth) --disable-auth Disable bearer token authentication for HTTP transport --help, -h Show this help message @@ -54,7 +54,7 @@ Environment Variables: Examples: notion-mcp-server # Use stdio transport (default) notion-mcp-server --transport stdio # Use stdio transport explicitly - notion-mcp-server --transport http # Use Streamable HTTP transport on port 3000 + notion-mcp-server --transport http --auth-token mytoken # Use Streamable HTTP transport on port 3000 notion-mcp-server --transport http --port 8080 # Use Streamable HTTP transport on port 8080 notion-mcp-server --transport http --auth-token mytoken # Use Streamable HTTP transport with custom auth token notion-mcp-server --transport http --disable-auth # Use Streamable HTTP transport without authentication @@ -84,10 +84,11 @@ Examples: // Generate or use provided auth token (from CLI arg or env var) only if auth is enabled let authToken: string | undefined if (!options.disableAuth) { - authToken = options.authToken || process.env.AUTH_TOKEN || randomBytes(32).toString('hex') - if (!options.authToken && !process.env.AUTH_TOKEN) { - console.log(`Generated auth token: ${authToken}`) - console.log(`Use this token in the Authorization header: Bearer ${authToken}`) + authToken = options.authToken || process.env.AUTH_TOKEN + if (!authToken) { + console.error('Error: No auth token provided for HTTP transport.') + console.error('Provide a token via --auth-token or AUTH_TOKEN env var, or use --disable-auth to disable authentication.') + process.exit(1) } } diff --git a/src/openapi-mcp-server/client/http-client.ts b/src/openapi-mcp-server/client/http-client.ts index db129c9..d18a951 100644 --- a/src/openapi-mcp-server/client/http-client.ts +++ b/src/openapi-mcp-server/client/http-client.ts @@ -182,7 +182,6 @@ export class HttpClient { console.error('Error in http client', { status: error.response.status, statusText: error.response.statusText, - data: error.response.data, }) } const headers = new Headers() diff --git a/src/openapi-mcp-server/mcp/proxy.ts b/src/openapi-mcp-server/mcp/proxy.ts index 4f370f7..b7cd876 100644 --- a/src/openapi-mcp-server/mcp/proxy.ts +++ b/src/openapi-mcp-server/mcp/proxy.ts @@ -151,9 +151,9 @@ export class MCPProxy { ], } } catch (error) { - console.error('Error in tool call', error) + console.error('Error in tool call', error instanceof Error ? error.message : 'Unknown error') if (error instanceof HttpClientError) { - console.error('HttpClientError encountered, returning structured error', error) + console.error('HttpClientError encountered, returning structured error', { status: error.status }) const data = error.data?.response?.data ?? error.data ?? {} return { content: [ From 7d77d2062cc8ba4650f06a274b9f42f285b9a8c4 Mon Sep 17 00:00:00 2001 From: Kenneth Sinder Date: Wed, 4 Mar 2026 14:37:34 -0800 Subject: [PATCH 2/2] fix: write auto-generated auth token to file, add Notion integration link Instead of logging the auto-generated HTTP auth token in cleartext, write it to a temp file with restricted permissions (0600). Also resolve the bot ID via /v1/users/me and log a direct link to the Notion integration settings page where users can manage their token. Co-Authored-By: Claude Opus 4.6 (1M context) --- scripts/start-server.ts | 46 +++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/scripts/start-server.ts b/scripts/start-server.ts index 5995118..025223e 100644 --- a/scripts/start-server.ts +++ b/scripts/start-server.ts @@ -3,7 +3,9 @@ import { fileURLToPath } from 'url' import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js' import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js' import { isInitializeRequest } from '@modelcontextprotocol/sdk/types.js' -import { randomUUID } from 'node:crypto' +import { randomUUID, randomBytes } from 'node:crypto' +import fs from 'node:fs' +import os from 'node:os' import express from 'express' import { initProxy, ValidationError } from '../src/init-server' @@ -42,7 +44,7 @@ Usage: notion-mcp-server [options] Options: --transport Transport type: 'stdio' or 'http' (default: stdio) --port Port for HTTP server when using Streamable HTTP transport (default: 3000) - --auth-token Bearer token for HTTP transport authentication (required unless --disable-auth) + --auth-token Bearer token for HTTP transport authentication (auto-generated if not provided) --disable-auth Disable bearer token authentication for HTTP transport --help, -h Show this help message @@ -54,7 +56,7 @@ Environment Variables: Examples: notion-mcp-server # Use stdio transport (default) notion-mcp-server --transport stdio # Use stdio transport explicitly - notion-mcp-server --transport http --auth-token mytoken # Use Streamable HTTP transport on port 3000 + notion-mcp-server --transport http # Use Streamable HTTP transport on port 3000 notion-mcp-server --transport http --port 8080 # Use Streamable HTTP transport on port 8080 notion-mcp-server --transport http --auth-token mytoken # Use Streamable HTTP transport with custom auth token notion-mcp-server --transport http --disable-auth # Use Streamable HTTP transport without authentication @@ -83,12 +85,14 @@ Examples: // Generate or use provided auth token (from CLI arg or env var) only if auth is enabled let authToken: string | undefined + let authTokenFilePath: string | undefined if (!options.disableAuth) { - authToken = options.authToken || process.env.AUTH_TOKEN - if (!authToken) { - console.error('Error: No auth token provided for HTTP transport.') - console.error('Provide a token via --auth-token or AUTH_TOKEN env var, or use --disable-auth to disable authentication.') - process.exit(1) + authToken = options.authToken || process.env.AUTH_TOKEN || randomBytes(32).toString('hex') + if (!options.authToken && !process.env.AUTH_TOKEN) { + // Write auto-generated token to a file with restricted permissions instead of logging it + authTokenFilePath = path.join(os.tmpdir(), `.notion-mcp-auth-token-${process.pid}`) + fs.writeFileSync(authTokenFilePath, authToken, { mode: 0o600 }) + console.log(`Generated auth token written to: ${authTokenFilePath}`) } } @@ -226,7 +230,7 @@ Examples: }) const port = options.port - app.listen(port, '0.0.0.0', () => { + app.listen(port, '0.0.0.0', async () => { console.log(`MCP Server listening on port ${port}`) console.log(`Endpoint: http://0.0.0.0:${port}/mcp`) console.log(`Health check: http://0.0.0.0:${port}/health`) @@ -234,8 +238,28 @@ Examples: console.log(`Authentication: Disabled`) } else { console.log(`Authentication: Bearer token required`) - if (options.authToken) { - console.log(`Using provided auth token`) + if (authTokenFilePath) { + console.log(`Read your auth token from: ${authTokenFilePath}`) + } + } + // Try to resolve the Notion integration link so users can manage their token + const notionToken = process.env.NOTION_TOKEN + if (notionToken) { + try { + const res = await fetch('https://api.notion.com/v1/users/me', { + headers: { + 'Authorization': `Bearer ${notionToken}`, + 'Notion-Version': '2022-06-28', + }, + }) + if (res.ok) { + const data = await res.json() as { id?: string; type?: string } + if (data.id && data.type === 'bot') { + console.log(`Notion integration settings: https://www.notion.so/profile/integrations/internal/${data.id}`) + } + } + } catch { + // Non-critical: silently ignore if we can't resolve the bot ID } } })