@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/README.md +10 -4
- package/bin/cli.mjs +28 -28
- package/package.json +9 -8
- package/scripts/notion-openapi.json +77 -36
- package/scripts/start-server.ts +17 -59
- package/src/init-server.ts +50 -0
- package/src/openapi-mcp-server/README.md +2 -0
- package/src/openapi-mcp-server/client/http-client.ts +1 -0
- package/src/openapi-mcp-server/mcp/proxy.ts +4 -0
- package/tsconfig.json +1 -1
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.
|
|
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.
|
|
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": "
|
|
39
|
-
"esbuild": "^0.
|
|
39
|
+
"@vitest/coverage-v8": "3.1.1",
|
|
40
|
+
"esbuild": "^0.25.2",
|
|
40
41
|
"multer": "1.4.5-lts.1",
|
|
41
|
-
"openai": "^4.
|
|
42
|
-
"tsx": "^4.19.
|
|
43
|
-
"typescript": "^5.
|
|
44
|
-
"vitest": "^
|
|
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
|
-
"
|
|
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": "
|
|
727
|
-
"
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
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": "
|
|
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
|
-
"
|
|
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
|
}
|
package/scripts/start-server.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
53
|
-
const
|
|
11
|
+
|
|
12
|
+
const baseUrl = process.env.BASE_URL ?? undefined
|
|
54
13
|
|
|
55
|
-
|
|
56
|
-
|
|
14
|
+
const proxy = await initProxy(specPath, baseUrl)
|
|
15
|
+
await proxy.connect(new StdioServerTransport())
|
|
57
16
|
|
|
58
|
-
|
|
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
|
+
}
|
package/tsconfig.json
CHANGED