Metadata-Version: 2.4
Name: librarian-mcp
Version: 1.0.1
Summary: MCP server for document indexing and semantic search
Author: Adam Knight
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: AsyncIO
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Database :: Database Engines/Servers
Classifier: Topic :: Office/Business
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Text Processing :: Markup :: Markdown
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: aiosqlite>=0.19
Requires-Dist: alembic>=1.13
Requires-Dist: click>=8.0
Requires-Dist: fastmcp<4,>=3.0.1
Requires-Dist: loguru>=0.7
Requires-Dist: mdformat-frontmatter>=2.0
Requires-Dist: mdformat-gfm>=0.3
Requires-Dist: mdformat>=0.7
Requires-Dist: pybars3>=0.9
Requires-Dist: pydantic>=2.0
Requires-Dist: python-frontmatter>=1.0
Requires-Dist: sqlalchemy[asyncio]>=2.0
Requires-Dist: unidecode>=1.4.0
Requires-Dist: watchfiles>=0.21
Provides-Extra: dev
Requires-Dist: basedpyright>=1.0; extra == 'dev'
Requires-Dist: faker>=20.0; extra == 'dev'
Requires-Dist: freezegun>=1.0; extra == 'dev'
Requires-Dist: pre-commit>=3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest-mock>=3.0; extra == 'dev'
Requires-Dist: pytest-testmon>=2.0; extra == 'dev'
Requires-Dist: pytest-xdist>=3.0; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Description-Content-Type: text/markdown

# Librarian MCP Server

A semantic knowledge graph server implementing the Model Context Protocol (MCP). Librarian transforms your markdown files into a persistent, queryable knowledge base with semantic annotations, full-text search, and graph-based context building.

## Features

- **Semantic Annotations**: Categorized observations and typed relations create a knowledge graph
- **Full-Text Search**: SQLite FTS5 with BM25 ranking for fast, relevant searches
- **Multi-Project Support**: Manage multiple isolated knowledge bases
- **Real-Time Sync**: File watcher automatically indexes external changes
- **MCP Resources**: Notes exposed as standard MCP resources with URI-based navigation
- **MCP Tools**: 15 tools for creating, editing, searching, and analyzing knowledge
- **MCP Prompts**: 6 pre-built workflows for common knowledge management tasks
- **Local-First**: All data stored in plain markdown files you own

## Quick Start

### Installation

Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).

```bash
# Install from the package registry
uv pip install librarian-mcp --index-url https://code.movq.us/api/packages/movq/pypi/simple/

# Or install with pip
pip install librarian-mcp --index-url https://code.movq.us/api/packages/movq/pypi/simple/
```

#### Development Setup

```bash
# Clone the repository
git clone https://code.movq.us/movq/librarian-mcp.git
cd librarian-mcp

# Install with dev dependencies
uv sync --extra dev
```

### Initialize Your First Project

```bash
# Initialize a project from an existing directory of markdown files
uv run librarian init ~/Documents/notes --set-default

# Or create a new project
mkdir -p ~/knowledge-base
uv run librarian init ~/knowledge-base --name main --set-default
```

### Start the MCP Server

```bash
# Start with stdio transport (for Claude Desktop)
uv run librarian mcp

# Start with HTTP transport for network access
uv run librarian mcp --transport http --host 0.0.0.0 --port 4242
```

### Configure Your MCP Client

#### Claude Desktop

Add to your Claude Desktop MCP settings (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):

```json
{
  "mcpServers": {
    "librarian": {
      "command": "uvx",
      "args": [
        "--index-url", "https://code.movq.us/api/packages/movq/pypi/simple/",
        "librarian-mcp",
        "mcp"
      ]
    }
  }
}
```

## Usage

### Creating Notes with Semantic Annotations

Librarian recognizes two types of semantic annotations in your markdown:

#### Observations

Categorized facts within notes:

```markdown
## Observations
- [decision] Chose PostgreSQL for ACID compliance #database #architecture
- [requirement] Must support 10k concurrent users #scale
- [technique] Use connection pooling with pgbouncer #performance
```

Standard categories: `idea`, `decision`, `fact`, `technique`, `requirement`, `question`, `insight`

#### Relations

Directional links between notes using WikiLink syntax:

