Initial working plugin for BRAT testing

- Complete Obsidian plugin structure with TypeScript build pipeline
- Basic plugin lifecycle (onload/onunload) with settings management
- Settings UI for HTTP server configuration (ports, SSL, debug)
- Status bar indicator and restart command
- Ready for BRAT installation and testing

Phase 1 foundation complete - plugin loads successfully in Obsidian
This commit is contained in:
Aaron Bockelie 2025-06-27 11:00:05 -05:00
commit 8ca6fc4942
15 changed files with 8426 additions and 0 deletions

123
.gitignore vendored Normal file
View file

@ -0,0 +1,123 @@
# Logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
.pnpm-debug.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variable files
.env
.env.development.local
.env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# Obsidian workspace
.obsidian/
# Plugin build outputs
main.js
*.js.map
data.json

287
ARCHITECTURE.md Normal file
View file

@ -0,0 +1,287 @@
# Technical Architecture
## ObsidianAPI Abstraction Layer - The Critical Design Pattern
The success of this hybrid plugin depends on preserving and enhancing the `ObsidianAPI` abstraction layer. This allows us to reuse all existing MCP server logic while gaining the performance benefits of direct plugin API access.
## Current vs. New Implementation
### Current Implementation Analysis
The existing `ObsidianAPI` class in `obsidian-semantic-mcp/src/utils/obsidian-api.ts` provides:
```typescript
export class ObsidianAPI {
private client: AxiosInstance; // HTTP client
// Server operations
async getServerInfo()
async getActiveFile(): Promise<ObsidianFile>
async updateActiveFile(content: string)
// Vault operations
async listFiles(directory?: string)
async getFile(path: string): Promise<ObsidianFileResponse>
async createFile(path: string, content: string)
async updateFile(path: string, content: string)
async deleteFile(path: string)
// Search operations
async searchSimple(query: string)
async searchPaginated(query: string, page: number, pageSize: number)
// Advanced operations
async patchVaultFile(path: string, params: PatchParams)
async openFile(path: string)
async getCommands()
async executeCommand(commandId: string)
}
```
### New Implementation Strategy
Replace HTTP calls with direct Obsidian API calls while maintaining identical interface:
```typescript
import { App, TFile, TFolder, Vault, Workspace } from 'obsidian';
export class ObsidianAPI {
private app: App; // Direct Obsidian app reference
constructor(app: App) {
this.app = app;
}
// Maintain exact same method signatures
async getServerInfo() {
return {
authenticated: true,
ok: true,
service: 'Obsidian MCP Plugin',
version: this.app.vault.adapter.version || '1.0.0'
};
}
async getActiveFile(): Promise<ObsidianFile> {
const activeFile = this.app.workspace.getActiveFile();
if (!activeFile) {
throw new Error('No active file');
}
const content = await this.app.vault.read(activeFile);
return {
path: activeFile.path,
content,
stat: activeFile.stat
};
}
async listFiles(directory?: string): Promise<string[]> {
const folder = directory
? this.app.vault.getAbstractFileByPath(directory) as TFolder
: this.app.vault.getRoot();
if (!folder || !(folder instanceof TFolder)) {
throw new Error(`Directory not found: ${directory || 'root'}`);
}
return folder.children.map(file => file.name);
}
async getFile(path: string): Promise<ObsidianFileResponse> {
const file = this.app.vault.getAbstractFileByPath(path);
if (!file || !(file instanceof TFile)) {
throw new Error(`File not found: ${path}`);
}
// Handle images vs text files
if (this.isImageFile(path)) {
const arrayBuffer = await this.app.vault.readBinary(file);
return this.processImageResponse(arrayBuffer, path);
} else {
const content = await this.app.vault.read(file);
return { content, path, stat: file.stat };
}
}
async searchSimple(query: string): Promise<any[]> {
// Use Obsidian's built-in search or implement file-based search
return this.performDirectSearch(query);
}
// ... implement all other methods with direct API calls
}
```
## Performance Improvements
### HTTP vs. Direct API Comparison
| Operation | HTTP (Current) | Direct API (New) | Improvement |
|-----------|----------------|------------------|-------------|
| File Read | ~50-100ms | ~1-5ms | 10-50x faster |
| File List | ~30-60ms | ~1-3ms | 10-20x faster |
| Search | ~100-300ms | ~10-50ms | 5-10x faster |
| Patch Operations | ~80-150ms | ~5-15ms | 10-15x faster |
### Direct API Advantages
1. **No Network Overhead**: Eliminate HTTP request/response cycles
2. **No Serialization**: Direct object access instead of JSON serialization
3. **Real-time Updates**: Direct access to Obsidian's reactive system
4. **Enhanced Metadata**: Access to internal file properties and relationships
5. **Memory Efficiency**: Shared memory space instead of separate processes
## Enhanced Capabilities
### Obsidian-Native Features
With direct plugin access, we can provide capabilities impossible via HTTP:
```typescript
// Real-time file watching
this.app.vault.on('modify', (file) => {
this.notifyMCPClients('file-changed', { path: file.path });
});
// Access to internal search index
const searchResults = this.app.internalPlugins.getPluginById('global-search')
?.instance?.searchIndex?.search(query);
// Direct workspace manipulation
this.app.workspace.openLinkText(linkText, sourcePath);
// Plugin ecosystem integration
const dataviewAPI = this.app.plugins.plugins['dataview']?.api;
if (dataviewAPI) {
const pages = dataviewAPI.pages();
// Enhanced semantic operations with Dataview integration
}
```
### Enhanced Search Implementation
Combine multiple search strategies for comprehensive results:
```typescript
async performEnhancedSearch(query: string): Promise<SearchResult[]> {
const results: SearchResult[] = [];
// 1. Obsidian's native search (if available)
try {
const nativeResults = await this.searchWithObsidianIndex(query);
results.push(...nativeResults);
} catch (e) {
// Fallback to file-based search
}
// 2. Filename-based search (for media files)
const filenameResults = await this.searchByFilename(query);
results.push(...filenameResults);
// 3. Tag and link search
const metadataResults = await this.searchMetadata(query);
results.push(...metadataResults);
// 4. Plugin integration (Dataview, etc.)
const pluginResults = await this.searchWithPlugins(query);
results.push(...pluginResults);
return this.deduplicateAndSort(results);
}
```
## MCP Protocol Integration
### HTTP MCP Server Embedding
```typescript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import express from 'express';
export class MCPHttpServer {
private mcpServer: Server;
private httpServer: express.Application;
private obsidianAPI: ObsidianAPI;
constructor(app: App) {
this.obsidianAPI = new ObsidianAPI(app);
this.setupMCPServer();
this.setupHttpEndpoints();
}
private setupHttpEndpoints() {
// REST API compatibility endpoints
this.httpServer.get('/vault/:path', async (req, res) => {
const result = await this.obsidianAPI.getFile(req.params.path);
res.json(result);
});
// MCP protocol endpoint
this.httpServer.post('/mcp', async (req, res) => {
// Handle MCP protocol over HTTP
const mcpResponse = await this.handleMCPRequest(req.body);
res.json(mcpResponse);
});
}
}
```
## Plugin Lifecycle Integration
### Obsidian Plugin Structure
```typescript
import { Plugin, Setting, PluginSettingTab } from 'obsidian';
export default class ObsidianMCPPlugin extends Plugin {
private mcpServer: MCPHttpServer;
private obsidianAPI: ObsidianAPI;
async onload() {
console.log('Loading Obsidian MCP Plugin');
// Initialize API abstraction layer
this.obsidianAPI = new ObsidianAPI(this.app);
// Start HTTP server for MCP and REST endpoints
this.mcpServer = new MCPHttpServer(this.app);
await this.mcpServer.start();
// Add settings tab
this.addSettingTab(new MCPSettingTab(this.app, this));
// Register commands
this.addCommand({
id: 'restart-mcp-server',
name: 'Restart MCP Server',
callback: () => this.restartMCPServer()
});
}
async onunload() {
console.log('Unloading Obsidian MCP Plugin');
await this.mcpServer.stop();
}
}
```
## Migration Strategy
### Preserving Backward Compatibility
1. **API Interface Preservation**: Exact method signatures maintained
2. **Response Format Compatibility**: Identical JSON response structures
3. **Error Handling Consistency**: Same error types and messages
4. **Configuration Migration**: Automatic settings import from REST API plugin
### Gradual Migration Path
1. **Phase 1**: Plugin provides both HTTP REST and MCP endpoints
2. **Phase 2**: Enhanced features only available via plugin (performance benefits)
3. **Phase 3**: Deprecation notice for separate REST API plugin setup
4. **Phase 4**: Full migration to plugin-native approach
This architecture ensures we can reuse all existing MCP server logic while gaining significant performance improvements and new capabilities through direct Obsidian API integration.

