@notionhq/notion-mcp-server 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,10 +2,11 @@
2
2
  "name": "@notionhq/notion-mcp-server",
3
3
  "keywords": [
4
4
  "notion",
5
+ "api",
5
6
  "mcp",
6
7
  "server"
7
8
  ],
8
- "version": "1.0.0",
9
+ "version": "1.2.0",
9
10
  "license": "MIT",
10
11
  "type": "module",
11
12
  "scripts": {
@@ -17,7 +18,7 @@
17
18
  },
18
19
  "dependencies": {
19
20
  "@modelcontextprotocol/sdk": "^1.8.0",
20
- "axios": "^1.7.9",
21
+ "axios": "^1.8.4",
21
22
  "express": "^4.21.2",
22
23
  "form-data": "^4.0.1",
23
24
  "mustache": "^4.2.0",
@@ -35,13 +36,13 @@
35
36
  "@types/mustache": "^4.2.5",
36
37
  "@types/node": "^20.17.16",
37
38
  "@types/which": "^3.0.4",
38
- "@vitest/coverage-v8": "2.1.8",
39
- "esbuild": "^0.24.2",
39
+ "@vitest/coverage-v8": "3.1.1",
40
+ "esbuild": "^0.25.2",
40
41
  "multer": "1.4.5-lts.1",
41
- "openai": "^4.80.1",
42
- "tsx": "^4.19.2",
43
- "typescript": "^5.7.3",
44
- "vitest": "^2.1.8"
42
+ "openai": "^4.91.1",
43
+ "tsx": "^4.19.3",
44
+ "typescript": "^5.8.2",
45
+ "vitest": "^3.1.1"
45
46
  },
46
47
  "description": "Official MCP server for Notion API",
47
48
  "main": "index.js",
@@ -31,28 +31,7 @@
31
31
  "description": "The [API version](https://developers.notion.com/reference/versioning) to use for this request. The latest version is `2022-06-28`."
32
32
  }
33
33
  },
34
- "schemas": {
35
- "pageIdObject": {
36
- "type": "object",
37
- "properties": {
38
- "page_id": {
39
- "type": "string"
40
- }
41
- },
42
- "additionalProperties": false,
43
- "required": ["page_id"]
44
- },
45
- "databaseIdObject": {
46
- "type": "object",
47
- "properties": {
48
- "database_id": {
49
- "type": "string"
50
- }
51
- },
52
- "additionalProperties": false,
53
- "required": ["database_id"]
54
- }
55
- }
34
+ "schemas": {}
56
35
  },
