NobGit
public anord read

Ledger

Why work hard when you can work easier?

Languages

Repository composition by tracked source files.

TypeScript
TypeScript 86% CSS 10% SQL 3% Shell 1% HTML 0%
Create file Wiki Documentation
Clone
https://nobgit.com/orgs/anord/ledger.git
ssh://[email protected]:2222/orgs/anord/ledger.git
import { Router } from "express";
import { z } from "zod";
import { createOrUpdatePage, getPageBySlug, getPageMetadata, listSpaces } from "../../services/pages.js";
import { searchPages } from "../../services/search.js";
import { canEditPage } from "@ledger/shared";

const toolsCallSchema = z.object({
  method: z.string(),
  params: z.record(z.any()).optional(),
  id: z.union([z.string(), z.number()]).optional()
});

export const mcpRouter = Router();

mcpRouter.post("/", async (req, res) => {
  const body = toolsCallSchema.parse(req.body);

  if (body.method === "tools/list") {
    return res.json({
      id: body.id,
      result: {
        tools: [
          { name: "search_knowledge_base", description: "Search knowledge base pages visible to the current auth context and return structured page summaries." },
          { name: "read_page", description: "Read a page by slug when the current auth context is allowed to access it." },
          { name: "list_spaces", description: "List spaces visible to the current auth context." },
          { name: "get_page_metadata", description: "Return non-sensitive page metadata for a visible page id." },
          { name: "create_draft_page", description: "Create a draft page in a space when the current auth context can edit content." }
        ]
      }
    });
  }

  if (body.method === "tools/call") {
    const name = String(body.params?.name ?? "");
    const args = body.params?.arguments ?? {};

    if (name === "search_knowledge_base") {
      const result = await searchPages(String(args.query ?? ""), req.user ?? null);
      return res.json({ id: body.id, result: { pages: result } });
    }

    if (name === "read_page") {
      const result = await getPageBySlug(String(args.slug ?? ""), req.user ?? null);
      return res.json({ id: body.id, result: result ? { page: result } : null });
    }

    if (name === "list_spaces") {
      const result = await listSpaces(req.user ?? null);
      return res.json({ id: body.id, result: { spaces: result } });
    }

    if (name === "get_page_metadata") {
      const result = await getPageMetadata(String(args.pageId ?? ""), req.user ?? null);
      return res.json({ id: body.id, result: result ? { page: result } : null });
    }

    if (name === "create_draft_page") {
      if (!canEditPage(req.user ?? null)) {
        return res.status(403).json({ error: "Editor access required" });
      }

      const result = await createOrUpdatePage(
        null,
        {
          spaceId: String(args.spaceId),
          title: String(args.title),
          bodyMarkdown: String(args.bodyMarkdown),
          visibility: "internal",
          state: "draft"
        },
        req.user!.id
      );

      return res.json({ id: body.id, result: { page: result } });
    }
  }

  return res.status(400).json({ error: "Unsupported MCP method" });
});