Skip to main content
Glama

Obsidian MCP Server

Apache 2.0
338
222
  • Apple
  • Linux
vaultMethods.ts6.84 kB
/** * @module VaultMethods * @description * Methods for interacting with vault files and directories via the Obsidian REST API. */ import { RequestContext } from "../../../utils/index.js"; import { NoteJson, FileListResponse, NoteStat, RequestFunction, } from "../types.js"; import { encodeVaultPath } from "../../../utils/obsidian/obsidianApiUtils.js"; /** * Gets the content of a specific file in the vault. * @param _request - The internal request function from the service instance. * @param filePath - Vault-relative path to the file. * @param format - 'markdown' or 'json' (for NoteJson). * @param context - Request context. * @returns The file content (string) or NoteJson object. */ export async function getFileContent( _request: RequestFunction, filePath: string, format: "markdown" | "json" = "markdown", context: RequestContext, ): Promise<string | NoteJson> { const acceptHeader = format === "json" ? "application/vnd.olrapi.note+json" : "text/markdown"; const encodedPath = encodeVaultPath(filePath); // Use the new encoding function return _request<string | NoteJson>( { method: "GET", url: `/vault${encodedPath}`, headers: { Accept: acceptHeader }, }, context, "getFileContent", ); } /** * Updates (overwrites) the content of a file or creates it if it doesn't exist. * @param _request - The internal request function from the service instance. * @param filePath - Vault-relative path to the file. * @param content - The new content for the file. * @param context - Request context. * @returns {Promise<void>} Resolves on success (204 No Content). */ export async function updateFileContent( _request: RequestFunction, filePath: string, content: string, context: RequestContext, ): Promise<void> { const encodedPath = encodeVaultPath(filePath); // Use the new encoding function // PUT returns 204 No Content, so the expected type is void await _request<void>( { method: "PUT", url: `/vault${encodedPath}`, // Construct URL correctly headers: { "Content-Type": "text/markdown" }, data: content, }, context, "updateFileContent", ); } /** * Appends content to the end of a file. Creates the file if it doesn't exist. * @param _request - The internal request function from the service instance. * @param filePath - Vault-relative path to the file. * @param content - The content to append. * @param context - Request context. * @returns {Promise<void>} Resolves on success (204 No Content). */ export async function appendFileContent( _request: RequestFunction, filePath: string, content: string, context: RequestContext, ): Promise<void> { const encodedPath = encodeVaultPath(filePath); // Use the new encoding function await _request<void>( { method: "POST", url: `/vault${encodedPath}`, // Construct URL correctly headers: { "Content-Type": "text/markdown" }, data: content, }, context, "appendFileContent", ); } /** * Deletes a specific file in the vault. * @param _request - The internal request function from the service instance. * @param filePath - Vault-relative path to the file. * @param context - Request context. * @returns {Promise<void>} Resolves on success (204 No Content). */ export async function deleteFile( _request: RequestFunction, filePath: string, context: RequestContext, ): Promise<void> { const encodedPath = encodeVaultPath(filePath); // Use the new encoding function await _request<void>( { method: "DELETE", url: `/vault${encodedPath}`, // Construct URL correctly }, context, "deleteFile", ); } /** * Lists files within a specified directory in the vault. * @param _request - The internal request function from the service instance. * @param dirPath - Vault-relative path to the directory. Use empty string "" or "/" for the root. * @param context - Request context. * @returns A list of file and directory names. */ export async function listFiles( _request: RequestFunction, dirPath: string, context: RequestContext, ): Promise<string[]> { // Normalize path: remove leading/trailing slashes for consistency, except for root let pathSegment = dirPath.trim(); // Explicitly handle root path variations ('', '/') by setting pathSegment to empty. // This ensures that the final URL constructed later will be '/vault/', which the API // uses to list the root directory contents. if (pathSegment === "" || pathSegment === "/") { pathSegment = ""; // Use empty string to signify root for URL construction } else { // For non-root paths: // 1. Remove any leading/trailing slashes to prevent issues like '/vault//path/' or '/vault/path//'. // 2. URI-encode *each component* of the remaining path segment to handle special characters safely. pathSegment = pathSegment .replace(/^\/+|\/+$/g, "") .split("/") .map(encodeURIComponent) .join("/"); } // Construct the final URL for the API request: // - If pathSegment is not empty (i.e., it's a specific directory), format as '/vault/{encoded_path}/'. // - If pathSegment IS empty (signifying the root), format as '/vault/'. // The trailing slash is important for directory listing endpoints in this API. const url = pathSegment ? `/vault/${pathSegment}/` : "/vault/"; const response = await _request<FileListResponse>( { method: "GET", url: url, // Use the correctly constructed URL }, context, "listFiles", ); return response.files; } /** * Gets the metadata (stat) of a specific file using a lightweight HEAD request. * @param _request - The internal request function from the service instance. * @param filePath - Vault-relative path to the file. * @param context - Request context. * @returns The file's metadata. */ export async function getFileMetadata( _request: RequestFunction, filePath: string, context: RequestContext, ): Promise<NoteStat | null> { const encodedPath = encodeVaultPath(filePath); try { const response = await _request<any>( { method: "HEAD", url: `/vault${encodedPath}`, }, context, "getFileMetadata", ); if (response && response.headers) { const headers = response.headers; return { mtime: headers["x-obsidian-mtime"] ? parseFloat(headers["x-obsidian-mtime"]) * 1000 : 0, ctime: headers["x-obsidian-ctime"] ? parseFloat(headers["x-obsidian-ctime"]) * 1000 : 0, size: headers["content-length"] ? parseInt(headers["content-length"], 10) : 0, }; } return null; } catch (error) { // Errors are already logged by the _request function, so we can just return null return null; } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/cyanheads/obsidian-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server