MCP server service discovery - Read-only Python library for querying MCP server capabilities
Project description
chora-manifest
MCP Server Service Discovery and Capability Catalog
Overview
chora-manifest is a Python library for querying MCP (Model Context Protocol) server capabilities from a centralized registry. It provides a simple, async API for service discovery, enabling applications to find and inspect available MCP servers programmatically.
Version 0.1.0 is a focused, read-only implementation perfect for:
- Discovering available MCP servers in your ecosystem
- Querying server capabilities and tools
- Filtering servers by category (integration, database, productivity, infrastructure)
- Building service catalogs and dashboards
Features
v0.1.0 Capabilities
- ✅ Load Registry: Read MCP server definitions from YAML
- ✅ List Capabilities: Get all registered MCP servers
- ✅ Get by ID: Retrieve specific server by identifier
- ✅ Filter by Category: Find servers by type (integration, database, etc.)
- ✅ Search: Query by name or description (case-insensitive)
- ✅ Count Operations: Get totals overall or by category
- ✅ Type Safety: Full Pydantic validation throughout
- ✅ Async API: Built with async/await for modern Python
- ✅ 100% Test Coverage: Comprehensive test suite (51 tests)
What's NOT in v0.1.0
The following features are planned for future versions:
- ❌ Write operations (add/update/remove servers)
- ❌ CLI interface
- ❌ REST API
- ❌ MCP server interface
- ❌ GitHub discovery/import
- ❌ Health monitoring
- ❌ Maturity levels
Installation
From PyPI
pip install chora-manifest
From Source
git clone https://github.com/yourusername/chora-manifest.git
cd chora-manifest
pip install -e .
Quick Start
Basic Usage
import asyncio
from manifest import create_manifest_service
async def main():
# Create service (uses ecosystem-manifest/registry.yaml by default)
service = create_manifest_service()
# Initialize (loads registry)
await service.initialize()
# List all capabilities
capabilities = await service.list_capabilities()
print(f"Found {len(capabilities)} MCP servers")
# Get specific server
github = await service.get_capability("github")
if github:
print(f"GitHub server: {github.description}")
print(f"Tools: {len(github.tools)}")
# Filter by category
databases = await service.filter_by_category("database")
print(f"Database servers: {len(databases)}")
# Search
results = await service.search("integration")
print(f"Integration-related servers: {len(results)}")
asyncio.run(main())
Custom Registry Path
from pathlib import Path
from manifest import create_manifest_service
service = create_manifest_service(
registry_path=Path("my-registry.yaml")
)
await service.initialize()
API Reference
Factory Function
create_manifest_service(registry_path=None)
Create a ManifestService instance.
Parameters:
registry_path(Path | str | None): Path to registry YAML. Defaults toecosystem-manifest/registry.yaml
Returns: ManifestService (not yet initialized)
Example:
service = create_manifest_service()
await service.initialize()
ManifestService
Async service for querying MCP server capabilities.
async initialize()
Load registry from file. Must be called before using query methods.
Raises:
FileNotFoundError: If registry file doesn't existyaml.YAMLError: If YAML is malformed
async list_capabilities() -> list[Capability]
List all registered MCP server capabilities.
Returns: List of all Capability objects
Example:
capabilities = await service.list_capabilities()
for cap in capabilities:
print(f"{cap.name}: {cap.description}")
async get_capability(id: str) -> Capability | None
Get capability by ID.
Parameters:
id(str): Capability identifier (e.g., "github", "slack")
Returns: Capability if found, None otherwise
Example:
github = await service.get_capability("github")
if github:
print(f"Version: {github.version}")
async filter_by_category(category: Category) -> list[Capability]
Filter capabilities by category.
Parameters:
category(Category): Category enum value
Returns: List of capabilities in the category
Example:
from manifest import Category
databases = await service.filter_by_category(Category.DATABASE)
async search(query: str) -> list[Capability]
Search capabilities by name or description (case-insensitive).
Parameters:
query(str): Search string
Returns: List of matching capabilities
Example:
results = await service.search("database")
async count_total() -> int
Count total registered capabilities.
Returns: Total count
async count_by_category(category: Category) -> int
Count capabilities in a specific category.
Parameters:
category(Category): Category enum value
Returns: Count in category
Data Models
Category (Enum)
MCP server categories:
Category.INTEGRATION- Integration servers (GitHub, Slack, etc.)Category.DATABASE- Database servers (PostgreSQL, MySQL, etc.)Category.PRODUCTIVITY- Productivity tools (Jira, Notion, etc.)Category.INFRASTRUCTURE- Infrastructure tools (Docker, Kubernetes, etc.)
Capability (Pydantic Model)
Represents an MCP server capability.
Fields:
id(str): Unique identifiername(str): Human-readable namedescription(str): Brief descriptionversion(str): Semantic version (e.g., "1.0.0")docker_image(str): Docker image referencetools(list[dict]): List of tool definitionscategory(Category): Server categorytags(list[str]): Searchable tags (default: [])repository(str | None): Source repository URL (optional)
Example:
from manifest import Capability, Category
capability = Capability(
id="my-server",
name="My Server",
description="Custom MCP server",
version="1.0.0",
docker_image="my-server:1.0.0",
tools=[{"name": "my_tool", "description": "Does something"}],
category=Category.INTEGRATION,
tags=["custom"],
repository="https://github.com/example/my-server"
)
Registry Format
The registry is a YAML file with the following structure:
version: "1.0.0"
updated: "2025-11-15T00:00:00Z"
servers:
- server:
name: github
description: GitHub integration MCP server
version: 1.0.0
repository: https://github.com/modelcontextprotocol/servers/tree/main/src/github
transport: stdio
tools:
- name: create_or_update_file
description: Create or update a file in a repository
input_schema:
type: object
properties:
path:
type: string
content:
type: string
metadata:
tags:
- integration
- version-control
- git
The service automatically converts the servers format to Capability objects.
Examples
Example 1: List All Servers
import asyncio
from manifest import create_manifest_service
async def main():
service = create_manifest_service()
await service.initialize()
capabilities = await service.list_capabilities()
print(f"MCP Server Catalog ({len(capabilities)} servers)\n")
print("-" * 60)
for cap in capabilities:
print(f"\n{cap.name} (v{cap.version})")
print(f" {cap.description}")
print(f" Category: {cap.category}")
print(f" Tools: {len(cap.tools)}")
if cap.repository:
print(f" Repo: {cap.repository}")
asyncio.run(main())
Example 2: Filter by Category
from manifest import create_manifest_service, Category
async def show_category_stats():
service = create_manifest_service()
await service.initialize()
categories = [
Category.INTEGRATION,
Category.DATABASE,
Category.PRODUCTIVITY,
Category.INFRASTRUCTURE
]
print("Server Distribution by Category\n")
for category in categories:
count = await service.count_by_category(category)
servers = await service.filter_by_category(category)
names = [s.name for s in servers]
print(f"{category.value.upper()}: {count}")
if names:
print(f" → {', '.join(names)}")
total = await service.count_total()
print(f"\nTotal: {total} servers")
Example 3: Search and Inspect
from manifest import create_manifest_service
async def search_and_inspect(query: str):
service = create_manifest_service()
await service.initialize()
results = await service.search(query)
print(f"Search results for '{query}': {len(results)} found\n")
for cap in results:
print(f"{cap.name}")
print(f" Description: {cap.description}")
print(f" Category: {cap.category}")
print(f" Available tools:")
for tool in cap.tools:
print(f" - {tool['name']}: {tool['description']}")
print()
Development
Setup
# Clone repository
git clone https://github.com/yourusername/chora-manifest.git
cd chora-manifest
# Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install development dependencies
pip install -e ".[dev]"
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=manifest --cov-report=html
# Run specific test file
pytest tests/test_service.py
# Run with verbose output
pytest -v
Code Quality
# Lint with ruff
ruff check .
# Format with ruff
ruff format .
# Type check with mypy
mypy manifest
Testing
chora-manifest v0.1.0 has comprehensive test coverage:
- 51 tests across 4 test modules
- 100% coverage on core implementation files
- TDD methodology: All tests written before implementation
- Fixtures: Reusable test data in
conftest.py
Test modules:
test_models.py: Pydantic model validation (9 tests)test_loader.py: YAML loading and parsing (10 tests)test_service.py: Service query methods (21 tests)test_factory.py: Factory function and API (11 tests)
Roadmap
v0.2.0 (Planned)
- Write operations (add/update/remove servers)
- GitHub discovery and import
- Health monitoring and status checks
v0.3.0 (Planned)
- CLI interface
- REST API
- Maturity level support
v1.0.0 (Future)
- MCP server interface
- Advanced querying and filtering
- Performance optimizations
Contributing
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass (
pytest) - Run code quality checks (
ruff check,mypy manifest) - Submit a pull request
License
This project is licensed under the MIT License - see LICENSE file for details.
Acknowledgments
- Built with Pydantic for data validation
- Powered by PyYAML for registry parsing
- Part of the chora ecosystem for MCP server management
Links
- GitHub: https://github.com/yourusername/chora-manifest
- Issues: https://github.com/yourusername/chora-manifest/issues
- Changelog: CHANGELOG.md
- PyPI: https://pypi.org/project/chora-manifest/
Version: 0.1.0 Status: Stable Python: 3.11+ License: MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file chora_manifest-0.1.1.tar.gz.
File metadata
- Download URL: chora_manifest-0.1.1.tar.gz
- Upload date:
- Size: 45.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84ac592d5bec61962042c4685c0159e0adea379a32b81a240839b0bb57bcd0d1
|
|
| MD5 |
b735b6d21a120bfba0dbbf51ad7b2203
|
|
| BLAKE2b-256 |
e2bb2b1686e88ff1448e84bac902bb875004a7f618b39a53f799580f1873ced5
|
File details
Details for the file chora_manifest-0.1.1-py3-none-any.whl.
File metadata
- Download URL: chora_manifest-0.1.1-py3-none-any.whl
- Upload date:
- Size: 41.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
94118be2c9a1ff9f11f11810f37a90813d08f6c0999978533d1339801bc2c51e
|
|
| MD5 |
5df7d093685f9287eefbbcb8281133c0
|
|
| BLAKE2b-256 |
53154ea33773f1bea0ce788a730995f55e0f96e40758a16ff173f8fb38f37b79
|