server.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. // Package server builds the MCP server and registers the WikiJS tools.
  2. package server
  3. import (
  4. "log/slog"
  5. "wikijs-mcp/internal/wikijs"
  6. "github.com/modelcontextprotocol/go-sdk/mcp"
  7. )
  8. const instructions = `This server exposes a WikiJS knowledge base.
  9. Use search_pages to find pages by full-text query, get_page_by_id or
  10. get_page_by_path to read a page, and get_all_pages to browse the wiki.
  11. Page results include absolute URLs that can be shared with the user.`
  12. // Options configures the MCP server.
  13. type Options struct {
  14. // Version is reported to MCP clients.
  15. Version string
  16. // EnableEdit exposes the create_page and edit_page tools.
  17. EnableEdit bool
  18. // Logger receives MCP protocol logs. It must write to stderr when the
  19. // stdio transport is used.
  20. Logger *slog.Logger
  21. }
  22. // New creates an MCP server with all WikiJS tools registered.
  23. func New(client *wikijs.Client, opts Options) *mcp.Server {
  24. logger := opts.Logger
  25. if logger == nil {
  26. logger = slog.New(slog.DiscardHandler)
  27. }
  28. s := mcp.NewServer(&mcp.Implementation{
  29. Name: "wikijs-mcp-server",
  30. Title: "WikiJS MCP Server",
  31. Version: opts.Version,
  32. Description: "Search, read, and optionally edit pages in a WikiJS instance.",
  33. }, &mcp.ServerOptions{
  34. Instructions: instructions,
  35. Logger: logger,
  36. })
  37. h := &handlers{wiki: client}
  38. readOnly := &mcp.ToolAnnotations{ReadOnlyHint: true}
  39. mcp.AddTool(s, &mcp.Tool{
  40. Name: "search_pages",
  41. Title: "Search pages",
  42. Description: "Search for pages in WikiJS by query string.",
  43. Annotations: readOnly,
  44. }, h.searchPages)
  45. mcp.AddTool(s, &mcp.Tool{
  46. Name: "get_page_by_id",
  47. Title: "Get page by ID",
  48. Description: "Get a WikiJS page by its numeric ID.",
  49. Annotations: readOnly,
  50. }, h.pageByID)
  51. mcp.AddTool(s, &mcp.Tool{
  52. Name: "get_page_by_path",
  53. Title: "Get page by path",
  54. Description: "Get a WikiJS page by its path and locale.",
  55. Annotations: readOnly,
  56. }, h.pageByPath)
  57. mcp.AddTool(s, &mcp.Tool{
  58. Name: "get_all_pages",
  59. Title: "List pages",
  60. Description: "List pages in WikiJS, optionally filtered by limit, locale, and tags.",
  61. Annotations: readOnly,
  62. }, h.listPages)
  63. if opts.EnableEdit {
  64. notDestructive := false
  65. mcp.AddTool(s, &mcp.Tool{
  66. Name: "create_page",
  67. Title: "Create page",
  68. Description: "Create a new WikiJS page.",
  69. Annotations: &mcp.ToolAnnotations{DestructiveHint: &notDestructive},
  70. }, h.createPage)
  71. mcp.AddTool(s, &mcp.Tool{
  72. Name: "edit_page",
  73. Title: "Edit page",
  74. Description: "Edit an existing WikiJS page by its numeric ID.",
  75. Annotations: &mcp.ToolAnnotations{IdempotentHint: true},
  76. }, h.editPage)
  77. }
  78. return s
  79. }