obsidian-mcp-ts

duquesnay/obsidian-mcp-ts

3.3

If you are the rightful owner of obsidian-mcp-ts and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

The Obsidian MCP Server is a TypeScript implementation designed to interact with Obsidian via the Local REST API community plugin.

Tools
14
Resources
0
Prompts
0

Obsidian MCP Server (TypeScript)

A TypeScript MCP server to interact with Obsidian via the Local REST API community plugin.

Note: This is a TypeScript port of the original mcp-obsidian Python project by MarkusPfundstein. All credit for the original concept and API design goes to the original author.

Features

  • 🚀 High Performance: LRU caching, request deduplication, and optimized batch processing
  • 🔧 Type Safety: Full TypeScript with strict typing and comprehensive error handling
  • 📋 Dynamic Tool Discovery: Automatically discovers and loads tools with metadata
  • 🎯 Smart Error Handling: Simplified error responses with actionable suggestions
  • 📦 Modular Architecture: Clean separation of concerns with reusable utilities
  • 📊 MCP Resources: Read-only access to vault data through the resources protocol
  • 📏 Resource Metadata: File size and last modified timestamps for better cache optimization
  • ⚠️ Protocol-Compliant Errors: Standard MCP error codes for consistent error handling

Performance Optimization: Internal Resource Caching

The Obsidian MCP server automatically optimizes performance through intelligent internal resource caching. This system provides significant speed improvements for frequently used operations while remaining completely transparent to users.

Real-time Cache Synchronization

The server includes a sophisticated subscription system that automatically invalidates cached data when files change. This ensures you always see current data without manual cache clearing:

  • Automatic Updates: File operations (create, update, delete) trigger immediate cache invalidation
  • Smart Invalidation: Only affected caches are cleared, preserving unrelated cached data
  • MCP Client Notifications: Connected clients receive real-time resource update notifications
  • Zero Configuration: The subscription system works automatically with no setup required

For technical details, see the .

How It Works

Several major tools now use internal MCP resources with smart caching instead of making direct API calls every time:

ToolInternal ResourceCache DurationPerformance Benefit
obsidian_get_all_tagsvault://tags5 minutes10-50x faster for tag operations
obsidian_get_recent_changesvault://recent30 secondsNear-instant recent file listings with titles & previews
obsidian_get_file_contentsvault://note/{path}2 minutesDramatically faster for repeated file access
obsidian_simple_searchvault://search/{query}1 minuteCached search results for common queries
obsidian_list_files_in_vaultvault://structure5 minutesInstant vault browsing after first load
obsidian_list_files_in_dirvault://folder/{path}2 minutesFast folder navigation

User Benefits

  • Transparent Performance: All speed improvements happen automatically - no configuration required
  • Backward Compatible: Existing workflows continue to work exactly the same way
  • Smart Invalidation: Cache automatically updates when you modify files through the tools
  • Reduced API Load: Fewer direct calls to Obsidian's REST API improves overall responsiveness
  • Better User Experience: Operations like browsing tags, searching, and accessing recent files feel instant

Technical Details

The optimization works by:

  1. Resource-First Strategy: Tools check internal MCP resources before making API calls
  2. Tiered Caching: Different cache durations based on data volatility (30s for recent changes, 5min for vault structure)
  3. Graceful Fallback: If resources aren't available, tools automatically fall back to direct API calls
  4. Memory Efficient: Uses LRU caching with automatic cleanup to prevent memory leaks

This optimization is part of our commitment to making the Obsidian MCP server both powerful and performant for daily use.

MCP Resource Enhancements

Resource Metadata (v2.3.0)

All MCP resources now include optional metadata in the _meta field, providing file size and modification timestamps without requiring additional API calls. This enables better cache optimization and resource management by clients.

Metadata Structure
{
  "uri": "vault://note/meeting-notes.md",
  "name": "Meeting Notes",
  "mimeType": "text/plain",
  "text": "# Meeting Notes\n...",
  "_meta": {
    "size": 2048,                           // File size in bytes
    "sizeFormatted": "2.00 KB",             // Human-readable size
    "lastModified": "2025-10-07T14:30:00.000Z"  // ISO 8601 timestamp (UTC)
  }
}
Use Cases
  • Cache Validation: Use lastModified timestamps to determine if cached resources are stale
  • Resource Filtering: Filter resources by size before fetching full content
  • Performance Monitoring: Track resource sizes to optimize batch operations
  • User Feedback: Display file sizes and modification dates in UI
