smoking-mirror 1.0.0

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.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +259 -0
  3. package/dist/index.js +1196 -0
  4. package/package.json +61 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ben Cassie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,259 @@
1
+ # smoking-mirror
2
+
3
+ > Obsidian vault intelligence for Claude Code - graph queries, wikilink suggestions, and vault health
4
+
5
+ [![npm version](https://badge.fury.io/js/smoking-mirror.svg)](https://www.npmjs.com/package/smoking-mirror)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## What is smoking-mirror?
9
+
10
+ "Smoking mirror" (tezcatl in Nahuatl) is the literal translation of "obsidian". This MCP server acts as a reflective surface that reveals the hidden structure of your Obsidian vault to Claude Code.
11
+
12
+ **First-to-market** features:
13
+ - **Graph Intelligence** - Backlinks, forward links, orphan detection, hub analysis
14
+ - **Wikilink Services** - Auto-suggest entities, validate links
15
+ - **Vault Health** - Broken link detection, comprehensive statistics
16
+ - **Frontmatter Queries** - Search notes by metadata, tags, folders
17
+
18
+ ## Installation
19
+
20
+ ### Quick Install (Claude Code CLI)
21
+
22
+ **macOS / Linux:**
23
+
24
+ ```bash
25
+ claude mcp add smoking-mirror -e OBSIDIAN_VAULT_PATH=/path/to/your/vault -- npx -y smoking-mirror
26
+ ```
27
+
28
+ **Windows:**
29
+
30
+ ```bash
31
+ claude mcp add smoking-mirror -e OBSIDIAN_VAULT_PATH=C:\path\to\your\vault -- cmd /c npx -y smoking-mirror
32
+ ```
33
+
34
+ ### Manual Configuration
35
+
36
+ Alternatively, add to your `.mcp.json` file:
37
+
38
+ **Windows:**
39
+
40
+ ```json
41
+ {
42
+ "mcpServers": {
43
+ "smoking-mirror": {
44
+ "command": "cmd",
45
+ "args": ["/c", "npx", "-y", "smoking-mirror"],
46
+ "env": {
47
+ "OBSIDIAN_VAULT_PATH": "C:\\Users\\you\\Documents\\MyVault"
48
+ }
49
+ }
50
+ }
51
+ }
52
+ ```
53
+
54
+ **macOS / Linux:**
55
+
56
+ ```json
57
+ {
58
+ "mcpServers": {
59
+ "smoking-mirror": {
60
+ "command": "npx",
61
+ "args": ["-y", "smoking-mirror"],
62
+ "env": {
63
+ "OBSIDIAN_VAULT_PATH": "/Users/you/Documents/MyVault"
64
+ }
65
+ }
66
+ }
67
+ }
68
+ ```
69
+
70
+ ### Verify Installation
71
+
72
+ After adding, verify with:
73
+
74
+ ```bash
75
+ claude mcp list
76
+ ```
77
+
78
+ You should see `smoking-mirror` in the list of configured servers.
79
+
80
+ ## Tools
81
+
82
+ ### Graph Intelligence
83
+
84
+ #### `get_backlinks`
85
+ Find all notes that link TO a specific note.
86
+
87
+ ```
88
+ Input: { path: "projects/My Project.md" }
89
+ Output: [{ source: "daily/2024-01-15.md", line: 42, context: "Working on [[My Project]] today" }]
90
+ ```
91
+
92
+ #### `get_forward_links`
93
+ Find all notes that a specific note links TO.
94
+
95
+ ```
96
+ Input: { path: "projects/My Project.md" }
97
+ Output: [{ target: "Team Members", exists: true, resolved_path: "people/Team Members.md" }]
98
+ ```
99
+
100
+ #### `find_orphan_notes`
101
+ Find notes with no incoming links (potential cleanup candidates).
102
+
103
+ ```
104
+ Input: { folder: "archive" } // optional folder filter
105
+ Output: [{ path: "archive/old-idea.md", title: "old-idea", modified: "2024-01-01" }]
106
+ ```
107
+
108
+ #### `find_hub_notes`
109
+ Find highly connected notes (potential MOCs or index notes).
110
+
111
+ ```
112
+ Input: { min_links: 10 } // minimum total connections
113
+ Output: [{ path: "MOC.md", backlink_count: 45, forward_link_count: 23, total_connections: 68 }]
114
+ ```
115
+
116
+ ### Wikilink Services
117
+
118
+ #### `suggest_wikilinks`
119
+ Analyze text and suggest where wikilinks could be added based on existing notes.
120
+
121
+ ```
122
+ Input: { text: "Meeting with John about the API project" }
123
+ Output: [
124
+ { entity: "John", start: 13, end: 17, target: "people/John Smith.md" },
125
+ { entity: "API project", start: 28, end: 39, target: "projects/API Project.md" }
126
+ ]
127
+ ```
128
+
129
+ #### `validate_links`
130
+ Check wikilinks in a note (or all notes) and report broken links.
131
+
132
+ ```
133
+ Input: { path: "projects/My Project.md" } // optional, validates all if omitted
134
+ Output: [{ source: "projects/My Project.md", target: "Missing Note", line: 15, exists: false }]
135
+ ```
136
+
137
+ ### Vault Health
138
+
139
+ #### `get_vault_stats`
140
+ Get comprehensive statistics about your vault.
141
+
142
+ ```
143
+ Output: {
144
+ total_notes: 1444,
145
+ total_links: 20373,
146
+ total_tags: 431,
147
+ orphan_notes: 971,
148
+ broken_links: 8565,
149
+ average_links_per_note: 14.11,
150
+ most_linked_notes: [...],
151
+ top_tags: [...],
152
+ folders: [...]
153
+ }
154
+ ```
155
+
156
+ #### `find_broken_links`
157
+ Find all wikilinks that point to non-existent notes.
158
+
159
+ ```
160
+ Input: { folder: "projects" } // optional folder filter
161
+ Output: [{ source: "projects/Old.md", target: "Deleted Note", line: 5 }]
162
+ ```
163
+
164
+ ### Query
165
+
166
+ #### `search_notes`
167
+ Search notes by frontmatter fields, tags, folders, or title. Covers ~80% of Dataview use cases.
168
+
169
+ ```
170
+ Input: {
171
+ has_tag: "project",
172
+ where: { status: "active" },
173
+ folder: "work",
174
+ sort_by: "modified",
175
+ limit: 10
176
+ }
177
+ Output: [{ path: "work/Current.md", title: "Current", frontmatter: {...}, tags: [...] }]
178
+ ```
179
+
180
+ **Parameters:**
181
+ - `where` - Frontmatter key-value filters (e.g., `{ type: "book", rating: 5 }`)
182
+ - `has_tag` - Filter by single tag
183
+ - `has_any_tag` - Filter by any of these tags
184
+ - `has_all_tags` - Filter by all of these tags
185
+ - `folder` - Limit to notes in this folder
186
+ - `title_contains` - Filter by title substring
187
+ - `sort_by` - Sort by "modified", "created", or "title"
188
+ - `order` - "asc" or "desc"
189
+ - `limit` - Maximum results to return
190
+
191
+ ## Architecture
192
+
193
+ - **File-first**: Parses markdown directly, no database required
194
+ - **Works offline**: No connection to Obsidian needed
195
+ - **Fast startup**: <2s for 1500+ notes
196
+ - **Memory efficient**: ~50MB for large vaults
197
+ - **Parallel parsing**: Processes files in batches for speed
198
+
199
+ ### Performance
200
+
201
+ | Vault Size | Startup Time | Memory |
202
+ |------------|--------------|--------|
203
+ | 100 notes | <200ms | ~20MB |
204
+ | 500 notes | <500ms | ~30MB |
205
+ | 1500 notes | <2s | ~50MB |
206
+ | 5000 notes | <5s | ~100MB |
207
+
208
+ ### Error Handling
209
+
210
+ - Malformed YAML frontmatter: Gracefully skipped, file treated as content
211
+ - Binary files: Detected and skipped
212
+ - Empty files: Indexed with no links/tags
213
+ - Large files (>10MB): Skipped with warning
214
+ - Timeout protection: 5-minute default for vault indexing
215
+
216
+ ## Development
217
+
218
+ ```bash
219
+ # Install dependencies
220
+ bun install
221
+
222
+ # Run in development mode
223
+ OBSIDIAN_VAULT_PATH=/path/to/vault bun run dev
224
+
225
+ # Build for distribution
226
+ bun run build
227
+
228
+ # Test with MCP inspector
229
+ bun run inspect
230
+
231
+ # Run tests
232
+ bun test
233
+ ```
234
+
235
+ ## Why not Dataview?
236
+
237
+ We initially planned to use `obsidian-dataview` as a library, but discovered it requires Obsidian's internal `CachedMetadata` API and cannot run standalone. See [this discussion](https://github.com/blacksmithgu/obsidian-dataview/discussions/1811).
238
+
239
+ Instead, smoking-mirror:
240
+ - Parses markdown files directly using `gray-matter`
241
+ - Builds its own in-memory graph index
242
+ - Provides ~80% of Dataview functionality with simpler syntax
243
+
244
+ ## Roadmap
245
+
246
+ - [ ] MarkdownDB integration for SQL-like queries
247
+ - [ ] Watch mode for incremental updates
248
+ - [ ] `rename_with_links` - Safe note renaming with reference updates
249
+ - [ ] Obsidian REST API integration for live Dataview queries
250
+
251
+ ## License
252
+
253
+ MIT - Ben Cassie
254
+
255
+ ## Related
256
+
257
+ - [Model Context Protocol](https://modelcontextprotocol.io/)
258
+ - [Claude Code](https://claude.ai/code)
259
+ - [Obsidian](https://obsidian.md/)