Semantic Notes Vault MCP
Memory server
Created by Aaron Bockelie
Published in aaronsb/obsidian-mcp-plugin. Publisher page
468 GitHub stars
What it is
Read, write, search, and traverse your vault from Claude Desktop and any AI assistant — via a built-in MCP server, no external server to run.
AutoGineer overview, from the brain’s own files
Semantic Notes Vault MCP transforms your Obsidian vault into a persistent, intelligent memory layer for AI agents. By running an MCP server directly within the Obsidian application, it eliminates the need for external processes or complex API bridges. The plugin exposes eight tool families that allow AI assistants to perform comprehensive vault operations, including file management, graph traversal, and semantic search. It is designed to respect user-defined security permissions, ensuring that AI interactions remain within controlled boundaries while enabling deep, context-aware knowledge synthesis.
How it works
Memory model: Knowledge graph
AutoGineer overview, from the brain’s own files
The plugin functions as a built-in Model Context Protocol (MCP) server inside Obsidian. It uses a direct Obsidian API integration to read, write, and traverse your notes. It organizes your data into a knowledge graph, allowing AI to navigate links, tags, and backlinks. The system includes a security layer for path validation and permissions, and it supports Dataview queries and database views for advanced data retrieval.
| Folder | Role | Files |
|---|---|---|
| .github | agent-config | 11 |
| docs | docs | 34 |
| scripts | scripts | 9 |
| src | source-code | 79 |
| tests | tests | 74 |
| wiki | wiki | 1 |
| .claude-github | folder | 2 |
| mcpb | folder | 2 |
The agent reads
- scripts/scorecard.mjs evidence: CLAUDE.md
- manifest.json evidence: CLAUDE.md
The agent writes
- package.json evidence: CLAUDE.md
- sync-version.mjs evidence: CLAUDE.md
- manifest.json evidence: CLAUDE.md
Requirements
Apps: Obsidian
Runtimes: Node.js
API keys (by name): YOUR_API_KEY
Works with: Claude Code, OpenCode
Set it up
This brain runs code automatically: 1 plugin code item (obsidian), 1 script. Review Makefile, manifest.json before opening the folder in Claude Code. No step below turns a hook on for you.
Makefile:npm installmanifest.json:runs inside Obsidian once the plugin is enabled
- Download main.js, manifest.json and styles.css of release 0.13.0: https://github.com/aaronsb/obsidian-mcp-plugin/releases/tag/0.13.0
Check main.js against the SHA-256 AutoGineer recorded:
curl -fsSLO https://github.com/aaronsb/obsidian-mcp-plugin/releases/download/0.13.0/main.js && shasum -a 256 main.js # expect 47da0b5aa8880e21d50bb7c883c976d8563d19694620ae8f3a3f84ead28d65b8Copy the three files into <vault>/.obsidian/plugins/semantic-vault-mcp/ and enable the plugin in Settings → Community plugins.
You will install release 0.13.0, which AutoGineer scanned (main.js SHA-256 47da0b5aa8880e21d50bb7c883c976d8563d19694620ae8f3a3f84ead28d65b8).
- Not scanned by AutoGineerObsidian installs the plugin’s current release; AutoGineer scanned release 0.13.0 (2026-11-12). https://obsidian.md/plugins?id=semantic-vault-mcp
Created by Aaron Bockelie. Published in aaronsb/obsidian-mcp-plugin. Licence: MIT License.
Usage
AutoGineer overview, from the brain’s own files
- Connect Claude Desktop to your Obsidian vault for direct note interaction.
- Enable AI agents to perform complex research by traversing your note graph.
- Automate note creation and organization based on existing knowledge structures.
- Execute Dataview queries via AI prompts to summarize or analyze your vault data.
- “What are my recent thoughts on project X?”
- The AI searches your vault for notes related to project X and synthesizes your recent entries.
- “Find connections between my psychology and philosophy notes”
- The AI traverses your knowledge graph to identify shared concepts and bridge notes between the two domains.
Documentation by Aaron Bockelie
Semantic Notes Vault MCP
Image: GitHub stars Image: GitHub forks Image: Downloads Image: Latest Release Image: License
📦 Available in the Obsidian Community Plugin directory →
Read, write, search, and traverse your Obsidian vault from any AI assistant — through an MCP server that runs inside Obsidian.
No external Node process to launch, no separate REST-API plugin to bridge through: the server is the plugin. Setup is a drag-and-drop — drop the .mcpb bundle onto Claude Desktop, paste your key, done.
It exposes 8 powerful tools — each a whole family of operations, not a single call (the vault tool alone handles 13: list, read, create, search, move, split, combine, and more) — with first-class Dataview and Bases support plus graph traversal across links, tags, and backlinks. And every operation respects the permissions you set — a read-only mode, per-operation controls, and path allow/block lists — so the AI only ever does what you've allowed, not unrestricted run of your vault.
Works with any MCP-compatible client — Claude Desktop, Claude Code, Cline, Continue.dev, and anything that speaks local MCP.
New to MCP? The Model Context Protocol is the open standard that lets AI assistants interact with external tools and data. You don't need to understand it to use this — the Quick Start is three steps.
Quick Start
Prerequisites: an MCP-compatible AI client like Claude Desktop, Claude Code, or Continue.dev.
📦 ──drag──▶ 🤖💬
Download the
.mcpbbundle from the plugin's config page → drag it onto Claude Desktop → paste your key. Done.
For most people that's the entire setup. The numbered steps below spell it out, then cover other MCP clients.
1. Install the Plugin
Via Obsidian Community Plugins
Open Settings → Community plugins → Browse
Search for "Semantic Notes Vault MCP"
Install and enable — or install straight from the plugin listing
Via BRAT (for beta testing)
Install BRAT
Add beta plugin:
aaronsb/obsidian-mcp-plugin
2. Configure Your AI Client
Three onboarding paths, ordered by audience. All three are also shown in the plugin's Settings tab with copy-ready values.
📦 → 🤖 Claude Desktop — one-click .mcpb install (recommended)
Download obsidian-mcp-<version>.mcpb — either from the plugin's Settings tab (button right on the config page) or the latest release — then either drag it onto the Claude Desktop window or double-click it. Claude Desktop opens an install dialog with two fields — paste the URL and API key shown in the plugin's Settings tab, hit Save, and you're done.
Cross-platform note:
.mcpbfiles install via Claude Desktop's bundled handler. If double-click doesn't trigger Claude on your system, drag the file onto Claude Desktop's window instead, or right-click → "Open with…" and pick Claude Desktop (then "always open with" if your OS asks). Behavior varies by platform: macOS usually auto-associates, Windows may need a one-time association, Linux varies by desktop environment.
Claude Code — one command (copy the ready-made version with your API key from the plugin's Settings tab):
claude mcp add --transport http obsidian http://localhost:3001/mcp --header "Authorization: Bearer YOUR_API_KEY"For HTTPS, use https://localhost:3443/mcp instead — see Trusting the self-signed certificate below. Claude Code runs on Bun, which does not read the macOS system keychain, so you will need to set NODE_EXTRA_CA_CERTS.
Other MCP clients (Cline, Continue, custom integrations, multi-vault setups)
Add an entry to the client's MCP config file — one entry per vault if you run multiple Obsidian instances on different ports:
{
"mcpServers": {
"obsidian-vault": {
"transport": {
"type": "http",
"url": "http://localhost:3001/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}
}Advanced: custom .mcpb per vault
For multi-vault setups that want one-click install per vault, clone this repo and run the maker:
node scripts/make-mcpb.mjs
# Prompts for display name, URL, and API key
# Outputs obsidian-mcp-<slug>.mcpb with everything pre-filledDrop the resulting bundle into Claude Desktop and click Install — no fields to type.
Trusting the self-signed certificate
The plugin's HTTPS server uses a self-signed certificate auto-generated on first start and stored under .obsidian/plugins/semantic-vault-mcp/certificates/default.crt inside your vault. MCP clients reject self-signed certificates by default, so you need to explicitly trust it before connecting over HTTPS. Pick the method that matches your client runtime.
macOS Keychain (for clients that use the system trust store — Claude Desktop, browser-based tools, Node with --use-system-ca):
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain \
/path/to/vault/.obsidian/plugins/semantic-vault-mcp/certificates/default.crtNODE_EXTRA_CA_CERTS (required for Claude Code and other Bun-based runtimes):
Bun does not consult the macOS system keychain for TLS trust, so trusting the certificate via Keychain Access alone has no effect — this is almost always the real reason an HTTPS connection from Claude Code fails. Bun only honors certificates listed in NODE_EXTRA_CA_CERTS:
# Point directly at the plugin cert, or append it to an existing CA bundle:
export NODE_EXTRA_CA_CERTS=/path/to/vault/.obsidian/plugins/semantic-vault-mcp/certificates/default.crt
# Propagate to GUI apps launched from the macOS dock (including Claude Code):
launchctl setenv NODE_EXTRA_CA_CERTS /path/to/vault/.obsidian/plugins/semantic-vault-mcp/certificates/default.crtRe-run these whenever the plugin regenerates its certificate (e.g. after the 1-year validity expires).
Avoid
NODE_TLS_REJECT_UNAUTHORIZED=0. It disables TLS verification process-wide — for every HTTPS connection the client makes, not just this plugin — and masks legitimate certificate problems (expired, revoked, tampered). Trust the certificate explicitly instead.
3. Start Using
Once connected, simply chat with your AI assistant about your notes! For example:
"What are my recent thoughts on project X?"
"Find connections between my psychology and philosophy notes"
"Summarize my meeting notes from this week"
"Create a new note linking my ideas about Y"
Your AI assistant now has these capabilities:
Navigate your vault's link structure
Search and rank across all notes
Read, edit, and create notes
Analyze your knowledge graph
Work with Dataview queries (if installed)
Manage Obsidian Bases (database views)
Why It's Different
Traditional file access gives AI a narrow view — one document at a time. This plugin gives it the whole connected picture:
Graph Navigation: AI follows links between notes, understanding relationships and context
Concept Discovery: Search and graph traversal surface related ideas across your vault
Contextual Awareness: AI understands where information lives in your knowledge structure
Intelligent Synthesis: Combine fragments from multiple notes to answer complex questions
Core Tools
The plugin provides 8 powerful tools that give AI comprehensive vault access — each one a family of related operations, all subject to the permissions you set:
| Tool | Purpose | Key Actions |
|---|---|---|
| 📁 vault | File operations | list, read, create, search, move, split, combine |
| ✏️ edit | Content modification | window editing, append, patch sections |
| 👁️ view | Content display | view files, windows, active note |
| 🕸️ graph | Link navigation | traverse, find paths, analyze connections |
| 💡 workflow | Contextual hints | suggest next actions based on state |
| 📊 dataview | Query notes | Execute DQL queries (if installed) |
| 🗃️ bases | Database views | Query and export Bases (if available) |
| ℹ️ system | Vault info | Server status, commands, web fetch (off by default), running allowlisted commands (off by default) |
Documentation
Detailed documentation for each tool and feature:
📁 Vault Operations - File management and search
🕸️ Graph Navigation - Link traversal and analysis
ℹ️ System Operations - Server info, web fetch, and gated command execution
🔧 Configuration - Server settings and options
❓ Troubleshooting - Common issues and solutions
In Practice
This plugin doesn't just give AI access to files — it lets AI work across your vault as a connected whole:
Example: Research Assistant
User: "Summarize my research on machine learning optimization"
AI uses these tools to:
1. Search for notes with ML optimization concepts
2. Traverse graph to find related papers and techniques
3. Follow backlinks to discover applications
4. Synthesize findings from multiple connected notesExample: Knowledge Explorer
User: "What connections exist between my notes on philosophy and cognitive science?"
AI uses graph tools to:
1. Find notes tagged with both topics
2. Analyze shared concepts via graph traversal
3. Identify bridge notes that connect domains
4. Map the conceptual overlapFeatures
Full-Text Search
Advanced query operators:
tag:,path:,content:Regular expressions and phrase matching
Relevance ranking and snippet extraction
Graph Intelligence
Multi-hop traversal with depth control
Backlink and forward-link analysis
Path finding between concepts
Tag-based navigation
Content Operations
Fuzzy text matching for edits
Structure-aware modifications (headings, blocks)
Batch operations (split, combine, move)
Template support
Integration
Dataview query execution
Bases database operations
Web content fetching
Read-only mode for safety
Plugin Settings
Access settings via: Settings → Community plugins → Semantic Notes Vault MCP
Key configuration options:
Server Ports: HTTP (3001) and HTTPS (3443)
Authentication: API key protection
Security: Path validation and permissions
Performance: Connection pooling and caching
Support
Issues: GitHub Issues
Discussions: GitHub Discussions
Sponsor: GitHub Sponsors
License
CLAUDE.md
Claude Development Guidelines for Obsidian MCP Plugin
Project Context
This is a hybrid Obsidian plugin that combines:
Local REST API functionality (from coddingtonbear's plugin)
Semantic MCP operations (from aaronsb/obsidian-semantic-mcp)
Direct Obsidian API integration for enhanced performance
The critical architectural pattern is preserving the ObsidianAPI abstraction layer while replacing HTTP calls with direct Obsidian plugin API calls. This allows reuse of all existing MCP server logic while gaining performance benefits.
Code Quality Guidelines
SOLID Principles Application
Single Responsibility:
ObsidianAPIclass handles only vault operations abstractionMCPServerclass handles only MCP protocol operationsHTTPServerclass handles only REST endpoint managementPlugin main class handles only Obsidian plugin lifecycle
Open/Closed:
ObsidianAPI interface remains stable for extensions
MCP operations extensible through semantic router pattern
HTTP endpoints extensible without modifying core logic
Liskov Substitution:
New ObsidianAPI implementation must be drop-in replacement
All method signatures and return types must match exactly
Error handling behavior must be preserved
Interface Segregation:
Separate interfaces for vault operations, search operations, and workspace operations
MCP protocol separated from HTTP REST protocol
Plugin settings separated from server configuration
Dependency Inversion:
Depend on Obsidian Plugin API abstractions, not concrete implementations
MCP server depends on ObsidianAPI interface, not specific implementation
HTTP server depends on operation interfaces, not direct vault access
Architecture Patterns
Critical Abstraction Layer
// This interface MUST remain stable
interface IObsidianAPI {
getFile(path: string): Promise<ObsidianFileResponse>;
listFiles(directory?: string): Promise<string[]>;
searchSimple(query: string): Promise<any[]>;
// ... all existing methods preserved
}
// Implementation changes from HTTP to direct API
class ObsidianAPI implements IObsidianAPI {
constructor(private app: App) {} // Direct plugin access
async getFile(path: string): Promise<ObsidianFileResponse> {
// Direct vault access instead of HTTP call
const file = this.app.vault.getAbstractFileByPath(path);
// ... implementation
}
}Performance-Critical Patterns
Caching Layer: Implement intelligent caching for frequently accessed files
Lazy Loading: Load heavy operations only when needed
Batch Operations: Combine multiple vault operations where possible
Memory Management: Proper cleanup of file handles and event listeners
Error Handling Patterns
// Preserve exact error types and messages from HTTP implementation
class VaultError extends Error {
constructor(message: string, public code: string, public status: number) {
super(message);
}
}
// Maintain compatibility with existing error handling
async getFile(path: string): Promise<ObsidianFileResponse> {
try {
const file = this.app.vault.getAbstractFileByPath(path);
if (!file) {
throw new VaultError(`File not found: ${path}`, 'ENOENT', 404);
}
// ... rest of implementation
} catch (error) {
// Transform plugin errors to match HTTP API errors
throw this.transformError(error);
}
}Development Workflow
BRAT Development Release Process
When developing with Obsidian BRAT (Beta Reviewer's Auto-update Tool) for plugin side-loading:
Development vs Release Workflow
Development (no releases created):
Push commits to main freely - no automatic releases triggered
Test locally with
npm run buildIterate as needed without polluting release history
Creating a Release (manual trigger):
Via GitHub UI:
Go to Actions → Create Release
Click Run workflow
Optionally add release notes
Click Run
Via CLI:
# Simple release
gh workflow run release.yml
# With release notes
gh workflow run release.yml -f release_notes="Fixed VS Code compatibility, improved search"Version Updates
ONLY update
package.jsonversion -sync-version.mjsautomatically syncs tomanifest.jsonandversion.tsDO NOT manually update
manifest.json- the automation handles thisBump version in
package.jsonbefore triggering a release
Tag Management
Release workflow creates tags automatically (no 'v' prefix)
If a tag already exists for that version, the release is skipped
To re-release same version, delete existing tag first:
git tag -d X.Y.Z && git push origin :refs/tags/X.Y.Z
BRAT User Experience
Users install via:
aaronsb/obsidian-mcp-pluginin BRATBRAT checks GitHub releases for updates automatically
Version detection relies on
manifest.jsonversion fieldRelease assets (main.js, manifest.json, styles.css) are auto-generated by workflow
Version Naming Convention
Major releases:
X.Y.Z(e.g., 0.4.4) - NO 'v' prefixPatch releases:
X.Y.Za,X.Y.Zb(e.g., 0.4.4a, 0.4.4b) - NO 'v' prefixPre-releases: All releases ship as prereleases by default (
make release-patchetc.)Promoting to stable: When a release is bounded and proven, run
make promote(ormake promote TAG=X.Y.Z) to flip it from prerelease → stable and mark it as GitHub's "Latest" release. This is also what makes the/releases/latest/download/<asset>URL resolve — the MCPB download link in plugin Settings relies on it.IMPORTANT: Obsidian requires release tags WITHOUT 'v' prefix
Exploratory releases: Use letter suffix (a, b, c) for testing new features
File Organization
src/
├── main.ts # Plugin entry point
├── obsidian-api.ts # Direct API implementation (CRITICAL)
├── mcp-server.ts # MCP protocol handling
├── http-server.ts # REST API endpoints
├── semantic/ # Reused from obsidian-semantic-mcp
│ ├── router.ts # Semantic operations router
│ └── operations/ # Individual operation implementations
├── types/ # TypeScript type definitions
└── utils/ # Shared utilitiesTesting Strategy
Unit Tests: Each ObsidianAPI method tested against expected interface
Integration Tests: Full MCP and REST workflows tested
Performance Tests: Benchmarking against HTTP-based implementation
Compatibility Tests: Existing client code works without changes
Build Pipeline
{
"scripts": {
"dev": "tsc --watch",
"build": "tsc && node build-plugin.js",
"test": "jest",
"test:performance": "node performance-tests.js",
"package": "npm run build && npm run test && node package-release.js"
}
}Pre-Push Quality Checks
ALWAYS run these commands before pushing to GitHub:
# 1. Build the project to catch TypeScript errors
npm run build
# 2. Run linting to ensure code quality
npm run lint
# 3. Run tests to catch regressions
npm test
# 4. If all pass, commit and push
git add -A && git commit -m "..."
git push origin mainQuick one-liner for all checks:
npm run build && npm run lint && npm test && echo "✅ All checks passed!"Note: Even for "simple" changes like updating descriptions or documentation, running these checks ensures no accidental syntax errors or regressions are introduced.
Supply Chain — 7-Day Hold on Routine Upgrades (security fixes exempt)
npm supply-chain attacks have been ticking up — malicious package versions get published, ingested by automation, then discovered/yanked days later. To buy time for community discovery:
Land routine upgrades only to versions published more than 7 days ago — but security fixes are exempt and land immediately.
The exemption exists because the hold otherwise fights our own freshness goal: it delays exactly the vuln patches that Obsidian's plugin review (and npm audit) flag, leaving us knowingly exposed to a named, real CVE to guard against a hypothetical malicious republish. For a security fix the known exposure wins.
Practical application:
Security fix → land it now. If a dependabot/manual upgrade resolves a flagged vulnerability (dependabot security PR,
npm auditadvisory, or an Obsidian-review dependency warning), merge as soon as it's green regardless of version age.Routine bump → 7-day hold. For non-security version bumps, check the PR's open date. If it's ≥7 days old, proceed; if younger, hold (don't close — it ages into eligibility on its own).
The same split applies to manual
npm install/npm update: security fixes immediately, routine pins to versions older than 7 days.
Re-run npm audit after each merge batch to see what residual exposure remains.
The hold covers what ships. Analysis tooling is exempt.
The hold protects users from a malicious version reaching them through
main.js. Linters, formatters, type-checkers and test tooling never get bundled,
so holding them back protects nobody and costs something real: our lint drifts
from the portal's, and findings then arrive after a release is cut instead of
before. Hold anything that ships. Land analysis tooling as soon as it's green.
Two honest caveats. This is not zero-risk — an ESLint plugin executes on the
maintainer's machine during npm run lint, so the exposure moves from users to
the developer rather than disappearing.
Second, the mitigating control is weaker than it looks. Install scripts are
blocked pending approval (npm install-scripts ls shows what is waiting), but
that is npm 12+ default behaviour, not something this repo enforces — there is
no .npmrc or package.json setting pinning it. On an older npm a new dev
dependency's postinstall runs freely. So the exemption rests on the toolchain
the installer happens to be using. Approve install scripts one package at a time
and never with --all; if this needs to be guaranteed rather than assumed, that
means enforcing it in the repo, which is not done today.
Anything with a runtime import path — including a dev dependency that ends up bundled — is "what ships" and keeps the hold.
Plugin-Specific Guidelines
Obsidian Plugin Lifecycle
export default class ObsidianMCPPlugin extends Plugin {
private obsidianAPI: ObsidianAPI;
private mcpServer: MCPServer;
private httpServer: HTTPServer;
async onload() {
// 1. Initialize API abstraction layer FIRST
this.obsidianAPI = new ObsidianAPI(this.app);
// 2. Initialize servers with API dependency
this.mcpServer = new MCPServer(this.obsidianAPI);
this.httpServer = new HTTPServer(this.obsidianAPI);
// 3. Start servers
await this.startServers();
// 4. Register UI components
this.addSettingTab(new MCPSettingTab(this.app, this));
}
async onunload() {
// Clean shutdown in reverse order
await this.stopServers();
this.obsidianAPI.cleanup();
}
}Performance Monitoring
// Add performance tracking for optimization
class PerformanceTracker {
static async measure<T>(name: string, operation: () => Promise<T>): Promise<T> {
const start = performance.now();
const result = await operation();
const duration = performance.now() - start;
console.log(`${name}: ${duration.toFixed(2)}ms`);
return result;
}
}
// Usage in ObsidianAPI methods
async getFile(path: string): Promise<ObsidianFileResponse> {
return PerformanceTracker.measure(`getFile:${path}`, async () => {
// ... implementation
});
}Settings Management
interface MCPPluginSettings {
httpEnabled: boolean;
httpPort: number;
httpsPort: number;
enableSSL: boolean;
debugLogging: boolean;
performanceMetrics: boolean;
}
const DEFAULT_SETTINGS: MCPPluginSettings = {
httpEnabled: true,
httpPort: 27123,
httpsPort: 27124,
enableSSL: true,
debugLogging: false,
performanceMetrics: false
};Migration Guidelines
From HTTP-based Setup
Configuration Migration: Automatically detect and import REST API plugin settings
Port Compatibility: Default to same ports as REST API plugin
Feature Parity: All existing functionality must work identically
Performance Communication: Clearly communicate performance improvements
Backward Compatibility Requirements
API Responses: Identical JSON structure and field names
Error Codes: Same HTTP status codes and error messages
Authentication: Support existing API key mechanisms
Headers: Preserve expected request/response headers
Documentation Standards
Code Documentation
/**
* Enhanced file retrieval with direct vault access
*
* @param path - File path relative to vault root
* @returns Promise resolving to file content and metadata
* @throws VaultError when file not found or access denied
*
* Performance: ~1-5ms (vs ~50-100ms HTTP implementation)
* Compatibility: 100% compatible with HTTP API response format
*/
async getFile(path: string): Promise<ObsidianFileResponse> {
// Implementation...
}API Documentation
Maintain compatibility documentation showing HTTP vs Direct API equivalence
Performance benchmarks for each operation
Migration examples for common use cases
Troubleshooting guide for plugin-specific issues
Success Metrics
Performance Targets
File Operations: <10ms (vs ~50-100ms HTTP)
Search Operations: <50ms (vs ~100-300ms HTTP)
Directory Listing: <5ms (vs ~30-60ms HTTP)
Memory Usage: Stable, no leaks during extended operation
Quality Targets
API Compatibility: 100% backward compatible
Test Coverage: >90% code coverage
Error Handling: Graceful degradation for all failure modes
Documentation: Complete user and developer documentation
Community Targets
BRAT Testing: 100+ beta installations
Feedback Integration: Active response to community feedback
Migration Success: Smooth transition for existing users
Plugin Directory: Successful submission and approval
Obsidian Community Plugin Distribution
Status: The plugin is live in the community directory as of 2026-05-16 (in submittal since 2025-07-04). It is a maintained, shipped plugin now — not a submission in progress.
Historical note: Obsidian previously required a pull request against the
obsidianmd/obsidian-releasesrepo (editingcommunity-plugins.json) plus a manual "keep the PR alive" refresh dance. That process is defunct. Obsidian moved submission and maintenance to the community developer portal (community.obsidian.md). Do not recreate theobsidian-releasesfork workflow — there is no PR to maintain anymore.
Architecture: portal is the source of truth, community-plugins.json is a mirror
The developer portal (community.obsidian.md) is now authoritative. A bot
mirrors approved plugins from the portal into
obsidianmd/obsidian-releases/community-plugins.json (commits titled
chore: Mirror community plugins and themes). The desktop app's in-app
community browser still reads that mirror, not the portal directly.
Consequence: after a plugin is approved/updated on the portal, there is a propagation lag before it appears in the in-app browser search — the mirror bot has to run, then the app refreshes its cached list (a restart helps only after the mirror includes you). This is normal, not a bug. The portal page and its "Add to Obsidian" deep link work immediately. If still absent from the mirror after ~24h / many mirror commits, that's a real pipeline miss worth raising with Obsidian — not a repo-side fix.
make promote now auto-updates real users, not just BRAT testers. The
prerelease → BRAT → promote loop is the safety rail, not ceremony.
How distribution works now
The portal scans this repo's GitHub Releases. For the plugin to be scanned and distributed:
There must be a stable (non-prerelease) "Latest" release whose tag exactly matches the
versionfield inmanifest.json.Release tags use no
vprefix —0.11.21, notv0.11.21. The release workflow already produces the correct format.versions.jsonmust contain a"<version>": "<minAppVersion>"entry matchingmanifest.json(make release-*maintains this).Releases ship as prereleases by default, and a prerelease is invisible to the portal. Run
make promoteto flip the proven release to stable + "Latest". This is the step that makes the directory (and the MCPBreleases/latest/download/...link) pick up the new version.
Validating before publishing
The developer portal offers a "preview a branch scan" that accepts a
branch, tag, or commit SHA — use it to confirm a release candidate passes
Obsidian's checks before running make promote. Treat it as a
validation/dry-run tool: end-user installs and updates still come from the
matching stable release tag's assets, not from a scanned branch.
Where the listing text comes from
Short description — repo-driven. Single source of truth is
package.json;sync-version.mjspropagates it tomanifest.json; usemake set-description DESC='...'(never hand-edit the JSON). The portal's one-liner refreshes on the next scan after release.Long "About" — repo-extracted from the README on scan. Verified on the 0.11.39 portal scan (2026-07-04): the About rendered the README's top-of-file content — from the "Available in the directory" line through the "New to MCP?" aside — verbatim. This supersedes the earlier belief that the About was portal-only and decoupled from the repo: editing the README opening does change the About on the next scan. Consequence: the README opening now doubles as the directory About, so author it to read well in both places — README-only chrome (the "Available in the directory" self-link, which is circular on the portal; "Quick Start is three steps", which points at a section the About doesn't render) reads awkwardly there. (Historical note: Obsidian did seed a decoupled portal-side About during the community.obsidian.md migration; at some point the portal switched to extracting from the README. Trust a fresh scan over this doc if they diverge again.)
Reading the scorecard as free signal — make scorecard
The public plugin page (community.obsidian.md/plugins/semantic-vault-mcp)
renders an automated Health grade and Review scan — deterministic
static analysis, not an LLM. It is free signal we can pull without logging in:
make scorecard # prose + freshness delta, for reading
node scripts/scorecard.mjs --json # one JSON line, for diffing across releasesKey facts about this tool:
Freshness is not guaranteed. A fresh scan is only triggered from the authenticated developer portal. The public page reflects the last release Obsidian scanned, so the script reports a
freshnessdelta (portal version vsmanifest.json).STALEmeans a logged-in re-scan is still needed.Drift guard. The findings come from Obsidian's Next.js RSC payload, so the parser is coupled to their internal serialization. If the page structure changes, the script exits non-zero with a
SCRAPER DRIFTbanner — that means reviewscripts/scorecard.mjs, not that the scorecard is clean. The scorecard body itself never gates anything.
Known accepted review findings
The full submit review passed (0.11.23). Not every finding is a defect — several are deliberate trade-offs or false positives. Do not "fix" these by reverting the decision behind them; they were analysed and accepted:
.mcpbadditional files (Releases, Recommendation) — expected. Per ADR-102, releases intentionally ship the.mcpbbundles soreleases/latest/download/obsidian-mcp.mcpb(the plugin Settings download) resolves. Clearing it would break ADR-102. Confirmed non-gating.Direct filesystem access (Behavior, Warning) —
fsis used inpath-validator.ts(boundary enforcement viarealpathSync— itself a security control) andcertificate-manager.ts(self-signed TLS certs). Load-bearing; cannot remove without dropping HTTPS.Vault enumeration (Behavior, Recommendation) —
vault.getFilesetc. is the plugin's core purpose (semantic search / graph). By design.Clipboard access (Behavior, Recommendation) — write-only, user-initiated (copy API key / copy buttons). Benign.
README "unfilled placeholder text" (Warning) — false positive. No real placeholders exist; the heuristic trips on legitimate markdown badge/link labels (
[BRAT],[MIT], …). Mangling valid markdown to appease it is the wrong action — leave it."… scan not available" disclosures — neutral. Where Obsidian's malware/obfuscation scanners do not run, that is not a failure. The dependency scan does run, so treat a regression there as real, not a disclosure.
The portal scan and local
npm auditcan diverge, and the local audit is the leading indicator — it sees advisories published since the last portal scan. Re-runnpm auditbefore reading a portal result as current.
Reading npm audit — procedure, not a headline
The bare vulnerability count conflates two things with very different consequences for a plugin that ships a bundle: what reaches users, and what only runs on the maintainer's build machine. Judge them separately, in this order.
npm audit --omit=devis the number that gates a release. Anything it reports reaches users throughmain.js. Non-zero means fix now — per the supply-chain rule above, security fixes are exempt from the 7-day hold.If that is zero, the bare count is not a release problem. Confirm the remainder is dev-only rather than assuming it:
npm ls <pkg> --omit=devshows whether a package is in the production tree at all, and a production copy can sit outside an advisory's range while an older nested copy inside the toolchain sits within it. Note the count can be much larger than the number of distinct advisories — one issue in a widely-shared transitive package fans out across every dependent, so read the advisory IDs, not the total.Do not run
npm audit fix --forceto clear a dev-only finding. It moves dev dependencies across majors. Breaking the toolchain that verifies the security work is a worse trade than carrying a vulnerability reachable only by our own build processing adversarial input. Plainnpm audit fix(lockfile-only, nopackage.jsonchange) is the tool for this job.Record the split in the release notes when the two numbers differ, so the next reader is not startled by a large count that represents no user exposure.
Do not chase the headline count to zero — the same trap as the
new Function scorecard finding below. Zero on --omit=dev is the goal; the
bare count is context.
Dynamic code execution — the Bases-evaluator new Function (the
exploitable vector: arbitrary JS from a synced/shared .base) is removed
per ADR-201, implemented in #180 (PR #185 corpus/baseline, PR #186
expression-eval swap). The evaluator now parses with expression-eval (jsep
grammar, no globals) plus a tested constructor/__proto__/prototype/
this denylist; a differential corpus proves behavioural parity.
Caveat for future scans: grep "new Function" main.js is not zero by
design. The residual occurrences are transitive-dependency codegen — ajv
@6.14.0 schema-validator compilation + a library deprecation shim — a
different, library-internal class not reachable from vault content. They
were already in 0.11.25's bundle, the release that passed full review with
only the fs Warning, so they were non-gating then. The "Dynamic Code
Execution" Recommendation was attributed to the Bases path specifically;
this clears that path.
Settled at 0.11.42: the re-scan does still raise the "Dynamic Code
Execution" Recommendation, and it is the transitive class — verified at scan
time: src/ contains zero new Function/eval (the only match is a
comment in expression-evaluator.ts saying it avoids them), while main.js
has exactly 3, all library-internal (1× depd deprecation shim, 2× ajv's
makeValidate compiler). The heuristic greps the bundle, not the reachable
call graph, so ADR-201 cannot make it go away. It is a Recommendation, never
an Error — do not chase it to zero; the closed Bases vector is what
mattered and it stays closed.
Actionable findings became issues/PRs: #163/#164/#170 (SSL + attestation, shipped), #171/#173 (build-dep + CSS, shipped), #174 (js-yaml, shipped), #180 (sandboxed Bases evaluator, PR #185/#186), #176 (this doc). Scorecard CI-gate idea: #165.
Passing the source-code review — fix, never suppress
The portal's Source code check forbids disabling a specific set of lint
rules. An inline eslint-disable for @typescript-eslint/no-deprecated,
obsidianmd/prefer-window-timers, or obsidianmd/no-global-this is
itself a gating Error ("Disabling 'X' is not allowed"). It also errors on
any directive comment with no inline description ("Unexpected undescribed
directive comment"). So the reflex "just eslint-disable it" fails the
review — louder than the warning it was hiding. Fix the code or use a
non-deprecated path; never suppress these.
Nuance: our local eslint config disabling a rule for a whole file surfaces as a non-gating Warning in the review (tolerated). It's the inline directive comment that's banned. And the review is fail-fast — it halts at the first Error, so clearing one can reveal the next.
Patterns that worked (the 0.11.32 → 0.11.33 cleanup):
PluginSettingTab.display()deprecated (1.13.0) → superseded. Since 0.12.7minAppVersionis 1.13.0 and the tab is declarative: every setting is acontrolitem ingetSettingDefinitions(), custom blocks are namedrenderitems, side effects live in asetControlValueoverride, and re-renders callupdate()(#224).display()no longer exists in source.ButtonComponent.setWarning()deprecated →setDestructive()(1.13.0), now thatminAppVersionallows it (#224; the interimsetClass('mod-warning')workaround from #229 is gone).Global
setTimeout/setIntervalandglobalThis→window.*/window.console, and aliaswindow→globalThisintests/setup.tsso the node test env resolves them (#227).Low-level
Serverdeprecated;McpServer.registerToolwants Zod → constructMcpServer(non-deprecated) and register our raw JSON-Schema handlers on its.serveraccessor (a non-deprecated property); theServersymbol then never appears in source (#230). VerifiedMcpServerregisters its own tool handlers lazily (only viaregisterTool, which we never call), so it can't shadow ours — no empty-tools/listregression (cf. #221).
Allowed: a described disable of a non-forbidden rule (e.g.
no-require-imports, no-control-regex with -- reason) passes review — the
ban is that specific rule set, not all directives. minAppVersion is 1.13.0
(#224), so the 1.13.0 APIs are available outright; obsidianmd/no-unsupported-api
reads that field from manifest.json, and MIN_OBSIDIAN in the Makefile feeds
versions.json at release — keep the two equal.
Keep eslint-plugin-obsidianmd current, or local lint lies
The portal's source-code review runs its own copy of this plugin. When ours lags,
npm run lint passes while the portal reports warnings we cannot reproduce —
findings then arrive after a release is already cut. A rule can even be present
in our installed dist/ and still never fire, because it isn't wired into the
recommended config yet in that version; the file existing proves nothing.
Before a release scan, confirm parity:
node -e "console.log(require('eslint-plugin-obsidianmd/package.json').version)"
npm view eslint-plugin-obsidianmd versionIf they differ, upgrade and re-lint before scanning. A new minor of this plugin usually means new rules, and it is cheaper to see them locally than to read them off a scorecard. Treat a warning that only the portal can see as a tooling gap, not as a portal quirk. This upgrade does not wait on the 7-day hold — see the analysis-tooling exemption in the supply-chain section above.
Do not satisfy a rule by faking the implementation. The
prefer-setting-definitions warning can be silenced with a
getSettingDefinitions() that declares a few settings, which would leave users a
settings search that finds some and silently misses the rest. That is worse than
the warning, and the same failure mode as suppressing a rule: the check goes
green while the real problem grows. Either implement it fully or leave the
warning and track the work.
Important Notes
Critical Path: The ObsidianAPI abstraction layer is the cornerstone of this architecture
Performance Focus: Every operation should demonstrate measurable improvement
Compatibility First: When in doubt, maintain compatibility over new features
Plugin Ecosystem: Consider integration opportunities with other Obsidian plugins
Community Feedback: BRAT testing phase is crucial for identifying issues
This plugin represents the evolution of Obsidian AI integration. Maintain the highest standards as we build the definitive solution for AI-Obsidian connectivity.
236 files · 218 not served here
- .claude-github/design.md (not served here)
- .claude-github/issue-32-response.md (not served here)
- .github-tracking (not served here)
- .github/FUNDING.yml (not served here)
- .github/ISSUE_TEMPLATE/bug_report.md (not served here)
- .github/ISSUE_TEMPLATE/feature_request.md (not served here)
- .github/dependabot.yml (not served here)
- .github/pull_request_template.md (not served here)
- .github/workflows/build.yml (not served here)
- .github/workflows/feature-release.yml (not served here)
- .github/workflows/release.yml (not served here)
- .github/workflows/scorecard-watch.yml (not served here)
- .github/workflows/security.yml (not served here)
- .github/workflows/test.yml (not served here)
- .gitignore (not served here)
- ATTRIBUTION.md
- AUTOGINEER-RUNS.md
- CHANGELOG.md
- CLAUDE.md
- CODE_OF_CONDUCT.md
- CONTRIBUTING.md
- LICENSE
- Makefile (not served here)
- README.md
- SECURITY.md
- docs/PROJECT_STRUCTURE.md
- docs/Plugin_UI_July_2025.png (not served here)
- docs/SECURITY-IMPLEMENTATION.md
- docs/adr/ADR-001-adopting-adr-format.md (not served here)
- docs/adr/ADR-002-search-facade-architecture.md (not served here)
- docs/adr/ADR-003-presentation-facade.md (not served here)
- docs/architecture/INDEX.md (not served here)
- docs/architecture/adr.yaml (not served here)
- docs/architecture/core/ADR-100-remove-concurrent-mode-toggle-and-simplify-connection-setup.md (not served here)
- docs/architecture/core/ADR-101-tree-based-mcp-tool-visibility-gating.md (not served here)
- docs/architecture/core/ADR-102-ship-mcpb-bundle-as-primary-claude-desktop-onboarding.md (not served here)
- docs/architecture/core/ADR-103-tls-certificate-and-key-storage-strategy-for-localhost-https.md (not served here)
- docs/architecture/core/ADR-104-offload-cpu-bound-semantic-operations-to-worker-threads-and-deconflict-the-sse-route.md (not served here)
- docs/architecture/core/ADR-105-remove-dormant-worker-offload-path-partial-reversal-of-adr-104.md (not served here)
- docs/architecture/core/ADR-106-client-driven-session-re-initialization-via-spec-compliant-http-404.md (not served here)
- docs/architecture/core/ADR-107-network-exposure-modes-as-a-classified-state-machine.md (not served here)
- docs/architecture/core/ADR-108-consolidate-read-only-enforcement-onto-the-security-layer-and-make-it-live.md (not served here)
- docs/architecture/core/ADR-109-outbound-web-fetch-is-off-by-default-and-range-filtered-when-enabled.md (not served here)
- docs/architecture/delivery/ADR-300-single-branch-release-strategy-with-prerelease-promote.md (not served here)
- docs/architecture/tools/ADR-200-close-cli-parity-gaps-add-daily-notes-tasks-templates-and-properties-operations.md (not served here)
- docs/architecture/tools/ADR-201-replace-new-function-with-a-sandboxed-expression-evaluator-for-bases.md (not served here)
- docs/architecture/tools/ADR-202-split-semantic-router-monolith-into-per-operation-modules.md (not served here)
- docs/architecture/tools/ADR-203-faithful-by-default-content-reads-concise-by-default-tool-results.md (not served here)
- docs/architecture/tools/ADR-204-gated-command-palette-execution.md (not served here)
- docs/bases-implementation-fixes.md
- docs/bases-implementation-status.md
- docs/bases-implementation.md
- docs/bases-mcp-reference.md
- docs/graph-traversal.md
- docs/scripts/adr (not served here)
- docs/tools/graph.md (not served here)
- docs/tools/system.md (not served here)
- docs/tools/vault.md (not served here)
- docs/troubleshooting.md
- esbuild.config.mjs (not served here)
- eslint.config.mts (not served here)
- jest.config.js (not served here)
- manifest.json
- mcpb/manifest.json (not served here)
- mcpb/server.js (not served here)
- package-lock.json (not served here)
- package.json (not served here)
- scripts/build-mcpb.mjs (not served here)
- scripts/coverage-map.mjs (not served here)
- scripts/make-mcpb.mjs (not served here)
- scripts/scorecard-baseline.json (not served here)
- scripts/scorecard-baseline.mjs (not served here)
- scripts/scorecard-findings.mjs (not served here)
- scripts/scorecard-gate.mjs (not served here)
- scripts/scorecard.mjs (not served here)
- scripts/set-description.mjs (not served here)
- src/config/response-limits.json (not served here)
- src/config/workflow-schema.json (not served here)
- src/config/workflows.json (not served here)
- src/formatters/dataview.ts (not served here)
- src/formatters/graph.ts (not served here)
- src/formatters/index.ts (not served here)
- src/formatters/search.ts (not served here)
- src/formatters/system.ts (not served here)
- src/formatters/utils.ts (not served here)
- src/formatters/vault.ts (not served here)
- src/formatters/view.ts (not served here)
- src/indexing/adaptive-index.ts (not served here)
- src/indexing/fragment-retriever.ts (not served here)
- src/indexing/proximity-index.ts (not served here)
- src/indexing/semantic-chunk-index.ts (not served here)
- src/main.ts (not served here)
- src/mcp-server.ts (not served here)
- src/plugin-settings.ts (not served here)
- src/security/http-auth.ts (not served here)
- src/security/index.ts (not served here)
- src/security/mcp-ignore-manager.ts (not served here)
- src/security/path-validator.ts (not served here)
- src/security/safe-fetch.ts (not served here)
- src/security/secure-obsidian-api.ts (not served here)
- src/security/url-validator.ts (not served here)
- src/security/vault-security-manager.ts (not served here)
- src/semantic/operations/bases.ts (not served here)
- src/semantic/operations/edit.ts (not served here)
- src/semantic/operations/graph.ts (not served here)
- src/semantic/operations/router-context.ts (not served here)
- src/semantic/operations/shared.ts (not served here)
- src/semantic/operations/system.ts (not served here)
- src/semantic/operations/vault.ts (not served here)
- src/semantic/operations/view.ts (not served here)
- src/semantic/operations/workflow.ts (not served here)
- src/semantic/router.ts (not served here)
- src/semantic/state-tokens.ts (not served here)
- src/tools/dataview-tool.ts (not served here)
- src/tools/fetch.ts (not served here)
- src/tools/graph-search-tag-traversal.ts (not served here)
- src/tools/graph-search-tool.ts (not served here)
- src/tools/graph-search-traversal.ts (not served here)
- src/tools/graph-search.ts (not served here)
- src/tools/graph-tag-tool.ts (not served here)
- src/tools/semantic-tools.ts (not served here)
- src/tools/window-edit.ts (not served here)
- src/types/bases-yaml.ts (not served here)
- src/types/bases.ts (not served here)
- src/types/fragment.ts (not served here)
- src/types/obsidian.ts (not served here)
- src/types/semantic.ts (not served here)
- src/utils/__tests__/response-limiter.test.ts (not served here)
- src/utils/advanced-search.ts (not served here)
- src/utils/bases-api.ts (not served here)
- src/utils/bases-reference.ts (not served here)
- src/utils/certificate-manager.ts (not served here)
- src/utils/connection-pool.ts (not served here)
- src/utils/content-buffer.ts (not served here)
- src/utils/content-handler.ts (not served here)
- src/utils/debug.ts (not served here)
- src/utils/expression-evaluator.ts (not served here)
- src/utils/file-lock.ts (not served here)
- src/utils/file-reader.ts (not served here)
- src/utils/formula-engine.ts (not served here)
- src/utils/fuzzy-match.ts (not served here)
- src/utils/graph-traversal.ts (not served here)
- src/utils/image-handler.ts (not served here)
- src/utils/mcp-server-pool.ts (not served here)
- src/utils/network-classifier.ts (not served here)
- src/utils/obsidian-api.ts (not served here)
- src/utils/obsidian-commands.ts (not served here)
- src/utils/plugin-detector.ts (not served here)
- src/utils/response-limiter.ts (not served here)
- src/utils/search-core.ts (not served here)
- src/utils/search-facade.ts (not served here)
- src/utils/session-manager.ts (not served here)
- src/utils/yaml-bridge.ts (not served here)
- src/validation/input-validator.ts (not served here)
- src/version.ts (not served here)
- styles.css (not served here)
- sync-version.mjs (not served here)
- test-concurrent.js (not served here)
- tests/__mocks__/obsidian.ts (not served here)
- tests/bases-expression-evaluator.test.ts (not served here)
- tests/bases-router-dispatch.test.ts (not served here)
- tests/bases-yaml.test.ts (not served here)
- tests/bridge-bootstrap.test.ts (not served here)
- tests/bridge-self-heal.test.ts (not served here)
- tests/combine-inline-router.test.ts (not served here)
- tests/combine-inline.test.ts (not served here)
- tests/dataview-integration.test.ts (not served here)
- tests/dispatch-param-guards.test.ts (not served here)
- tests/edit-router-dispatch.test.ts (not served here)
- tests/file-lock-edit-serialization.test.ts (not served here)
- tests/fixtures/base-corpus.ts (not served here)
- tests/fixtures/scorecard-page.html (not served here)
- tests/formatters/graph-vault-stats.test.ts (not served here)
- tests/formatters/path-fidelity.test.ts (not served here)
- tests/formatters/read-frontmatter-dedup.test.ts (not served here)
- tests/formatters/search-signal-honesty.test.ts (not served here)
- tests/formatters/summary-footer.test.ts (not served here)
- tests/formatters/system-commands.test.ts (not served here)
- tests/fragments-path-scope.test.ts (not served here)
- tests/fuzzy-match.test.ts (not served here)
- tests/graph-ignore-exclusion.test.ts (not served here)
- tests/graph-node-title.test.ts (not served here)
- tests/graph-router-dispatch.test.ts (not served here)
- tests/graph-search-traversal.test.ts (not served here)
- tests/graph-search.test.ts (not served here)
- tests/graph-statistics-vault-wide.test.ts (not served here)
- tests/list-files-recursive.test.ts (not served here)
- tests/mcp-server-pool-tool-timeout.test.ts (not served here)
- tests/mcp-server.test.ts (not served here)
- tests/mcp-session-reinit.test.ts (not served here)
- tests/network-classifier.test.ts (not served here)
- tests/network-exposure-integration.test.ts (not served here)
- tests/patch-operations.test.ts (not served here)
- tests/plugin-settings.test.ts (not served here)
- tests/read-only-mode.test.ts (not served here)
- tests/recursive-copy.test.ts (not served here)
- tests/scorecard-gate.test.ts (not served here)
- tests/scorecard.test.ts (not served here)
- tests/search-tag-operator.test.ts (not served here)
- tests/security/active-file-path-checks.test.ts (not served here)
- tests/security/config-dir-protection.test.ts (not served here)
- tests/security/fetch-tool-gate.test.ts (not served here)
- tests/security/fetch-web-enumeration.test.ts (not served here)
- tests/security/http-auth.test.ts (not served here)
- tests/security/mcp-ignore-manager.test.ts (not served here)
- tests/security/mcpignore-readonly.test.ts (not served here)
- tests/security/param-validation.test.ts (not served here)
- tests/security/path-validator.test.ts (not served here)
- tests/security/read-only-action-matrix.test.ts (not served here)
- tests/security/read-only-liveness.test.ts (not served here)
- tests/security/safe-fetch.test.ts (not served here)
- tests/security/session-api-enforcement.test.ts (not served here)
- tests/security/system-execute.test.ts (not served here)
- tests/security/tls-cert-verification.test.ts (not served here)
- tests/security/tls-min-version.test.ts (not served here)
- tests/security/tool-list-liveness.test.ts (not served here)
- tests/security/tool-visibility.test.ts (not served here)
- tests/security/url-validator.test.ts (not served here)
- tests/security/vault-security-manager.test.ts (not served here)
- tests/security/write-path-containment.test.ts (not served here)
- tests/server-info-version.test.ts (not served here)
- tests/setup.ts (not served here)
- tests/sse-socket-timeout.test.ts (not served here)
- tests/system-router-dispatch.test.ts (not served here)
- tests/test-contract.test.ts (not served here)
- tests/validation/input-validator.test.ts (not served here)
- tests/vault-read-fidelity.test.ts (not served here)
- tests/vault-rename-extension.test.ts (not served here)
- tests/vault-replace.test.ts (not served here)
- tests/view-router-dispatch.test.ts (not served here)
- tests/web-fetch-large-response.test.ts (not served here)
- tests/workflow-router-dispatch.test.ts (not served here)
- tsconfig.json (not served here)
- version-bump.mjs (not served here)
- versions.json (not served here)
- wiki/Design.md (not served here)
Advantages
- No external Node process to launch, no separate REST-API plugin to bridge through: the server is the plugin. evidence: README.md
- Every operation respects the permissions you set — a read-only mode, per-operation controls, and path allow/block lists. evidence: README.md
Limitations
- MCP clients reject self-signed certificates by default, so you need to explicitly trust it before connecting over HTTPS. evidence: README.md
Security
Risk level: Medium risk
This brain runs
Agent instructions that run or fetch something (42)
CLAUDE.md:Test locally with `npm run build`CLAUDE.md:Click **Run workflow**CLAUDE.md:Click **Run**CLAUDE.md:git tag -d X.Y.Z && git push origin :refs/tags/X.Y.Z· uses the networkCLAUDE.md:Users install via: `aaronsb/obsidian-mcp-plugin` in BRATCLAUDE.md:**Pre-releases**: All releases ship as prereleases by default (`make release-patch` etc.)CLAUDE.md:**Promoting to stable**: When a release is bounded and proven, run `make promote` (or `make promote TAG=X.Y.Z`) to flip it from prerelease → stable and mark it as GitHub's "Latest" release.CLAUDE.md:"package": "npm run build && npm run test && node package-release.js"CLAUDE.md:**ALWAYS run these commands before pushing to GitHub:**CLAUDE.md:npm run buildCLAUDE.md:# 2. Run linting to ensure code qualityCLAUDE.md:npm run lintCLAUDE.md:# 3. Run tests to catch regressionsCLAUDE.md:npm testCLAUDE.md:git add -A && git commit -m "..."CLAUDE.md:git push origin main· uses the networkCLAUDE.md:npm run build && npm run lint && npm test && echo "✅ All checks passed!"CLAUDE.md:npm supply-chain attacks have been ticking up — malicious package versions get published, ingested by automation, then discovered/yanked days later.CLAUDE.md:The exemption exists because the hold otherwise fights our own freshness goal: it delays exactly the vuln patches that Obsidian's plugin review (and `npm audit`) flag, leaving us knowingly exposed to a *named, real* CVE to guard against a *hypothetical* malicious republish.CLAUDE.md:**Security fix → land it now.** If a dependabot/manual upgrade resolves a flagged vulnerability (dependabot security PR, `npm audit` advisory, or an Obsidian-review dependency warning), merge as soon as it's green regardless of version age.CLAUDE.md:The same split applies to manual `npm install` / `npm update`: security fixes immediately, routine pins to versions older than 7 days.CLAUDE.md:Re-run `npm audit` after each merge batch to see what residual exposure remains.CLAUDE.md:This is not zero-risk — an ESLint plugin executes on the maintainer's machine during `npm run lint`, so the exposure moves from users to the developer rather than disappearing.CLAUDE.md:Install scripts are blocked pending approval (`npm install-scripts ls` shows what is waiting), but that is **npm 12+ default behaviour, not something this repo enforces** — there is no `.npmrc` or `package.json` setting pinning it.CLAUDE.md:Approve install scripts one package at a time and never with `--all`;CLAUDE.md:Consequence: after a plugin is approved/updated on the portal, there is a **propagation lag** before it appears in the in-app browser search — the mirror bot has to run, then the app refreshes its cached list (a restart helps *only after* the mirror includes you).CLAUDE.md:`make promote` now auto-updates **real users**, not just BRAT testers.CLAUDE.md:`versions.json` must contain a `"<version>": "<minAppVersion>"` entry matching `manifest.json` (`make release-*` maintains this).CLAUDE.md:Run `make promote` to flip the proven release to stable + "Latest".CLAUDE.md:The developer portal offers a **"preview a branch scan"** that accepts a branch, tag, or commit SHA — use it to confirm a release candidate passes Obsidian's checks *before* running `make promote`.CLAUDE.md:Treat it as a validation/dry-run tool: end-user installs and updates still come from the matching stable release tag's assets, not from a scanned branch.CLAUDE.md:make scorecard # prose + freshness delta, for readingCLAUDE.md:node scripts/scorecard.mjs --json # one JSON line, for diffing across releasesCLAUDE.md:The **dependency** scan *does* run, so treat a regression there as real, not a disclosure.CLAUDE.md:The portal scan and local `npm audit` **can diverge**, and the local audit is the leading indicator — it sees advisories published since the last portal scan.CLAUDE.md:Re-run `npm audit` before reading a portal result as current.CLAUDE.md:**`npm audit --omit=dev` is the number that gates a release.** Anything it reports reaches users through `main.js`.CLAUDE.md:**If that is zero, the bare count is not a release problem.** Confirm the remainder is dev-only rather than assuming it: `npm ls <pkg> --omit=dev` shows whether a package is in the production tree at all, and a production copy can sit *outside* an advisory's range while an older nested …[+41 chars]CLAUDE.md:Plain `npm audit fix` (lockfile-only, no `package.json` change) is the tool for this job.CLAUDE.md:When ours lags, `npm run lint` passes while the portal reports warnings we cannot reproduce — findings then arrive *after* a release is already cut.CLAUDE.md:node -e "console.log(require('eslint-plugin-obsidianmd/package.json').version)"CLAUDE.md:npm view eslint-plugin-obsidianmd version
Install scripts (1)
Makefile(make install):npm install
Plugin code (1)
manifest.json:runs inside Obsidian once the plugin is enabled
- Medium risk: runs-instruction-instruction-network (CLAUDE.md:136)
- Medium risk: runs-instruction-instruction-network (CLAUDE.md:202)
- Low risk: scripts-present (esbuild.config.mjs)
- Low risk: scripts-present (scripts/build-mcpb.mjs)
- Low risk: scripts-present (scripts/scorecard-findings.mjs)
- Low risk: scripts-present (scripts/scorecard.mjs)
- Low risk: scripts-present (src/formatters/dataview.ts)
- Low risk: scripts-present (src/formatters/graph.ts)
- Low risk: scripts-present (src/formatters/index.ts)
- Low risk: scripts-present (src/formatters/search.ts)
- Low risk: scripts-present (src/formatters/system.ts)
- Low risk: scripts-present (src/formatters/utils.ts)
- Low risk: scripts-present (src/formatters/vault.ts)
- Low risk: scripts-present (src/formatters/view.ts)
- Low risk: scripts-present (src/indexing/adaptive-index.ts)
- Low risk: scripts-present (src/indexing/fragment-retriever.ts)
- Low risk: scripts-present (src/indexing/proximity-index.ts)
- Low risk: scripts-present (src/indexing/semantic-chunk-index.ts)
- Low risk: scripts-present (src/main.ts)
- Low risk: scripts-present (src/mcp-server.ts)
- Low risk: scripts-present (src/plugin-settings.ts)
- Low risk: scripts-present (src/security/http-auth.ts)
- Low risk: scripts-present (src/security/index.ts)
- Low risk: scripts-present (src/security/mcp-ignore-manager.ts)
- Low risk: scripts-present (src/security/path-validator.ts)
- Low risk: scripts-present (src/security/safe-fetch.ts)
- Low risk: scripts-present (src/security/secure-obsidian-api.ts)
- Low risk: scripts-present (src/security/url-validator.ts)
- Low risk: scripts-present (src/security/vault-security-manager.ts)
- Low risk: scripts-present (src/semantic/operations/bases.ts)
- Low risk: scripts-present (src/semantic/operations/edit.ts)
- Low risk: scripts-present (src/semantic/operations/graph.ts)
- Low risk: scripts-present (src/semantic/operations/router-context.ts)
- Low risk: scripts-present (src/semantic/operations/shared.ts)
- Low risk: scripts-present (src/semantic/operations/system.ts)
- Low risk: scripts-present (src/semantic/operations/vault.ts)
- Low risk: scripts-present (src/semantic/operations/view.ts)
- Low risk: scripts-present (src/semantic/operations/workflow.ts)
- Low risk: scripts-present (src/semantic/router.ts)
- Low risk: scripts-present (src/semantic/state-tokens.ts)
- Low risk: scripts-present (src/tools/dataview-tool.ts)
- Low risk: scripts-present (src/tools/fetch.ts)
- Low risk: scripts-present (src/tools/graph-search-tag-traversal.ts)
- Low risk: scripts-present (src/tools/graph-search-tool.ts)
- Low risk: scripts-present (src/tools/graph-search-traversal.ts)
- Low risk: scripts-present (src/tools/graph-search.ts)
- Low risk: scripts-present (src/tools/graph-tag-tool.ts)
- Low risk: scripts-present (src/tools/semantic-tools.ts)
- Low risk: scripts-present (src/tools/window-edit.ts)
- Low risk: scripts-present (src/types/bases-yaml.ts)
The plugin you install is release 0.13.0, which AutoGineer scanned.
Attribution and licence
- Created by
- Aaron Bockelie
- Declared authors
- Aaron Bockelie (declared in package.json)
- Aaron Bockelie (declared in manifest.json)
- Publisher
- Aaron Bockelie (Community)
- Source
- aaronsb/obsidian-mcp-plugin · commit 103ee96
- Licence
- MIT License (files served here)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Aaron Bockelie.
Install from source
218 of its files are not served here, so there is no ZIP. aaronsb/obsidian-mcp-plugin at 103ee96