Graceful Degradation

The _meta field is optional. If metadata cannot be fetched (e.g., API errors), resources will still work without metadata. This ensures backward compatibility and reliability.

Protocol-Compliant Error Handling

Error handling now uses standard MCP error codes for consistent protocol integration:

HTTP StatusMCP Error CodeUsage
404MethodNotFound (-32601)Resource or file not found
400, 401, 403InvalidParams (-32602)Validation or authentication errors
500, 502, 503, 504InternalError (-32603)Server errors

Error Response Example:

// Before: Tool-specific error format
{
  "success": false,
  "error": "File not found",
  "tool": "obsidian_get_file_contents"
}

// After: MCP protocol-compliant
throw new McpError(
  ErrorCode.MethodNotFound,
  "Resource not found: vault://note/missing.md"
);

This standardization enables better error handling across all MCP clients and tools.

Binary File Support (MCP4 - v2.4.0)

Access images, PDFs, audio, and video files through the same unified vault://note/{path} URI. The server automatically detects binary files and returns them as base64-encoded blobs.

Supported Formats:

  • Images: PNG, JPG, JPEG, GIF, SVG, WebP, BMP, ICO
  • Documents: PDF
  • Audio: MP3, WAV, OGG, AAC, FLAC, M4A
  • Video: MP4, WebM, MOV, AVI, MKV

How It Works: The server automatically detects file type based on extension and returns appropriate content:

  • Text files (.md, .txt): Returned as TextResourceContents with markdown
  • Binary files: Returned as BlobResourceContents with base64-encoded data

Example - Accessing an image:

// Request an image resource
const imageResource = await client.readResource('vault://note/attachments/diagram.png');

// Response structure for binary files
{
  "uri": "vault://note/attachments/diagram.png",
  "name": "diagram.png",
  "mimeType": "image/png",
  "blob": "iVBORw0KGgoAAAANSUhEUgAA...", // base64-encoded data
  "_meta": {
    "size": 45678,
    "sizeFormatted": "44.61 KB",
    "lastModified": "2025-10-07T14:30:00.000Z"
  }
}

Size Limits: Binary files are limited to 10 MB for safety and performance. Files exceeding this limit will return an error with suggestions to access through tools instead.

Use Cases:

  • Display images embedded in notes
  • Access PDF attachments for processing
  • Extract audio/video metadata
  • Download binary assets programmatically

Feature Status

This section shows what resources and capabilities are available in the Obsidian MCP server.

MCP Resources Available ✅

MCP Resources provide read-only access to data from your Obsidian vault through the resources protocol. These are ideal for AI assistants to maintain context about your vault.

📚 See the for detailed documentation, examples, and best practices.

Static Resources (Cached 5min)
ResourceDescriptionExample URI
Vault TagsAll unique tags with usage countsvault://tags
Vault StatisticsFile and note counts for the vaultvault://stats
Recent ChangesRecently modified notes with preview mode (cached 30s)vault://recent or vault://recent?mode=full
Vault StructureComplete hierarchical structurevault://structure
Dynamic Resources (Cached 1-2min)
ResourceDescriptionExample URI
Individual NotesRead any note by pathvault://note/Daily/2024-01-01.md
Folder ContentsBrowse folder contents by pathvault://folder/Projects
Daily NotesAccess daily notes by datevault://daily/2024-01-15
Notes by TagFind all notes with specific tagvault://tag/project
Search ResultsSearch vault for contentvault://search/meeting%20notes
Using Resources

Resources are accessed through the MCP protocol's resources/list and resources/read methods:

// List available resources
const resources = await client.listResources();

// Read specific resources
const tags = await client.readResource('vault://tags');
const stats = await client.readResource('vault://stats');
const note = await client.readResource('vault://note/meeting-notes.md');
const folder = await client.readResource('vault://folder/Projects');

// Recent changes with preview mode (default)
const recentPreview = await client.readResource('vault://recent');
// Returns: { notes: [{ path, title, modifiedAt, preview }], mode: 'preview' }

// Recent changes with full content 
const recentFull = await client.readResource('vault://recent?mode=full');
// Returns: { notes: [{ path, title, modifiedAt, content }], mode: 'full' }

