feat(notion): 添加Notion数据库集成功能和相关脚本
添加Notion数据库集成配置和访问脚本,包括: - 配置Notion MCP服务器设置 - 添加数据库查询、内容查看和添加功能 - 创建测试脚本和集成文档
This commit is contained in:
47
NOTION_INTEGRATION.md
Normal file
47
NOTION_INTEGRATION.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Notion 数据库集成
|
||||||
|
|
||||||
|
此项目已配置为通过 Model Context Protocol (MCP) 与 Notion 数据库进行集成。
|
||||||
|
|
||||||
|
## 配置详情
|
||||||
|
|
||||||
|
已在 `mcp_settings.json` 中添加了 Notion 服务器配置:
|
||||||
|
|
||||||
|
```json
|
||||||
|
"notion": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@notionhq/notion-mcp-server"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer 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\", \"Notion-Version\": \"2022-06-28\"}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
### 1. 运行 Notion 数据库访问脚本
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python notion_database_access.py
|
||||||
|
```
|
||||||
|
|
||||||
|
这将显示所有可访问的 Notion 数据库及其详细信息。
|
||||||
|
|
||||||
|
### 2. 手动测试 API
|
||||||
|
|
||||||
|
您也可以使用以下命令测试 API 连接:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -H "Authorization: Bearer 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" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-H "Notion-Version: 2022-06-28" \
|
||||||
|
https://api.notion.com/v1/users/me
|
||||||
|
```
|
||||||
|
|
||||||
|
## 注意事项
|
||||||
|
|
||||||
|
- 确保您的 Notion 集成已正确连接到所需的页面
|
||||||
|
- 请妥善保管您的 API 密钥
|
||||||
|
- 如果遇到权限错误,请检查 Notion 集成的权限设置
|
||||||
11
README.md
11
README.md
@@ -1,3 +1,12 @@
|
|||||||
# 项目说明
|
# 项目说明
|
||||||
|
|
||||||
这是一个概念验证项目,旨在通过控制我不方便控制的阿里巴巴的 DSW WebIDE,让它当牛马,它上面已经运行了 runner。
|
"notion": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@notionhq/notion-mcp-server"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer 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\", \"Notion-Version\": \"2022-06-28\"}"
|
||||||
|
}
|
||||||
|
}
|
||||||
85
add_notion_content.py
Normal file
85
add_notion_content.py
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
Script to add sample content to your Notion database
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
class NotionDatabaseUpdater:
|
||||||
|
def __init__(self, integration_token="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"):
|
||||||
|
self.integration_token = integration_token
|
||||||
|
self.headers = {
|
||||||
|
"Authorization": f"Bearer {integration_token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Notion-Version": "2022-06-28"
|
||||||
|
}
|
||||||
|
self.base_url = "https://api.notion.com/v1"
|
||||||
|
|
||||||
|
def create_page_in_database(self, database_id, page_title, additional_properties=None):
|
||||||
|
"""Create a new page in the specified database"""
|
||||||
|
url = f"{self.base_url}/pages"
|
||||||
|
|
||||||
|
# Basic structure for a page with a title
|
||||||
|
data = {
|
||||||
|
"parent": {"database_id": database_id},
|
||||||
|
"properties": {
|
||||||
|
"名称": { # Assuming "名称" is the title property based on our earlier discovery
|
||||||
|
"title": [
|
||||||
|
{
|
||||||
|
"text": {
|
||||||
|
"content": page_title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Add any additional properties if provided
|
||||||
|
if additional_properties:
|
||||||
|
for prop_name, prop_value in additional_properties.items():
|
||||||
|
data["properties"][prop_name] = prop_value
|
||||||
|
|
||||||
|
response = requests.post(url, headers=self.headers, json=data)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
print(f"Error creating page: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Initialize the updater
|
||||||
|
updater = NotionDatabaseUpdater()
|
||||||
|
|
||||||
|
# Use the database ID we found earlier
|
||||||
|
database_id = "2fbdaaa6-ba07-804a-b48a-ce9c0a107416"
|
||||||
|
|
||||||
|
# Create a sample page
|
||||||
|
sample_pages = [
|
||||||
|
{
|
||||||
|
"title": "今天的工作计划",
|
||||||
|
"properties": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "学习新技能",
|
||||||
|
"properties": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "项目进展",
|
||||||
|
"properties": {}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
print("正在向您的 Notion 数据库添加示例内容...")
|
||||||
|
|
||||||
|
for page in sample_pages:
|
||||||
|
print(f"添加页面: {page['title']}")
|
||||||
|
result = updater.create_page_in_database(database_id, page['title'], page['properties'])
|
||||||
|
if result:
|
||||||
|
print(f" ✓ 页面创建成功! 页面ID: {result['id']}")
|
||||||
|
else:
|
||||||
|
print(f" ✗ 页面创建失败")
|
||||||
|
print()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
103
mcp_settings.json
Normal file
103
mcp_settings.json
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"context7": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@upstash/context7-mcp"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"DEFAULT_MINIMUM_TOKENS": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"filesystem": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@modelcontextprotocol/server-filesystem",
|
||||||
|
"./"
|
||||||
|
],
|
||||||
|
"alwaysAllow": [
|
||||||
|
"create_directory",
|
||||||
|
"write_file",
|
||||||
|
"edit_file"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sequentialthinking": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@modelcontextprotocol/server-sequential-thinking"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"memory": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@modelcontextprotocol/server-memory"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"tavily": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"tavily-mcp@0.2.3"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"TAVILY_API_KEY": "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"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supabase": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@supabase/mcp-server-supabase@0.5.5",
|
||||||
|
"--access-token",
|
||||||
|
"sbp_v0_cb9da057017b752cd9dbd232d92e482a123f787b"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"n8n-mcp": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"n8n-mcp@2.12.2"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"MCP_MODE": "stdio",
|
||||||
|
"LOG_LEVEL": "error",
|
||||||
|
"DISABLE_CONSOLE_OUTPUT": "true",
|
||||||
|
"N8N_API_KEY": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1ODY1YmU5Mi0wNGVkLTRiODItYjY4OC1hODc3ODZmYTZhYzQiLCJpc3MiOiJuOG4iLCJhdWQiOiJwdWJsaWMtYXBpIiwiaWF0IjoxNzY5ODMyNjY1fQ.hy-MEy2qZzipI42mHrWtWoWx3t2Cm5UXJnHUwt7zObM",
|
||||||
|
"N8N_HOST": "houzhongxu-n8n-free.hf.space",
|
||||||
|
"N8N_PROTOCOL": "https",
|
||||||
|
"N8N_PORT": "443"
|
||||||
|
},
|
||||||
|
"alwaysAllow": [
|
||||||
|
"get_database_statistics",
|
||||||
|
"list_nodes",
|
||||||
|
"search_templates"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"gitea": {
|
||||||
|
"command": "/home/ben/comfy/modelscope/gitea-mcp",
|
||||||
|
"args": [
|
||||||
|
"-t",
|
||||||
|
"stdio",
|
||||||
|
"--host",
|
||||||
|
" `https://gitea.tailnet-68f9.ts.net` "
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"GITEA_ACCESS_TOKEN": "8d7d70f324796be650b79415303c31f567bf459b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notion": {
|
||||||
|
"command": "npx",
|
||||||
|
"args": [
|
||||||
|
"-y",
|
||||||
|
"@notionhq/notion-mcp-server"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"OPENAPI_MCP_HEADERS": "{\"Authorization\": \"Bearer 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\", \"Notion-Version\": \"2022-06-28\"}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
95
notion_database_access.py
Normal file
95
notion_database_access.py
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
"""
|
||||||
|
Notion Database Access Script
|
||||||
|
This script demonstrates how to connect to and access your Notion database
|
||||||
|
using the Notion API with the configuration you have set up.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
class NotionDatabaseAccess:
|
||||||
|
def __init__(self, integration_token="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"):
|
||||||
|
self.integration_token = integration_token
|
||||||
|
self.headers = {
|
||||||
|
"Authorization": f"Bearer {integration_token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Notion-Version": "2022-06-28"
|
||||||
|
}
|
||||||
|
self.base_url = "https://api.notion.com/v1"
|
||||||
|
|
||||||
|
def list_databases(self):
|
||||||
|
"""List all databases accessible with the integration token"""
|
||||||
|
url = f"{self.base_url}/search"
|
||||||
|
payload = {
|
||||||
|
"filter": {
|
||||||
|
"property": "object",
|
||||||
|
"value": "database"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
response = requests.post(url, headers=self.headers, json=payload)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
print(f"Error: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def query_database(self, database_id):
|
||||||
|
"""Query a specific database by ID"""
|
||||||
|
url = f"{self.base_url}/databases/{database_id}/query"
|
||||||
|
response = requests.post(url, headers=self.headers)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
print(f"Error querying database: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_database_info(self, database_id):
|
||||||
|
"""Get information about a specific database"""
|
||||||
|
url = f"{self.base_url}/databases/{database_id}"
|
||||||
|
response = requests.get(url, headers=self.headers)
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
print(f"Error getting database info: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Initialize the Notion database access
|
||||||
|
notion = NotionDatabaseAccess()
|
||||||
|
|
||||||
|
print("Connecting to your Notion account...")
|
||||||
|
print("Searching for accessible databases...")
|
||||||
|
|
||||||
|
# List all databases
|
||||||
|
databases_result = notion.list_databases()
|
||||||
|
|
||||||
|
if databases_result and 'results' in databases_result:
|
||||||
|
databases = databases_result['results']
|
||||||
|
|
||||||
|
if databases:
|
||||||
|
print(f"\nFound {len(databases)} database(s):\n")
|
||||||
|
|
||||||
|
for db in databases:
|
||||||
|
db_id = db['id']
|
||||||
|
db_title = ''.join([title.get('plain_text', '') for title in db.get('title', [])])
|
||||||
|
|
||||||
|
print(f"Database ID: {db_id}")
|
||||||
|
print(f"Title: {db_title}")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
# Get detailed info about each database
|
||||||
|
db_info = notion.get_database_info(db_id)
|
||||||
|
if db_info:
|
||||||
|
print(f"Description: {''.join([desc.get('plain_text', '') for desc in db_info.get('description', [])])}")
|
||||||
|
print(f"Properties:")
|
||||||
|
for prop_name, prop_info in db_info.get('properties', {}).items():
|
||||||
|
print(f" - {prop_name}: {prop_info.get('type', 'unknown')}")
|
||||||
|
print()
|
||||||
|
else:
|
||||||
|
print("No databases found. Make sure your integration is properly connected to your Notion pages.")
|
||||||
|
else:
|
||||||
|
print("Failed to retrieve databases. Check your integration token and permissions.")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
44
scripts/test-api-endpoints.sh
Executable file
44
scripts/test-api-endpoints.sh
Executable file
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 配置信息
|
||||||
|
GITEA_URL="https://gitea.tailnet-68f9.ts.net"
|
||||||
|
TOKEN="8d7d70f324796be650b79415303c31f567bf459b"
|
||||||
|
|
||||||
|
# 函数:测试API端点
|
||||||
|
function test_endpoint() {
|
||||||
|
local endpoint=$1
|
||||||
|
echo "测试端点: $endpoint"
|
||||||
|
|
||||||
|
response=$(curl -s -w "\n%{http_code}" \
|
||||||
|
-H "Authorization: token $TOKEN" \
|
||||||
|
"$GITEA_URL$endpoint")
|
||||||
|
|
||||||
|
# 分离响应内容和HTTP状态码
|
||||||
|
http_status=$(echo "$response" | tail -n1)
|
||||||
|
response_body=$(echo "$response" | sed '$d')
|
||||||
|
|
||||||
|
echo "HTTP状态码: $http_status"
|
||||||
|
if [ "$http_status" -eq 200 ]; then
|
||||||
|
echo "✓ 成功 - 响应: $response_body"
|
||||||
|
elif [ "$http_status" -eq 404 ]; then
|
||||||
|
echo "✗ 未找到"
|
||||||
|
elif [ "$http_status" -eq 403 ] || [ "$http_status" -eq 401 ]; then
|
||||||
|
echo "✗ 访问被拒绝 (可能权限不足)"
|
||||||
|
else
|
||||||
|
echo "✗ 其他错误 - 响应: $response_body"
|
||||||
|
fi
|
||||||
|
echo "---"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "=== 测试Gitea Actions Runner API端点 ==="
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# 测试可能的API端点
|
||||||
|
test_endpoint "/api/v1/actions/runners"
|
||||||
|
test_endpoint "/api/v1/actions/runners/5"
|
||||||
|
test_endpoint "/api/v1/admin/runners"
|
||||||
|
test_endpoint "/api/v1/admin/runners/5"
|
||||||
|
test_endpoint "/api/v1/user/actions/runners"
|
||||||
|
test_endpoint "/api/v1/user/actions/runners/5"
|
||||||
|
test_endpoint "/api/v1/users/ben/actions/runners"
|
||||||
|
test_endpoint "/api/v1/repos/ben/modelscope/actions/runners"
|
||||||
59
view_database_content.py
Normal file
59
view_database_content.py
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
"""
|
||||||
|
Script to view content in your Notion database
|
||||||
|
"""
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
|
||||||
|
class NotionDatabaseViewer:
|
||||||
|
def __init__(self, integration_token="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"):
|
||||||
|
self.integration_token = integration_token
|
||||||
|
self.headers = {
|
||||||
|
"Authorization": f"Bearer {integration_token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Notion-Version": "2022-06-28"
|
||||||
|
}
|
||||||
|
self.base_url = "https://api.notion.com/v1"
|
||||||
|
|
||||||
|
def query_database(self, database_id):
|
||||||
|
"""Query a specific database to get its content"""
|
||||||
|
url = f"{self.base_url}/databases/{database_id}/query"
|
||||||
|
response = requests.post(url, headers=self.headers, json={})
|
||||||
|
if response.status_code == 200:
|
||||||
|
return response.json()
|
||||||
|
else:
|
||||||
|
print(f"Error querying database: {response.status_code} - {response.text}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
# Initialize the viewer
|
||||||
|
viewer = NotionDatabaseViewer()
|
||||||
|
|
||||||
|
# Use the database ID we found earlier
|
||||||
|
database_id = "2fbdaaa6-ba07-804a-b48a-ce9c0a107416"
|
||||||
|
|
||||||
|
print("正在查询数据库内容...")
|
||||||
|
result = viewer.query_database(database_id)
|
||||||
|
|
||||||
|
if result and 'results' in result:
|
||||||
|
pages = result['results']
|
||||||
|
print(f"在数据库中找到 {len(pages)} 个页面:\n")
|
||||||
|
|
||||||
|
for page in pages:
|
||||||
|
page_id = page['id']
|
||||||
|
# Extract the title from the page properties
|
||||||
|
title_property = page['properties'].get('名称', {})
|
||||||
|
if title_property and 'title' in title_property:
|
||||||
|
title_parts = title_property['title']
|
||||||
|
page_title = ''.join([part.get('text', {}).get('content', '') for part in title_parts])
|
||||||
|
else:
|
||||||
|
page_title = "[无标题]"
|
||||||
|
|
||||||
|
print(f"页面ID: {page_id}")
|
||||||
|
print(f"标题: {page_title}")
|
||||||
|
print("-" * 50)
|
||||||
|
else:
|
||||||
|
print("未能检索到数据库内容")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user