Skip to main content
Glama
mcp_server_notion.py12.1 kB
import json import logging import sys import os from mcp.server.fastmcp import FastMCP from notion_client import Client logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Notion API 키와 페이지 ID 설정 def get_notion_credentials(): return os.getenv("NOTION_API_KEY"), os.getenv("NOTION_PAGE_ID") mcp = FastMCP( name="mcp-notion", instructions="Notion API를 사용하여 페이지를 생성하고 관리합니다." ) @mcp.tool() def add_to_notion_page(title: str, content: str) -> str: """ 지정된 Notion 페이지에 내용을 추가합니다. Args: title: 제목 content: 추가할 내용 Returns: 추가 결과 """ try: if not NOTION_API_KEY: return "Notion API 키가 설정되지 않았습니다." if not NOTION_PAGE_ID: return "Notion 페이지 ID가 설정되지 않았습니다." notion = Client(auth=NOTION_API_KEY) # 제목 블록 추가 title_block = { "object": "block", "type": "heading_2", "heading_2": { "rich_text": [{ "type": "text", "text": {"content": title} }] } } # 내용을 2000자씩 나누어 블록 생성 content_blocks = [] max_length = 2000 for i in range(0, len(content), max_length): chunk = content[i:i + max_length] content_blocks.append({ "object": "block", "type": "paragraph", "paragraph": { "rich_text": [{ "type": "text", "text": {"content": chunk} }] } }) # 모든 블록을 페이지에 추가 all_blocks = [title_block] + content_blocks response = notion.blocks.children.append( block_id=NOTION_PAGE_ID, children=all_blocks ) logger.info(f"블록 추가 성공: {len(all_blocks)}개 블록") # 저장된 전체 내용을 반환 full_saved_content = f"📋 Notion에 저장된 전체 내용:\n\n# {title}\n\n{content}" return full_saved_content except Exception as e: logger.error(f"Notion 페이지 내용 추가 실패: {str(e)}") return f"내용 추가 실패: {str(e)}" @mcp.tool() def get_notion_page() -> str: """ 현재 설정된 Notion 페이지 정보를 가져옵니다. Returns: 페이지 정보 JSON """ try: api_key, page_id = get_notion_credentials() if not api_key or not page_id: return "Notion API 키 또는 페이지 ID가 설정되지 않았습니다." notion = Client(auth=api_key) page = notion.pages.retrieve(page_id=page_id) return json.dumps(page, ensure_ascii=False, indent=2) except Exception as e: logger.error(f"페이지 정보 가져오기 실패: {str(e)}") return f"페이지 정보 가져오기 실패: {str(e)}" @mcp.tool() def get_notion_blocks() -> str: """ 현재 설정된 Notion 페이지의 모든 블록을 재귀적으로 가져옵니다. Returns: 블록 정보 JSON """ try: api_key, page_id = get_notion_credentials() if not api_key or not page_id: return json.dumps({"blocks": [], "error": "Notion API 키 또는 페이지 ID가 설정되지 않았습니다."}, ensure_ascii=False) notion = Client(auth=api_key) def get_blocks_recursive(block_id): blocks = notion.blocks.children.list(block_id=block_id) result = [] for block in blocks["results"]: block_data = { "id": block["id"], "type": block["type"], "text": "", "url": "", "caption": "", "children": [] } # 텍스트 추출 if block["type"] in ["paragraph", "heading_1", "heading_2", "heading_3", "bulleted_list_item", "numbered_list_item", "toggle", "quote"]: rich_text = block[block["type"]].get("rich_text", []) block_data["text"] = "".join([t.get("plain_text", "") for t in rich_text]) # 이미지 처리 elif block["type"] == "image": image_data = block["image"] if image_data["type"] == "file": block_data["url"] = image_data["file"]["url"] elif image_data["type"] == "external": block_data["url"] = image_data["external"]["url"] caption = image_data.get("caption", []) block_data["caption"] = "".join([t.get("plain_text", "") for t in caption]) # 코드 처리 elif block["type"] == "code": rich_text = block["code"].get("rich_text", []) block_data["text"] = "".join([t.get("plain_text", "") for t in rich_text]) block_data["language"] = block["code"].get("language", "") # 하위 블록 처리 if block.get("has_children", False): block_data["children"] = get_blocks_recursive(block["id"]) result.append(block_data) return result blocks = get_blocks_recursive(page_id) return json.dumps({"blocks": blocks}, ensure_ascii=False, indent=2) except Exception as e: logger.error(f"블록 가져오기 실패: {str(e)}") return f"블록 가져오기 실패: {str(e)}" @mcp.tool() def get_notion_images() -> str: """ 현재 설정된 Notion 페이지의 모든 이미지를 가져옵니다. Returns: 이미지 정보 JSON """ try: api_key, page_id = get_notion_credentials() if not api_key or not page_id: return json.dumps({"images": [], "error": "Notion API 키 또는 페이지 ID가 설정되지 않았습니다."}, ensure_ascii=False) notion = Client(auth=api_key) def extract_images_recursive(block_id, current_title=""): blocks = notion.blocks.children.list(block_id=block_id) images = [] title = current_title for block in blocks["results"]: # 제목 업데이트 if block["type"] in ["heading_1", "heading_2", "heading_3"]: rich_text = block[block["type"]].get("rich_text", []) title = "".join([t.get("plain_text", "") for t in rich_text]) # 이미지 처리 elif block["type"] == "image": image_data = block["image"] image_url = "" if image_data["type"] == "file": image_url = image_data["file"]["url"] elif image_data["type"] == "external": image_url = image_data["external"]["url"] if image_url: caption = image_data.get("caption", []) caption_text = "".join([t.get("plain_text", "") for t in caption]) images.append({ "url": image_url, "caption": caption_text, "title": title }) # 하위 블록에서도 이미지 찾기 if block.get("has_children", False): child_images = extract_images_recursive(block["id"], title) images.extend(child_images) return images images = extract_images_recursive(page_id) return json.dumps({"images": images}, ensure_ascii=False, indent=2) except Exception as e: logger.error(f"이미지 가져오기 실패: {str(e)}") return f"이미지 가져오기 실패: {str(e)}" @mcp.tool() def get_child_pages() -> str: """ 현재 설정된 Notion 페이지의 하위 페이지들을 가져옵니다. Returns: 하위 페이지 정보 JSON """ try: api_key, page_id = get_notion_credentials() if not api_key or not page_id: return json.dumps({"child_pages": [], "error": "Notion API 키 또는 페이지 ID가 설정되지 않았습니다."}, ensure_ascii=False) notion = Client(auth=api_key) def find_child_pages_recursive(block_id): blocks = notion.blocks.children.list(block_id=block_id) child_pages = [] for block in blocks["results"]: if block["type"] == "child_page": try: page = notion.pages.retrieve(page_id=block["id"]) page_title = "제목 없음" if "properties" in page: for prop_name, prop_data in page["properties"].items(): if prop_data["type"] == "title": title_array = prop_data["title"] page_title = "".join([t.get("plain_text", "") for t in title_array]) break child_pages.append({ "id": block["id"], "title": page_title, "url": page.get("url", "") }) except Exception as e: logger.error(f"하위 페이지 정보 가져오기 실패: {e}") # 하위 블록에서도 child_page 찾기 if block.get("has_children", False): nested_pages = find_child_pages_recursive(block["id"]) child_pages.extend(nested_pages) return child_pages child_pages = find_child_pages_recursive(page_id) return json.dumps({"child_pages": child_pages}, ensure_ascii=False, indent=2) except Exception as e: logger.error(f"하위 페이지 가져오기 실패: {str(e)}") return f"하위 페이지 가져오기 실패: {str(e)}" @mcp.tool() def search_notion_pages(query: str) -> str: """ Notion에서 페이지를 검색합니다. Args: query: 검색할 키워드 Returns: 검색 결과 """ try: notion = Client(auth=NOTION_API_KEY) results = notion.search( query=query, filter={ "value": "page", "property": "object" } ) pages = [] for page in results["results"]: title = "제목 없음" if "properties" in page and "title" in page["properties"]: title_prop = page["properties"]["title"] if "title" in title_prop and title_prop["title"]: title = title_prop["title"][0]["text"]["content"] pages.append({ "title": title, "url": page["url"], "id": page["id"] }) return json.dumps(pages, ensure_ascii=False, indent=2) except Exception as e: logger.error(f"Notion 검색 실패: {str(e)}") return f"검색 실패: {str(e)}" if __name__ == "__main__": mcp.run(transport="stdio")

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ar-codelabs/MCP_NotionMCP_Webviewer'

If you have feedback or need assistance with the MCP directory API, please join our Discord server