obsidian-mcp-server 1.2.2 → 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue.svg)](https://www.typescriptlang.org/)
4
4
  [![Model Context Protocol](https://img.shields.io/badge/MCP-1.4.0-green.svg)](https://modelcontextprotocol.io/)
5
- [![Version](https://img.shields.io/badge/Version-1.2.2-blue.svg)]()
5
+ [![Version](https://img.shields.io/badge/Version-1.2.3-blue.svg)]()
6
6
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
7
7
  [![Status](https://img.shields.io/badge/Status-Stable-blue.svg)]()
8
8
  [![GitHub](https://img.shields.io/github/stars/cyanheads/obsidian-mcp-server?style=social)](https://github.com/cyanheads/obsidian-mcp-server)
@@ -1,5 +1,5 @@
1
1
  import { parse, stringify } from 'yaml';
2
- import { ObsidianPropertiesSchema } from './propertyTypes.js';
2
+ import { ObsidianPropertiesSchema, PropertyUpdateSchema } from './propertyTypes.js';
3
3
  export class PropertyManager {
4
4
  client;
5
5
  constructor(client) {
@@ -51,7 +51,7 @@ export class PropertyManager {
51
51
  * Validate property values
52
52
  */
53
53
  validateProperties(properties) {
54
- const result = ObsidianPropertiesSchema.safeParse(properties);
54
+ const result = PropertyUpdateSchema.safeParse(properties);
55
55
  if (result.success) {
56
56
  return { valid: true, errors: [] };
57
57
  }
@@ -66,7 +66,8 @@ export class PropertyManager {
66
66
  mergeProperties(existing, updates) {
67
67
  const merged = { ...existing };
68
68
  for (const [key, value] of Object.entries(updates)) {
69
- if (value === undefined)
69
+ // Skip undefined values and timestamp fields
70
+ if (value === undefined || key === 'created' || key === 'modified')
70
71
  continue;
71
72
  const currentValue = merged[key];
72
73
  // Special handling for arrays - merge rather than replace
@@ -87,7 +88,7 @@ export class PropertyManager {
87
88
  merged[key] = value;
88
89
  }
89
90
  }
90
- // Always update modified date
91
+ // Always update modified date (this is the only place we set it)
91
92
  merged.modified = new Date().toISOString();
92
93
  return merged;
93
94
  }
@@ -60,7 +60,7 @@ export class UpdatePropertiesToolHandler extends BaseToolHandler {
60
60
  getToolDescription() {
61
61
  return {
62
62
  name: this.name,
63
- description: "Update properties in an Obsidian note's YAML frontmatter. Intelligently merges arrays (tags, type, status), handles custom fields, and automatically updates the modified timestamp. Existing properties not included in the update are preserved.",
63
+ description: "Update properties in an Obsidian note's YAML frontmatter. Intelligently merges arrays (tags, type, status), handles custom fields, and automatically manages timestamps (created by Obsidian, modified by MCP server). Existing properties not included in the update are preserved.",
64
64
  examples: [
65
65
  {
66
66
  description: "Update basic metadata",
@@ -111,9 +111,8 @@ export class UpdatePropertiesToolHandler extends BaseToolHandler {
111
111
  description: "Properties to update",
112
112
  properties: {
113
113
  title: { type: "string" },
114
- created: { type: "string", format: "date-time" },
115
- modified: { type: "string", format: "date-time" },
116
114
  author: { type: "string" },
115
+ // Note: created and modified timestamps are managed automatically
117
116
  type: {
118
117
  type: "array",
119
118
  items: {
@@ -17,11 +17,34 @@ export const StatusEnum = z.enum([
17
17
  "review",
18
18
  "complete"
19
19
  ]);
20
+ // Schema for reading properties (includes timestamps)
20
21
  export const ObsidianPropertiesSchema = z.object({
22
+ // Basic Metadata
23
+ // Note: Timestamps are managed automatically
24
+ title: z.string().optional(),
25
+ modified: z.string().datetime().optional(), // Read-only, managed by MCP server
26
+ author: z.string().optional(),
27
+ // Classification
28
+ type: z.array(PropertyTypeEnum).optional(),
29
+ // Organization
30
+ tags: z.array(z.string().startsWith("#")).optional(),
31
+ // Technical Metadata
32
+ status: z.array(StatusEnum).optional(),
33
+ version: z.string().optional(),
34
+ platform: z.string().optional(),
35
+ repository: z.string().url().optional(),
36
+ dependencies: z.array(z.string()).optional(),
37
+ // References
38
+ sources: z.array(z.string()).optional(),
39
+ urls: z.array(z.string().url()).optional(),
40
+ papers: z.array(z.string()).optional(),
41
+ // Custom Fields
42
+ custom: z.record(z.unknown()).optional()
43
+ });
44
+ // Schema for validating property updates (excludes timestamps)
45
+ export const PropertyUpdateSchema = z.object({
21
46
  // Basic Metadata
22
47
  title: z.string().optional(),
23
- created: z.string().datetime().optional(),
24
- modified: z.string().datetime().optional(),
25
48
  author: z.string().optional(),
26
49
  // Classification
27
50
  type: z.array(PropertyTypeEnum).optional(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "obsidian-mcp-server",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "Model Context Protocol server for Obsidian integration with token-aware response handling",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
package/src/properties.ts CHANGED
@@ -1,10 +1,11 @@
1
1
  import { parse, stringify } from 'yaml';
2
2
  import { ObsidianClient } from './obsidian.js';
3
- import {
4
- ObsidianProperties,
5
- ObsidianPropertiesSchema,
3
+ import {
4
+ ObsidianProperties,
5
+ ObsidianPropertiesSchema,
6
+ PropertyUpdateSchema,
6
7
  PropertyManagerResult,
7
- ValidationResult
8
+ ValidationResult
8
9
  } from './propertyTypes.js';
9
10
 
10
11
  export class PropertyManager {
@@ -62,7 +63,7 @@ export class PropertyManager {
62
63
  * Validate property values
63
64
  */
64
65
  validateProperties(properties: Partial<ObsidianProperties>): ValidationResult {
65
- const result = ObsidianPropertiesSchema.safeParse(properties);
66
+ const result = PropertyUpdateSchema.safeParse(properties);
66
67
 
67
68
  if (result.success) {
68
69
  return { valid: true, errors: [] };
@@ -70,7 +71,7 @@ export class PropertyManager {
70
71
 
71
72
  return {
72
73
  valid: false,
73
- errors: result.error.errors.map(err =>
74
+ errors: result.error.errors.map(err =>
74
75
  `${err.path.join('.')}: ${err.message}`
75
76
  )
76
77
  };
@@ -86,7 +87,8 @@ export class PropertyManager {
86
87
  const merged = { ...existing };
87
88
 
88
89
  for (const [key, value] of Object.entries(updates)) {
89
- if (value === undefined) continue;
90
+ // Skip undefined values and timestamp fields
91
+ if (value === undefined || key === 'created' || key === 'modified') continue;
90
92
 
91
93
  const currentValue = merged[key as keyof ObsidianProperties];
92
94
 
@@ -109,7 +111,7 @@ export class PropertyManager {
109
111
  }
110
112
  }
111
113
 
112
- // Always update modified date
114
+ // Always update modified date (this is the only place we set it)
113
115
  merged.modified = new Date().toISOString();
114
116
 
115
117
  return merged;
@@ -79,7 +79,7 @@ export class UpdatePropertiesToolHandler extends BaseToolHandler<UpdatePropertie
79
79
  getToolDescription(): Tool {
80
80
  return {
81
81
  name: this.name,
82
- description: "Update properties in an Obsidian note's YAML frontmatter. Intelligently merges arrays (tags, type, status), handles custom fields, and automatically updates the modified timestamp. Existing properties not included in the update are preserved.",
82
+ description: "Update properties in an Obsidian note's YAML frontmatter. Intelligently merges arrays (tags, type, status), handles custom fields, and automatically manages timestamps (created by Obsidian, modified by MCP server). Existing properties not included in the update are preserved.",
83
83
  examples: [
84
84
  {
85
85
  description: "Update basic metadata",
@@ -130,9 +130,8 @@ export class UpdatePropertiesToolHandler extends BaseToolHandler<UpdatePropertie
130
130
  description: "Properties to update",
131
131
  properties: {
132
132
  title: { type: "string" },
133
- created: { type: "string", format: "date-time" },
134
- modified: { type: "string", format: "date-time" },
135
133
  author: { type: "string" },
134
+ // Note: created and modified timestamps are managed automatically
136
135
  type: {
137
136
  type: "array",
138
137
  items: {
@@ -20,11 +20,40 @@ export const StatusEnum = z.enum([
20
20
  "complete"
21
21
  ]);
22
22
 
23
+ // Schema for reading properties (includes timestamps)
23
24
  export const ObsidianPropertiesSchema = z.object({
25
+ // Basic Metadata
26
+ // Note: Timestamps are managed automatically
27
+ title: z.string().optional(),
28
+ modified: z.string().datetime().optional(), // Read-only, managed by MCP server
29
+ author: z.string().optional(),
30
+
31
+ // Classification
32
+ type: z.array(PropertyTypeEnum).optional(),
33
+
34
+ // Organization
35
+ tags: z.array(z.string().startsWith("#")).optional(),
36
+
37
+ // Technical Metadata
38
+ status: z.array(StatusEnum).optional(),
39
+ version: z.string().optional(),
40
+ platform: z.string().optional(),
41
+ repository: z.string().url().optional(),
42
+ dependencies: z.array(z.string()).optional(),
43
+
44
+ // References
45
+ sources: z.array(z.string()).optional(),
46
+ urls: z.array(z.string().url()).optional(),
47
+ papers: z.array(z.string()).optional(),
48
+
49
+ // Custom Fields
50
+ custom: z.record(z.unknown()).optional()
51
+ });
52
+
53
+ // Schema for validating property updates (excludes timestamps)
54
+ export const PropertyUpdateSchema = z.object({
24
55
  // Basic Metadata
25
56
  title: z.string().optional(),
26
- created: z.string().datetime().optional(),
27
- modified: z.string().datetime().optional(),
28
57
  author: z.string().optional(),
29
58
 
30
59
  // Classification
@@ -50,6 +79,7 @@ export const ObsidianPropertiesSchema = z.object({
50
79
  });
51
80
 
52
81
  export type ObsidianProperties = z.infer<typeof ObsidianPropertiesSchema>;
82
+ export type PropertyUpdate = z.infer<typeof PropertyUpdateSchema>;
53
83
 
54
84
  export interface PropertyOperation {
55
85
  operation: 'get' | 'update' | 'patch';