⚠️ Claude Desktop Limitation: Resources currently cannot be accessed directly in Claude Desktop due to a known limitation. However, equivalent tools provide the same functionality with automatic caching benefits. See for details.

Resource vs Tool Decision
  • Resources: Read-only data access, cached responses, reference information that AI needs in context
  • Tools: Actions that modify content, real-time operations, one-time queries

Example workflow: Use vault://tags resource to see available tags → Use obsidian_get_files_by_tag tool to find specific files → Use vault://note/{path} resource to read those files.

Tools

The server implements multiple tools to interact with Obsidian:

  • list_files_in_vault: Lists all files and directories in the root directory of your Obsidian vault
  • list_files_in_dir: Lists all files and directories in a specific Obsidian directory (now returns empty array for empty directories instead of error)
  • find_empty_directories: Find all empty directories in your vault by scanning the directory structure
  • get_file_contents: Return the content of a single file in your vault
  • batch_get_file_contents: Return the contents of multiple files in your vault, concatenated with headers
  • simple_search: Simple search for documents matching a specified text query across all files in the vault
  • advanced_search: Advanced search with structured filters for content, metadata, tags, and frontmatter (recommended)
  • complex_search: Complex search using JsonLogic queries - requires Obsidian REST API support for JsonLogic operators
  • obsidian_edit: Edit Obsidian vault notes with smart operations - progressive complexity from simple appends to structured edits
  • simple_append: Simple text appending to files - reliable for basic additions
  • simple_replace: Simple find and replace operations - straightforward text replacement
  • query_structure: Query document structure to get headings, blocks, and sections - useful for LLMs to build unambiguous references before modifying content
  • append_content: Append content to a new or existing file in the vault
  • delete_file: Delete a file or directory from your vault
  • rename_file: Rename a file within the same directory while preserving history and updating links (requires updated REST API plugin)
  • move_file: Move a file to a different location (can move between directories, rename in place, or both) while preserving history and updating links (requires updated REST API plugin)
  • move_directory: Move an entire directory and all its contents to a different location while preserving the internal structure and updating all links
  • copy_file: Copy a file to a new location within the vault, creating a duplicate with all content preserved
  • copy_directory: Copy an entire directory and all its contents to a new location, preserving the internal structure
  • check_path_exists: Check if a file or directory exists in the vault and determine its type
  • create_directory: Create a new directory in the vault, with support for creating nested directory structures
  • delete_directory: Delete a directory from the vault, with optional recursive deletion of contents
  • get_all_tags: List all unique tags in the vault with their usage counts
  • get_files_by_tag: Get all files that contain a specific tag
  • rename_tag: Rename a tag across the entire vault
  • manage_file_tags: Add or remove tags from a specific file (batch operations - 10x-100x faster for multiple tags)
  • get_periodic_note: Get current periodic note for the specified period (daily, weekly, monthly, quarterly, yearly)
  • get_recent_periodic_notes: Get most recent periodic notes for the specified period type
  • get_recent_changes: Get recently modified files in the vault (note: content preview parameter not yet supported by API)
  • get_file_metadata: Get file metadata (size, dates, permissions) without retrieving content - efficient for large files
  • get_file_frontmatter: Get only the frontmatter of a file without content - efficient for metadata analysis
  • get_file_formatted: Get file in different formats (plain text, HTML, etc.) for token optimization

Example prompts

Its good to first instruct Claude to use Obsidian. Then it will always call the tool.

