A Python framework for building MCP-first, Agent-first applications: model entities, relationships, and use cases once — MCP, GraphQL, REST, CLI, and TS SDK all derive from it. Its specialty: APIs that agents understand easily — agents always have enough context to know what the data looks like, and fetch only the fields they need.
pip install nexusx
The same typed business model serves AI agents and developers as first-class consumers.
MCP is a first-class protocol: strongly typed, GraphQL under the hood. Three capabilities make an API agent-friendly:
Write SQLModel entities and typed DTOs; that is the whole job.
LLMs generate code fast — but without structural constraints, the debt surfaces weeks later: duplicated logic, components bleeding into each other, debugging by guesswork. The industry calls it the cost of vibe coding.
nexusx narrows what AI writes to a declarative model — entities, relationships, and typed use-case methods. Structure is not something the AI has to get right; it is guaranteed by the model.
AI writes the model and use-case methods — not scattered glue code. Small diffs, reviewable by humans.
Change a business rule once; every protocol updates in sync. Maintenance cost does not multiply per delivery.
Typed contracts, plus Voyager: entities, relationships, use cases, and their dependencies rendered as one live ER view — grasp the whole project without reading code first, whether you are a new human or a fresh AI session. Voyager →
Semantic-level isomorphism — every protocol is generated from the same typed model, not wrapped around a copy of it.
# "list sprints" — written once per protocol
@app.get("/sprints")
async def rest_list_sprints() -> list[SprintOut]:
... # query + assembly, again
@strawberry.field
async def graphql_sprints(self) -> list[SprintType]:
... # types + loaders, again
@mcp.tool()
async def sprints_for_agents() -> str:
... # JSON dumping, again
# ↑ change the rule → fix every copy
class SprintService(UseCaseService):
"""Sprint planning operations."""
@query
async def list_sprints(cls) -> list[SprintSummary]:
"""List sprints with tasks, owners, and task count."""
return await load_sprints()
# six deliveries, one model ↓
Typed FastAPI route, visible in OpenAPI.
create_use_case_router(api)
Entities become by_id / by_filter roots for exploring connected data.
Sprint { by_filter(limit: 10) { ... } }
Use-case methods become typed fields via the compose schema.
compose_query(app, query, args)
Agents discover it progressively.
create_use_case_graphql_mcp_server([api])
Services become command groups.
list_sprints --select "name task_count"
Typed client generated from the compose schema.
sprintService.listSprints()
Two GraphQL surfaces for two different jobs — use either one, or both.
SQLModel entities and relationships become by_id / by_filter query roots. No relationship resolvers to write — DataLoader batching keeps it N+1-proof as callers traverse.
GraphQLHandlerTyped business methods expose stable capabilities to web clients, integrations, and AI agents — served over REST, MCP, CLI, and SDK from one definition.
UseCaseServiceEntities are not API contracts. DefineSubset hides internal columns, auto-loads relationships, and computes derived fields.
# Per-endpoint: manual SQL, N+1, dict munging
async def get_sprints():
sprints = await session.exec(select(Sprint))
result = []
for s in sprints:
tasks = await session.exec(
select(Task).where(Task.sprint_id == s.id))
for t in tasks:
t.owner = await session.get(User, t.owner_id)
# N+1 queries, fragile dict construction
from nexusx import DefineSubset, ErManager, build_dto_select
class UserDTO(DefineSubset):
__subset__ = (User, ("id", "name"))
class TaskDTO(DefineSubset):
__subset__ = (Task, ("id", "title", "owner_id"))
owner: UserDTO | None = None # auto-loaded
class SprintDTO(DefineSubset):
__subset__ = (Sprint, ("id", "name"))
tasks: list[TaskDTO] = [] # auto-loaded
er = ErManager(entities=[User, Sprint, Task], session_factory=async_session)
Resolver = er.create_resolver()
async def load_sprints() -> list[SprintDTO]:
stmt = build_dto_select(SprintDTO) # root columns only
async with async_session() as session:
rows = (await session.exec(stmt)).all()
dtos = [SprintDTO(**dict(r._mapping)) for r in rows]
return await Resolver().resolve(dtos) # tree filled, batched
# 1 query per relationship, zero N+1
The same relationship model stretches into more advanced architectures.
DataLoader batching, SQL column pruning, window-function pagination — and total_count computed only when the response asks for it.
post_* for aggregations, ExposeAs / SendTo for cross-layer data flow.
Ordinary Pydantic models as non-table graph roots — Redis, search, and SDK-backed data join the same graph.
Compose multiple nexusx data graphs without a central gateway — homogeneous federation of nexusx services.
ComposedErManager composes multiple engines in one process; DTO federation loads public DTO trees across services.
Independently packaged applications and databases, combined into a single MCP server.
The principles that shape every API decision.
One field selection shapes the GraphQL response, the SQL columns loaded, the DTO fields copied, the MCP output, CLI --select, and whether total_count is even computed.
Redis, search engines, other databases, external APIs — declare a Relationship with an async batch function and they join the same loader, DTO, GraphQL, and ER-diagram infrastructure.
Business methods depend on no protocol object — builders inspect the typed signature and attach REST / MCP / CLI / SDK adapters. FromContext injects trusted values (user, tenant) without exposing them as client arguments.
Install the 4-phase skill into your coding agent — Claude Code, Codex, Cursor, and more — then describe your app in plain words. The agent drives the staged workflow; you review the model.
npx skills add KLR-Pattern/nexusx -s nexusx-4phase -a claude-code
Confirm the domain model and persistence strategy with you before any code is written.
Entities and relationships, GraphQL helper surface, then UseCase REST / MCP / CLI deliveries.
Optionally emit a typed TypeScript SDK from the compose schema.
The original prompt that built MindMap X was one line — /nexusx-4phase — plus a requirement list:
Works with your existing frameworks and tools.
Declare the model once — the data graph, response DTOs, and every delivery follow.