The ORM for AI Agents - Turn your data model into a semantic MCP layer
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.
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
pip install enrichmcp
# With SQLAlchemy support
pip install enrichmcp[sqlalchemy]
Option 1: I Have SQLAlchemy Models (30 seconds)
Transform your existing SQLAlchemy models into an AI-navigable API:
explore_data_model() - understand your entire schema
list_users(status='active') - query with filters
get_user(id=123) - fetch specific records
Navigate relationships: user.orders → order.user
Option 2: I Have REST APIs (2 minutes)
Wrap your existing APIs with semantic understanding:
fromenrichmcpimportEnrichMCP, EnrichModel, RelationshipfrompydanticimportFieldapp=EnrichMCP("API Gateway")
@app.entityclassCustomer(EnrichModel):
"""Customer in our CRM system."""id: int=Field(description="Unique customer ID")
email: str=Field(description="Primary contact email")
tier: str=Field(description="Subscription tier: free, pro, enterprise")
# Define navigable relationshipsorders: list["Order"] =Relationship(description="Customer's purchase history")
@app.entityclassOrder(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: str=Field(description="Order status: pending, shipped, delivered")
customer: Customer=Relationship(description="Customer who placed this order")
# Define how to fetch data@app.resourceasyncdefget_customer(customer_id: int) ->Customer:
"""Fetch customer from CRM API."""response=awaithttp.get(f"/api/customers/{customer_id}")
returnCustomer(**response.json())
# Define relationship resolvers@Customer.orders.resolverasyncdefget_customer_orders(customer_id: int) ->list[Order]:
"""Fetch orders for a customer."""response=awaithttp.get(f"/api/customers/{customer_id}/orders")
return [Order(**order) fororderinresponse.json()]
app.run()
Option 3: I Want Full Control (5 minutes)
Build a complete data layer with custom logic:
fromenrichmcpimportEnrichMCP, EnrichModel, Relationship, EnrichContextfromdatetimeimportdatetimefromdecimalimportDecimalapp=EnrichMCP("Analytics Platform")
@app.entityclassUser(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 fieldslifetime_value: Decimal=Field(description="Total revenue from user")
churn_risk: float=Field(description="ML-predicted churn probability 0-1")
# Relationshipsorders: list["Order"] =Relationship(description="Purchase history")
segments: list["Segment"] =Relationship(description="Marketing segments")
@app.entityclassSegment(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")
# Complex resource with business logic@app.resourceasyncdeffind_high_value_at_risk_users(
lifetime_value_min: Decimal=1000,
churn_risk_min: float=0.7,
limit: int=100
) ->list[User]:
"""Find valuable customers likely to churn."""users=awaitdb.query(
""" SELECT * FROM users WHERE lifetime_value >= ? AND churn_risk >= ? ORDER BY lifetime_value DESC LIMIT ? """,
lifetime_value_min, churn_risk_min, limit
)
return [User(**u) foruinusers]
# Async computed field resolver@User.lifetime_value.resolverasyncdefcalculate_lifetime_value(user_id: int) ->Decimal:
"""Calculate total revenue from user's orders."""total=awaitdb.query_single(
"SELECT SUM(total) FROM orders WHERE user_id = ?",
user_id
)
returnDecimal(str(totalor0))
# ML-powered field@User.churn_risk.resolverasyncdefpredict_churn_risk(user_id: int, context: EnrichContext) ->float:
"""Run churn prediction model."""features=awaitgather_user_features(user_id)
model=context.get("ml_models")["churn"]
returnfloat(model.predict_proba(features)[0][1])
app.run()
🔍 Automatic Schema Discovery
AI agents explore your entire data model with one call:
schema=awaitexplore_data_model()
# Returns complete schema with entities, fields, types, and relationships
🔗 Relationship Navigation
Define relationships once, AI agents traverse naturally:
# AI can navigate: user → orders → products → categoriesuser=awaitget_user(123)
orders=awaituser.orders() # Automatic resolverproducts=awaitorders[0].products()
@app.resourceasyncdefget_user_profile(user_id: int, context: EnrichContext) ->UserProfile:
# Access context provided by MCP clientauth_user=context.get("authenticated_user_id")
ifauth_user!=user_id:
raisePermissionError("Can only access your own profile")
returnawaitdb.get_profile(user_id)
EnrichMCP adds three critical layers on top of MCP:
Semantic Layer - AI agents understand what your data means, not just its structure
Data Layer - Type-safe models with validation and relationships
Control Layer - Authentication, pagination, and business logic
The result: AI agents can work with your data as naturally as a developer using an ORM.