The use prompts like this:

  • Get the contents of the last architecture call note and summarize them
  • Search for all files where Azure CosmosDb is mentioned and quickly explain to me the context in which it is mentioned
  • Summarize the last meeting notes and put them into a new note 'summary meeting.md'. Add an introduction so that I can send it via email.
  • Rename my file 'draft-proposal.md' to 'final-proposal-2024.md'
  • Replace all occurrences of '![[old-image.png]]' with '![[new-image.png]]' in my notes
  • Find and replace 'TODO:' with '- [ ]' in meeting-notes.md to convert to checkboxes
  • Move 'inbox/todo.md' to 'projects/active/todo.md' to reorganize it
  • Move all files from the 'inbox' folder to 'processed/2024' folder
  • Move the entire 'drafts/2023' directory to 'archive/2023/drafts' to organize old content
  • Copy 'templates/meeting-template.md' to 'meetings/2024-07-02-standup.md' for today's meeting
  • Check if 'projects/important-project/' directory exists before creating new files there
  • Create a new directory 'projects/2024/q3-initiatives' for organizing quarterly work
  • Delete the empty 'old-drafts/' directory (moves to trash by default)
  • Permanently delete 'temp-folder/' and all its contents with recursive=true and permanent=true
  • Copy 'projects/template-structure/' to 'projects/new-client/' to reuse project structure
  • List all tags in my vault to see which ones are most used
  • Find all files tagged with #project to review my active projects
  • Rename the tag #todo to #task across all my notes
  • Add tags #meeting #important to today's meeting notes
  • Search for files containing "API" that were modified in the last week
  • Find all notes with frontmatter field "status" equal to "in-progress"
  • Search for markdown files larger than 10KB containing regex pattern "TODO|FIXME"
  • Get just the metadata for large-notes.md to check its size before reading
  • Extract only the frontmatter from meeting-notes.md to analyze the tags and status
  • Get today's daily note in plain text format without markdown formatting
  • Retrieve project-readme.md as HTML for sharing outside Obsidian
  • Find all empty directories in my vault for cleanup
  • Search for empty directories within the 'archive' folder only
  • List files in 'projects/drafts/' - will return empty array if the directory is empty

Editing Tools Overview

The MCP server provides tools with progressive complexity for editing Obsidian notes:

Simple Operations

  • obsidian_simple_append - Append text to files with automatic newline handling
  • obsidian_simple_replace - Find and replace text in files

Smart Editing

  • obsidian_edit - Unified editing tool with progressive complexity:
    • Stage 1: Simple append operations (100% reliability)
    • Stage 2: Structure-aware edits (insert after/before headings)
    • Stage 3: Complex operations (batch edits, new sections)

Structure Query

  • obsidian_query_structure - Query document structure to find headings and blocks before editing

Usage examples:

// Simple append
await obsidian_simple_append({
  filepath: "note.md",
  content: "New paragraph"
});

// Smart editing - insert after heading
await obsidian_edit({
  file: "note.md",
  after: "Overview",
  add: "New content after the Overview heading"
});

// Find and replace
await obsidian_simple_replace({
  filepath: "note.md",
  find: "old text",
  replace: "new text"
});

// Complex batch operations
await obsidian_edit({
  file: "note.md",
  batch: [
    { after: "Introduction", add: "New intro content" },
    { find: "TODO", replace: "DONE" }
  ]
});

See the for details.

Tool Categories

Tools are organized into categories for better discoverability:

  • File Operations: Read, write, copy, move files
  • Directory Operations: Create, delete, move directories
  • Search: Simple and advanced search capabilities
  • Editing: Smart content editing with structure awareness
  • Tags: Tag management and operations
  • Periodic Notes: Daily, weekly, monthly note support

Configuration

Configuration Overview

The Obsidian MCP server supports flexible configuration through a hierarchical system that checks multiple sources in order of precedence. This allows you to configure the server in the way that best fits your workflow.

Configuration Hierarchy

The server loads configuration from these sources in order (higher priority overrides lower):

  1. Environment Variables (highest priority)

    • OBSIDIAN_API_KEY - Your Obsidian REST API key
    • OBSIDIAN_HOST - Obsidian REST API host (default: 127.0.0.1)
    • OBSIDIAN_CONFIG_FILE - Path to custom config file
  2. Config File (recommended for persistent setup)

    • Default location: ~/.config/mcp/obsidian.json
    • Custom location via OBSIDIAN_CONFIG_FILE environment variable
  3. Default Values (lowest priority)

    • Host: 127.0.0.1
    • Port: 27124 (Obsidian REST API default)

Configuration Methods

Method 1: Environment Variables

Best for: Temporary sessions, testing, CI/CD environments

# Set API key (required)
export OBSIDIAN_API_KEY=your_api_key_here

# Set custom host (optional, defaults to 127.0.0.1)
export OBSIDIAN_HOST=192.168.1.100

# Use custom config file location (optional)
export OBSIDIAN_CONFIG_FILE=/path/to/your/config.json
Method 2: Configuration File

