engram-notion-mcp 0.1.0 → 1.0.0-rc.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 +245 -0
- package/dist/index.js +18808 -0
- package/package.json +35 -7
- package/scripts/release.ts +76 -0
- package/src/{index.js → index.ts} +122 -81
- package/tsconfig.json +14 -0
package/package.json
CHANGED
|
@@ -1,19 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "engram-notion-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"main": "src/index.
|
|
3
|
+
"version": "1.0.0-rc.0",
|
|
4
|
+
"description": "Bun implementation of the Engram Notion MCP server",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"mcp",
|
|
9
|
+
"notion",
|
|
10
|
+
"ai",
|
|
11
|
+
"memory",
|
|
12
|
+
"agent",
|
|
13
|
+
"engram"
|
|
14
|
+
],
|
|
15
|
+
"author": "Shubham Omar",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"config": {
|
|
18
|
+
"release": "patch",
|
|
19
|
+
"preid": "rc",
|
|
20
|
+
"tagVersionPrefix": "REL-"
|
|
21
|
+
},
|
|
7
22
|
"scripts": {
|
|
8
|
-
"start": "
|
|
23
|
+
"start": "bun run src/index.ts",
|
|
24
|
+
"get-version": "echo $npm_package_version",
|
|
25
|
+
"get-name": "echo ${npm_package_name}",
|
|
26
|
+
"prebuild": "rm -rf ./dist",
|
|
27
|
+
"build": "bun build ./src/index.ts --outfile ./dist/index.js --target node --external better-sqlite3",
|
|
28
|
+
"preremove-dependencies": "rm -f ./bun.lock ./package-lock.json",
|
|
29
|
+
"remove-dependencies": "rm -rf ./node_modules",
|
|
30
|
+
"postremove-dependencies": "bun install",
|
|
31
|
+
"release": "bun run scripts/release.ts"
|
|
9
32
|
},
|
|
10
33
|
"dependencies": {
|
|
11
34
|
"@modelcontextprotocol/sdk": "^1.0.1",
|
|
12
35
|
"@notionhq/client": "^2.2.14",
|
|
13
|
-
"sqlite3": "^5.
|
|
36
|
+
"better-sqlite3": "^11.5.0",
|
|
14
37
|
"dotenv": "^16.4.5"
|
|
15
38
|
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/better-sqlite3": "^7.6.11",
|
|
41
|
+
"bun-types": "^1.1.0",
|
|
42
|
+
"typescript": "^5.0.0"
|
|
43
|
+
},
|
|
16
44
|
"bin": {
|
|
17
|
-
"engram-mcp": "
|
|
45
|
+
"engram-notion-mcp": "dist/index.js"
|
|
18
46
|
}
|
|
19
|
-
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { $ } from "bun";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
|
|
4
|
+
// 1. Load configuration: Env > package.json > Defaults
|
|
5
|
+
const pkgPath = join(import.meta.dir, "../package.json");
|
|
6
|
+
const pyPath = join(import.meta.dir, "../../python/pyproject.toml");
|
|
7
|
+
|
|
8
|
+
const pkg = await Bun.file(pkgPath).json();
|
|
9
|
+
|
|
10
|
+
const npmrcPath = join(import.meta.dir, "../.npmrc");
|
|
11
|
+
const npmrc = await (async () => {
|
|
12
|
+
try {
|
|
13
|
+
const content = await Bun.file(npmrcPath).text();
|
|
14
|
+
const config: Record<string, string> = {};
|
|
15
|
+
content.split('\n').filter(Boolean).forEach(line => {
|
|
16
|
+
const [key, value] = line.split('=');
|
|
17
|
+
if(key && value) config[key.trim()] = value.trim();
|
|
18
|
+
});
|
|
19
|
+
return config;
|
|
20
|
+
} catch {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
})();
|
|
24
|
+
|
|
25
|
+
// Helper to get config value with fallback: Env -> .npmrc -> package.json -> Default
|
|
26
|
+
const getConfig = (key: string, envKey: string, defaultVal: string) => {
|
|
27
|
+
return process.env[envKey] || npmrc[key] || pkg.config?.[key] || defaultVal;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const release = getConfig("release", "npm_config_release", "prerelease");
|
|
31
|
+
const preid = getConfig("preid", "npm_config_preid", "");
|
|
32
|
+
const tagPrefix = getConfig("tagVersionPrefix", "npm_config_tag_version_prefix", "v");
|
|
33
|
+
|
|
34
|
+
console.log(`🚀 Starting ${release} release (ID: ${preid || 'none'}) with prefix "${tagPrefix}"`);
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
// 2. Bump version in package.json (no git tag yet)
|
|
38
|
+
// We use --no-git-tag-version so we can sync python first, then commit all together
|
|
39
|
+
const preidFlag = preid ? `--preid=${preid}` : "";
|
|
40
|
+
await $`bun pm version ${release} ${preidFlag} --no-git-tag-version`;
|
|
41
|
+
|
|
42
|
+
// 3. Read the NEW version from updated package.json
|
|
43
|
+
const newPkg = await Bun.file(pkgPath).json();
|
|
44
|
+
const newVersion = newPkg.version;
|
|
45
|
+
console.log(`📦 New Version: ${newVersion}`);
|
|
46
|
+
|
|
47
|
+
// 4. Sync to Python (pyproject.toml)
|
|
48
|
+
console.log(`Syncing version to ${pyPath}...`);
|
|
49
|
+
let pyConfig = await Bun.file(pyPath).text();
|
|
50
|
+
const versionRegex = /^version\s*=\s*".*"/m;
|
|
51
|
+
|
|
52
|
+
if(versionRegex.test(pyConfig)) {
|
|
53
|
+
pyConfig = pyConfig.replace(versionRegex, `version = "${newVersion}"`);
|
|
54
|
+
await Bun.write(pyPath, pyConfig);
|
|
55
|
+
console.log("✅ Updated python/pyproject.toml");
|
|
56
|
+
} else {
|
|
57
|
+
throw new Error("Could not find version string in pyproject.toml");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// 5. Commit and Tag
|
|
61
|
+
const tagName = `${tagPrefix}${newVersion}`;
|
|
62
|
+
const message = `[skip ci] [npm-auto-versioning] new released version v${newVersion}`;
|
|
63
|
+
|
|
64
|
+
console.log("📝 Committing and Tagging...");
|
|
65
|
+
await $`git add ${pkgPath} ${pyPath}`;
|
|
66
|
+
await $`git commit -m ${message}`;
|
|
67
|
+
await $`git tag -a ${tagName} -m ${message}`;
|
|
68
|
+
|
|
69
|
+
// 6. Push (Optional, or leave to workflow)
|
|
70
|
+
// The workflow handles pushing, but for local runs:
|
|
71
|
+
console.log(`✅ Release ${tagName} ready! Don't forget to push: git push --follow-tags`);
|
|
72
|
+
|
|
73
|
+
} catch(err: any) {
|
|
74
|
+
console.error("❌ Release failed:", err.message);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
3
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
4
|
import {
|
|
@@ -6,26 +6,24 @@ import {
|
|
|
6
6
|
ListToolsRequestSchema,
|
|
7
7
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
8
8
|
import { Client } from "@notionhq/client";
|
|
9
|
-
|
|
9
|
+
|
|
10
10
|
import dotenv from "dotenv";
|
|
11
11
|
import path from "path";
|
|
12
|
-
import { fileURLToPath } from "url";
|
|
13
12
|
import fs from "fs";
|
|
14
13
|
import os from "os";
|
|
15
|
-
import https from "https";
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
dotenv.config({ path: path.join(__dirname, "../.env") });
|
|
15
|
+
// Load .env from parent directory
|
|
16
|
+
dotenv.config({ path: path.join(import.meta.dir, "../.env") });
|
|
20
17
|
|
|
21
18
|
// Initialize Notion Client
|
|
22
|
-
const
|
|
19
|
+
const notionApiKey = process.env.NOTION_API_KEY;
|
|
20
|
+
const notion = new Client({ auth: notionApiKey });
|
|
23
21
|
|
|
24
22
|
// Database Initialization
|
|
25
|
-
const get_default_db_path = () => {
|
|
23
|
+
const get_default_db_path = (): string => {
|
|
26
24
|
const system = os.platform();
|
|
27
25
|
const home = os.homedir();
|
|
28
|
-
let basePath;
|
|
26
|
+
let basePath: string;
|
|
29
27
|
|
|
30
28
|
if(system === "win32") {
|
|
31
29
|
basePath = path.join(home, ".engram", "data");
|
|
@@ -38,7 +36,14 @@ const get_default_db_path = () => {
|
|
|
38
36
|
return path.join(basePath, "agent_memory.db");
|
|
39
37
|
};
|
|
40
38
|
|
|
41
|
-
|
|
39
|
+
// Handle optional env var and path expansion
|
|
40
|
+
// Node/Bun usually handles ~ only if shell expands it, but here we can support explicit ~
|
|
41
|
+
let envDbPath = process.env.AGENT_MEMORY_PATH;
|
|
42
|
+
if(envDbPath && envDbPath.startsWith("~")) {
|
|
43
|
+
envDbPath = path.join(os.homedir(), envDbPath.slice(1));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let DB_PATH = envDbPath || get_default_db_path();
|
|
42
47
|
|
|
43
48
|
// Ensure directory exists
|
|
44
49
|
try {
|
|
@@ -48,49 +53,86 @@ try {
|
|
|
48
53
|
DB_PATH = "agent_memory.db";
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
// Database Interface
|
|
57
|
+
interface DBAdapter {
|
|
58
|
+
query(sql: string): any; // Abstracted query preparation relative to implementation
|
|
59
|
+
run(params: any): void; // Execution abstraction
|
|
60
|
+
}
|
|
52
61
|
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_index USING fts5(content, metadata, tokenize='porter')`, (err) => {
|
|
56
|
-
if(err) {
|
|
57
|
-
// Fallback
|
|
58
|
-
db.run(`CREATE TABLE IF NOT EXISTS memory_index (content TEXT, metadata TEXT)`);
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
};
|
|
62
|
+
const get_db_adapter = (dbPath: string): DBAdapter => {
|
|
63
|
+
const isBun = typeof Bun !== "undefined";
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
if(isBun) {
|
|
66
|
+
// runtime: Bun
|
|
67
|
+
// @ts-ignore
|
|
68
|
+
const { Database } = require("bun:sqlite");
|
|
69
|
+
const db = new Database(dbPath, { create: true });
|
|
65
70
|
|
|
66
|
-
|
|
67
|
-
return new Promise((resolve, reject) => {
|
|
71
|
+
// Init FTS5 for Bun
|
|
68
72
|
try {
|
|
69
|
-
|
|
70
|
-
// SQLite in Node usually handles concurrency better with a single connection in WAL mode, but standard is single connection object.
|
|
71
|
-
// We will use the global `db` object here, assuming single-threaded event loop access.
|
|
72
|
-
const meta_str = metadata ? JSON.stringify(metadata) : "{}";
|
|
73
|
-
const stmt = db.prepare("INSERT INTO memory_index (content, metadata) VALUES (?, ?)");
|
|
74
|
-
stmt.run(content, meta_str, function(err) {
|
|
75
|
-
if(err) {
|
|
76
|
-
console.error(`Error saving to DB: ${err}`);
|
|
77
|
-
reject(err);
|
|
78
|
-
} else {
|
|
79
|
-
resolve();
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
stmt.finalize();
|
|
73
|
+
db.run(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_index USING fts5(content, metadata, tokenize='porter')`);
|
|
83
74
|
} catch(e) {
|
|
84
|
-
console.
|
|
85
|
-
|
|
75
|
+
console.warn("FTS5 creation failed in Bun, falling back to standard table", e);
|
|
76
|
+
db.run(`CREATE TABLE IF NOT EXISTS memory_index (content TEXT, metadata TEXT)`);
|
|
86
77
|
}
|
|
87
|
-
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
query: (sql: string) => {
|
|
81
|
+
const stmt = db.query(sql);
|
|
82
|
+
return {
|
|
83
|
+
run: (params: any) => stmt.run(params)
|
|
84
|
+
};
|
|
85
|
+
},
|
|
86
|
+
run: () => {} // Not needed for Bun's prepared stmt flow
|
|
87
|
+
};
|
|
88
|
+
} else {
|
|
89
|
+
// runtime: Node.js (via better-sqlite3)
|
|
90
|
+
console.log("\x1b[33m%s\x1b[0m", "ℹ️ Tip: This MCP server runs 3x faster with Bun! Try: bunx engram-notion-mcp");
|
|
91
|
+
|
|
92
|
+
// @ts-ignore
|
|
93
|
+
const Database = require("better-sqlite3");
|
|
94
|
+
const db = new Database(dbPath);
|
|
95
|
+
|
|
96
|
+
// Init FTS5 for Node (better-sqlite3 usually bundles it)
|
|
97
|
+
try {
|
|
98
|
+
db.prepare(`CREATE VIRTUAL TABLE IF NOT EXISTS memory_index USING fts5(content, metadata, tokenize='porter')`).run();
|
|
99
|
+
} catch(e) {
|
|
100
|
+
console.warn("FTS5 creation failed in Node, falling back to standard table", e);
|
|
101
|
+
db.prepare(`CREATE TABLE IF NOT EXISTS memory_index (content TEXT, metadata TEXT)`).run();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
query: (sql: string) => {
|
|
106
|
+
const stmt = db.prepare(sql);
|
|
107
|
+
return {
|
|
108
|
+
run: (params: any) => stmt.run(params)
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
run: () => {}
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const dbAdapter = get_db_adapter(DB_PATH);
|
|
117
|
+
|
|
118
|
+
const _save_to_db = (content: string, metadata: any = null) => {
|
|
119
|
+
try {
|
|
120
|
+
const meta_str = metadata ? JSON.stringify(metadata) : "{}";
|
|
121
|
+
const query = dbAdapter.query("INSERT INTO memory_index (content, metadata) VALUES ($content, $metadata)");
|
|
122
|
+
query.run({ $content: content, $metadata: meta_str });
|
|
123
|
+
} catch(e) {
|
|
124
|
+
console.error(`Error saving to DB: ${e}`);
|
|
125
|
+
}
|
|
88
126
|
};
|
|
89
127
|
|
|
128
|
+
interface ToolArgs {
|
|
129
|
+
[key: string]: any;
|
|
130
|
+
}
|
|
131
|
+
|
|
90
132
|
// Tools implementation
|
|
91
|
-
const tools = {
|
|
133
|
+
const tools: Record<string, (args: ToolArgs) => Promise<string | string[]>> = {
|
|
92
134
|
remember_fact: async ({ fact }) => {
|
|
93
|
-
|
|
135
|
+
_save_to_db(fact, { type: "manual_fact", timestamp: new Date().toISOString() });
|
|
94
136
|
return `Remembered: ${fact}`;
|
|
95
137
|
},
|
|
96
138
|
|
|
@@ -101,18 +143,18 @@ const tools = {
|
|
|
101
143
|
}
|
|
102
144
|
|
|
103
145
|
try {
|
|
104
|
-
const children = [];
|
|
146
|
+
const children: any[] = [];
|
|
105
147
|
if(content) {
|
|
106
148
|
children.push({
|
|
107
149
|
object: "block",
|
|
108
150
|
type: "paragraph",
|
|
109
151
|
paragraph: {
|
|
110
|
-
rich_text: [
|
|
152
|
+
rich_text: [{ type: "text", text: { content: content } }]
|
|
111
153
|
}
|
|
112
154
|
});
|
|
113
155
|
}
|
|
114
156
|
|
|
115
|
-
const response = await notion.pages.create({
|
|
157
|
+
const response: any = await notion.pages.create({
|
|
116
158
|
parent: { page_id: target_parent },
|
|
117
159
|
properties: {
|
|
118
160
|
title: [
|
|
@@ -128,7 +170,6 @@ const tools = {
|
|
|
128
170
|
|
|
129
171
|
const page_url = response.url || "URL not found";
|
|
130
172
|
|
|
131
|
-
// Spy Logging
|
|
132
173
|
const log_content = `Created Page: ${title}. Content snippet: ${content.substring(0, 100)}`;
|
|
133
174
|
const meta = {
|
|
134
175
|
type: "create_page",
|
|
@@ -136,10 +177,10 @@ const tools = {
|
|
|
136
177
|
url: page_url,
|
|
137
178
|
timestamp: new Date().toISOString()
|
|
138
179
|
};
|
|
139
|
-
|
|
180
|
+
_save_to_db(log_content, meta);
|
|
140
181
|
|
|
141
182
|
return `Successfully created page '${title}'. URL: ${page_url}`;
|
|
142
|
-
} catch(e) {
|
|
183
|
+
} catch(e: any) {
|
|
143
184
|
return `Error creating page: ${e.message}`;
|
|
144
185
|
}
|
|
145
186
|
},
|
|
@@ -153,19 +194,19 @@ const tools = {
|
|
|
153
194
|
section_title: title,
|
|
154
195
|
timestamp: new Date().toISOString()
|
|
155
196
|
};
|
|
156
|
-
|
|
197
|
+
_save_to_db(log_content, meta);
|
|
157
198
|
|
|
158
|
-
const validTypes = [
|
|
199
|
+
const validTypes = ["paragraph", "bulleted_list_item", "code", "table"];
|
|
159
200
|
if(!validTypes.includes(type)) {
|
|
160
201
|
return `Error: Invalid type '${type}'. Must be 'paragraph', 'bulleted_list_item', 'code', or 'table'.`;
|
|
161
202
|
}
|
|
162
203
|
|
|
163
|
-
const children = [
|
|
204
|
+
const children: any[] = [
|
|
164
205
|
{
|
|
165
206
|
object: "block",
|
|
166
207
|
type: "heading_2",
|
|
167
208
|
heading_2: {
|
|
168
|
-
rich_text: [
|
|
209
|
+
rich_text: [{ type: "text", text: { content: title } }]
|
|
169
210
|
}
|
|
170
211
|
}
|
|
171
212
|
];
|
|
@@ -176,23 +217,23 @@ const tools = {
|
|
|
176
217
|
object: "block",
|
|
177
218
|
type: "code",
|
|
178
219
|
code: {
|
|
179
|
-
rich_text: [
|
|
220
|
+
rich_text: [{ type: "text", text: { content: cleaned_content } }],
|
|
180
221
|
language: language
|
|
181
222
|
}
|
|
182
223
|
});
|
|
183
224
|
} else if(type === "table") {
|
|
184
|
-
const rows = [];
|
|
225
|
+
const rows: string[][] = [];
|
|
185
226
|
const lines = content.trim().split('\n');
|
|
186
227
|
let has_header = false;
|
|
187
228
|
|
|
188
229
|
for(let i = 0; i < lines.length; i++) {
|
|
189
|
-
const line = lines[
|
|
230
|
+
const line = lines[i];
|
|
190
231
|
if(/^\s*\|?[\s\-:|]+\|?\s*$/.test(line)) {
|
|
191
232
|
if(i === 1) has_header = true;
|
|
192
233
|
continue;
|
|
193
234
|
}
|
|
194
235
|
|
|
195
|
-
let cells = line.split('|').map(c => c.trim());
|
|
236
|
+
let cells = line.split('|').map((c: string) => c.trim());
|
|
196
237
|
if(line.trim().startsWith('|') && cells.length > 0) cells.shift();
|
|
197
238
|
if(line.trim().endsWith('|') && cells.length > 0) cells.pop();
|
|
198
239
|
|
|
@@ -203,14 +244,14 @@ const tools = {
|
|
|
203
244
|
|
|
204
245
|
if(rows.length === 0) return "Error: Could not parse table content.";
|
|
205
246
|
|
|
206
|
-
const table_width = rows[
|
|
247
|
+
const table_width = rows[0].length;
|
|
207
248
|
const table_children = rows.map(row => {
|
|
208
249
|
while(row.length < table_width) row.push("");
|
|
209
250
|
return {
|
|
210
251
|
object: "block",
|
|
211
252
|
type: "table_row",
|
|
212
253
|
table_row: {
|
|
213
|
-
cells: row.map(cell => [
|
|
254
|
+
cells: row.map(cell => [{ type: "text", text: { content: cell } }])
|
|
214
255
|
}
|
|
215
256
|
};
|
|
216
257
|
});
|
|
@@ -230,8 +271,8 @@ const tools = {
|
|
|
230
271
|
children.push({
|
|
231
272
|
object: "block",
|
|
232
273
|
type: type,
|
|
233
|
-
[
|
|
234
|
-
rich_text: [
|
|
274
|
+
[type]: {
|
|
275
|
+
rich_text: [{ type: "text", text: { content: content } }]
|
|
235
276
|
}
|
|
236
277
|
});
|
|
237
278
|
}
|
|
@@ -239,7 +280,7 @@ const tools = {
|
|
|
239
280
|
try {
|
|
240
281
|
await notion.blocks.children.append({ block_id: page_id, children: children });
|
|
241
282
|
return `Successfully updated page ${page_id}: ${title}`;
|
|
242
|
-
} catch(e) {
|
|
283
|
+
} catch(e: any) {
|
|
243
284
|
return `Error updating page: ${e.message}`;
|
|
244
285
|
}
|
|
245
286
|
},
|
|
@@ -249,7 +290,6 @@ const tools = {
|
|
|
249
290
|
if(!target_page) {
|
|
250
291
|
return "Error: No page_id provided and NOTION_PAGE_ID not set.";
|
|
251
292
|
}
|
|
252
|
-
// Re-use update_page logic
|
|
253
293
|
return tools.update_page({ page_id: target_page, title, content, type, language });
|
|
254
294
|
},
|
|
255
295
|
|
|
@@ -262,8 +302,8 @@ const tools = {
|
|
|
262
302
|
|
|
263
303
|
try {
|
|
264
304
|
const response = await notion.blocks.children.list({ block_id: target_id });
|
|
265
|
-
const pages = [];
|
|
266
|
-
for(const block of response.results) {
|
|
305
|
+
const pages: string[] = [];
|
|
306
|
+
for(const block of response.results as any[]) {
|
|
267
307
|
if(block.type === "child_page") {
|
|
268
308
|
pages.push(`- ${block.child_page.title} (ID: ${block.id})`);
|
|
269
309
|
}
|
|
@@ -271,7 +311,7 @@ const tools = {
|
|
|
271
311
|
|
|
272
312
|
if(pages.length === 0) return "No sub-pages found.";
|
|
273
313
|
return pages.join("\n");
|
|
274
|
-
} catch(e) {
|
|
314
|
+
} catch(e: any) {
|
|
275
315
|
return `Error listing sub-pages: ${e.message}`;
|
|
276
316
|
}
|
|
277
317
|
},
|
|
@@ -285,8 +325,6 @@ const tools = {
|
|
|
285
325
|
}
|
|
286
326
|
|
|
287
327
|
try {
|
|
288
|
-
// Using built-in https request for zero dependency http, or we could use fetch if node 18+
|
|
289
|
-
// Using fetch is cleaner.
|
|
290
328
|
const response = await fetch(`https://api.telegram.org/bot${bot_token}/sendMessage`, {
|
|
291
329
|
method: 'POST',
|
|
292
330
|
headers: {
|
|
@@ -299,7 +337,7 @@ const tools = {
|
|
|
299
337
|
throw new Error(`HTTP error! status: ${response.status}`);
|
|
300
338
|
}
|
|
301
339
|
return "Alert sent successfully.";
|
|
302
|
-
} catch(e) {
|
|
340
|
+
} catch(e: any) {
|
|
303
341
|
return `Failed to send alert: ${e.message}`;
|
|
304
342
|
}
|
|
305
343
|
}
|
|
@@ -307,8 +345,8 @@ const tools = {
|
|
|
307
345
|
|
|
308
346
|
const server = new Server(
|
|
309
347
|
{
|
|
310
|
-
name: "engram-mcp",
|
|
311
|
-
version: "0.
|
|
348
|
+
name: "engram-notion-mcp",
|
|
349
|
+
version: "0.2.0-rc.1",
|
|
312
350
|
},
|
|
313
351
|
{
|
|
314
352
|
capabilities: {
|
|
@@ -328,7 +366,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
328
366
|
properties: {
|
|
329
367
|
fact: { type: "string" },
|
|
330
368
|
},
|
|
331
|
-
required: [
|
|
369
|
+
required: ["fact"],
|
|
332
370
|
},
|
|
333
371
|
},
|
|
334
372
|
{
|
|
@@ -341,7 +379,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
341
379
|
content: { type: "string" },
|
|
342
380
|
parent_id: { type: "string" }
|
|
343
381
|
},
|
|
344
|
-
required: [
|
|
382
|
+
required: ["title"],
|
|
345
383
|
},
|
|
346
384
|
},
|
|
347
385
|
{
|
|
@@ -353,10 +391,10 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
353
391
|
page_id: { type: "string" },
|
|
354
392
|
title: { type: "string" },
|
|
355
393
|
content: { type: "string" },
|
|
356
|
-
type: { type: "string", enum: [
|
|
394
|
+
type: { type: "string", enum: ["paragraph", "bulleted_list_item", "code", "table"], default: "paragraph" },
|
|
357
395
|
language: { type: "string", default: "plain text" }
|
|
358
396
|
},
|
|
359
|
-
required: [
|
|
397
|
+
required: ["page_id", "title", "content"],
|
|
360
398
|
},
|
|
361
399
|
},
|
|
362
400
|
{
|
|
@@ -367,11 +405,11 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
367
405
|
properties: {
|
|
368
406
|
title: { type: "string" },
|
|
369
407
|
content: { type: "string" },
|
|
370
|
-
type: { type: "string", enum: [
|
|
408
|
+
type: { type: "string", enum: ["paragraph", "bulleted_list_item", "code", "table"], default: "paragraph" },
|
|
371
409
|
language: { type: "string", default: "plain text" },
|
|
372
410
|
page_id: { type: "string" }
|
|
373
411
|
},
|
|
374
|
-
required: [
|
|
412
|
+
required: ["title", "content"],
|
|
375
413
|
},
|
|
376
414
|
},
|
|
377
415
|
{
|
|
@@ -392,7 +430,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
392
430
|
properties: {
|
|
393
431
|
message: { type: "string" }
|
|
394
432
|
},
|
|
395
|
-
required: [
|
|
433
|
+
required: ["message"],
|
|
396
434
|
},
|
|
397
435
|
}
|
|
398
436
|
],
|
|
@@ -402,12 +440,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
402
440
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
403
441
|
const { name, arguments: args } = request.params;
|
|
404
442
|
|
|
405
|
-
if(tools[
|
|
443
|
+
if(tools[name]) {
|
|
444
|
+
const result = await tools[name](args as ToolArgs);
|
|
445
|
+
// Handle array result (from multiple blocks?) or string
|
|
446
|
+
const textContent = Array.isArray(result) ? result.join("\n") : result;
|
|
406
447
|
return {
|
|
407
448
|
content: [
|
|
408
449
|
{
|
|
409
450
|
type: "text",
|
|
410
|
-
text:
|
|
451
|
+
text: textContent
|
|
411
452
|
}
|
|
412
453
|
]
|
|
413
454
|
};
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "esnext",
|
|
4
|
+
"module": "esnext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"types": [
|
|
7
|
+
"bun-types"
|
|
8
|
+
],
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true
|
|
13
|
+
}
|
|
14
|
+
}
|