57
36
  "security": [
58
37
  {
@@ -647,7 +626,14 @@
647
626
  ],
648
627
  "properties": {
649
628
  "parent": {
650
- "$ref": "#/components/schemas/pageIdObject"
629
+ "type": "object",
630
+ "properties": {
631
+ "page_id": {
632
+ "type": "string",
633
+ "format": "uuid"
634
+ }
635
+ },
636
+ "required": ["page_id"]
651
637
  },
652
638
  "properties": {
653
639
  "type": "object",
@@ -717,24 +703,79 @@
717
703
  "application/json": {
718
704
  "schema": {
719
705
  "type": "object",
720
- "required": [
721
- "parent",
722
- "properties"
723
- ],
706
+ "required": ["parent","properties"],
724
707
  "properties": {
725
708
  "parent": {
726
- "type": "string",
727
- "description": "A [page parent](/reference/database#page-parent)",
728
- "format": "json"
729
- },
730
- "title": {
731
- "type": "array",
732
- "description": "Title of database as it appears in Notion. An array of [rich text objects](ref:rich-text)."
709
+ "type": "object",
710
+ "properties": {
711
+ "type": {
712
+ "enum": ["page_id"]
713
+ },
714
+ "page_id": {
715
+ "type": "string",
716
+ "format": "uuid"
717
+ }
718
+ },
719
+ "required": ["type", "page_id"]
733
720
  },
734
721
  "properties": {
735
- "type": "string",
722
+ "type": "object",
736
723
  "description": "Property schema of database. The keys are the names of properties as they appear in Notion and the values are [property schema objects](https://developers.notion.com/reference/property-schema-object).",
737
- "format": "json"
724
+ "additionalProperties": {
725
+ "oneOf": [
726
+ {
727
+ "type": "object",
728
+ "properties": {
729
+ "title": {
730
+ "type": "object",
731
+ "properties": {},
732
+ "additionalProperties": false
733
+ },
734
+ "description": {
735
+ "type": "string",
736
+ "maxLength": 280,
737
+ "minLength": 1
738
+ }
739
+ },
740
+ "additionalProperties": false,
741
+ "required": ["title"]
742
+ }
743
+ ]
744
+ }
745
+ },
746
+ "title": {
747
+ "type": "array",
748
+ "items": {
749
+ "type": "object",
750
+ "required": ["text"],
751
+ "properties": {
752
+ "text": {
753
+ "type": "object",
754
+ "properties": {
755
+ "content": {
756
+ "type": "string",
757
+ "maxLength": 2000
758
+ },
759
+ "link": {
760
+ "type": ["object", "null"],
761
+ "properties": {
762
+ "url": {
763
+ "type": "string"
764
+ }
765
+ },
766
+ "required": ["url"]
767
+ }
768
+ },
769
+ "additionalProperties": false,
770
+ "required": ["content"]
771
+ },
772
+ "type": {
773
+ "enum": ["text"]
774
+ }
775
+ },
776
+ "additionalProperties": false
777
+ },
778
+ "maxItems": 100
738
779
  }
739
780
  }
740
781
  }
@@ -1,70 +1,28 @@
1
- import fs from 'node:fs'
2
1
  import path from 'node:path'
3
2
  import { fileURLToPath } from 'url'
4
-
5
- import { OpenAPIV3 } from 'openapi-types'
6
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
7
- import OpenAPISchemaValidator from 'openapi-schema-validator'
8
-
9
- import { MCPProxy } from '../src/openapi-mcp-server/mcp/proxy'
10
-
11
- export class ValidationError extends Error {
12
- constructor(public errors: any[]) {
13
- super('OpenAPI validation failed')
14
- this.name = 'ValidationError'
15
- }
16
- }
17
-
18
- export async function loadOpenApiSpec(specPath: string): Promise<OpenAPIV3.Document> {
19
- let rawSpec: string
20
-
21
- try {
22
- rawSpec = fs.readFileSync(path.resolve(process.cwd(), specPath), 'utf-8')
23
- } catch (error) {
24
- console.error('Failed to read OpenAPI specification file:', (error as Error).message)
25
- process.exit(1)
26
- }
27
4
 
28
- // Parse and validate the spec
29
- try {
30
- const parsed = JSON.parse(rawSpec)
31
- const baseUrl = process.env.BASE_URL
5
+ import { initProxy, ValidationError } from '../src/init-server'
32
6
 
33
- if (baseUrl) {
34
- parsed.servers[0].url = baseUrl
35
- }
36
-
37
- return parsed as OpenAPIV3.Document
38
- } catch (error) {
39
- if (error instanceof ValidationError) {
40
- throw error
41
- }
42
- console.error('Failed to parse OpenAPI specification:', (error as Error).message)
43
- process.exit(1)
44
- }
45
- }
46
-
47
- // Main execution
48
- export async function main(args: string[] = process.argv.slice(2)) {
7
+ export async function startServer(args: string[] = process.argv.slice(2)) {
49
8
  const filename = fileURLToPath(import.meta.url)
50
9
  const directory = path.dirname(filename)
51
10
  const specPath = path.resolve(directory, '../scripts/notion-openapi.json')
52
- const openApiSpec = await loadOpenApiSpec(specPath)
53
- const proxy = new MCPProxy('OpenAPI Tools', openApiSpec)
11
+
12
+ const baseUrl = process.env.BASE_URL ?? undefined
54
13
 
55
- return proxy.connect(new StdioServerTransport())
56
- }
14
+ const proxy = await initProxy(specPath, baseUrl)
15
+ await proxy.connect(new StdioServerTransport())
57
16
 
58
- const shouldStart = process.argv[1].endsWith('notion-mcp-server')
59
- // Only run main if this is the entry point
60
- if (shouldStart) {
61
- main().catch(error => {
62
- if (error instanceof ValidationError) {
63
- console.error('Invalid OpenAPI 3.1 specification:')
64
- error.errors.forEach(err => console.error(err))
65
- } else {
66
- console.error('Error:', error.message)
67
- }
68
- process.exit(1)
69
- })
17
+ return proxy.getServer()
70
18
  }
19
+
20
+ startServer().catch(error => {
21
+ if (error instanceof ValidationError) {
22
+ console.error('Invalid OpenAPI 3.1 specification:')
23
+ error.errors.forEach(err => console.error(err))
24
+ } else {
25
+ console.error('Error:', error)
26
+ }
27
+ process.exit(1)
28
+ })
@@ -0,0 +1,50 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ import { OpenAPIV3 } from 'openapi-types'
5
+ import OpenAPISchemaValidator from 'openapi-schema-validator'
6
+
7
+ import { MCPProxy } from './openapi-mcp-server/mcp/proxy'
8
+
9
+ export class ValidationError extends Error {
10
+ constructor(public errors: any[]) {
11
+ super('OpenAPI validation failed')
12
+ this.name = 'ValidationError'
13
+ }
14
+ }
15
+
16
+ async function loadOpenApiSpec(specPath: string, baseUrl: string | undefined): Promise<OpenAPIV3.Document> {
17
+ let rawSpec: string
18
+
19
+ try {
20
+ rawSpec = fs.readFileSync(path.resolve(process.cwd(), specPath), 'utf-8')
21
+ } catch (error) {
22
+ console.error('Failed to read OpenAPI specification file:', (error as Error).message)
23
+ process.exit(1)
24
+ }
25
+
26
+ // Parse and validate the OpenApi Spec
27
+ try {
28
+ const parsed = JSON.parse(rawSpec)
29
+
30
+ // Override baseUrl if specified.
31
+ if (baseUrl) {
32
+ parsed.servers[0].url = baseUrl
33
+ }
34
+
35
+ return parsed as OpenAPIV3.Document
36
+ } catch (error) {
37
+ if (error instanceof ValidationError) {
38
+ throw error
39
+ }
40
+ console.error('Failed to parse OpenAPI spec:', (error as Error).message)
41
+ process.exit(1)
42
+ }
43
+ }
44
+
45
+ export async function initProxy(specPath: string, baseUrl: string |undefined) {
46
+ const openApiSpec = await loadOpenApiSpec(specPath, baseUrl)
47
+ const proxy = new MCPProxy('Notion API', openApiSpec)
48
+
49
+ return proxy
50
+ }
@@ -1 +1,3 @@
1
1
  Note: This is a fork from v1 of https://github.com/snaggle-ai/openapi-mcp-server. The library took a different direction with v2 which is not compatible with our development approach.
2
+
3
+ Forked to upgrade vulnerable dependencies and easier setup.
@@ -40,6 +40,7 @@ export class HttpClient {
40
40
  baseURL: config.baseUrl,
41
41
  headers: {
42
42
  'Content-Type': 'application/json',
43
+ 'User-Agent': 'notion-mcp-server',
43
44
  ...config.headers,
44
45
  },
45
46
  },
@@ -167,4 +167,8 @@ export class MCPProxy {
167
167
  // The SDK will handle stdio communication
168
168
  await this.server.connect(transport)
169
169
  }
170
+
171
+ getServer() {
172
+ return this.server
173
+ }
170
174
  }
package/tsconfig.json CHANGED
@@ -22,5 +22,5 @@
22
22
  "strict": true,
23
23
  "skipLibCheck": true
24
24
  },
25
- "include": [ "test/**/*.ts", "scripts/**/*.ts", "src/**/*.ts", "examples/**/*"]
25
+ "include": [ "test/**/*.ts", "scripts/**/*.ts", "src/**/*.ts"]
26
26
  }