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: [{