fix: add missing input schemas to property discovery tools

Fixed obsidian_list_properties and obsidian_get_property_count tools
to properly expose their input parameters in the tools/list response.

Changes:
- obsidian_list_properties: Added 8 parameters (file, path, name, total,
  sort, counts, format, active) based on 'obsidian help properties'
- obsidian_get_property_count: Added required 'name' parameter
- Fixed command names: 'property' → 'properties' (correct command)
- Added formatParam() for parameter quoting
- Changed parameter format to match Obsidian CLI: param=value

Before: Empty properties: {} meant tools appeared in list but with no
documented parameters for MCP clients.

After: Full parameter schemas with descriptions, types, and constraints
properly exposed via tools/list handler.

Build:  0 TypeScript errors

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-03-22 16:24:20 -05:00
parent 2d7418825d
commit 35ab9cda79

View File

@@ -43,19 +43,48 @@ export async function registerPropertyDiscoveryTools(server: ObsidianMCPServer):
server.registerTool(
'obsidian_list_properties',
'List all properties used in the vault. Shows property keys and optionally their types and usage counts.',
{ type: 'object', properties: {} },
{
type: 'object',
properties: {
file: { type: 'string', description: 'Show properties for file' },
path: { type: 'string', description: 'Show properties for path' },
name: { type: 'string', description: 'Get specific property count' },
total: { type: 'boolean', description: 'Return property count' },
sort: { type: 'string', enum: ['count'], description: 'Sort by count (default: name)' },
counts: { type: 'boolean', description: 'Include occurrence counts' },
format: { type: 'string', enum: ['yaml', 'json', 'tsv'], description: 'Output format (default: yaml)' },
active: { type: 'boolean', description: 'Show properties for active file' },
},
},
createToolHandler(
'List all properties in vault',
{ type: 'object', properties: {} },
{
type: 'object',
properties: {
file: { type: 'string', description: 'Show properties for file' },
path: { type: 'string', description: 'Show properties for path' },
name: { type: 'string', description: 'Get specific property count' },
total: { type: 'boolean', description: 'Return property count' },
sort: { type: 'string', enum: ['count'], description: 'Sort by count' },
counts: { type: 'boolean', description: 'Include occurrence counts' },
format: { type: 'string', enum: ['yaml', 'json', 'tsv'], description: 'Output format' },
active: { type: 'boolean', description: 'Show properties for active file' },
},
},
async (args) => {
const sanitized = sanitizeParameters(args as any) as any;
const cmdArgs: string[] = ['list-properties'];
if (sanitized.counts) cmdArgs.push('--counts');
if (sanitized.types) cmdArgs.push('--types');
if (sanitized.format) cmdArgs.push('--format', sanitized.format as string);
const cmdArgs: string[] = [];
if (sanitized.file) cmdArgs.push(formatParam('file', sanitized.file));
if (sanitized.path) cmdArgs.push(formatParam('path', sanitized.path));
if (sanitized.name) cmdArgs.push(formatParam('name', sanitized.name));
if (sanitized.total) cmdArgs.push('total');
if (sanitized.sort) cmdArgs.push(formatParam('sort', sanitized.sort));
if (sanitized.counts) cmdArgs.push('counts');
if (sanitized.format) cmdArgs.push(formatParam('format', sanitized.format));
if (sanitized.active) cmdArgs.push('active');
const result = await executeObsidianCommand('property', cmdArgs);
const result = await executeObsidianCommand('properties', cmdArgs);
handleCLIResult(result, { operation: 'list_properties' });
const format = sanitized.format || 'text';
@@ -77,31 +106,39 @@ export async function registerPropertyDiscoveryTools(server: ObsidianMCPServer):
server.registerTool(
'obsidian_get_property_count',
'Get the usage count for a specific property across the vault. Shows how many notes use this property.',
{ type: 'object', properties: {} },
{
type: 'object',
required: ['name'],
properties: {
name: { type: 'string', description: 'Property name to count (required)' },
},
},
createToolHandler(
'Get property usage count',
{ type: 'object', properties: {} },
{
type: 'object',
required: ['name'],
properties: {
name: { type: 'string', description: 'Property name (required)' },
},
},
async (args) => {
const sanitized = sanitizeParameters(args as any) as any;
if (!sanitized.property) {
throw new Error('Property parameter is required');
if (!sanitized.name) {
throw new Error('Property name parameter is required');
}
const cmdArgs: string[] = ['property-count', sanitized.property as string];
if (sanitized.format) cmdArgs.push('--format', sanitized.format as string);
const cmdArgs: string[] = [formatParam('name', sanitized.name), 'total'];
const result = await executeObsidianCommand('property', cmdArgs);
handleCLIResult(result, { operation: 'property_count', property: sanitized.property });
const format = sanitized.format || 'text';
const parsedData = parseOutput(result.stdout, format);
const result = await executeObsidianCommand('properties', cmdArgs);
handleCLIResult(result, { operation: 'property_count', property: sanitized.name });
return {
content: [
{
type: 'text',
text: formatForMCP(parsedData, format),
text: result.stdout.trim(),
},
],
};