Official Model Context Protocol (MCP) server for Hillnote, enabling AI assistants to interact with your document workspaces programmatically.
Platform Support: Supports macOS, Windows, and Linux.
- π Multi-Workspace Support - Manage multiple document workspaces
- π Document Management - Full CRUD operations for documents
- π Smart Search - Fuzzy search with intelligent ranking across titles, tags, and content
- βοΈ Content Manipulation - Advanced content editing with validation and preview
- π― AI Recipes - Manage and execute AI prompt recipes
- π οΈ HTML Tools - Create interactive HTML-based utilities
- π Database & Task Management - Create databases with rows, columns, views, and kanban boards for task tracking
- π¨ Slide Presentations - Two-phase slide creation with storytelling guides and visual design tools
- π¨ Canvas Drawings - Create and edit Excalidraw canvas drawings with shapes, text, arrows, and more
- π·οΈ Metadata Support - Rich document metadata with tags, emojis, and descriptions
- macOS, Windows, or Linux
- Hillnote Desktop App
- Node.js >= 18.0.0
- MCP-compatible client (Claude Desktop, Cursor, VS Code, etc.)
# Install globally (IMPORTANT: Use -g flag!)
npm install -g @hillnote/mcp-server
# Verify installation worked
npm list -g @hillnote/mcp-server
# If using Homebrew Node.js, the files will be in:
# /opt/homebrew/lib/node_modules/@hillnote/mcp-server/-g flag is required for global installation. Without it, the package installs locally and won't work with the Claude Desktop configuration.
# Clone the repository
git clone https://github.com/HillnoteApp/hillnote-mcp-server.git
cd hillnote-mcp-server
# Install dependencies (NO -g flag needed here)
npm install# Update to the latest version
npm update -g @hillnote/mcp-server
# Or reinstall to force latest version
npm install -g @hillnote/mcp-server@latest
# Check current version
npm list -g @hillnote/mcp-server
# After updating, restart your MCP client (Claude Desktop, Cursor, etc.)# Navigate to your cloned repository
cd /path/to/hillnote-mcp-server
# Pull latest changes
git pull origin main
# Reinstall dependencies
npm install
# After updating, restart your MCP clientTo see what version you're currently running:
# For NPM installation
npm list -g @hillnote/mcp-server
# For source installation
cd /path/to/hillnote-mcp-server
cat package.json | grep versionIf you experience issues after updating:
-
Clear npm cache:
npm cache clean --force
-
Uninstall and reinstall:
npm uninstall -g @hillnote/mcp-server npm install -g @hillnote/mcp-server
-
Restart your MCP client completely (not just reload - fully quit and reopen)
The MCP server automatically discovers all your Hillnote workspaces from the app's configuration:
- macOS:
~/Library/Application Support/Hillnote/workspaces.json - Windows:
%APPDATA%/Hillnote/workspaces.json - Linux:
~/.config/Hillnote/workspaces.json
If installed via NPM, use your global Node modules path:
{
"mcpServers": {
"hillnote": {
"command": "hillnote-mcp"
}
}
}Find your path with: npm root -g
If cloned from GitHub:
{
"mcpServers": {
"hillnote": {
"command": "node",
"args": ["/path/to/hillnote-mcp-server/index.js"]
}
}
}Claude Desktop
Location: ~/Library/Application Support/Claude/claude_desktop_config.json
Add the configuration above to this file.
Cursor
Location: Settings β Features β MCP
Add the configuration above to the MCP servers section.
VS Code
Install an MCP extension and add the configuration to your settings.json or extension configuration.
Lists all available workspaces with document counts and metadata.
// No input required
// Returns: Array of workspace objects with path, name, overview, and documentCountGet complete workspace overview including all documents, folders, and relationships.
// Input: { workspace: "workspace-name" }
// Returns: Complete registry with documents and folder structureRead a specific document's content and metadata.
// Input: { workspace: "workspace-name", documentId: "doc-id" }
// Returns: Document content, metadata, and frontmatterCreate a new document with content and metadata.
// Input: {
// workspace: "workspace-name",
// name: "Document Name",
// content: "Document content",
// emoji: "π",
// description: "Brief description",
// parent: "optional-folder-id"
// }
// Returns: { success: true, documentId: "new-id", fileName: "document-name.md" }Update an existing document's content or metadata.
// Input: {
// workspace: "workspace-name",
// documentId: "doc-id",
// content: "New content",
// name: "New Name",
// emoji: "π",
// description: "Updated description"
// }
// Returns: { success: true }Rename a document and update its file name.
// Input: { workspace: "workspace-name", documentId: "doc-id", newTitle: "New Title" }
// Returns: { success: true, newFileName: "new-title.md" }Delete a document from the workspace.
// Input: { workspace: "workspace-name", documentId: "doc-id" }
// Returns: { success: true }Search documents with fuzzy matching and smart ranking.
// Input: {
// query: "search term",
// workspace: "optional-workspace",
// fuzzy: true,
// threshold: 0.6,
// limit: 10
// }
// Returns: Ranked search results with snippets and scoresInsert content at a specific position with validation.
// Input: {
// workspace: "workspace-name",
// documentId: "doc-id",
// position: "start" | "end" | number | { line: number } | { after: "heading" },
// text: "Content to insert",
// validate: true,
// preview: true
// }
// Returns: { success: true, preview: "...", validation: {...} }Replace text in a document with preview and occurrence info.
// Input: {
// workspace: "workspace-name",
// documentId: "doc-id",
// searchText: "text to find",
// replaceText: "replacement text",
// all: false,
// caseSensitive: false,
// wholeWord: false,
// useRegex: false
// }
// Returns: { success: true, replacements: 1, preview: "..." }Delete content between positions or patterns.
// Input: {
// workspace: "workspace-name",
// documentId: "doc-id",
// startPos: 0 | { line: 5 } | { pattern: "## Section" },
// endPos: 100 | { line: 10 } | { pattern: "## Next Section" }
// }
// Returns: { success: true, deletedChars: 95, preview: "..." }Append content to a specific markdown section.
// Input: {
// workspace: "workspace-name",
// documentId: "doc-id",
// sectionHeading: "## Notes",
// content: "Additional notes"
// }
// Returns: { success: true }Recipes are AI prompt overrides that trigger custom instructions when a user's request matches specific topics.
List all AI prompt recipes in a workspace.
// Input: { workspacePath: "/path/to/workspace" }
// Returns: Array of recipe objects with metadataGet a specific recipe by ID.
// Input: { workspacePath: "/path/to/workspace", recipeId: "recipe-id" }
// Returns: Complete recipe with trigger, instructions, and document referencesCreate a new AI prompt recipe.
// Input: {
// workspacePath: "/path/to/workspace",
// recipe: {
// when_user_asks_about: "quarterly reports",
// override_instructions: "Use the company template and include KPIs...",
// required_documents: ["documents/template.md"],
// optional_documents: ["documents/past-reports.md"],
// output_format: "markdown"
// }
// }
// Returns: { success: true, recipe: { id: "recipe_...", ... } }Update an existing recipe.
// Input: {
// workspacePath: "/path/to/workspace",
// recipeId: "recipe-id",
// updates: {
// when_user_asks_about: "updated trigger",
// override_instructions: "updated instructions"
// }
// }
// Returns: { success: true }Load the content of documents referenced by a recipe.
// Input: { workspacePath: "/path/to/workspace", recipeId: "recipe-id", includeOptional: true }
// Returns: { recipe: {...}, documents: { required: [...], optional: [...] } }Databases are flexible folders containing markdown files (rows) with a database.json configuration. They can be used as task boards by adding status columns with kanban views.
Create a new database in a workspace.
// Input: {
// workspace: "workspace-name",
// name: "Project Tasks",
// columns: [
// { id: "title", name: "Title", type: "title" },
// { id: "status", name: "Status", type: "status",
// options: ["To Do", "In Progress", "Done", "Archived"],
// optionColors: { "To Do": "gray", "In Progress": "amber", "Done": "emerald", "Archived": "purple" },
// optionStates: { "To Do": "normal", "In Progress": "normal", "Done": "done", "Archived": "archive" }
// },
// { id: "priority", name: "Priority", type: "select", options: ["Low", "Medium", "High"] },
// { id: "recurring", name: "Recurring", type: "recurring" }
// ],
// views: [
// { id: "kanban", name: "Board", type: "kanban", groupBy: "status" },
// { id: "table", name: "Table", type: "table" }
// ],
// defaultView: "kanban",
// folderPath: "optional/subfolder"
// }
// Returns: { success: true, name: "...", path: "..." }Column types: title, text, number, select, multiselect, status, checkbox, date, url, email, recurring
Status columns support optionStates mapping each option to "normal", "done" (strikethrough), or "archive" (dimmed) β enabling kanban board behaviour.
Recurring columns support auto-resetting tasks on daily/weekly/monthly/yearly schedules.
Read a database with optional filtering, sorting, and searching.
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// search: "optional search query",
// filters: [{ column: "status", operator: "equals", value: "In Progress" }],
// sort: { column: "priority", direction: "desc" },
// viewId: "kanban",
// limit: 50
// }
// Returns: Database config (columns, views) and matching rowsList all databases in a workspace.
// Input: { workspace: "workspace-name" }
// Returns: Array of databases with metadata and row countsDelete a database and all its rows permanently.
// Input: { workspace: "workspace-name", databasePath: "Project Tasks" }
// Returns: { success: true }Add one or more rows to a database.
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// rows: [
// { title: "Implement feature X", status: "To Do", priority: "High", _content: "Task details..." },
// { title: "Fix bug Y", status: "In Progress", priority: "Medium" }
// ]
// }
// Returns: { success: true, added: [...] }Update rows by ID (file path) or matching criteria.
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// updates: { status: "Done", priority: "Low" },
// ids: ["/path/to/row.md"], // by file path
// where: { status: "In Progress" } // or by criteria
// }
// Returns: { success: true, updated: [...] }Delete rows by ID or matching criteria.
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// ids: ["/path/to/row.md"],
// where: { status: "Archived" }
// }
// Returns: { success: true }Add a new column to a database.
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// column: { id: "assignee", name: "Assignee", type: "text" },
// defaultValue: "Unassigned"
// }
// Returns: { success: true }Update column properties (name, type, options, colors, states).
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// columnId: "status",
// updates: { options: ["To Do", "In Progress", "Review", "Done"] }
// }
// Returns: { success: true }Remove a column from a database and all rows.
// Input: { workspace: "workspace-name", databasePath: "Project Tasks", columnId: "priority" }
// Returns: { success: true }Create a saved view with filters, sorts, and display options.
// Input: {
// workspace: "workspace-name",
// databasePath: "Project Tasks",
// view: {
// name: "Active Tasks",
// type: "kanban", // table, kanban, gallery, chart
// groupBy: "status",
// filters: [{ column: "status", operator: "notEquals", value: "Archived" }],
// sorts: [{ column: "priority", direction: "desc" }]
// }
// }
// Returns: { success: true, viewId: "..." }List all saved views for a database.
// Input: { workspace: "workspace-name", databasePath: "Project Tasks" }
// Returns: Array of view configurationsSlides use a two-phase workflow: write the story first, then add visual design.
Get the storytelling guide with 8 proven techniques (Hero's Journey, Sparklines, In Medias Res, etc.).
// No input required
// Returns: Story-writing guide with narrative techniques and structure advice
// Important: Do NOT use any visual layout markers (~split, ~inline, ~bg-, etc.) during this phaseGet the visual design guide for adding layout markers, images, charts, and diagrams.
// Input: { documentPath: "documents/my-presentation.slides.md" }
// Returns: Visual design guide with layout markers, chart types, mermaid diagrams, and examples
// Note: Requires the .slides.md file to already exist (proves story has been drafted)Important: When creating slides with add_document, the title MUST end with .slides.md (e.g., "My Presentation.slides.md"). The .slides.md extension is what makes it a slide presentation.
Example workflow:
// 1. Get the story guide first
get_slides_story_guide()
// 2. Create the slide presentation (story content only, no visual markers)
add_document({
workspace: "workspace-name",
name: "Quarterly Review.slides.md", // Note: ends with .slides.md
content: `---
type: slides
theme: minimal
---
# Quarterly Review
Q4 2024 Results
***
# Key Metrics
- Revenue: $1.2M
- Growth: 25%
- Users: 10,000+
`
})
// 3. Get the visual guide and enhance slides in batches of 3-5
get_slides_visual_guide({ documentPath: "documents/quarterly-review.slides.md" })
// Then edit the file to add ~split, ~inline, ~bg-, images, charts, etc.Get the comprehensive guide for creating and editing Excalidraw canvas drawings in Hillnote.
// No input required
// Returns: Complete guide with element types, layout planning, spacing rules, colors, and best practicesImportant: When creating a canvas with add_document, the title MUST end with .canvas.md (e.g., "Architecture Diagram.canvas.md"). Do NOT provide content β the system generates it automatically.
Read and parse a canvas file, returning a structured description of all elements.
// Input: { workspace: "workspace-name", canvasPath: "documents/my-drawing.canvas.md" }
// Returns: { canvasPath: "...", elementCount: 5, elements: [...] }Add shapes, text, arrows, and other elements to a canvas file.
// Input: {
// workspace: "workspace-name",
// canvasPath: "documents/my-drawing.canvas.md",
// elements: [
// { type: "rectangle", x: 0, y: 0, width: 200, height: 100, label: "Start", backgroundColor: "#a5d8ff" },
// { type: "arrow", x: 200, y: 50, points: [[0, 0], [100, 0]] },
// { type: "rectangle", x: 300, y: 0, width: 200, height: 100, label: "End", backgroundColor: "#b2f2bb" },
// { type: "text", x: 0, y: 120, text: "My Diagram", fontSize: 28 }
// ]
// }
// Returns: { success: true, added: 4, totalElements: 4, elementIds: [...] }Supported element types: rectangle, ellipse, diamond, text, arrow, line
Element properties:
- Position/size:
x,y,width,height - Styling:
strokeColor,backgroundColor,fillStyle(solid/hachure/cross-hatch),strokeWidth,roughness(0-2),opacity(0-100) - Text:
text,fontSize,fontFamily(1=Virgil, 2=Helvetica, 3=Cascadia, 5=Excalifont),textAlign - Arrows/lines:
points(e.g.,[[0,0],[200,100]]),startArrowhead,endArrowhead - Shapes:
label(centered text inside rectangle/ellipse/diamond) - Grouping:
groupId
Remove all elements from a canvas file, giving a blank slate.
// Input: { workspace: "workspace-name", canvasPath: "documents/my-drawing.canvas.md" }
// Returns: { success: true, message: "All elements cleared from canvas" }Example workflow:
// 1. Get the canvas guide first
get_canvas_guide()
// 2. Create a new canvas
add_document({
workspace: "workspace-name",
name: "Architecture Diagram.canvas.md" // Note: ends with .canvas.md, no content needed
})
// 3. Add elements to the canvas
add_canvas_elements({
workspace: "workspace-name",
canvasPath: "documents/architecture-diagram.canvas.md",
elements: [
{ type: "text", x: 0, y: 0, text: "System Architecture", fontSize: 28 },
{ type: "rectangle", x: 0, y: 50, width: 200, height: 80, label: "Frontend", backgroundColor: "#a5d8ff" },
{ type: "arrow", x: 200, y: 90, points: [[0, 0], [100, 0]] },
{ type: "rectangle", x: 300, y: 50, width: 200, height: 80, label: "Backend", backgroundColor: "#b2f2bb" }
]
})
// 4. To redraw from scratch
clear_canvas({ workspace: "workspace-name", canvasPath: "documents/architecture-diagram.canvas.md" })
// Then add_canvas_elements again with new elementsCreate an interactive HTML tool in the workspace.
// Input: {
// workspacePath: "/path/to/workspace",
// toolName: "calculator",
// description: "Scientific calculator",
// category: "utilities", // optional
// files: [
// { filename: "index.html", content: "<!DOCTYPE html>...", isEntryPoint: true },
// { filename: "styles.css", content: "body { ... }" },
// { filename: "script.js", content: "// JS code" }
// ]
// }
// Returns: { success: true, path: "resources/html/calculator", entryPoint: "index.html", markdownLink: "[html:calculator](...)" }Edit files in an existing HTML tool (create, update, or delete files).
// Input: {
// workspacePath: "/path/to/workspace",
// toolName: "calculator",
// category: "utilities", // optional
// operations: [
// { action: "update", filename: "index.html", content: "<!DOCTYPE html>..." },
// { action: "create", filename: "utils.js", content: "// new file" },
// { action: "delete", filename: "old-file.js" }
// ],
// updateMetadata: { description: "Updated calculator" }
// }
// Returns: { success: true, changes: { created: [...], updated: [...], deleted: [...] } }Insert an HTML tool reference into a document.
// Input: {
// workspacePath: "/path/to/workspace",
// documentPath: "documents/my-doc.md",
// toolName: "calculator",
// displayName: "My Calculator", // optional
// position: "end" // "end", "beginning", or "after:<text>"
// }
// Returns: { success: true, toolLink: "[html:My Calculator](...)" }List all HTML tools in a workspace.
// Input: { workspacePath: "/path/to/workspace", category: "utilities" }
// Returns: Array of HTML tools with metadata and markdown linksGet a specific HTML tool's details and files.
// Input: { workspacePath: "/path/to/workspace", toolName: "calculator", category: "utilities" }
// Returns: Tool info with all file contents, entry point, and markdown linkRead the content of a specific file inside an HTML tool.
// Input: { workspacePath: "/path/to/workspace", filePath: "resources/html/calculator/index.html" }
// Returns: { filePath: "...", content: "..." }Write or create a file inside an HTML tool folder.
// Input: { workspacePath: "/path/to/workspace", filePath: "resources/html/calculator/style.css", content: "body { ... }" }
// Returns: { success: true, filePath: "..." }Find and replace text in an HTML tool file.
// Input: {
// workspacePath: "/path/to/workspace",
// filePath: "resources/html/calculator/index.html",
// searchText: "<title>Old Title</title>",
// replaceText: "<title>New Title</title>"
// }
// Returns: { success: true, filePath: "..." }Hillnote workspaces are typically stored in your Documents folder or custom locations:
~/Documents/YourWorkspace/
βββ readme.md # Workspace overview
βββ documents-registry.json # Document metadata
βββ ai_prompt_overrides.json # AI prompt recipes/overrides
βββ documents/ # Markdown documents and databases
β βββ document-1.md
β βββ folder/
β β βββ document-2.md
β βββ Project Tasks/ # Database (e.g., task board)
β βββ database.json # Database configuration (columns, views)
β βββ implement-feature-x.md # Row (task) with frontmatter
β βββ fix-bug-y.md # Row (task) with frontmatter
βββ resources/ # Assets and tools
βββ images/ # Image attachments
βββ html/ # HTML tools
βββ tool-name/
βββ index.html
βββ assets/
Documents use Markdown with YAML frontmatter:
---
title: Document Title
tags: [tag1, tag2]
emoji: π
description: Brief description
created: 2024-01-01T00:00:00Z
modified: 2024-01-02T00:00:00Z
---
# Document Title
Your content here...mcp-server/
βββ index.js # Main server entry point
βββ config.json # Server configuration
βββ package.json # Dependencies
βββ src/
β βββ tools/
β β βββ index.js # Tool aggregator
β β βββ workspace.js # Workspace tools
β β βββ document.js # Document tools
β β βββ content.js # Content manipulation
β β βββ search.js # Search tools
β β βββ recipe.js # Recipe management
β β βββ html-tool.js # HTML tool management
β β βββ database.js # Database, row, column, and view management
β β βββ slides.js # Slide presentation guides (story + visual)
β β βββ canvas.js # Excalidraw canvas drawings
β βββ utils/
β βββ helpers.js # Utility functions
βββ README.md
- Create a new tool file in
src/tools/ - Export tool definitions and handlers
- Import in
src/tools/index.js - Tools are automatically available to MCP clients
# Enable watch mode
npm run dev
# Run the server
npm startAll tools use structured error responses:
InvalidParams: Missing or invalid parametersInternalError: Server-side errorsMethodNotFound: Unknown tool name
- File operations are sandboxed to workspace directories
- No network requests are made
- Path traversal protection included
- Input validation on all operations
MIT - See LICENSE file
- Issues: GitHub Issues
- Email: support@hillnote.com
- Documentation: Hillnote Docs
Built with β€οΈ by Rajath Bail