```markdown
## Relations
- implements [[System Architecture]]
- requires [[Database Schema]]
- relates_to [[Performance Requirements]]
```

Standard relation types: `relates_to`, `implements`, `requires`, `extends`, `part_of`, `contrasts_with`, `preceded_by`, `influenced_by`

### Using MCP Tools

#### Available Tools

| Tool | Purpose |
|------|---------|
| **ping** | Echo a message (diagnostic) |
| **status** | Server status information (diagnostic) |
| **write_note** | Create or update a markdown note |
| **edit_note** | Modify existing notes (append, prepend, find_replace, replace_section) |
| **delete_note** | Remove notes or directories |
| **move_note** | Relocate notes while maintaining WikiLink references |
| **search_notes** | Full-text search with filtering and pagination |
| **search** | Cross-project search returning URIs |
| **build_context** | Graph traversal to gather related entities |
| **recent_activity** | View recent changes across projects |
| **find_stale_notes** | Find notes not updated in N days |
| **canvas_tool** | Create visual knowledge maps (Obsidian-compatible) |
| **list_projects** | Show all configured projects |
| **create_project** | Register a new project |
| **delete_project** | Remove a project from configuration |

#### Example: Creating a Note

```javascript
// Via MCP tool call
{
  "tool": "write_note",
  "arguments": {
    "title": "API Design Decisions",
    "directory": "projects",
    "project": "main",
    "content": `# API Design Decisions

## Context
Evaluated options for the new service API.

## Observations
- [decision] REST over GraphQL for simplicity #api
- [requirement] Must support pagination #api
- [technique] Use OpenAPI 3.0 for documentation

## Relations
- implements [[System Architecture]]
- requires [[Authentication]]`
  }
}
```

### Using MCP Resources

Notes are exposed as standard MCP Resources with URI-based navigation:

```
librarian://notes/{project}/{permalink}           # Full note
librarian://notes/{project}/{permalink}#Section   # Specific section
librarian://notes/{project}/{permalink}?page=2    # Paginated
```

#### Example: Reading a Note Section

```javascript
{
  "method": "resources/read",
  "params": {
    "uri": "librarian://notes/main/api-design#Observations"
  }
}
```

### Using MCP Prompts

Prompts provide pre-built workflows for common tasks:

1. **restore** - Restore session context from the knowledge base
2. **consolidate** - Extract knowledge from current conversation
3. **done** - End session: consolidate + append to journal
4. **search** - Search with guided follow-up instructions
5. **connect** - Find potential connections for a note (TF-IDF keyword extraction)
6. **review** - Surface maintenance issues (orphaned notes, unresolved references, stale content)

#### Example: Using the Review Prompt

```javascript
{
  "method": "prompts/get",
  "params": {
    "name": "review",
    "arguments": {
      "project": "main",
      "days_stale": 90
    }
  }
}
```

## Configuration

### Project Management

```bash
# List all projects
uv run librarian project list

# Add a new project
uv run librarian project add work ~/work/knowledge-base --default

# Set custom database location
uv run librarian project add shared ~/team/kb \
  --database-url sqlite:////var/data/shared-kb.db

# Remove a project (files are not deleted)
uv run librarian project remove old-project

# Get/set default project
uv run librarian project default           # Show current default
uv run librarian project default main      # Set 'main' as default
```

### Configuration Files

Located at `~/.config/librarian/` (or `~/Library/Application Support/librarian/` on macOS):

**config.toml**:
```toml
default_project_mode = false
```

**projects.toml**:
```toml
default_project = "main"

[[projects]]
name = "main"
path = "~/Documents/notes"
# database_url defaults to {path}/.librarian/index.db

[[projects]]
name = "work"
path = "~/work/knowledge-base"
database_url = "sqlite:////var/data/work-kb.db"
```

### Project-Level Database

Each project stores its index in `{project_path}/.librarian/index.db` by default. Add this to your `.gitignore`:

```
.librarian/
```

The database is regenerated from markdown files, so it doesn't need to be version controlled.

## Development

### Setup

```bash
# Install development dependencies
uv sync --extra dev

# Run tests
uv run pytest

# Run tests with coverage
uv run pytest --cov=librarian --cov-report=term-missing

# Type checking
uv run basedpyright

# Linting and formatting
uv run ruff check src tests
uv run ruff format src tests

# Run pre-commit hooks on all files
uv run pre-commit run --all-files
```

