feat: implement Obsidian MCP Bundle MVP (Phase 1-3)
- Complete project setup with TypeScript, Jest, MCPB manifest - Implement foundational infrastructure (CLI executor, logger, error handler) - Add 9 file operation tools for User Story 1 - Full MCP protocol compliance with stdio transport - Input validation and sanitization for security - Comprehensive error handling with actionable messages - Constitutional compliance: all 6 principles satisfied MVP includes: - obsidian_create_note, read, append, prepend, delete, move, rename, open, file_info - Zod validation schemas for all parameters - 30s timeout configuration with per-command overrides - Stderr-only logging with sanitized output - Graceful shutdown handling Build: ✅ 0 errors, 0 vulnerabilities Tasks: 48/167 complete (MVP milestone) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
242
specs/001-obsidian-mcp-bundle/contracts/mcp-protocol.md
Normal file
242
specs/001-obsidian-mcp-bundle/contracts/mcp-protocol.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# MCP Protocol Contract
|
||||
|
||||
**Purpose**: Define the JSON-RPC communication contract between AI assistants and the Obsidian MCP server
|
||||
|
||||
## Transport
|
||||
|
||||
**Protocol**: JSON-RPC 2.0 over stdio
|
||||
**Direction**: Bidirectional (client ↔ server)
|
||||
|
||||
### Stdio Requirements
|
||||
|
||||
- **stdin**: Server reads JSON-RPC requests line-by-line
|
||||
- **stdout**: Server writes JSON-RPC responses line-by-line (one message per line)
|
||||
- **stderr**: Server logs debugging information (never JSON-RPC messages)
|
||||
|
||||
### Message Format
|
||||
|
||||
All messages are single-line JSON objects ending with `\n`:
|
||||
|
||||
```json
|
||||
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{...}}\n
|
||||
```
|
||||
|
||||
## Initialization Handshake
|
||||
|
||||
### Request: initialize
|
||||
|
||||
Client sends capabilities and version information:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"method": "initialize",
|
||||
"params": {
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {},
|
||||
"clientInfo": {
|
||||
"name": "Claude Desktop",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response: initialize
|
||||
|
||||
Server responds with its capabilities:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 1,
|
||||
"result": {
|
||||
"protocolVersion": "2024-11-05",
|
||||
"capabilities": {
|
||||
"tools": {}
|
||||
},
|
||||
"serverInfo": {
|
||||
"name": "obsidian-mcp",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Discovery
|
||||
|
||||
### Request: tools/list
|
||||
|
||||
Client requests available tools:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"method": "tools/list",
|
||||
"params": {}
|
||||
}
|
||||
```
|
||||
|
||||
### Response: tools/list
|
||||
|
||||
Server returns tool definitions with schemas:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 2,
|
||||
"result": {
|
||||
"tools": [
|
||||
{
|
||||
"name": "obsidian_create_note",
|
||||
"description": "Create a new note in the vault",
|
||||
"inputSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Note name (without .md extension) or exact path"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Initial note content (markdown)"
|
||||
},
|
||||
"overwrite": {
|
||||
"type": "boolean",
|
||||
"description": "Overwrite if file exists"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
}
|
||||
// ... more tools
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Tool Invocation
|
||||
|
||||
### Request: tools/call
|
||||
|
||||
Client invokes a tool:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"method": "tools/call",
|
||||
"params": {
|
||||
"name": "obsidian_create_note",
|
||||
"arguments": {
|
||||
"name": "Meeting Notes",
|
||||
"content": "# Meeting Notes\n\n- Agenda item 1"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response: Success
|
||||
|
||||
Tool execution succeeded:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"result": {
|
||||
"content": [
|
||||
{
|
||||
"type": "text",
|
||||
"text": "{\"success\":true,\"data\":{\"path\":\"Meeting Notes.md\",\"created\":true}}"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Response: Error
|
||||
|
||||
Tool execution failed:
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": 3,
|
||||
"error": {
|
||||
"code": -32000,
|
||||
"message": "Obsidian application is not running. Please start Obsidian and try again.",
|
||||
"data": {
|
||||
"errorCode": "OBSIDIAN_NOT_RUNNING"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Error Codes
|
||||
|
||||
### JSON-RPC Standard Errors
|
||||
|
||||
| Code | Message | Meaning |
|
||||
|------|---------|---------|
|
||||
| -32700 | Parse error | Invalid JSON |
|
||||
| -32600 | Invalid Request | Invalid JSON-RPC structure |
|
||||
| -32601 | Method not found | Unknown method |
|
||||
| -32602 | Invalid params | Parameter validation failed |
|
||||
| -32603 | Internal error | Server internal error |
|
||||
|
||||
### Application Errors
|
||||
|
||||
| Code | Message | When |
|
||||
|------|---------|------|
|
||||
| -32000 | Server error | Generic application error |
|
||||
| -32001 | Obsidian not running | Obsidian app not detected |
|
||||
| -32002 | Vault not found | Invalid vault name |
|
||||
| -32003 | File not found | Note doesn't exist |
|
||||
| -32004 | Ambiguous name | Multiple files match name |
|
||||
| -32005 | Permission denied | Filesystem permission issue |
|
||||
| -32006 | Timeout | Operation exceeded 30s |
|
||||
|
||||
## Shutdown
|
||||
|
||||
### Notification: exit
|
||||
|
||||
Client notifies server of shutdown (no response expected):
|
||||
|
||||
```json
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"method": "exit"
|
||||
}
|
||||
```
|
||||
|
||||
Server should:
|
||||
1. Complete any in-flight operations
|
||||
2. Close file handles
|
||||
3. Flush logs
|
||||
4. Exit process
|
||||
|
||||
### EOF on stdin
|
||||
|
||||
If stdin closes without `exit` notification, server should gracefully shutdown.
|
||||
|
||||
## Performance Requirements
|
||||
|
||||
- **initialize response**: <100ms
|
||||
- **tools/list response**: <200ms
|
||||
- **tools/call response**: <3s for file ops, <5s for search (per SC-001, SC-002)
|
||||
|
||||
## Compliance Checklist
|
||||
|
||||
- [x] JSON-RPC 2.0 format for all messages
|
||||
- [x] Stdio transport (stdin for requests, stdout for responses)
|
||||
- [x] Line-by-line message format (newline-delimited)
|
||||
- [x] Initialize handshake before tool calls
|
||||
- [x] Tool schemas in tools/list response
|
||||
- [x] Structured error responses with codes
|
||||
- [x] Graceful shutdown on exit notification
|
||||
- [x] No stdout pollution (logs to stderr only)
|
||||
- [x] Immediate stdout flushing after responses
|
||||
- [x] EOF handling (graceful shutdown)
|
||||
692
specs/001-obsidian-mcp-bundle/contracts/tools.md
Normal file
692
specs/001-obsidian-mcp-bundle/contracts/tools.md
Normal file
@@ -0,0 +1,692 @@
|
||||
# Tool Schemas
|
||||
|
||||
**Purpose**: Define input/output schemas for all MCP tools exposed by the Obsidian bundle
|
||||
|
||||
## Tool Naming Convention
|
||||
|
||||
All tools use prefix `obsidian_` followed by the operation:
|
||||
- `obsidian_create_note`
|
||||
- `obsidian_search`
|
||||
- `obsidian_list_tasks`
|
||||
|
||||
This prevents naming conflicts with other MCP servers.
|
||||
|
||||
## Priority 1 Tools: File Operations (15 tools)
|
||||
|
||||
### obsidian_create_note
|
||||
|
||||
**Description**: Create a new note in the vault
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Note name (without .md extension) or exact path",
|
||||
"minLength": 1,
|
||||
"maxLength": 255
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Optional: Directory path within vault"
|
||||
},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Initial note content (markdown)"
|
||||
},
|
||||
"template": {
|
||||
"type": "string",
|
||||
"description": "Template name to use"
|
||||
},
|
||||
"overwrite": {
|
||||
"type": "boolean",
|
||||
"description": "Overwrite if file exists (default: false)"
|
||||
},
|
||||
"open": {
|
||||
"type": "boolean",
|
||||
"description": "Open file after creating (default: false)"
|
||||
}
|
||||
},
|
||||
"required": ["name"]
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"path": "Projects/Meeting Notes.md",
|
||||
"created": true,
|
||||
"opened": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_read_note
|
||||
|
||||
**Description**: Read the contents of a note
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string",
|
||||
"description": "Note name (wikilink-style resolution)"
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"description": "Exact path to note"
|
||||
}
|
||||
},
|
||||
"oneOf": [{"required": ["file"]}, {"required": ["path"]}]
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"path": "Projects/Meeting Notes.md",
|
||||
"content": "# Meeting Notes\n\n- Agenda item 1\n- Agenda item 2",
|
||||
"size": 52,
|
||||
"modified": "2026-03-22T15:30:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_append_to_note
|
||||
|
||||
**Description**: Append content to a note
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"},
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Content to append (required)"
|
||||
},
|
||||
"inline": {
|
||||
"type": "boolean",
|
||||
"description": "Append without newline (default: false)"
|
||||
}
|
||||
},
|
||||
"required": ["content"],
|
||||
"oneOf": [{"required": ["file"]}, {"required": ["path"]}]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_delete_note
|
||||
|
||||
**Description**: Delete a note (moves to trash by default)
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"},
|
||||
"permanent": {
|
||||
"type": "boolean",
|
||||
"description": "Skip trash, delete permanently (default: false)"
|
||||
}
|
||||
},
|
||||
"oneOf": [{"required": ["file"]}, {"required": ["path"]}]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_move_note
|
||||
|
||||
**Description**: Move or rename a note
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"},
|
||||
"to": {
|
||||
"type": "string",
|
||||
"description": "Destination folder or full path (required)"
|
||||
}
|
||||
},
|
||||
"required": ["to"],
|
||||
"oneOf": [{"required": ["file"]}, {"required": ["path"]}]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Priority 2 Tools: Search & Discovery (20 tools)
|
||||
|
||||
### obsidian_search
|
||||
|
||||
**Description**: Search vault for text
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "Search query (required)"
|
||||
},
|
||||
"folder": {
|
||||
"type": "string",
|
||||
"description": "Limit search to specific folder"
|
||||
},
|
||||
"limit": {
|
||||
"type": "number",
|
||||
"description": "Maximum number of results"
|
||||
},
|
||||
"caseSensitive": {
|
||||
"type": "boolean",
|
||||
"description": "Case-sensitive search (default: false)"
|
||||
}
|
||||
},
|
||||
"required": ["query"]
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"query": "machine learning",
|
||||
"matchCount": 5,
|
||||
"files": [
|
||||
{"path": "Research/AI Notes.md", "matches": 3},
|
||||
{"path": "Projects/ML Project.md", "matches": 2}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_get_backlinks
|
||||
|
||||
**Description**: List backlinks to a note
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"},
|
||||
"counts": {
|
||||
"type": "boolean",
|
||||
"description": "Include link counts (default: false)"
|
||||
}
|
||||
},
|
||||
"oneOf": [{"required": ["file"]}, {"required": ["path"]}]
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"target": "Projects/ML Project.md",
|
||||
"backlinks": [
|
||||
{"source": "Research/AI Notes.md", "count": 2},
|
||||
{"source": "Weekly Review.md", "count": 1}
|
||||
],
|
||||
"totalBacklinks": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_list_tags
|
||||
|
||||
**Description**: List tags in the vault or specific file
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {"type": "string", "description": "Limit to specific file"},
|
||||
"path": {"type": "string", "description": "Limit to specific path"},
|
||||
"counts": {
|
||||
"type": "boolean",
|
||||
"description": "Include occurrence counts (default: false)"
|
||||
},
|
||||
"sortBy": {
|
||||
"type": "string",
|
||||
"enum": ["name", "count"],
|
||||
"description": "Sort order (default: name)"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"tags": [
|
||||
{"name": "project", "count": 15},
|
||||
{"name": "important", "count": 8},
|
||||
{"name": "todo", "count": 5}
|
||||
],
|
||||
"totalTags": 3
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Priority 3 Tools: Tasks & Properties (15 tools)
|
||||
|
||||
### obsidian_list_tasks
|
||||
|
||||
**Description**: List tasks in the vault or specific file
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"enum": ["todo", "done", "all"],
|
||||
"description": "Filter by status (default: all)"
|
||||
},
|
||||
"verbose": {
|
||||
"type": "boolean",
|
||||
"description": "Group by file with line numbers (default: false)"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"tasks": [
|
||||
{
|
||||
"ref": "Projects/TODO.md:5",
|
||||
"file": "Projects/TODO.md",
|
||||
"line": 5,
|
||||
"text": "Finish documentation",
|
||||
"status": "",
|
||||
"done": false
|
||||
},
|
||||
{
|
||||
"ref": "Weekly Review.md:12",
|
||||
"file": "Weekly Review.md",
|
||||
"line": 12,
|
||||
"text": "Review PRs",
|
||||
"status": "x",
|
||||
"done": true
|
||||
}
|
||||
],
|
||||
"totalTasks": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_toggle_task
|
||||
|
||||
**Description**: Toggle a task's completion status
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ref": {
|
||||
"type": "string",
|
||||
"description": "Task reference (path:line)"
|
||||
},
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"},
|
||||
"line": {
|
||||
"type": "number",
|
||||
"description": "Line number (1-indexed)"
|
||||
}
|
||||
},
|
||||
"oneOf": [
|
||||
{"required": ["ref"]},
|
||||
{"required": ["file", "line"]},
|
||||
{"required": ["path", "line"]}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_set_property
|
||||
|
||||
**Description**: Set a property value on a note
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Property name (required)"
|
||||
},
|
||||
"value": {
|
||||
"description": "Property value (required, type: string|number|boolean|array)"
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": ["text", "number", "checkbox", "date", "datetime", "list"],
|
||||
"description": "Property type (optional, inferred from value)"
|
||||
},
|
||||
"file": {"type": "string"},
|
||||
"path": {"type": "string"}
|
||||
},
|
||||
"required": ["name", "value"],
|
||||
"oneOf": [{"required": ["file"]}, {"required": ["path"]}]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Priority 4 Tools: Vault Navigation (15 tools)
|
||||
|
||||
### obsidian_list_files
|
||||
|
||||
**Description**: List files in the vault
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"folder": {
|
||||
"type": "string",
|
||||
"description": "Filter by folder"
|
||||
},
|
||||
"extension": {
|
||||
"type": "string",
|
||||
"description": "Filter by extension (e.g., 'md')"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_get_vault_info
|
||||
|
||||
**Description**: Get vault statistics
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"info": {
|
||||
"type": "string",
|
||||
"enum": ["name", "path", "files", "folders", "size", "all"],
|
||||
"description": "Specific info to return (default: all)"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Output Example**:
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"name": "My Vault",
|
||||
"path": "/Users/user/Documents/Obsidian/My Vault",
|
||||
"fileCount": 1234,
|
||||
"folderCount": 56,
|
||||
"totalSize": 5242880
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Priority 5 Tools: Advanced Features (30 tools)
|
||||
|
||||
### obsidian_daily_append
|
||||
|
||||
**Description**: Append content to today's daily note
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {
|
||||
"type": "string",
|
||||
"description": "Content to append (required)"
|
||||
},
|
||||
"inline": {
|
||||
"type": "boolean",
|
||||
"description": "Append without newline (default: false)"
|
||||
},
|
||||
"open": {
|
||||
"type": "boolean",
|
||||
"description": "Open daily note after appending (default: false)"
|
||||
}
|
||||
},
|
||||
"required": ["content"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_list_templates
|
||||
|
||||
**Description**: List available templates
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### obsidian_list_plugins
|
||||
|
||||
**Description**: List installed plugins
|
||||
|
||||
**Input Schema**:
|
||||
```json
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"filter": {
|
||||
"type": "string",
|
||||
"enum": ["core", "community", "all"],
|
||||
"description": "Filter by plugin type (default: all)"
|
||||
},
|
||||
"enabledOnly": {
|
||||
"type": "boolean",
|
||||
"description": "Show only enabled plugins (default: false)"
|
||||
},
|
||||
"includeVersions": {
|
||||
"type": "boolean",
|
||||
"description": "Include version numbers (default: false)"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Tool List (95 tools)
|
||||
|
||||
### File Operations (15)
|
||||
1. obsidian_create_note
|
||||
2. obsidian_read_note
|
||||
3. obsidian_append_to_note
|
||||
4. obsidian_prepend_to_note
|
||||
5. obsidian_delete_note
|
||||
6. obsidian_move_note
|
||||
7. obsidian_rename_note
|
||||
8. obsidian_open_note
|
||||
9. obsidian_get_file_info
|
||||
10. obsidian_list_recents
|
||||
11. obsidian_get_outline
|
||||
12. obsidian_get_wordcount
|
||||
13. obsidian_random_note
|
||||
14. obsidian_open_file
|
||||
15. obsidian_list_orphans
|
||||
|
||||
### Search & Discovery (20)
|
||||
16. obsidian_search
|
||||
17. obsidian_search_with_context
|
||||
18. obsidian_get_backlinks
|
||||
19. obsidian_get_outgoing_links
|
||||
20. obsidian_list_unresolved_links
|
||||
21. obsidian_list_tags
|
||||
22. obsidian_get_tag_info
|
||||
23. obsidian_list_aliases
|
||||
24. obsidian_list_properties
|
||||
25. obsidian_get_property_count
|
||||
26. obsidian_list_deadends
|
||||
27. obsidian_list_files
|
||||
28. obsidian_list_folders
|
||||
29. obsidian_get_folder_info
|
||||
30. obsidian_get_vault_info
|
||||
31. obsidian_list_vaults
|
||||
32. obsidian_open_search
|
||||
33. obsidian_get_version
|
||||
34. obsidian_reload_vault
|
||||
35. obsidian_list_workspace_tabs
|
||||
|
||||
### Tasks & Properties (15)
|
||||
36. obsidian_list_tasks
|
||||
37. obsidian_toggle_task
|
||||
38. obsidian_mark_task_done
|
||||
39. obsidian_mark_task_todo
|
||||
40. obsidian_update_task_status
|
||||
41. obsidian_get_property
|
||||
42. obsidian_set_property
|
||||
43. obsidian_remove_property
|
||||
44. obsidian_list_note_properties
|
||||
45. obsidian_list_vault_properties
|
||||
46. obsidian_daily_tasks
|
||||
47. obsidian_active_file_tasks
|
||||
48. obsidian_active_file_properties
|
||||
49. obsidian_active_file_tags
|
||||
50. obsidian_active_file_aliases
|
||||
|
||||
### Daily Notes (6)
|
||||
51. obsidian_open_daily_note
|
||||
52. obsidian_daily_append
|
||||
53. obsidian_daily_prepend
|
||||
54. obsidian_daily_read
|
||||
55. obsidian_daily_path
|
||||
56. obsidian_random_read
|
||||
|
||||
### Templates & Bookmarks (8)
|
||||
57. obsidian_list_templates
|
||||
58. obsidian_read_template
|
||||
59. obsidian_insert_template
|
||||
60. obsidian_create_bookmark
|
||||
61. obsidian_list_bookmarks
|
||||
62. obsidian_bookmark_file
|
||||
63. obsidian_bookmark_search
|
||||
64. obsidian_bookmark_url
|
||||
|
||||
### Plugins & Themes (12)
|
||||
65. obsidian_list_plugins
|
||||
66. obsidian_list_enabled_plugins
|
||||
67. obsidian_get_plugin_info
|
||||
68. obsidian_enable_plugin
|
||||
69. obsidian_disable_plugin
|
||||
70. obsidian_list_themes
|
||||
71. obsidian_get_active_theme
|
||||
72. obsidian_set_theme
|
||||
73. obsidian_list_css_snippets
|
||||
74. obsidian_enable_snippet
|
||||
75. obsidian_disable_snippet
|
||||
76. obsidian_restricted_mode_status
|
||||
|
||||
### File History & Sync (12)
|
||||
77. obsidian_list_file_versions
|
||||
78. obsidian_read_version
|
||||
79. obsidian_restore_version
|
||||
80. obsidian_list_files_with_history
|
||||
81. obsidian_open_history
|
||||
82. obsidian_list_sync_versions
|
||||
83. obsidian_read_sync_version
|
||||
84. obsidian_restore_sync_version
|
||||
85. obsidian_get_sync_status
|
||||
86. obsidian_pause_sync
|
||||
87. obsidian_resume_sync
|
||||
88. obsidian_list_sync_deleted
|
||||
|
||||
### Bases & Commands (7)
|
||||
89. obsidian_list_bases
|
||||
90. obsidian_list_base_views
|
||||
91. obsidian_query_base
|
||||
92. obsidian_create_base_item
|
||||
93. obsidian_list_commands
|
||||
94. obsidian_execute_command
|
||||
95. obsidian_get_hotkey
|
||||
|
||||
## Error Response Format
|
||||
|
||||
All tools return errors in consistent structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": {
|
||||
"code": "OBSIDIAN_NOT_RUNNING",
|
||||
"message": "Obsidian application is not running. Please start Obsidian and try again.",
|
||||
"details": {
|
||||
"attempted": "create_note",
|
||||
"file": "Meeting Notes.md"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Validation Rules
|
||||
|
||||
All input schemas enforce:
|
||||
- String min/max lengths
|
||||
- Required fields
|
||||
- Enum constraints for predefined values
|
||||
- Type coercion where safe
|
||||
- Sanitization of special characters before CLI execution
|
||||
Reference in New Issue
Block a user