MCPEngine

by featureform

646 stars
246 downloads
Not rated
GitHub Website

About

EnrichMCP is a python framework for building data driven MCP servers

Details

Author
featureform
GitHub stars
646
Downloads
246
Categories
Other

- Automatic schema discovery – AI agents explore your entire data model with one call
- Relationship navigation – define relationships once, agents traverse naturally
- Type safety and validation – full Pydantic validation on every interaction
- Mutability and CRUD – auto-generated patch models for updates
- Built-in pagination – handle large datasets with PageResult
- Context and authentication – pass auth, database connections, or any context
- Request caching – reduce API overhead with per-request or global cache

Install via pip install enrichmcp or pip install enrichmcp[sqlalchemy] for SQLAlchemy support. To use, define data entities as Pydantic models with the EnrichModel base class and decorate them with @app.entity(). For SQLAlchemy users, add the EnrichSQLAlchemyMixin to your declarative base and call include_sqlalchemy_models(). Then run the MCP server with app.run(). AI agents can then call tools like explore_data_model(), list_*(), and navigate relationships automatically.

EnrichMCP

The ORM for AI Agents - Turn your data model into a semantic MCP layer

CI
Coverage
PyPI
Python 3.11+
License
Docs

EnrichMCP is a Python framework that helps AI agents understand and navigate your data. Built on MCP (Model Context Protocol), it adds a semantic layer that turns your data model into typed, discoverable tools - like an ORM for AI.

What is EnrichMCP?

Think of it as SQLAlchemy for AI agents. EnrichMCP automatically:

- Generates typed tools from your data models
- Handles relationships between entities (users → orders → products)
- Provides schema discovery so AI agents understand your data structure
- Validates all inputs/outputs with Pydantic models
- Works with any backend - databases, APIs, or custom logic

Installation

pip install enrichmcp

With SQLAlchemy support

pip install enrichmcp[sqlalchemy]

Show Me Code

Option 1: I Have SQLAlchemy Models (30 seconds)

Transform your existing SQLAlchemy models into an AI-navigable API:

from enrichmcp import EnrichMCP
from enrichmcp.sqlalchemy import (
    include_sqlalchemy_models,
    sqlalchemy_lifespan,
    EnrichSQLAlchemyMixin,
)
from sqlalchemy import ForeignKey
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship

engine = create_async_engine("postgresql+asyncpg://user:pass@localhost/db")

Add the mixin to your declarative base

class Base(DeclarativeBase, EnrichSQLAlchemyMixin): pass

class User(Base):
"""User account."""

__tablename__ = "users"

id: Mapped[int] = mapped_column(primary_key=True, info={"description": "Unique user ID"})
email: Mapped[str] = mapped_column(unique=True, info={"description": "Email address"})
status: Mapped[str] = mapped_column(default="active", info={"description": "Account status"})
orders: Mapped[list["Order"]] = relationship(
back_populates="user", info={"description": "All orders for this user"}
)

class Order(Base):
"""Customer order."""

__tablename__ = "orders"

id: Mapped[int] = mapped_column(primary_key=True, info={"description": "Order ID"})
user_id: Mapped[int] = mapped_column(
ForeignKey("users.id"), info={"description": "Owner user ID"}
)
total: Mapped[float] = mapped_column(info={"description": "Order total"})
user: Mapped[User] = relationship(
back_populates="orders", info={"description": "User who placed the order"}
)

That's it! Create your MCP app

app = EnrichMCP( "E-commerce Data", "API generated from SQLAlchemy models", lifespan=sqlalchemy_lifespan(Base, engine, cleanup_db_file=True), ) include_sqlalchemy_models(app, Base)

if __name__ == "__main__":
app.run()


AI agents can now:
- explore_data_model() - understand your entire schema
- list_users(status='active') - query with filters
- get_user(id=123) - fetch specific records
- Navigate relationships: user.ordersorder.user

Option 2: I Have REST APIs (2 minutes)

Wrap your existing APIs with semantic understanding:

from typing import Literal
from enrichmcp import EnrichMCP, EnrichModel, Relationship
from pydantic import Field
import httpx

app = EnrichMCP("API Gateway", "Wrapper around existing REST APIs")
http = httpx.AsyncClient(base_url="https://api.example.com")

@app.entity()
class Customer(EnrichModel):
"""Customer in our CRM system."""

id: int = Field(description="Unique customer ID")
email: str = Field(description="Primary contact email")
tier: Literal["free", "pro", "enterprise"] = Field(description="Subscription tier")

# Define navigable relationships
orders: list["Order"] = Relationship(description="Customer's purchase history")

@app.entity()
class Order(EnrichModel):
"""Customer order from our e-commerce platform."""

id: int = Field(description="Order ID")
customer_id: int = Field(description="Associated customer")
total: float = Field(description="Order total in USD")
status: Literal["pending", "shipped", "delivered"] = Field(description="Order status")

customer: Customer = Relationship(description="Customer who placed this order")

Define how to fetch data

@app.retrieve() async def get_customer(customer_id: int) -> Customer: """Fetch customer from CRM API.""" response = await http.get(f"/api/customers/{customer_id}") return Customer(response.json())

Define relationship resolvers

@Customer.orders.resolver async def get_customer_orders(customer_id: int) -> list[Order]: """Fetch orders for a customer.""" response = await http.get(f"/api/customers/{customer_id}/orders") return [Order(
order) for order in response.json()]

@Order.customer.resolver
async def get_order_customer(order_id: int) -> Customer:
"""Fetch the customer for an order."""
response = await http.get(f"/api/orders/{order_id}/customer")
return Customer(response.json())

app.run()

Option 3: I Want Full Control (5 minutes)

Build a complete data layer with custom logic:

```python
from enrichmcp import EnrichMCP, EnrichModel, Relationship
from datetime import datetime
from decimal import Decimal
from pydantic import Field

app = EnrichMCP("Analytics Platform", "Custom analytics API")

db = ... # your database connection

@app.entity()
class User(EnrichModel):
"""User with computed analytics fields."""

id: int = Field(description="User ID")
email: str = Field(description="Contact email")
created_at: datetime = Field(description="Registration date")

# Computed fields
lifetime_value: Decimal = Field(description="Total revenue from user")
churn_risk: float = Field(description="ML-predicted churn probability 0-1")

# Relationships
orders: list["Order"] = Relationship(description="Purchase history")
segments: list["Segment"] = Relationship(description="Marketing segments")

@app.entity()
class Segment(EnrichModel):
"""Dynamic user segment for marketing."""

name: str = Field(description="Segment name")
criteria: dict = Field(description="Segment criteria")
users: list[User] = Relationship(description="Users in this segment")

@app.entity()
class Order(EnrichModel):
"""Simplified order record."""

id: int = Field(description="Order ID")
user_id: int = Field(description="Owner user ID")
total: Decimal = Field(description="Order total")

@User.orders.resolver
async def list_user_orders(user_id: int) -> list[Order]:
"""Fetch orders for a user."""
rows = await db.query(
"SELECT FROM orders WHERE user_id = ? ORDER BY id DESC",
user_id,
)
return [Order(
row) for row in rows]

@User.segments.resolver
async def list_user_segments(user_id: int) -> list[Segment]:
"""Fetch segments that include the user."""
rows = await db.query(
"SELECT s.
FROM segments s JOIN user_segments us ON s.name = us.segment_name WHERE us.user_id = ?",
user_id,
)
return [Segment(**row) for row in rows]

No reviews yet — be the first

Sign in to leave a review

Use Google, GitHub, or an email account so ratings stay tied to real people.

Email sign in

No reviews posted yet.