### Running Tests

The project has 960+ tests covering:

- Domain models (Note, Observation, Relation)
- Database operations (CRUD, indexing, FTS5)
- Search and graph traversal
- MCP tools, resources, and prompts
- MCP client integration tests (full protocol stack)
- File watching and synchronization
- Error handling and edge cases

```bash
# Run all tests
uv run pytest

# Run specific test file
uv run pytest tests/test_models.py

# Run with verbose output
uv run pytest -v

# Run with coverage
uv run pytest --cov=librarian --cov-report=html
open htmlcov/index.html
```

### Project Structure

```
librarian/
├── src/librarian/
│   ├── models/              # Domain models (Note, Observation, Relation)
│   ├── database/            # SQLAlchemy ORM and repository
│   ├── indexer/             # File-to-database synchronization
│   ├── search/              # Full-text search and graph traversal
│   ├── markdown/            # Markdown parsing and formatting
│   ├── project/             # Project and note lifecycle management
│   ├── mcp/                 # MCP interface layer
│   │   ├── tools/           # Tool implementations
│   │   ├── resources.py     # Resource handlers
│   │   ├── prompts/         # Prompt implementations
│   │   └── templates/       # Handlebars templates for prompts
│   ├── watcher.py           # File system monitoring
│   ├── server.py            # FastMCP server setup
│   └── cli.py               # Command-line interface
├── tests/                   # Unit tests
│   ├── integration/         # MCP client integration tests
│   └── fixtures/            # Fixture markdown files for integration tests
├── docs/                    # Documentation
│   ├── librarian-spec.md    # Complete specification
│   └── PLAN.md              # Implementation plan
└── CLAUDE.md                # Development instructions
```

## Architecture

Librarian follows a layered architecture with dependency injection:

1. **Domain Layer**: Pure Python models (Note, Observation, Relation) that own their markdown syntax
2. **Database Layer**: Repository pattern with SQLAlchemy ORM and FTS5 integration
3. **Indexer Layer**: Bridges markdown files and database
4. **Project Layer**: Coordinates note lifecycle and cross-note operations
5. **Search Layer**: Graph traversal and semantic search
6. **MCP Layer**: Thin wrappers exposing domain layer via MCP protocol

This design enables:
- **Testability**: All layers use dependency injection
- **Separation of Concerns**: Each layer has a single responsibility
- **Maintainability**: Clear boundaries between components

## Troubleshooting

### Server won't start

```bash
# Check if port is already in use (HTTP transport)
lsof -i :4242

# Verify project configuration
uv run librarian project list

# Check logs
uv run librarian mcp --log /tmp/librarian.log --loglevel DEBUG
tail -f /tmp/librarian.log
```

### Notes not indexing

```bash
# Verify file permissions
ls -la ~/Documents/notes

# Check database exists
ls -la ~/Documents/notes/.librarian/

# Force re-index (delete database and restart server)
rm -rf ~/Documents/notes/.librarian/
uv run librarian mcp
```

### Search not finding notes

- Ensure notes have been indexed (check `.librarian/index.db` exists)
- Verify FTS5 is enabled in your SQLite build: `sqlite3 :memory: "pragma compile_options;"`
- Check that your search terms match note content, titles, or tags

## Contributing

Contributions are welcome! Please:

1. Read `CLAUDE.md` for development guidelines
2. Follow the existing code style (enforced by pre-commit hooks)
3. Add tests for new features
4. Update documentation as needed
5. Run the full test suite before submitting PRs

## License

MIT License

## Links

- [Specification](docs/librarian-spec.md) - Complete technical specification
- [Development Plan](docs/PLAN.md) - Phased implementation plan
- [MCP Protocol](https://modelcontextprotocol.io) - Model Context Protocol documentation
- [FastMCP](https://gofastmcp.com) - MCP server framework

## Acknowledgments

Built with:
- [FastMCP](https://github.com/jlowin/fastmcp) - MCP server framework
- [SQLAlchemy](https://www.sqlalchemy.org/) - Database ORM
- [Click](https://click.palletsprojects.com/) - CLI framework
- [Loguru](https://github.com/Delgan/loguru) - Logging
- [Watchfiles](https://github.com/samuelcolvin/watchfiles) - File system monitoring
