Skip to main content
Glama

Notion MCP Server

by HariFatherKR
index.html30.5 kB
<!DOCTYPE html> <html lang="ko"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Notion API 테스트</title> <style> body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; max-width: 1000px; margin: 0 auto; padding: 20px; line-height: 1.6; } h1 { color: #2e3a59; } .card { background-color: #f7f9fc; border-radius: 8px; padding: 16px; margin-bottom: 16px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); } .form-group { margin-bottom: 16px; } label { display: block; margin-bottom: 8px; font-weight: 500; } input, select, textarea { width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px; font-size: 14px; } textarea { height: 100px; font-family: monospace; } button { background-color: #2e75b5; color: white; border: none; padding: 10px 16px; border-radius: 4px; cursor: pointer; font-size: 14px; } button:hover { background-color: #1d5a9f; } pre { background-color: #f0f2f5; padding: 12px; border-radius: 4px; overflow: auto; font-size: 13px; max-height: 300px; } .result { margin-top: 20px; } .tabs { display: flex; border-bottom: 1px solid #ddd; margin-bottom: 20px; } .tab { padding: 10px 15px; cursor: pointer; background: #f0f2f5; margin-right: 5px; border-radius: 4px 4px 0 0; } .tab.active { background: #2e75b5; color: white; } .tab-content { display: none; } .tab-content.active { display: block; } .api-section { margin-bottom: 30px; } .collapsible { cursor: pointer; background-color: #eaecf0; padding: 10px; border-radius: 4px; margin-bottom: 10px; } .collapsible:hover { background-color: #e0e3e9; } .collapsible-content { display: none; } .collapsible-content.active { display: block; } </style> </head> <body> <h1>Notion API 테스트</h1> <div class="tabs"> <div class="tab active" data-tab="search">검색</div> <div class="tab" data-tab="pages">페이지</div> <div class="tab" data-tab="databases">데이터베이스</div> <div class="tab" data-tab="blocks">블록</div> <div class="tab" data-tab="users">사용자</div> <div class="tab" data-tab="comments">코멘트</div> </div> <!-- 검색 탭 --> <div class="tab-content active" id="search-tab"> <div class="card"> <h2>검색 API</h2> <div class="form-group"> <label for="searchQuery">검색어:</label> <input type="text" id="searchQuery" placeholder="검색어를 입력하세요"> </div> <div class="form-group"> <label for="searchFilter">필터 (선택사항):</label> <select id="searchFilter"> <option value="">필터 없음</option> <option value="page">페이지만</option> <option value="database">데이터베이스만</option> </select> </div> <button id="searchButton">검색</button> <div id="searchResult" class="result"> <h3>검색 결과:</h3> <pre id="searchOutput">검색 결과가 여기에 표시됩니다.</pre> </div> </div> </div> <!-- 페이지 탭 --> <div class="tab-content" id="pages-tab"> <div class="api-section"> <div class="collapsible"> <h2>페이지 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="pageId">페이지 ID:</label> <input type="text" id="pageId" placeholder="페이지 ID를 입력하세요"> </div> <button id="pageButton">조회</button> <div id="pageResult" class="result"> <h3>페이지 정보:</h3> <pre id="pageOutput">페이지 정보가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>페이지 생성</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="createPageParent">상위 페이지 ID:</label> <input type="text" id="createPageParent" placeholder="페이지를 생성할 상위 페이지 ID"> </div> <div class="form-group"> <label for="createPageTitle">페이지 제목:</label> <input type="text" id="createPageTitle" placeholder="새 페이지 제목"> </div> <div class="form-group"> <label for="createPageJson">페이지 속성 (JSON):</label> <textarea id="createPageJson" placeholder='{ "parent": { "page_id": "페이지ID" }, "properties": { "title": { "title": [{ "text": { "content": "새 페이지 제목" } }] } } }'></textarea> </div> <button id="createPageButton">페이지 생성</button> <div id="createPageResult" class="result"> <h3>생성 결과:</h3> <pre id="createPageOutput">페이지 생성 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>페이지 업데이트</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="updatePageId">페이지 ID:</label> <input type="text" id="updatePageId" placeholder="업데이트할 페이지 ID"> </div> <div class="form-group"> <label for="updatePageJson">업데이트 내용 (JSON):</label> <textarea id="updatePageJson" placeholder='{ "properties": { "title": { "title": [{ "text": { "content": "업데이트된 제목" } }] } } }'></textarea> </div> <button id="updatePageButton">페이지 업데이트</button> <div id="updatePageResult" class="result"> <h3>업데이트 결과:</h3> <pre id="updatePageOutput">페이지 업데이트 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>페이지 속성 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="propertyPageId">페이지 ID:</label> <input type="text" id="propertyPageId" placeholder="페이지 ID를 입력하세요"> </div> <div class="form-group"> <label for="propertyId">속성 ID:</label> <input type="text" id="propertyId" placeholder="속성 ID를 입력하세요"> </div> <button id="propertyButton">속성 조회</button> <div id="propertyResult" class="result"> <h3>속성 정보:</h3> <pre id="propertyOutput">속성 정보가 여기에 표시됩니다.</pre> </div> </div> </div> </div> </div> <!-- 데이터베이스 탭 --> <div class="tab-content" id="databases-tab"> <div class="api-section"> <div class="collapsible"> <h2>데이터베이스 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="databaseId">데이터베이스 ID:</label> <input type="text" id="databaseId" placeholder="데이터베이스 ID를 입력하세요"> </div> <button id="databaseButton">조회</button> <div id="databaseResult" class="result"> <h3>데이터베이스 정보:</h3> <pre id="databaseOutput">데이터베이스 정보가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>데이터베이스 생성</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="createDatabaseParent">상위 페이지 ID:</label> <input type="text" id="createDatabaseParent" placeholder="데이터베이스를 생성할 상위 페이지 ID"> </div> <div class="form-group"> <label for="createDatabaseTitle">데이터베이스 제목:</label> <input type="text" id="createDatabaseTitle" placeholder="새 데이터베이스 제목"> </div> <div class="form-group"> <label for="createDatabaseJson">데이터베이스 속성 (JSON):</label> <textarea id="createDatabaseJson" placeholder='{ "parent": { "page_id": "페이지ID" }, "title": [{ "text": { "content": "새 데이터베이스" } }], "properties": { "이름": { "title": {} }, "설명": { "rich_text": {} }, "상태": { "select": { "options": [ { "name": "진행중", "color": "blue" }, { "name": "완료", "color": "green" } ] } } } }'></textarea> </div> <button id="createDatabaseButton">데이터베이스 생성</button> <div id="createDatabaseResult" class="result"> <h3>생성 결과:</h3> <pre id="createDatabaseOutput">데이터베이스 생성 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>데이터베이스 쿼리</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="queryDatabaseId">데이터베이스 ID:</label> <input type="text" id="queryDatabaseId" placeholder="쿼리할 데이터베이스 ID"> </div> <div class="form-group"> <label for="queryDatabaseJson">쿼리 내용 (JSON):</label> <textarea id="queryDatabaseJson" placeholder='{ "filter": { "property": "속성명", "rich_text": { "contains": "검색어" } }, "sorts": [ { "property": "속성명", "direction": "ascending" } ] }'></textarea> </div> <button id="queryDatabaseButton">쿼리 실행</button> <div id="queryDatabaseResult" class="result"> <h3>쿼리 결과:</h3> <pre id="queryDatabaseOutput">쿼리 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> </div> <!-- 블록 탭 --> <div class="tab-content" id="blocks-tab"> <div class="api-section"> <div class="collapsible"> <h2>블록 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="blockId">블록 ID:</label> <input type="text" id="blockId" placeholder="블록 ID를 입력하세요"> </div> <button id="blockButton">조회</button> <div id="blockResult" class="result"> <h3>블록 정보:</h3> <pre id="blockOutput">블록 정보가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>블록 내용 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="blockChildrenId">블록 ID:</label> <input type="text" id="blockChildrenId" placeholder="블록 ID를 입력하세요 (페이지 ID도 가능)"> </div> <button id="blockChildrenButton">내용 조회</button> <div id="blockChildrenResult" class="result"> <h3>블록 내용:</h3> <pre id="blockChildrenOutput">블록 내용이 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>블록 추가</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="appendBlockId">블록 ID:</label> <input type="text" id="appendBlockId" placeholder="블록을 추가할 상위 블록 ID (페이지 ID도 가능)"> </div> <div class="form-group"> <label for="appendBlockJson">추가할 블록 (JSON):</label> <textarea id="appendBlockJson" placeholder='{ "children": [ { "object": "block", "type": "paragraph", "paragraph": { "rich_text": [ { "type": "text", "text": { "content": "Hello world" } } ] } } ] }'></textarea> </div> <button id="appendBlockButton">블록 추가</button> <div id="appendBlockResult" class="result"> <h3>추가 결과:</h3> <pre id="appendBlockOutput">블록 추가 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>블록 삭제</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="deleteBlockId">블록 ID:</label> <input type="text" id="deleteBlockId" placeholder="삭제할 블록 ID"> </div> <button id="deleteBlockButton">블록 삭제</button> <div id="deleteBlockResult" class="result"> <h3>삭제 결과:</h3> <pre id="deleteBlockOutput">블록 삭제 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> </div> <!-- 사용자 탭 --> <div class="tab-content" id="users-tab"> <div class="api-section"> <div class="collapsible"> <h2>사용자 목록 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <button id="usersButton">사용자 목록 조회</button> <div id="usersResult" class="result"> <h3>사용자 목록:</h3> <pre id="usersOutput">사용자 목록이 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>사용자 정보 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="userId">사용자 ID:</label> <input type="text" id="userId" placeholder="사용자 ID를 입력하세요"> </div> <button id="userButton">사용자 조회</button> <div id="userResult" class="result"> <h3>사용자 정보:</h3> <pre id="userOutput">사용자 정보가 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>자신의 사용자 정보 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <button id="meButton">내 정보 조회</button> <div id="meResult" class="result"> <h3>내 정보:</h3> <pre id="meOutput">내 정보가 여기에 표시됩니다.</pre> </div> </div> </div> </div> </div> <!-- 코멘트 탭 --> <div class="tab-content" id="comments-tab"> <div class="api-section"> <div class="collapsible"> <h2>코멘트 조회</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="commentsBlockId">블록 ID:</label> <input type="text" id="commentsBlockId" placeholder="코멘트를 조회할 블록 ID"> </div> <button id="commentsButton">코멘트 조회</button> <div id="commentsResult" class="result"> <h3>코멘트 목록:</h3> <pre id="commentsOutput">코멘트 목록이 여기에 표시됩니다.</pre> </div> </div> </div> </div> <div class="api-section"> <div class="collapsible"> <h2>코멘트 생성</h2> </div> <div class="collapsible-content"> <div class="card"> <div class="form-group"> <label for="createCommentParent">페이지 ID:</label> <input type="text" id="createCommentParent" placeholder="코멘트를 생성할 페이지 ID"> </div> <div class="form-group"> <label for="createCommentText">코멘트 내용:</label> <textarea id="createCommentText" placeholder="코멘트 내용을 입력하세요"></textarea> </div> <button id="createCommentButton">코멘트 생성</button> <div id="createCommentResult" class="result"> <h3>생성 결과:</h3> <pre id="createCommentOutput">코멘트 생성 결과가 여기에 표시됩니다.</pre> </div> </div> </div> </div> </div> <script> // API 기본 URL const API_BASE_URL = 'http://localhost:3000/api'; // 탭 기능 document.querySelectorAll('.tab').forEach(tab => { tab.addEventListener('click', function() { document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active')); this.classList.add('active'); document.getElementById(`${this.dataset.tab}-tab`).classList.add('active'); }); }); // 접을 수 있는 섹션 document.querySelectorAll('.collapsible').forEach(coll => { coll.addEventListener('click', function() { const content = this.nextElementSibling; content.classList.toggle('active'); }); }); // API 통신 공통 함수 async function apiCall(endpoint, method = 'GET', body = null) { try { const options = { method, headers: { 'Content-Type': 'application/json', }, }; if (body) { options.body = JSON.stringify(body); } const response = await fetch(`${API_BASE_URL}${endpoint}`, options); return await response.json(); } catch (error) { return { error: error.message }; } } // ========= 검색 API ========= document.getElementById('searchButton').addEventListener('click', async function() { const query = document.getElementById('searchQuery').value; const filterValue = document.getElementById('searchFilter').value; const output = document.getElementById('searchOutput'); output.textContent = '로딩 중...'; const body = { query }; if (filterValue) { body.filter = { property: 'object', value: filterValue }; } const data = await apiCall('/search', 'POST', body); output.textContent = JSON.stringify(data, null, 2); }); // ========= 페이지 API ========= // 페이지 조회 document.getElementById('pageButton').addEventListener('click', async function() { const pageId = document.getElementById('pageId').value; const output = document.getElementById('pageOutput'); if (!pageId) { output.textContent = '페이지 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/pages/${pageId}`); output.textContent = JSON.stringify(data, null, 2); }); // 페이지 생성 document.getElementById('createPageButton').addEventListener('click', async function() { const pageParent = document.getElementById('createPageParent').value; const pageTitle = document.getElementById('createPageTitle').value; const pageJson = document.getElementById('createPageJson').value; const output = document.getElementById('createPageOutput'); output.textContent = '로딩 중...'; let body; try { if (pageJson.trim()) { body = JSON.parse(pageJson); } else { body = { parent: { page_id: pageParent }, properties: { title: { title: [{ text: { content: pageTitle } }] } } }; } const data = await apiCall('/pages', 'POST', body); output.textContent = JSON.stringify(data, null, 2); } catch (error) { output.textContent = `오류 발생: ${error.message}`; } }); // 페이지 업데이트 document.getElementById('updatePageButton').addEventListener('click', async function() { const pageId = document.getElementById('updatePageId').value; const pageJson = document.getElementById('updatePageJson').value; const output = document.getElementById('updatePageOutput'); if (!pageId) { output.textContent = '페이지 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; try { const body = pageJson.trim() ? JSON.parse(pageJson) : {}; const data = await apiCall(`/pages/${pageId}`, 'PATCH', body); output.textContent = JSON.stringify(data, null, 2); } catch (error) { output.textContent = `오류 발생: ${error.message}`; } }); // 페이지 속성 조회 document.getElementById('propertyButton').addEventListener('click', async function() { const pageId = document.getElementById('propertyPageId').value; const propertyId = document.getElementById('propertyId').value; const output = document.getElementById('propertyOutput'); if (!pageId || !propertyId) { output.textContent = '페이지 ID와 속성 ID를 모두 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/pages/${pageId}/properties/${propertyId}`); output.textContent = JSON.stringify(data, null, 2); }); // ========= 데이터베이스 API ========= // 데이터베이스 조회 document.getElementById('databaseButton').addEventListener('click', async function() { const databaseId = document.getElementById('databaseId').value; const output = document.getElementById('databaseOutput'); if (!databaseId) { output.textContent = '데이터베이스 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/databases/${databaseId}`); output.textContent = JSON.stringify(data, null, 2); }); // 데이터베이스 생성 document.getElementById('createDatabaseButton').addEventListener('click', async function() { const parentId = document.getElementById('createDatabaseParent').value; const title = document.getElementById('createDatabaseTitle').value; const json = document.getElementById('createDatabaseJson').value; const output = document.getElementById('createDatabaseOutput'); output.textContent = '로딩 중...'; try { let body; if (json.trim()) { body = JSON.parse(json); } else { body = { parent: { page_id: parentId }, title: [{ text: { content: title } }], properties: { 이름: { title: {} } } }; } const data = await apiCall('/databases', 'POST', body); output.textContent = JSON.stringify(data, null, 2); } catch (error) { output.textContent = `오류 발생: ${error.message}`; } }); // 데이터베이스 쿼리 document.getElementById('queryDatabaseButton').addEventListener('click', async function() { const databaseId = document.getElementById('queryDatabaseId').value; const queryJson = document.getElementById('queryDatabaseJson').value; const output = document.getElementById('queryDatabaseOutput'); if (!databaseId) { output.textContent = '데이터베이스 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; try { const body = queryJson.trim() ? JSON.parse(queryJson) : {}; const data = await apiCall(`/databases/${databaseId}/query`, 'POST', body); output.textContent = JSON.stringify(data, null, 2); } catch (error) { output.textContent = `오류 발생: ${error.message}`; } }); // ========= 블록 API ========= // 블록 조회 document.getElementById('blockButton').addEventListener('click', async function() { const blockId = document.getElementById('blockId').value; const output = document.getElementById('blockOutput'); if (!blockId) { output.textContent = '블록 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/blocks/${blockId}`); output.textContent = JSON.stringify(data, null, 2); }); // 블록 내용 조회 document.getElementById('blockChildrenButton').addEventListener('click', async function() { const blockId = document.getElementById('blockChildrenId').value; const output = document.getElementById('blockChildrenOutput'); if (!blockId) { output.textContent = '블록 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/blocks/${blockId}/children`); output.textContent = JSON.stringify(data, null, 2); }); // 블록 추가 document.getElementById('appendBlockButton').addEventListener('click', async function() { const blockId = document.getElementById('appendBlockId').value; const blockJson = document.getElementById('appendBlockJson').value; const output = document.getElementById('appendBlockOutput'); if (!blockId) { output.textContent = '블록 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; try { const body = blockJson.trim() ? JSON.parse(blockJson) : { children: [] }; const data = await apiCall(`/blocks/${blockId}/children`, 'PATCH', body); output.textContent = JSON.stringify(data, null, 2); } catch (error) { output.textContent = `오류 발생: ${error.message}`; } }); // 블록 삭제 document.getElementById('deleteBlockButton').addEventListener('click', async function() { const blockId = document.getElementById('deleteBlockId').value; const output = document.getElementById('deleteBlockOutput'); if (!blockId) { output.textContent = '블록 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/blocks/${blockId}`, 'DELETE'); output.textContent = JSON.stringify(data, null, 2); }); // ========= 사용자 API ========= // 사용자 목록 조회 document.getElementById('usersButton').addEventListener('click', async function() { const output = document.getElementById('usersOutput'); output.textContent = '로딩 중...'; const data = await apiCall('/users'); output.textContent = JSON.stringify(data, null, 2); }); // 사용자 조회 document.getElementById('userButton').addEventListener('click', async function() { const userId = document.getElementById('userId').value; const output = document.getElementById('userOutput'); if (!userId) { output.textContent = '사용자 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/users/${userId}`); output.textContent = JSON.stringify(data, null, 2); }); // 자신의 사용자 정보 조회 document.getElementById('meButton').addEventListener('click', async function() { const output = document.getElementById('meOutput'); output.textContent = '로딩 중...'; const data = await apiCall('/users/me'); output.textContent = JSON.stringify(data, null, 2); }); // ========= 코멘트 API ========= // 코멘트 조회 document.getElementById('commentsButton').addEventListener('click', async function() { const blockId = document.getElementById('commentsBlockId').value; const output = document.getElementById('commentsOutput'); if (!blockId) { output.textContent = '블록 ID를 입력해주세요.'; return; } output.textContent = '로딩 중...'; const data = await apiCall(`/comments?block_id=${blockId}`); output.textContent = JSON.stringify(data, null, 2); }); // 코멘트 생성 document.getElementById('createCommentButton').addEventListener('click', async function() { const pageId = document.getElementById('createCommentParent').value; const text = document.getElementById('createCommentText').value; const output = document.getElementById('createCommentOutput'); if (!pageId || !text) { output.textContent = '페이지 ID와 코멘트 내용을 모두 입력해주세요.'; return; } output.textContent = '로딩 중...'; const body = { parent: { page_id: pageId }, rich_text: [{ text: { content: text } }] }; const data = await apiCall('/comments', 'POST', body); output.textContent = JSON.stringify(data, null, 2); }); </script> </body> </html>

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/HariFatherKR/notion_mcp_server'

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