Best for: Persistent setup, multiple vaults, shared configurations

Default location: ~/.config/mcp/obsidian.json

{
  "apiKey": "your_api_key_here",
  "host": "127.0.0.1"
}

Custom location: Set via environment variable

export OBSIDIAN_CONFIG_FILE=/path/to/your/custom-config.json
Method 3: Claude Desktop Configuration

Best for: Claude Desktop users who want all config in one place

{
  "mcpServers": {
    "obsidian-mcp-ts": {
      "command": "npx",
      "args": ["obsidian-mcp-ts"],
      "env": {
        "OBSIDIAN_API_KEY": "your_api_key_here",
        "OBSIDIAN_HOST": "127.0.0.1"
      }
    }
  }
}

Configuration Precedence Examples

Example 1: Environment variable overrides config file

# Config file has apiKey: "file-key"
export OBSIDIAN_API_KEY="env-key"
# Server will use "env-key"

Example 2: Using config file with custom host

// ~/.config/mcp/obsidian.json
{
  "apiKey": "your-key",
  "host": "10.0.0.5"
}

Example 3: Custom config file location

export OBSIDIAN_CONFIG_FILE=/home/user/vault-configs/work-vault.json

Finding Your API Key

  1. Open Obsidian
  2. Go to Settings → Community Plugins
  3. Find "Local REST API" and click the gear icon
  4. Copy the API key from the plugin settings

Security Best Practices

  1. Never commit API keys to version control
  2. Use config files instead of environment variables for persistent setups
  3. Set appropriate permissions on config files:
    chmod 600 ~/.config/mcp/obsidian.json
    
  4. Use different API keys for different vaults when possible

Troubleshooting Configuration Issues

If the server can't find your API key, it will show:

OBSIDIAN_API_KEY not found. Please provide it via:
1. OBSIDIAN_API_KEY environment variable
2. Config file at ~/.config/mcp/obsidian.json
3. Custom config file via OBSIDIAN_CONFIG_FILE environment variable

Common issues:

  • Permission denied: Check your API key is correct
  • Connection failed: Verify Obsidian is running and REST API plugin is enabled
  • File not found: Ensure config file path is absolute, not relative

Quick Setup

Use the provided setup script for interactive configuration:

./setup-config.sh

Or manually use the configuration template at obsidian-config-template.json:

cp obsidian-config-template.json ~/.config/mcp/obsidian.json
# Edit the file and replace YOUR_OBSIDIAN_API_KEY_HERE with your actual key

Advanced Configuration

For detailed configuration options, multiple vault setups, and troubleshooting, see the .

Quickstart

Install

Install from npm
npm install -g obsidian-mcp-ts
Obsidian REST API

You need the Obsidian REST API community plugin running: https://github.com/coddingtonbear/obsidian-local-rest-api

Install and enable it in the settings and copy the api key.

Claude Desktop

On MacOS: ~/Library/Application\ Support/Claude/claude_desktop_config.json

On Windows: %APPDATA%/Claude/claude_desktop_config.json

Development/Unpublished Servers Configuration
{
  "mcpServers": {
    "obsidian-mcp-ts": {
      "command": "node",
      "args": [
        "<path_to>/obsidian-mcp-ts/dist/index.js"
      ],
      "env": {
        "OBSIDIAN_API_KEY": "<YOUR_OBSIDIAN_API_KEY>"
      }
    }
  }
}
Published Servers Configuration
{
  "mcpServers": {
    "obsidian-mcp-ts": {
      "command": "npx",
      "args": [
        "obsidian-mcp-ts"
      ],
      "env": {
        "OBSIDIAN_API_KEY": "<YOUR_OBSIDIAN_API_KEY>"
      }
    }
  }
}
Using External Config File (Recommended)

First, create the config file at ~/.config/mcp/obsidian.json:

{
  "apiKey": "your-obsidian-api-key-here",
  "host": "127.0.0.1"
}

Then in Claude Desktop config, you only need:

{
  "mcpServers": {
    "obsidian-mcp-ts": {
      "command": "npx",
      "args": ["obsidian-mcp-ts"]
    }
  }
}

The server will automatically load the API key from the config file. You can also use a custom config location:

