Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions scripts/start-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ 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 fs from 'node:fs'
import os from 'node:os'
import express from 'express'

import { initProxy, ValidationError } from '../src/init-server'
Expand Down Expand Up @@ -42,7 +44,7 @@ Usage: notion-mcp-server [options]
Options:
--transport <type> Transport type: 'stdio' or 'http' (default: stdio)
--port <number> Port for HTTP server when using Streamable HTTP transport (default: 3000)
--auth-token <token> Bearer token for HTTP transport authentication (optional)
--auth-token <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

Expand Down Expand Up @@ -83,11 +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 || 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}`)
// 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}`)
}
}

Expand Down Expand Up @@ -225,16 +230,36 @@ 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`)
if (options.disableAuth) {
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
}
}
})
Expand Down
1 change: 0 additions & 1 deletion src/openapi-mcp-server/client/http-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
4 changes: 2 additions & 2 deletions src/openapi-mcp-server/mcp/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down