274
CLAUDE.md Normal file
View file

@ -0,0 +1,274 @@
# 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**:
- `ObsidianAPI` class handles only vault operations abstraction
- `MCPServer` class handles only MCP protocol operations
- `HTTPServer` class handles only REST endpoint management
- Plugin 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
```typescript
// 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
```typescript
// 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
### 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 utilities
```
### Testing 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
```json
{
"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"
}
}
```
## Plugin-Specific Guidelines
### Obsidian Plugin Lifecycle
```typescript
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
```typescript
// 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
```typescript
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
1. **Configuration Migration**: Automatically detect and import REST API plugin settings
2. **Port Compatibility**: Default to same ports as REST API plugin
3. **Feature Parity**: All existing functionality must work identically
4. **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
```typescript
/**
* 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
## 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.*

254
PROJECT-PLAN.md Normal file
View file

@ -0,0 +1,254 @@
# Project Implementation Plan
## Overview
This document outlines the phased approach to building the Obsidian MCP Plugin, combining REST API functionality with semantic MCP operations in a single, high-performance plugin.
## Phase 1: Foundation Setup (Week 1)
### Goal: Basic plugin structure with core abstraction layer
#### 1.1 Repository and Build Setup
- [ ] Initialize TypeScript plugin structure
- [ ] Set up build pipeline (tsc + bundling)
- [ ] Create proper manifest.json for Obsidian plugin
- [ ] Configure development workflow with hot reloading
- [ ] Set up testing framework (Jest)
#### 1.2 Core ObsidianAPI Implementation
- [ ] Create new ObsidianAPI class with direct Obsidian App integration
- [ ] Implement core vault operations (getFile, listFiles, createFile, updateFile, deleteFile)
- [ ] Implement active file operations (getActiveFile, updateActiveFile)
- [ ] Add image file handling with binary data support
- [ ] Implement basic error handling and type conversion
#### 1.3 Plugin Lifecycle Integration
- [ ] Create main plugin class extending Obsidian Plugin
- [ ] Implement onload/onunload lifecycle
- [ ] Add basic settings management
- [ ] Create settings UI tab
**Deliverable**: Installable plugin that provides direct API access to vault operations
**Testing**: Manual testing of core file operations via plugin console
---
## Phase 2: HTTP Server Integration (Week 2)
### Goal: Embedded HTTP server with REST API compatibility
#### 2.1 HTTP Server Setup
- [ ] Integrate Express/Fastify server within plugin
- [ ] Configure HTTP and HTTPS ports (27123, 27124)
- [ ] Implement SSL certificate handling
- [ ] Add CORS support for web clients
- [ ] Create server start/stop lifecycle management
#### 2.2 REST API Endpoints
- [ ] Implement all vault endpoints (`/vault/*`)
- [ ] Implement active file endpoints (`/active`)
- [ ] Implement search endpoint (`/search/simple`)
- [ ] Implement utility endpoints (`/open/*`, `/commands/*`)
- [ ] Add authentication middleware
#### 2.3 Compatibility Testing
- [ ] Test against existing REST API client code
- [ ] Verify response format compatibility
- [ ] Benchmark performance vs HTTP-based approach
- [ ] Test error handling and edge cases
**Deliverable**: Plugin provides full REST API compatibility with performance improvements
**Testing**: Automated tests against all REST endpoints
---
## Phase 3: MCP Server Integration (Week 3)
### Goal: Embedded MCP server with existing semantic operations
#### 3.1 MCP Protocol Implementation
- [ ] Integrate MCP server framework within plugin
- [ ] Add HTTP transport for MCP protocol
- [ ] Copy semantic router from obsidian-semantic-mcp
- [ ] Integrate fragment retrieval system
- [ ] Add workflow hint generation
#### 3.2 Semantic Operations Migration
- [ ] Port all vault operations (list, read, create, update, delete, search)
- [ ] Port all edit operations (window, append, patch, from_buffer)
- [ ] Port all view operations (file, window, active, open_in_obsidian)
- [ ] Port workflow and system operations
- [ ] Implement enhanced search with snippets and media file discovery
#### 3.3 Performance Optimization
- [ ] Replace all HTTP calls in semantic operations with direct API calls
- [ ] Optimize fragment retrieval for direct vault access
- [ ] Implement caching layer for frequently accessed files
- [ ] Add performance monitoring and metrics
**Deliverable**: Plugin provides both REST and MCP protocols with enhanced search capabilities
**Testing**: Full MCP protocol testing with existing client tools
---
## Phase 4: Enhancement and Polish (Week 4)
### Goal: Advanced features and production readiness
#### 4.1 Advanced Obsidian Integration
- [ ] Add real-time file change notifications
- [ ] Integrate with Obsidian's internal search (if available)
- [ ] Add plugin ecosystem integration hooks (Dataview, etc.)
- [ ] Implement workspace manipulation capabilities
- [ ] Add tag and metadata extraction
#### 4.2 User Experience Improvements
- [ ] Create comprehensive settings UI
- [ ] Add status indicators and health monitoring
- [ ] Implement troubleshooting diagnostics
- [ ] Add performance metrics dashboard
- [ ] Create user-friendly error messages
#### 4.3 Documentation and Examples
- [ ] Write complete user documentation
- [ ] Create migration guide from existing setups
- [ ] Document API compatibility
- [ ] Provide configuration examples
- [ ] Create troubleshooting guide
**Deliverable**: Production-ready plugin with advanced features and documentation
**Testing**: Comprehensive integration testing and user acceptance testing
---
## Phase 5: Community Testing (Week 5-6)
### Goal: BRAT testing and community feedback
#### 5.1 BRAT Preparation
- [ ] Prepare GitHub repository for BRAT
- [ ] Create release with proper plugin assets
- [ ] Write installation instructions for BRAT users
- [ ] Set up issue tracking and feedback collection
- [ ] Create beta testing guidelines
#### 5.2 Community Engagement
- [ ] Announce beta testing in Obsidian community
- [ ] Collect and prioritize feedback
- [ ] Fix critical issues discovered during testing
- [ ] Iterate on user experience improvements
- [ ] Performance optimization based on real usage
#### 5.3 Stability and Performance
- [ ] Stress testing with large vaults
- [ ] Memory leak testing during extended operation
- [ ] Cross-platform compatibility testing
- [ ] Mobile Obsidian compatibility assessment
- [ ] Plugin conflict testing
**Deliverable**: Stable, community-tested plugin ready for official release
**Testing**: Real-world usage by beta testers with feedback integration
---
## Phase 6: Official Release (Week 7)
### Goal: Submit to Obsidian plugin directory
#### 6.1 Final Polish
- [ ] Address all critical feedback from BRAT testing
- [ ] Finalize documentation and user guides
- [ ] Complete performance optimization
- [ ] Implement any remaining compatibility requirements
- [ ] Create release notes and changelog
#### 6.2 Official Submission
- [ ] Prepare submission to Obsidian plugin directory
- [ ] Create final GitHub release with proper assets
- [ ] Submit community-plugins.json pull request
- [ ] Respond to review feedback
- [ ] Coordinate release announcement
#### 6.3 Community Launch
- [ ] Announce in Obsidian forums and Discord
- [ ] Create showcase content and demos
- [ ] Provide migration assistance for existing users
- [ ] Set up ongoing support and maintenance plan
**Deliverable**: Official Obsidian plugin available in directory
---
## Success Criteria by Phase
### Phase 1 Success
- Plugin installs and loads without errors
- Basic file operations work via direct API
- Performance improvements measurable
### Phase 2 Success
- Full REST API compatibility achieved
- Performance benchmarks show 5-10x improvement
- Existing client code works without changes
### Phase 3 Success
- All MCP operations functional
- Enhanced search with snippets working
- Semantic operations performance optimized
### Phase 4 Success
- Advanced Obsidian features integrated
- User experience polished and intuitive
- Documentation complete and helpful
### Phase 5 Success
- 50+ active BRAT testers
- Critical issues identified and resolved
- Positive community feedback
### Phase 6 Success
- Plugin approved for official directory
- Smooth migration path for existing users
- Active community adoption
## Risk Mitigation
### Technical Risks
- **Obsidian API Changes**: Pin to specific API version, test compatibility
- **Performance Issues**: Continuous benchmarking and optimization
- **Plugin Conflicts**: Test with common plugin combinations
### Community Risks
- **Adoption Challenges**: Clear migration documentation and support
- **Feedback Overload**: Prioritize critical issues and core functionality
- **Competition**: Focus on unique value proposition (performance + features)
### Release Risks
- **Review Delays**: Submit early, respond quickly to feedback
- **Breaking Changes**: Maintain backward compatibility throughout
- **Support Burden**: Create comprehensive documentation and FAQ
## Resource Requirements
### Development Time
- **Estimated Total**: 6-7 weeks full-time development
- **Critical Path**: ObsidianAPI abstraction layer implementation
- **Buffer Time**: 1 week for unexpected issues and feedback integration
### Testing Resources
- **Unit Testing**: Automated via CI/CD pipeline
- **Integration Testing**: Manual testing with real Obsidian vaults
- **Community Testing**: BRAT beta testing program
- **Performance Testing**: Benchmarking suite with various vault sizes
### Documentation Requirements
- **User Documentation**: Installation, configuration, migration guides
- **Developer Documentation**: API reference, architecture overview
- **Community Resources**: Examples, tutorials, troubleshooting
This phased approach ensures steady progress while maintaining quality and community engagement throughout the development process.

206
README.md Normal file
View file

@ -0,0 +1,206 @@
# Obsidian MCP Plugin
A hybrid Obsidian plugin that combines the functionality of the Local REST API plugin with an embedded MCP (Model Context Protocol) server, providing both HTTP REST endpoints and streamable MCP protocol access for AI tools.
## Architecture Overview
This plugin is designed as a clean evolution of two existing projects:
- **coddingtonbear/obsidian-local-rest-api**: Provides HTTP REST API access to Obsidian
- **aaronsb/obsidian-semantic-mcp**: Provides semantic MCP operations with enhanced search, fragment retrieval, and AI-optimized workflows
### Key Innovation: Abstraction Layer Preservation
The critical architectural decision is to **preserve the existing `ObsidianAPI` abstraction layer** while replacing its HTTP-based implementation with direct Obsidian plugin API calls. This allows us to:
1. **Reuse all existing MCP server logic** without modification
2. **Maintain API compatibility** with existing integrations
3. **Improve performance** by eliminating HTTP overhead
4. **Add new capabilities** only possible with direct plugin access
## Goals & Requirements
### Primary Goals
1. **Seamless Migration**: Drop-in replacement for separate REST API plugin + MCP server setup
2. **Performance Enhancement**: Direct vault access instead of HTTP round-trips
3. **Extended Capabilities**: Access to Obsidian internals not available via REST API
4. **Dual Protocol Support**: Both HTTP REST and MCP protocols from single plugin
5. **Community Ready**: Proper plugin structure for BRAT testing and official submission
### Technical Requirements
#### Core Functionality Preservation
- ✅ All existing REST API endpoints from coddingtonbear's plugin
- ✅ All semantic MCP operations from our existing server
- ✅ Enhanced search with content snippets and media file discovery
- ✅ Fragment retrieval and intelligent content extraction
- ✅ Workflow hints and contextual suggestions
#### Architecture Requirements
- ✅ Plugin-native implementation (no external processes)
- ✅ Direct Obsidian API integration via `app.vault.*` and `app.workspace.*`
- ✅ HTTP server for REST and MCP protocol endpoints
- ✅ Maintained abstraction layer for code reuse
- ✅ TypeScript implementation with proper types
#### Performance Requirements
- ✅ Sub-100ms response times for file operations
- ✅ Efficient search with combined API + filename results
- ✅ Memory-efficient fragment retrieval
- ✅ Minimal plugin startup time
#### Compatibility Requirements
- ✅ Obsidian API version compatibility
- ✅ Cross-platform support (Windows, macOS, Linux)
- ✅ Mobile Obsidian compatibility considerations
- ✅ Plugin ecosystem integration capabilities
## Implementation Plan
### Phase 1: Foundation (Initial BRAT Release)
1. **Fork and Setup**
- Fork REST API plugin codebase
- Set up TypeScript build pipeline
- Create proper plugin manifest and structure
2. **Direct API Implementation**
- Replace `ObsidianAPI` HTTP calls with direct vault operations
- Implement plugin lifecycle management
- Add error handling for plugin context
3. **MCP Server Integration**
- Embed semantic router and operations
- Add HTTP MCP protocol endpoints
- Preserve existing semantic operations
### Phase 2: Enhancement (BRAT Testing)
1. **Advanced Features**
- Real-time vault change notifications
- Enhanced metadata access (tags, links, frontmatter)
- Plugin ecosystem integration hooks
2. **Performance Optimization**
- Caching layer for frequently accessed files
- Efficient search indexing
- Memory usage optimization
3. **Testing & Iteration**
- Community feedback via BRAT
- Performance benchmarking
- API stability testing
### Phase 3: Production (Official Submission)
1. **Documentation & Polish**
- Complete user documentation
- Developer API documentation
- Migration guides from existing setups
2. **Official Submission**
- Obsidian plugin directory submission
- Community announcement
- Support and maintenance plan
## Technical Architecture
### Core Components
```
┌─────────────────────────────────────────────────────────────┐
│ Obsidian MCP Plugin │
├─────────────────────────────────────────────────────────────┤
│ HTTP Server (Express/Fastify) │
│ ├── REST API Endpoints (coddingtonbear compatibility) │
│ └── MCP Protocol Endpoints (streamable) │
├─────────────────────────────────────────────────────────────┤
│ Semantic Operations Layer │
│ ├── Enhanced Search (API + filename + snippets) │
│ ├── Fragment Retrieval │
│ ├── Workflow Hints │
│ └── File Type Detection │
├─────────────────────────────────────────────────────────────┤
│ ObsidianAPI Abstraction Layer (CRITICAL) │
│ ├── Direct Vault Operations (app.vault.*) │
│ ├── Workspace Operations (app.workspace.*) │
│ ├── Search Integration │
│ └── Plugin Lifecycle Management │
├─────────────────────────────────────────────────────────────┤
│ Obsidian Plugin Foundation │
│ ├── Plugin Class & Lifecycle │
│ ├── Settings Management │
│ ├── UI Components (optional) │
│ └── Error Handling │
└─────────────────────────────────────────────────────────────┘
```
### Key Abstraction Layer Transformation
**Current (HTTP-based):**
```typescript
class ObsidianAPI {
async getFile(path: string): Promise<ObsidianFileResponse> {
const response = await this.client.get(`/vault/${path}`);
return response.data;
}
}
```
**New (Direct plugin API):**
```typescript
class ObsidianAPI {
constructor(private app: App) {}
async getFile(path: string): Promise<ObsidianFileResponse> {
const file = this.app.vault.getAbstractFileByPath(path);
if (file instanceof TFile) {
const content = await this.app.vault.read(file);
return { content, path, stat: file.stat };
}
throw new Error(`File not found: ${path}`);
}
}
```
## Development Workflow
### Local Development
1. Clone repo to Obsidian plugins folder: `.obsidian/plugins/obsidian-mcp-plugin/`
2. Install dependencies: `npm install`
3. Build and watch: `npm run dev`
4. Reload plugin in Obsidian: Ctrl/Cmd+P → "Reload app without saving"
### BRAT Testing
1. Push changes to GitHub
2. Users install via BRAT: `aaronsb/obsidian-mcp-plugin`
3. Automatic updates for testers
4. Collect feedback and iterate
### Official Release
1. Final testing and documentation
2. Create GitHub release with plugin assets
3. Submit to Obsidian plugin directory
4. Community announcement
## Success Metrics
### Technical Metrics
- ⚡ **Performance**: 50%+ faster than HTTP-based approach
- 🔍 **Search Quality**: Enhanced results with snippets + media files
- 🛠️ **Compatibility**: 100% API compatibility with existing tools
- 📈 **Adoption**: BRAT testing with community feedback
### Community Metrics
- 📥 **Installation**: Target 1000+ BRAT installations during testing
- ⭐ **Reviews**: Positive feedback on functionality and performance
- 🔧 **Integration**: AI tools adopting the plugin for Obsidian access
- 📖 **Documentation**: Clear migration path from existing setups
## Next Steps
1. **Repository Setup**: Initialize TypeScript plugin structure
2. **Core Implementation**: Begin ObsidianAPI direct integration
3. **MCP Integration**: Embed existing semantic operations
4. **BRAT Preparation**: Prepare for beta testing release
---
*This plugin represents the natural evolution of Obsidian AI integration, combining the best of REST API access with semantic MCP operations in a single, high-performance package.*

253
REQUIREMENTS.md Normal file
View file

@ -0,0 +1,253 @@
# Requirements Specification
## Functional Requirements
### FR-1: HTTP REST API Compatibility
**Priority**: Critical
**Description**: Maintain 100% API compatibility with coddingtonbear's Local REST API plugin
**Acceptance Criteria**:
- [ ] All existing REST endpoints function identically
- [ ] Response formats match exactly (JSON structure, status codes, headers)
- [ ] Error messages and error handling behavior preserved
- [ ] Authentication mechanisms supported
- [ ] HTTPS with self-signed certificate support
**Endpoints to Implement**:
```
GET / - Server info
GET /active - Get active file
PUT /active - Update active file
POST /active - Append to active file
DELETE /active - Delete active file
PATCH /active - Patch active file
GET /vault/ - List root files
GET /vault/{path}/ - List directory
GET /vault/{path} - Get file content
PUT /vault/{path} - Create/update file
POST /vault/{path} - Append to file
DELETE /vault/{path} - Delete file
PATCH /vault/{path} - Patch file
POST /search/simple - Simple search
POST /open/{path} - Open file in Obsidian
GET /commands/ - List commands
POST /commands/{id}/ - Execute command
```
### FR-2: MCP Protocol Support
**Priority**: Critical
**Description**: Provide streamable HTTP MCP protocol endpoints
**Acceptance Criteria**:
- [ ] HTTP transport for MCP protocol messages
- [ ] All existing semantic operations from obsidian-semantic-mcp
- [ ] Enhanced search with content snippets
- [ ] Fragment retrieval functionality
- [ ] Workflow hints and contextual suggestions
**MCP Operations to Support**:
```
vault:list - List files with workflow suggestions
vault:read - Read file with fragment extraction
vault:create - Create new file
vault:update - Update existing file
vault:delete - Delete file
vault:search - Enhanced search with snippets + media files
edit:window - Edit file with context window
edit:append - Append content to file
edit:patch - Patch file with targeting
edit:from_buffer - Edit from buffered content
view:file - View file content
view:window - View file window around line
view:active - View currently active file
view:open_in_obsidian - Open file in Obsidian UI
workflow:suggest - Get contextual workflow suggestions
system:info - Get system information
system:commands - List available operations
```
### FR-3: Performance Enhancement
**Priority**: High
**Description**: Achieve significant performance improvements over HTTP-based approach
**Acceptance Criteria**:
- [ ] File operations complete in <10ms (vs ~50-100ms HTTP)
- [ ] Search operations complete in <50ms (vs ~100-300ms HTTP)
- [ ] Directory listing completes in <5ms (vs ~30-60ms HTTP)
- [ ] Memory usage remains stable during extended use
- [ ] No noticeable impact on Obsidian's UI responsiveness
### FR-4: Enhanced Search Capabilities
**Priority**: High
**Description**: Provide superior search functionality combining multiple strategies
**Acceptance Criteria**:
- [ ] Content search with snippets (existing functionality preserved)
- [ ] Filename search for media files (images, videos, audio)
- [ ] Combined results with intelligent deduplication
- [ ] File type detection and appropriate workflow hints
- [ ] Configurable snippet inclusion (includeContent parameter)
- [ ] Pagination support for large result sets
### FR-5: Direct Obsidian Integration
**Priority**: Medium
**Description**: Leverage direct plugin access for enhanced capabilities
**Acceptance Criteria**:
- [ ] Real-time file change notifications
- [ ] Access to Obsidian's internal search index (when available)
- [ ] Plugin ecosystem integration hooks (Dataview, etc.)
- [ ] Workspace manipulation capabilities
- [ ] Tag and metadata extraction
- [ ] Link relationship traversal
## Technical Requirements
### TR-1: Plugin Architecture
**Priority**: Critical
**Description**: Implement as proper Obsidian plugin with standard lifecycle
**Acceptance Criteria**:
- [ ] Standard Obsidian plugin structure (main.ts, manifest.json, styles.css)
- [ ] Proper plugin lifecycle (onload, onunload)
- [ ] Settings management with UI
- [ ] Command registration for user interactions
- [ ] Error handling and logging
### TR-2: HTTP Server Integration
**Priority**: Critical
**Description**: Embed HTTP server within plugin for external access
**Acceptance Criteria**:
- [ ] HTTP server starts/stops with plugin lifecycle
- [ ] Configurable port (default 27123 HTTP, 27124 HTTPS)
- [ ] HTTPS support with self-signed certificates
- [ ] CORS handling for web client access
- [ ] Request/response logging for debugging
### TR-3: ObsidianAPI Abstraction Layer
**Priority**: Critical
**Description**: Implement direct API replacement while preserving interface
**Acceptance Criteria**:
- [ ] Identical method signatures to existing ObsidianAPI class
- [ ] Direct app.vault and app.workspace integration
- [ ] Image file handling with binary data support
- [ ] Error types and messages match existing implementation
- [ ] Response formats identical to HTTP API responses
### TR-4: TypeScript Implementation
**Priority**: High
**Description**: Maintain type safety and development experience
**Acceptance Criteria**:
- [ ] Full TypeScript implementation with strict types
- [ ] Obsidian API types properly imported and used
- [ ] MCP protocol types maintained
- [ ] Build pipeline with proper bundling
- [ ] Source maps for debugging
### TR-5: Testing Framework
**Priority**: Medium
**Description**: Comprehensive testing for reliability
**Acceptance Criteria**:
- [ ] Unit tests for ObsidianAPI implementation
- [ ] Integration tests for MCP operations
- [ ] HTTP endpoint testing
- [ ] Performance benchmarks
- [ ] Error condition testing
## Migration Requirements
### MR-1: Backward Compatibility
**Priority**: Critical
**Description**: Seamless migration from existing setups
**Acceptance Criteria**:
- [ ] Existing MCP client configurations work without changes
- [ ] Existing REST API client code works without modifications
- [ ] Configuration migration from Local REST API plugin
- [ ] Clear migration documentation
### MR-2: Configuration Management
**Priority**: High
**Description**: Plugin settings and configuration
**Acceptance Criteria**:
- [ ] HTTP server enable/disable toggle
- [ ] Port configuration (HTTP and HTTPS)
- [ ] SSL certificate configuration
- [ ] Authentication settings
- [ ] Debug logging controls
- [ ] Performance monitoring options
### MR-3: Documentation
**Priority**: High
**Description**: Complete documentation for users and developers
**Acceptance Criteria**:
- [ ] User installation and setup guide
- [ ] Migration guide from existing plugins
- [ ] API documentation for both REST and MCP protocols
- [ ] Developer documentation for plugin architecture
- [ ] Troubleshooting guide
- [ ] Performance tuning recommendations
## Quality Requirements
### QR-1: Reliability
- [ ] Plugin handles Obsidian app lifecycle properly
- [ ] Graceful degradation when features unavailable
- [ ] Comprehensive error handling and recovery
- [ ] No memory leaks during extended operation
- [ ] Stable operation across Obsidian restarts
### QR-2: Security
- [ ] Authentication for HTTP endpoints
- [ ] HTTPS encryption support
- [ ] Input validation and sanitization
- [ ] Safe file path handling (no directory traversal)
- [ ] Configurable access controls
### QR-3: Usability
- [ ] Clear plugin settings interface
- [ ] Helpful error messages with recovery suggestions
- [ ] Performance monitoring and diagnostics
- [ ] Easy troubleshooting and debugging
- [ ] Community documentation and examples
### QR-4: Maintainability
- [ ] Modular code architecture
- [ ] Clear separation of concerns
- [ ] Comprehensive code documentation
- [ ] Automated testing pipeline
- [ ] Version compatibility strategy
## Success Criteria
### Minimum Viable Product (MVP)
- [ ] All FR-1 endpoints implemented and tested
- [ ] All FR-2 MCP operations working
- [ ] Basic performance improvements demonstrated
- [ ] Plugin installable via BRAT
- [ ] Migration guide published
### Full Release
- [ ] All functional requirements met
- [ ] Performance benchmarks achieved
- [ ] Comprehensive documentation complete
- [ ] Community testing via BRAT successful
- [ ] Ready for Obsidian plugin directory submission
### Success Metrics
- **Performance**: 5-10x improvement over HTTP-based approach
- **Adoption**: 100+ BRAT installations during testing phase
- **Compatibility**: 100% API compatibility maintained
- **Community**: Positive feedback and active usage
- **Migration**: Smooth transition path for existing users

48
esbuild.config.mjs Normal file
View file

@ -0,0 +1,48 @@
import esbuild from "esbuild";
import process from "process";
import builtins from "builtin-modules";
const banner =
`/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
`;
const prod = (process.argv[2] === 'production');
const context = await esbuild.context({
banner: {
js: banner,
},
entryPoints: ['src/main.ts'],
bundle: true,
external: [
'obsidian',
'electron',
'@codemirror/autocomplete',
'@codemirror/collab',
'@codemirror/commands',
'@codemirror/language',
'@codemirror/lint',
'@codemirror/search',
'@codemirror/state',
'@codemirror/view',
'@lezer/common',
'@lezer/highlight',
'@lezer/lr',
...builtins],
format: 'cjs',
target: 'es2018',
logLevel: "info",
sourcemap: prod ? false : 'inline',
treeShaking: true,
outfile: 'main.js',
});
if (prod) {
await context.rebuild();
process.exit(0);
} else {
await context.watch();
}

11
manifest.json Normal file
View file

@ -0,0 +1,11 @@
{
"id": "obsidian-mcp-plugin",
"name": "Obsidian MCP Plugin",
"version": "1.0.0",
"minAppVersion": "0.15.0",
"description": "Hybrid plugin combining Local REST API with semantic MCP server for enhanced AI tool integration",
"author": "Aaron Blumenfeld",
"authorUrl": "https://github.com/aaronsb",
"fundingUrl": "https://github.com/sponsors/aaronsb",
"isDesktopOnly": false
}

6711
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

42
package.json Normal file
View file

@ -0,0 +1,42 @@
{
"name": "obsidian-mcp-plugin",
"version": "1.0.0",
"description": "Hybrid plugin combining Local REST API with semantic MCP server for enhanced AI tool integration",
"main": "main.js",
"scripts": {
"dev": "node esbuild.config.mjs",
"build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production",
"version": "node version-bump.mjs && git add manifest.json versions.json",
"test": "jest",
"lint": "eslint src --ext .ts,.tsx"
},
"keywords": [
"obsidian",
"plugin",
"mcp",
"rest-api",
"ai",
"semantic"
],
"author": "Aaron Blumenfeld",
"license": "MIT",
"devDependencies": {
"@types/jest": "^29.5.5",
"@types/node": "^20.6.2",
"@typescript-eslint/eslint-plugin": "^6.7.0",
"@typescript-eslint/parser": "^6.7.0",
"builtin-modules": "^3.3.0",
"esbuild": "0.19.2",
"eslint": "^8.49.0",
"jest": "^29.7.0",
"obsidian": "latest",
"ts-jest": "^29.1.1",
"tslib": "2.6.2",
"typescript": "5.2.2"
},
"dependencies": {
"express": "^4.18.2",
"@types/express": "^4.17.17",
"@modelcontextprotocol/sdk": "^0.4.0"
}
}

134
src/main.ts Normal file
View file

@ -0,0 +1,134 @@
import { App, Plugin, PluginSettingTab, Setting } from 'obsidian';
interface MCPPluginSettings {
httpEnabled: boolean;
httpPort: number;
httpsPort: number;
enableSSL: boolean;
debugLogging: boolean;
}
const DEFAULT_SETTINGS: MCPPluginSettings = {
httpEnabled: true,
httpPort: 27123,
httpsPort: 27124,
enableSSL: true,
debugLogging: false
};
export default class ObsidianMCPPlugin extends Plugin {
settings!: MCPPluginSettings;
async onload() {
await this.loadSettings();
console.log('Loading Obsidian MCP Plugin v1.0.0');
// Add settings tab
this.addSettingTab(new MCPSettingTab(this.app, this));
// Add command to restart server
this.addCommand({
id: 'restart-mcp-server',
name: 'Restart MCP Server',
callback: () => {
console.log('MCP Server restart requested');
// TODO: Implement server restart
}
});
// Add status bar item
const statusBarItemEl = this.addStatusBarItem();
statusBarItemEl.setText('MCP: Ready');
console.log('Obsidian MCP Plugin loaded successfully');
}
onunload() {
console.log('Unloading Obsidian MCP Plugin');
// TODO: Stop HTTP server
}
async loadSettings() {
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}
async saveSettings() {
await this.saveData(this.settings);
}
}
class MCPSettingTab extends PluginSettingTab {
plugin: ObsidianMCPPlugin;
constructor(app: App, plugin: ObsidianMCPPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const {containerEl} = this;
containerEl.empty();
containerEl.createEl('h2', {text: 'Obsidian MCP Plugin Settings'});
new Setting(containerEl)
.setName('Enable HTTP Server')
.setDesc('Enable the HTTP server for REST API and MCP access')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.httpEnabled)
.onChange(async (value) => {
this.plugin.settings.httpEnabled = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('HTTP Port')
.setDesc('Port for HTTP server (default: 27123)')
.addText(text => text
.setPlaceholder('27123')
.setValue(this.plugin.settings.httpPort.toString())
.onChange(async (value) => {
const port = parseInt(value);
if (!isNaN(port) && port > 0 && port < 65536) {
this.plugin.settings.httpPort = port;
await this.plugin.saveSettings();
}
}));
new Setting(containerEl)
.setName('HTTPS Port')
.setDesc('Port for HTTPS server (default: 27124)')
.addText(text => text
.setPlaceholder('27124')
.setValue(this.plugin.settings.httpsPort.toString())
.onChange(async (value) => {
const port = parseInt(value);
if (!isNaN(port) && port > 0 && port < 65536) {
this.plugin.settings.httpsPort = port;
await this.plugin.saveSettings();
}
}));
new Setting(containerEl)
.setName('Enable SSL')
.setDesc('Enable HTTPS with self-signed certificate')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.enableSSL)
.onChange(async (value) => {
this.plugin.settings.enableSSL = value;
await this.plugin.saveSettings();
}));
new Setting(containerEl)
.setName('Debug Logging')
.setDesc('Enable detailed debug logging')
.addToggle(toggle => toggle
.setValue(this.plugin.settings.debugLogging)
.onChange(async (value) => {
this.plugin.settings.debugLogging = value;
await this.plugin.saveSettings();
}));
}
}

31
styles.css Normal file
View file

@ -0,0 +1,31 @@
/* Obsidian MCP Plugin Styles */
.mcp-plugin-settings {
padding: 20px;
}
.mcp-plugin-settings h2 {
margin-bottom: 20px;
color: var(--text-accent);
}
.mcp-status-bar {
display: flex;
align-items: center;
gap: 5px;
}
.mcp-status-indicator {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: var(--text-success);
}
.mcp-status-indicator.error {
background-color: var(--text-error);
}
.mcp-status-indicator.warning {
background-color: var(--text-warning);
}

