Skip to main content
Glama
sunub

Obsidian MCP Server

Generate Obsidian Property

generate_property

Reads a markdown file and returns content preview with a property schema to generate frontmatter fields such as title, tags, and summary. Does not write to disk.

Instructions

Reads a target markdown document and returns an AI-facing payload for generating frontmatter properties.

This tool does not write to disk. It returns content_preview and a target output schema so an AI can produce a valid property object.

Use Cases:

  • After completing a draft, when you need property suggestions from content.

  • When missing frontmatter fields (title, tags, summary, slug, date, category, completed) should be generated.

To apply generated properties to a file, call 'write_property' with the resulting JSON.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
filenameYesThe name or path of the file to analyze and add properties to (e.g., "my-first-post.md")
overwriteNoIf set to true, existing properties will be overwritten by the AI-generated content. Default: false.

Implementation Reference

  • The main execute function that reads a target markdown document and returns content_preview + instructions for AI to generate frontmatter properties. It validates the vault manager, reads the document via vaultManager.getDocumentInfo(), and returns a JSON payload with filename, content_preview (first 300 chars), and an output schema instructing the AI on what properties to generate.
    export const execute = async (
    	params: ObsidianPropertyQueryParams,
    ): Promise<CallToolResult> => {
    	const response: CallToolResult = { content: [], isError: false };
    
    	let vaultManager = null;
    	try {
    		vaultManager = getGlobalVaultManager();
    	} catch (e) {
    		return createToolError((e as Error).message);
    	}
    	try {
    		const document = await vaultManager.getDocumentInfo(params.filename);
    		if (document === null) {
    			return createToolError(
    				`Document not found: ${params.filename}`,
    				"Use 'list_all' action to see available documents",
    			);
    		}
    
    		const documentData = {
    			filename: params.filename,
    			content_preview: `${document.content.substring(0, 300).replace(/\s+/g, " ")}...`,
    			instructions: {
    				purpose:
    					"Generate or update the document's frontmatter properties based on its content.",
    				usage:
    					"Analyze the provided content_preview. If more detail is needed to generate accurate properties, you MUST call the 'vault' tool with action='read' to get the full document content.",
    				content_type: "markdown",
    				overwrite: params.overwrite || false,
    				output_format: "Return a JSON object with the following structure",
    				schema: {
    					title: "string - Title representing the core topic",
    					tags: "string[] - Array of relevant tags from content keywords",
    					summary: "string - 1-2 sentence summary of the document",
    					slug: "string - URL-friendly hyphenated identifier",
    					date: "string - ISO 8601 date format",
    					completed: "boolean - Whether content is finalized",
    					aliases: "string[] - (Optional) Alternative names or synonyms",
    					category: "string - (Optional) Document category",
    				},
    			},
    		};
    
    		response.content.push({
    			type: "text",
    			text: JSON.stringify(documentData, null, 2),
    		});
    	} catch (error) {
    		return createToolError(
    			(error as Error).message,
    			"Ensure the VAULT_DIR_PATH environment variable is set to your Obsidian vault directory and the filename is correct.",
    		);
    	}
    	return response;
    };
  • Input/output schemas using Zod. Input schema (obsidianPropertyQueryParamsSchema) defines 'filename' (string) and optional 'overwrite' (boolean). Output schema (obsidianPropertyOutputSchema) defines cssclasses, tags, title, date, summary, slug, category, completed as optional fields. Also defines individual property types.
    import { z } from "zod";
    
    // input properties
    const obsidianGenerateInputFilename = z
    	.string()
    	.describe(
    		'The name or path of the file to analyze and add properties to (e.g., "my-first-post.md")',
    	);
    const obsidianGenerateInputOverwrite = z
    	.boolean()
    	.default(true)
    	.describe(
    		"If set to true, existing properties will be overwritten by the AI-generated content. Default: false.",
    	);
    
    // input schema
    export const obsidianPropertyQueryParamsSchema = z
    	.object({
    		filename: obsidianGenerateInputFilename,
    		overwrite: obsidianGenerateInputOverwrite.optional(),
    	})
    	.describe(
    		"Parameters for generating or updating Obsidian document properties",
    	);
    
    export type ObsidianPropertyQueryParams = z.infer<
    	typeof obsidianPropertyQueryParamsSchema
    >;
    
    // output properties
    export const obsidianCssClassesProperty = z
    	.array(z.string())
    	.describe("List of CSS classes associated with the document");
    export const obsidianTagsProperty = z
    	.array(z.string())
    	.describe("List of tags associated with the document");
    export const obsidianTitleProperty = z
    	.string()
    	.describe("Title of the document");
    export const obsidianDateProperty = z
    	.string()
    	.describe("Creation date of the document in ISO 8601 format");
    export const obsidianSummaryProperty = z
    	.string()
    	.describe("Brief summary or abstract of the document");
    export const obsidianSlugProperty = z
    	.string()
    	.describe("URL-friendly identifier for the document");
    export const obsidianCategoryProperty = z
    	.string()
    	.describe("Category or classification of the document");
    export const obsidianCompletedProperty = z
    	.boolean()
    	.describe("Indicates whether a task or item is completed");
    
    // output schema
    export const obsidianPropertyOutputSchema = z
    	.object({
    		cssclasses: obsidianCssClassesProperty.optional(),
    		tags: obsidianTagsProperty.optional(),
    		title: obsidianTitleProperty.optional(),
    		date: obsidianDateProperty.optional(),
    		summary: obsidianSummaryProperty.optional(),
    		slug: obsidianSlugProperty.optional(),
    		category: obsidianCategoryProperty.optional(),
    		completed: obsidianCompletedProperty.optional(),
    	})
    	.describe("Extracted properties from the Obsidian document content");
  • The register function that registers the tool with the MCP server using mcpServer.registerTool(). It binds the tool name 'generate_property', inputSchema, description, annotations, and the execute handler.
    export const register = (mcpServer: McpServer) => {
    	mcpServer.registerTool(
    		name,
    		{
    			title: annotations.title || name,
    			description: description,
    			inputSchema: obsidianPropertyQueryParamsSchema.shape,
    			annotations: annotations,
    		},
    		execute,
    	);
    };
  • src/server.ts:40-45 (registration)
    Server-level registration: iterates over all tools (including generate_property) from the tools index and calls their register() method.
    for (const tool of Object.values(tools)) {
    	tool.register(mcpServer);
    }
    
    return mcpServer;
  • CLI dispatcher helper mapping the '/genprop' chat command to the 'generate_property' tool, extracting the filename argument.
    "/genprop": {
    	tool: "generate_property",
    	requiresArgs: true,
    	noArgsMessage: '사용법: /genprop <파일명>\n예: /genprop "my-post.md"',
    	buildArgs: (args) => ({
    		filename: extractFilenameFromArgs(args),
    	}),
    },
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description explicitly states it does not write to disk and explains what it returns (content_preview and target output schema), adding value beyond minimal annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, front-loaded with the main purpose, and uses bullet points for use cases; every sentence is informative.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no output schema, the description explains the return payload and usage context, covering all necessary aspects for correct invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3; the description does not add further details about parameters beyond what the schema provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it reads a markdown document and returns an AI-facing payload for generating frontmatter properties, distinct from siblings like write_property.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit use cases provided (after draft completion, when missing fields) and it directs to write_property for applying, giving clear when-to-use guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

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/sunub/obsidian-mcp-server'

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