Replace the removed enterprise EE MCP (private apps/server/src/ee submodule,
license-gated /mcp route) with our docmost-mcp, vendored as an isolated ESM
workspace package and served by the server over HTTP — no enterprise license.
Backend:
- Add packages/mcp (@docmost/mcp): vendored docmost-mcp refactored into a
side-effect-free createDocmostMcpServer() factory (38 tools preserved),
stdio entry kept in stdio.ts, Streamable-HTTP session manager in http.ts.
- Add apps/server McpModule: @Post/@Get/@Delete('mcp') (served at /mcp via the
existing global-prefix exclude), @SkipTransform + reply.hijack to bridge raw
Fastify req/res into the SDK transport. The module dynamically imports the
ESM-only package from CommonJS via a Function-indirected import resolved with
require.resolve + file:// URL. Gated by the workspace ai.mcp toggle, a
service-account (MCP_DOCMOST_EMAIL/PASSWORD/API_URL) and optional MCP_TOKEN;
per-session idle eviction (MCP_SESSION_IDLE_MS).
- Drop the enterprise license check on mcpEnabled in workspace.service.
- Dockerfile: copy packages/mcp into the production image.
- .env.example: document MCP_DOCMOST_*, MCP_TOKEN, MCP_SESSION_IDLE_MS.
Frontend:
- Recreate the community "AI & MCP" workspace-settings panel (mcp-settings.tsx):
admin-only toggle on settings.ai.mcp with optimistic update, copyable
${APP_URL}/mcp URL; wired into workspace-settings page. Reuses existing i18n.
Fixes:
- Pin packages/mcp tiptap deps to 3.20.4 (matching the client) and inline
getStyleProperty, preventing a duplicate @tiptap/core@3.26.1 from leaking into
the client editor via pnpm shamefully-hoist (was breaking apps/client tsc).
49 lines
1.8 KiB
JavaScript
49 lines
1.8 KiB
JavaScript
#!/usr/bin/env node
|
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
import { createDocmostMcpServer } from "./index.js";
|
|
|
|
// Standalone stdio entrypoint. This restores the original behavior of the
|
|
// package when run as a CLI (`docmost-mcp`): it reads credentials from the
|
|
// environment and serves the MCP protocol over stdin/stdout. The factory in
|
|
// index.ts stays side-effect-free; all the process/transport lifecycle lives
|
|
// here.
|
|
|
|
const API_URL = process.env.DOCMOST_API_URL;
|
|
const EMAIL = process.env.DOCMOST_EMAIL;
|
|
const PASSWORD = process.env.DOCMOST_PASSWORD;
|
|
|
|
if (!API_URL || !EMAIL || !PASSWORD) {
|
|
console.error(
|
|
"Error: DOCMOST_API_URL, DOCMOST_EMAIL, and DOCMOST_PASSWORD environment variables are required.",
|
|
);
|
|
process.exit(1);
|
|
}
|
|
|
|
async function run() {
|
|
// Global safety nets so a stray rejection/exception cannot silently kill
|
|
// the stdio server. Per-tool errors still flow through the SDK and are not
|
|
// affected by these handlers; these only catch errors raised OUTSIDE a tool
|
|
// call (e.g. a transient ws/collab socket "error" event). Such errors must
|
|
// NOT tear down the whole stdio server, so we log only and keep running.
|
|
// Genuine startup failures are still fatal via run().catch(...) below.
|
|
process.on("unhandledRejection", (reason) => {
|
|
console.error("Unhandled promise rejection:", reason);
|
|
});
|
|
process.on("uncaughtException", (error) => {
|
|
console.error("Uncaught exception:", error);
|
|
});
|
|
|
|
const server = createDocmostMcpServer({
|
|
apiUrl: API_URL!,
|
|
email: EMAIL!,
|
|
password: PASSWORD!,
|
|
});
|
|
const transport = new StdioServerTransport();
|
|
await server.connect(transport);
|
|
}
|
|
|
|
run().catch((error) => {
|
|
console.error("Fatal error running server:", error);
|
|
process.exit(1);
|
|
});
|