35
tsconfig.json Normal file
View file

@ -0,0 +1,35 @@
{
"compilerOptions": {
"baseUrl": ".",
"inlineSourceMap": true,
"inlineSources": true,
"module": "ESNext",
"target": "ES6",
"allowJs": true,
"noImplicitAny": true,
"moduleResolution": "node",
"importHelpers": true,
"declaration": true,
"declarationMap": true,
"lib": ["DOM", "ES6"],
"outDir": "dist",
"typeRoots": [
"node_modules/@types"
],
"types": [
"node"
],
"strict": true,
"skipLibCheck": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist",
"main.js"
]
}

14
version-bump.mjs Normal file
View file

@ -0,0 +1,14 @@
import { readFileSync, writeFileSync } from "fs";
const targetVersion = process.env.npm_package_version;
// read minAppVersion from manifest.json and bump version to target version
let manifest = JSON.parse(readFileSync("manifest.json", "utf8"));
const { minAppVersion } = manifest;
manifest.version = targetVersion;
writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t"));
// update versions.json with target version and minAppVersion from manifest.json
let versions = JSON.parse(readFileSync("versions.json", "utf8"));
versions[targetVersion] = minAppVersion;
writeFileSync("versions.json", JSON.stringify(versions, null, "\t"));

3
versions.json Normal file
View file

@ -0,0 +1,3 @@
{
"1.0.0": "0.15.0"
}