{
  "mcpServers": {
    "obsidian-mcp-ts": {
      "command": "npx",
      "args": ["obsidian-mcp-ts"],
      "env": {
        "OBSIDIAN_CONFIG_FILE": "/path/to/your/config.json"
      }
    }
  }
}

Error Handling

The MCP server uses a simplified error format for clear and consistent error reporting:

Error Response Structure

All errors follow this structure:

{
  success: false,
  error: string,        // Error message
  tool: string,         // Tool name that generated the error
  suggestion?: string,  // Optional actionable suggestion
  example?: object      // Optional example of correct usage
}

Common Error Types

  1. File Not Found (404)

    {
      "success": false,
      "error": "File not found: notes/missing.md",
      "tool": "obsidian_get_file_contents",
      "suggestion": "Use obsidian_list_files_in_vault to browse available files first"
    }
    
  2. Authentication Failed (401)

    {
      "success": false,
      "error": "Authentication failed - check API key",
      "tool": "obsidian_list_files_in_vault",
      "suggestion": "Verify your OBSIDIAN_API_KEY is correct in Claude Desktop settings"
    }
    
  3. Invalid Parameters

    {
      "success": false,
      "error": "Missing required parameters",
      "tool": "obsidian_append_content",
      "suggestion": "Provide both filepath and content parameters",
      "example": {
        "filepath": "notes/example.md",
        "content": "New content to append"
      }
    }
    

Error Recovery

When you encounter an error:

  1. Check the suggestion field for immediate fixes
  2. Use the example field to understand correct parameter format
  3. For file operations, verify the file exists with obsidian_list_files_in_vault
  4. For authentication errors, check your API key configuration

Development

Building

To prepare the package for distribution:

  1. Install dependencies:
npm install
  1. Build the TypeScript code:
npm run build

Testing

Run the test suite:

# Run all tests
npm test

# Run integration tests (requires compiled code)
npm run build
npm run test:integration

# Run E2E tests against real Obsidian API
OBSIDIAN_API_KEY=your-key npm run test:e2e

# Run tests in watch mode during development
npm run test -- --watch

Debugging

Since MCP servers run over stdio, debugging can be challenging. For the best debugging experience, we strongly recommend using the MCP Inspector.

You can launch the MCP Inspector via npm with this command:

# For development (with TypeScript)
npx @modelcontextprotocol/inspector tsx src/index.ts

# For production (compiled)
npx @modelcontextprotocol/inspector node dist/index.js

Upon launching, the Inspector will display a URL that you can access in your browser to begin debugging.

You can also watch the server logs with this command:

tail -n 20 -f ~/Library/Logs/Claude/mcp-server-obsidian-mcp-ts.log

Development Commands

# Run in development mode with auto-reload
npm run dev

# Type check without building
npm run typecheck

# Build for production
npm run build

# Run the built server
npm start

# Lint code
npm run lint

Performance Optimization

The server includes several performance optimizations:

  • LRU Cache: Reduces API calls for frequently accessed data
  • Request Deduplication: Prevents duplicate concurrent requests
  • Optimized Batch Processing: Smart concurrency control with retry logic
  • Streaming Results: Process large datasets without loading everything into memory
Performance Benchmarks

Compare cached vs non-cached operations to understand when caching is beneficial:

# Run comprehensive benchmark test
npm test -- tests/benchmarks/cached-vs-noncached.benchmark.test.ts

# Quick standalone benchmark
npx tsx scripts/run-cache-benchmark.ts --scenario sequential

# Test with different configurations
npx tsx scripts/run-cache-benchmark.ts --iterations 100 --data-size 10240

The benchmarks test six scenarios:

  • Sequential Access: High hit rate (90-98%), 10-50x speedup ✅
  • 80/20 Pattern: Realistic usage (70-85% hit rate), 3-8x speedup ✅
  • Random Access: Low hit rate (10-30%), marginal benefit ⚠️
  • Unique Access: No cache benefit (0% hit rate), disable caching ❌

See for detailed analysis and configuration guidelines.

See for detailed optimization strategies.

Architecture

The codebase follows clean architecture principles:

  • Tools: Each tool is a self-contained class with metadata
  • Utilities: Reusable components (Cache, BatchProcessor, ErrorHandler)
  • Constants: Centralized configuration values
  • Types: Comprehensive TypeScript types for all operations

Tools are dynamically discovered at runtime, making it easy to add new functionality.