252 lines
7.1 KiB
JavaScript
Raw Permalink Normal View History

/**
*
* AGE OS · MCP 工具: Notion 操作
*
*
* 签发: 铸渊 · ICE-GL-ZY001
* 版权: 国作登字-2026-A-00037559
*
* 提供 5 Notion MCP 工具:
* notionQuery 查询 Notion 数据库
* notionReadPage 读取 Notion 页面内容
* notionWritePage 创建 Notion 页面
* notionUpdatePage 更新 Notion 页面属性
* notionWriteSyslog 写入系统日志到 Notion
*/
'use strict';
const notion = require('../notion-client');
/**
* notionQuery 查询 Notion 数据库
*
* input:
* database_id: string 数据库 ID或别名: changelog / receipt / syslog
* filter: object Notion 过滤器可选
* sorts: object[] 排序规则可选
* page_size: number 每页数量可选默认20
* start_cursor: string 分页游标可选
*/
async function notionQuery(input) {
const { database_id, filter, sorts, page_size, start_cursor } = input;
if (!database_id) throw new Error('缺少 database_id');
// 支持别名
const dbId = resolveDbAlias(database_id);
const result = await notion.queryDatabase(dbId, filter, sorts, page_size || 20, start_cursor);
return {
count: result.results.length,
has_more: result.has_more,
next_cursor: result.next_cursor,
items: result.results.map(simplifyPage)
};
}
/**
* notionReadPage 读取 Notion 页面完整内容
*
* input:
* page_id: string 页面 ID
*/
async function notionReadPage(input) {
const { page_id } = input;
if (!page_id) throw new Error('缺少 page_id');
const page = await notion.readPage(page_id);
return {
id: page.id,
created_time: page.created_time,
last_edited_time: page.last_edited_time,
properties: simplifyProperties(page.properties),
blocks_count: page.blocks.length,
blocks: page.blocks.map(simplifyBlock)
};
}
/**
* notionWritePage 在数据库中创建新页面
*
* input:
* database_id: string 数据库 ID或别名
* title: string 页面标题
* properties: object 额外属性Notion API 格式可选
* content: string 页面正文内容可选自动转为段落块
*/
async function notionWritePage(input) {
const { database_id, title, properties, content } = input;
if (!database_id) throw new Error('缺少 database_id');
if (!title) throw new Error('缺少 title');
const dbId = resolveDbAlias(database_id);
// 构建属性
const pageProps = {
...(properties || {}),
'标题': {
title: [{ text: { content: title } }]
}
};
// 构建内容块
const children = [];
if (content) {
// 按段落分割
const paragraphs = content.split('\n\n');
for (const para of paragraphs) {
if (para.trim()) {
children.push({
object: 'block',
type: 'paragraph',
paragraph: {
rich_text: [{ text: { content: para.trim() } }]
}
});
}
}
}
return notion.createPage(dbId, pageProps, children);
}
/**
* notionUpdatePage 更新 Notion 页面属性
*
* input:
* page_id: string 页面 ID
* properties: object 要更新的属性Notion API 格式
*/
async function notionUpdatePage(input) {
const { page_id, properties } = input;
if (!page_id) throw new Error('缺少 page_id');
if (!properties) throw new Error('缺少 properties');
return notion.updatePage(page_id, properties);
}
/**
* notionWriteSyslog 写入系统日志到 Notion
*
* input:
* level: string 日志级别: info / warning / error / critical
* source: string 来源: zhuyuan / agent / workflow / mcp
* message: string 日志内容
* details: object 附加详情可选
*/
async function notionWriteSyslog(input) {
const { level, source, message, details } = input;
if (!level) throw new Error('缺少 level');
if (!source) throw new Error('缺少 source');
if (!message) throw new Error('缺少 message');
return notion.writeSyslog(level, source, message, details);
}
// ═══════════════════════════════════════════════════════════
// 辅助函数
// ═══════════════════════════════════════════════════════════
/**
* 解析数据库别名
*/
function resolveDbAlias(id) {
const aliases = {
changelog: notion.NOTION_CONFIG.databases.changelog,
receipt: notion.NOTION_CONFIG.databases.receipt,
syslog: notion.NOTION_CONFIG.databases.syslog,
cognition_runtime: notion.NOTION_CONFIG.databases.cognition_runtime,
dev_workorder: notion.NOTION_CONFIG.databases.dev_workorder
};
return aliases[id] || id;
}
/**
* 简化页面对象去除 Notion API 冗余结构
*/
function simplifyPage(page) {
return {
id: page.id,
created_time: page.created_time,
last_edited_time: page.last_edited_time,
properties: simplifyProperties(page.properties)
};
}
/**
* 简化属性提取值
*/
function simplifyProperties(props) {
if (!props) return {};
const result = {};
for (const [name, prop] of Object.entries(props)) {
result[name] = extractPropertyValue(prop);
}
return result;
}
/**
* 提取 Notion 属性值
*/
function extractPropertyValue(prop) {
switch (prop.type) {
case 'title':
return prop.title.map(t => t.plain_text).join('');
case 'rich_text':
return prop.rich_text.map(t => t.plain_text).join('');
case 'number':
return prop.number;
case 'select':
return prop.select?.name || null;
case 'multi_select':
return prop.multi_select.map(s => s.name);
case 'date':
return prop.date?.start || null;
case 'checkbox':
return prop.checkbox;
case 'url':
return prop.url;
case 'email':
return prop.email;
case 'status':
return prop.status?.name || null;
case 'formula':
return prop.formula?.string || prop.formula?.number || null;
case 'relation':
return prop.relation.map(r => r.id);
default:
return `[${prop.type}]`;
}
}
/**
* 简化内容块
*/
function simplifyBlock(block) {
const simplified = {
id: block.id,
type: block.type,
has_children: block.has_children
};
const content = block[block.type];
if (content) {
if (content.rich_text) {
simplified.text = content.rich_text.map(t => t.plain_text).join('');
}
if (content.language) {
simplified.language = content.language;
}
}
return simplified;
}
module.exports = {
notionQuery,
notionReadPage,
notionWritePage,
notionUpdatePage,
notionWriteSyslog
};