From 12710c2b2f440736527db81f2c0351298048e0f5 Mon Sep 17 00:00:00 2001 From: Emanuel Almeida Date: Sat, 31 Jan 2026 20:35:45 +0000 Subject: [PATCH] fix(critical): Create revision on document creation Documents created via MCP were not visible in Outline interface. Outline requires an entry in the revisions table to display documents. Now uses transaction to insert into both documents and revisions tables. Co-Authored-By: Claude Opus 4.5 --- CHANGELOG.md | 10 ++++ CLAUDE.md | 2 +- CONTINUE.md | 2 +- package-lock.json | 4 +- package.json | 2 +- src/index-http.ts | 4 +- src/index.ts | 2 +- src/server/create-server.ts | 2 +- src/tools/documents.ts | 99 ++++++++++++++++++++++++------------- 9 files changed, 83 insertions(+), 44 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3161c57..6adb811 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. +## [1.3.9] - 2026-01-31 + +### Fixed + +- **Document Visibility (Critical):** `create_document` now creates initial revision + - Was: Documents created via MCP didn't appear in Outline interface + - Cause: Outline requires entry in `revisions` table to display documents + - Now: Uses transaction to insert into both `documents` and `revisions` tables + - Documents created via MCP now visible immediately in Outline + ## [1.3.8] - 2026-01-31 ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index 81c9d30..edc4eba 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co MCP server for direct PostgreSQL access to Outline Wiki database. Follows patterns established by `mcp-desk-crm-sql-v3`. -**Version:** 1.3.8 +**Version:** 1.3.9 **Total Tools:** 164 tools across 33 modules **Production:** hub.descomplicar.pt (via SSH tunnel) diff --git a/CONTINUE.md b/CONTINUE.md index f85fb75..ab747bb 100644 --- a/CONTINUE.md +++ b/CONTINUE.md @@ -1,7 +1,7 @@ # MCP Outline PostgreSQL - Continuacao de Testes **Ultima Sessao:** 2026-01-31 (actualizado) -**Versao Actual:** 1.3.8 +**Versao Actual:** 1.3.9 **Progresso:** ~95/164 tools testadas (58%) - **CÓDIGO VALIDADO** --- diff --git a/package-lock.json b/package-lock.json index 4c19042..0aebbdc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mcp-outline-postgresql", - "version": "1.3.8", + "version": "1.3.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mcp-outline-postgresql", - "version": "1.3.8", + "version": "1.3.9", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", diff --git a/package.json b/package.json index 124fc05..d90e8c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mcp-outline-postgresql", - "version": "1.3.8", + "version": "1.3.9", "description": "MCP Server for Outline Wiki via PostgreSQL direct access", "main": "dist/index.js", "scripts": { diff --git a/src/index-http.ts b/src/index-http.ts index 586a504..13f0330 100644 --- a/src/index-http.ts +++ b/src/index-http.ts @@ -68,7 +68,7 @@ async function main() { JSON.stringify({ status: 'ok', transport: 'streamable-http', - version: '1.3.8', + version: '1.3.9', sessions: sessions.size, stateful: STATEFUL, tools: allTools.length @@ -101,7 +101,7 @@ async function main() { // Create MCP server const server = createMcpServer(pgClient.getPool(), { name: 'mcp-outline-http', - version: '1.3.8' + version: '1.3.9' }); // Track session if stateful diff --git a/src/index.ts b/src/index.ts index 78368db..d072001 100644 --- a/src/index.ts +++ b/src/index.ts @@ -39,7 +39,7 @@ async function main() { // Create MCP server with shared configuration const server = createMcpServer(pgClient.getPool(), { name: 'mcp-outline-postgresql', - version: '1.3.8' + version: '1.3.9' }); // Connect stdio transport diff --git a/src/server/create-server.ts b/src/server/create-server.ts index cb55769..e562ae5 100644 --- a/src/server/create-server.ts +++ b/src/server/create-server.ts @@ -122,7 +122,7 @@ export function createMcpServer( ): Server { const server = new Server({ name: config.name || 'mcp-outline-postgresql', - version: config.version || '1.3.8' + version: config.version || '1.3.9' }); // Set capabilities (required for MCP v2.2+) diff --git a/src/tools/documents.ts b/src/tools/documents.ts index cf033e3..93e6a82 100644 --- a/src/tools/documents.ts +++ b/src/tools/documents.ts @@ -236,44 +236,73 @@ const createDocument: BaseTool = { ); const teamId = teamResult.rows[0]?.teamId; - const query = ` - INSERT INTO documents ( - id, "urlId", title, text, "collectionId", "teamId", "parentDocumentId", "createdById", - "lastModifiedById", template, "publishedAt", "createdAt", "updatedAt", version, - "isWelcome", "fullWidth", "insightsEnabled" - ) - VALUES ( - gen_random_uuid(), - substring(replace(gen_random_uuid()::text, '-', '') from 1 for 21), - $1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW(), 1, false, false, false - ) - RETURNING id, "urlId", title, "collectionId", "publishedAt", "createdAt" - `; + // Use transaction to ensure both document and revision are created + await pgClient.query('BEGIN'); - const params = [ - title, - text, - args.collection_id, - teamId, - args.parent_document_id || null, - userId, - userId, - args.template || false, - publishedAt - ]; + try { + const docQuery = ` + INSERT INTO documents ( + id, "urlId", title, text, "collectionId", "teamId", "parentDocumentId", "createdById", + "lastModifiedById", template, "publishedAt", "createdAt", "updatedAt", version, + "isWelcome", "fullWidth", "insightsEnabled" + ) + VALUES ( + gen_random_uuid(), + substring(replace(gen_random_uuid()::text, '-', '') from 1 for 21), + $1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW(), 1, false, false, false + ) + RETURNING id, "urlId", title, "collectionId", "publishedAt", "createdAt" + `; - const result = await pgClient.query(query, params); + const docParams = [ + title, + text, + args.collection_id, + teamId, + args.parent_document_id || null, + userId, + userId, + args.template || false, + publishedAt + ]; - return { - content: [{ - type: 'text', - text: JSON.stringify({ - success: true, - document: result.rows[0], - message: args.publish ? 'Documento criado e publicado' : 'Draft criado (não publicado)' - }, null, 2) - }] - }; + const docResult = await pgClient.query(docQuery, docParams); + const newDoc = docResult.rows[0]; + + // Insert initial revision (required for Outline to display the document) + const revisionQuery = ` + INSERT INTO revisions ( + id, "documentId", "userId", title, text, + "createdAt", "updatedAt" + ) + VALUES ( + gen_random_uuid(), $1, $2, $3, $4, NOW(), NOW() + ) + `; + + await pgClient.query(revisionQuery, [ + newDoc.id, + userId, + title, + text + ]); + + await pgClient.query('COMMIT'); + + return { + content: [{ + type: 'text', + text: JSON.stringify({ + success: true, + document: newDoc, + message: args.publish ? 'Documento criado e publicado' : 'Draft criado (não publicado)' + }, null, 2) + }] + }; + } catch (txError) { + await pgClient.query('ROLLBACK'); + throw txError; + } } catch (error) { return { content: [{