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:
@@ -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(),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user