Fyso MCP Guide for Builders
Connect your AI agent to Fyso and build a complete data backend in minutes.
What is Fyso MCP?
Fyso exposes a Model Context Protocol (MCP) server that lets AI agents (Claude Desktop, Claude Code, or any MCP-compatible client) create entities, manage records, define business rules, and deploy static sites — all through natural language.
Quick Start: Claude Desktop (< 3 min)
1. Get your API key
Sign up at app.fyso.dev and create a tenant. Your API key will be shown during onboarding.
2. Configure Claude Desktop
Open your Claude Desktop config file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json - Linux:
~/.config/Claude/claude_desktop_config.json
Add the Fyso MCP server:
{
"mcpServers": {
"fyso": {
"command": "npx",
"args": ["-y", "@fyso/mcp-server"],
"env": {
"FYSO_API_KEY": "fyso_ak_your_key_here",
"FYSO_API_URL": "https://app.fyso.dev/api"
}
}
}
}
3. Start building
Restart Claude Desktop. You now have access to 47 MCP tools. Try:
"List my tenants and select one"
"Create an entity called 'customers' with name, email, phone, and address fields"
"Add a business rule: when email changes, convert to lowercase"
Quick Start: Claude Code
claude mcp add fyso -- npx -y @fyso/mcp-server \
--env FYSO_API_KEY=fyso_ak_your_key_here \
--env FYSO_API_URL=https://app.fyso.dev/api
Or add to your project's .mcp.json:
{
"mcpServers": {
"fyso": {
"command": "npx",
"args": ["-y", "@fyso/mcp-server"],
"env": {
"FYSO_API_KEY": "fyso_ak_your_key_here",
"FYSO_API_URL": "https://app.fyso.dev/api"
}
}
}
}
Example: Build a Project Management System
Here's a step-by-step conversation with Claude using Fyso MCP:
Step 1: Create entities
"Create these entities for a project management system:
- projects: name (text, required), description (textarea), status (select: active/completed/archived), deadline (date)
- tasks: title (text, required), description (textarea), status (select: todo/in-progress/done), priority (select: low/medium/high/critical), project_id (relation to projects)
- team_members: name (text, required), email (email, required, unique), role (select: developer/designer/manager)"
Claude will call generate_entity three times, creating all entities with proper field types.
Step 2: Add business rules
"Add a rule to tasks: when status changes to 'done', validate that the title is not empty"
// Claude creates this rule via create_business_rule:
{
"triggerType": "field_change",
"triggerFields": ["status"],
"ruleDsl": {
"validate": [{
"id": "title_required_on_done",
"condition": "status != 'done' or len(title) > 0",
"message": "Tasks marked as done must have a title",
"severity": "error"
}]
}
}
Step 3: Add sample data
"Create 3 sample projects and 5 tasks distributed across them"
Claude calls create_record for each record, automatically linking tasks to projects via project_id.
Step 4: Query your data
"Show me all tasks with priority 'high' sorted by deadline"
// Claude calls query_records:
{
"entityName": "tasks",
"filter": "priority = high",
"orderBy": "deadline",
"orderDir": "asc"
}
Step 5: Generate an API client
"Generate a TypeScript API client for my project management entities"
Claude calls generate_api_client and returns ready-to-use TypeScript code with full types.
Multi-Tenancy: One Backend, Multiple Clients
Fyso isolates data per tenant using PostgreSQL schemas. Each tenant gets its own entities, records, rules, and users.
Create tenants for your clients
> "List my tenants"
> "Select tenant 'acme-corp'"
> "Import the freelancer prebuild for this tenant"
Switch between tenants
> "Select tenant 'client-a'"
> "Create a customer record: name 'John Doe', email 'john@example.com'"
> "Now select tenant 'client-b'"
> "List all customers" // Returns client-b's customers, not client-a's
Tenant users
Each tenant can have users with roles:
| Role | Permissions |
|---|---|
| owner | Full control over everything |
| admin | Manage users, settings, and data |
| member | Create and edit records |
| viewer | Read-only access |
> "Create a user in tenant 'acme-corp': email 'maria@acme.com', name 'Maria Garcia', role 'member'"
Channels: Share Tools Between Tenants
Channels let you expose your tenant's data as tools that other tenants (or agents) can use.
Publish your tenant as a channel
> "Publish my tenant as a channel called 'acme-products' with tags 'retail' and 'products'"
Define custom tools
> "Define a channel tool called 'search-products' that queries the products entity with semantic search"
This creates a tool other agents can discover and use:
// Other agents can call:
execute_channel_tool({
channel_slug: "acme-products",
tool_name: "search-products",
params: { query: "organic coffee beans", limit: 5 }
})
Set permissions
> "Set channel permissions: default read-only, but allow readwrite on the 'orders' entity"
Prebuilds: Import Ready-Made Templates
Fyso includes prebuild packages with entities, fields, rules, and sample data:
| Prebuild | Entities | Description |
|---|---|---|
| freelancer | 5 (clientes, proyectos, facturas, lineas_factura, pagos) | Freelance/consulting business |
| taller | 5 (clientes, vehiculos, ordenes, servicios, inventario) | Auto repair shop |
| tienda | 5 (clientes, categorias, productos, pedidos, lineas_pedido) | Retail store |
Import via MCP
> "Import the taller prebuild for my tenant"
This creates all entities with proper field types, business rules (including cross-entity lookups and aggregates), and optionally seed data.
Export and reimport
> "Export my tenant's metadata"
// Returns JSON with all entities, fields, and rules
> "Select tenant 'new-client'"
> "Import this metadata into the new tenant"
API Client Generator
Generate a complete TypeScript client for your entities:
> "Generate a TypeScript API client for all my entities"
Returns ready-to-use code:
import { FysoClient } from './fyso-client';
const client = new FysoClient({
baseUrl: 'https://app.fyso.dev/api',
apiKey: 'fyso_ak_...',
});
// Full type safety
const customers = await client.customers.list({ limit: 20 });
const customer = await client.customers.create({
name: 'Acme Corp',
email: 'contact@acme.com',
});
await client.customers.update(customer.id, { phone: '+34 912345678' });
await client.customers.delete(customer.id);
Available MCP Tools (47)
Tenant Management
| Tool | Description |
|---|---|
list_tenants | List all accessible tenants |
select_tenant | Select active tenant for the session |
Entity Management
| Tool | Description |
|---|---|
generate_entity | Create entity from JSON definition |
list_entities | List entities in current tenant |
get_entity_schema | Get field definitions for an entity |
publish_entity | Publish a draft entity |
delete_entity | Delete an entity (irreversible) |
list_entity_changes | Show draft changes vs published |
export_metadata | Export all entities, fields, and rules |
import_metadata | Import metadata into tenant |
Record CRUD
| Tool | Description |
|---|---|
query_records | List/filter/search/sort records |
create_record | Create a new record |
update_record | Update an existing record |
delete_record | Delete a record |
Custom Fields
| Tool | Description |
|---|---|
manage_custom_fields | Add, update, delete, or list custom fields |
Business Rules
| Tool | Description |
|---|---|
generate_business_rule | Generate rule from natural language |
create_business_rule | Create rule with DSL (compute, validate, transform, actions) |
list_business_rules | List rules for an entity |
get_business_rule | Get rule details and DSL |
test_business_rule | Test rule with sample data in sandbox |
publish_business_rule | Publish a draft rule |
delete_business_rule | Delete a rule |
API & Client
| Tool | Description |
|---|---|
get_rest_api_spec | Get REST API documentation with curl examples |
generate_api_client | Generate TypeScript API client with types |
User Management
| Tool | Description |
|---|---|
create_user | Create tenant user (owner/admin/member/viewer) |
list_users | List users in current tenant |
Channels
| Tool | Description |
|---|---|
search_channels | Discover public channels |
get_channel_info | Get channel details |
get_my_channel | Get your tenant's channel |
get_channel_tools | List tools available in a channel |
publish_channel | Make your tenant discoverable |
update_channel | Update channel metadata |
unpublish_channel | Remove from public catalog |
set_channel_permissions | Configure read/readwrite access |
define_channel_tool | Create custom tool with DSL |
update_channel_tool | Modify a custom tool |
remove_channel_tool | Delete a custom tool |
execute_channel_tool | Use a tool from another channel |
Static Sites
| Tool | Description |
|---|---|
deploy_static_site | Deploy to <subdomain>.sites.fyso.dev |
list_static_sites | List your deployments |
delete_static_site | Remove a deployment |
Bot Identity
| Tool | Description |
|---|---|
register_bot | Register a bot with a secret key |
identify_bot | Authenticate as a registered bot |
list_bots | List your registered bots |
whoami_bot | Check current bot identity |
revoke_bot | Deactivate a bot |
Business Rules DSL Reference
Rules use a declarative DSL with four sections:
compute — Calculate fields
{
"compute": {
"total": { "type": "formula", "expression": "cantidad * precio" },
"descuento": {
"type": "conditional",
"conditions": [{ "when": "total > 1000", "then": "total * 0.1" }],
"default": "0"
},
"precio_producto": {
"type": "lookup",
"entity": "productos",
"matchField": "id",
"matchValue": "producto_id",
"resultField": "precio"
},
"total_pedidos": {
"type": "aggregate",
"entity": "pedidos",
"aggregateOp": "count",
"filter": { "cliente_id": "id" }
}
}
}
validate — Check constraints
{
"validate": [{
"id": "email_required",
"condition": "len(email) > 0",
"message": "Email is required",
"severity": "error"
}]
}
transform — Format fields
{
"transform": {
"email": { "type": "lowercase" },
"nombre": { "type": "trim" },
"total": { "type": "round", "decimals": 2 }
}
}
actions — Cross-entity side effects (after_save only)
{
"actions": [{
"type": "update_related",
"entity": "post",
"recordId": "post_id",
"data": {
"comments_count": {
"type": "aggregate",
"entity": "comment",
"aggregateOp": "count",
"filter": { "post_id": "post_id" }
}
}
}]
}
Trigger types
| Trigger | When it fires |
|---|---|
field_change | When specified fields change |
before_save | Before the record is persisted |
after_save | After the record is persisted (supports actions) |
REST API
For programmatic access outside MCP, use the REST API directly:
# List records
curl -H "Authorization: Bearer $API_KEY" \
"https://app.fyso.dev/api/entities/customers/records?limit=10"
# Create a record
curl -X POST -H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "Acme Corp", "email": "contact@acme.com"}' \
"https://app.fyso.dev/api/entities/customers/records"
# Semantic search
curl -H "Authorization: Bearer $API_KEY" \
"https://app.fyso.dev/api/entities/products/records/search/semantic?q=organic+coffee&limit=5"
Important: Entity fields are nested inside record.data, not at the top level:
{
"id": "abc-123",
"data": {
"name": "Acme Corp",
"email": "contact@acme.com"
}
}
Access fields as record.data.email, not record.email.
Environment Variables
| Variable | Default | Description |
|---|---|---|
FYSO_API_KEY | — | Your tenant API key |
FYSO_API_URL | http://localhost:3001/api | Fyso API base URL |
MCP_SERVER_PORT | 3002 | HTTP server port (SSE mode) |
MCP_SERVER_URL | http://localhost:3002/mcp | MCP server URL (for JWT audience) |
Common Patterns
1. Scaffold a complete app backend
> "Create entities for an e-commerce app: products (name, description, price, stock, category),
> orders (customer_name, email, status, total), order_lines (order_id, product_id, quantity, subtotal)"
> "Add a rule to order_lines: when quantity or product changes, lookup product price and calculate subtotal"
> "Add an after_save rule to order_lines: count lines per order and update order total"
> "Generate a TypeScript API client"
> "Deploy a landing page for my store"
2. Import a prebuild and customize
> "Import the tienda prebuild"
> "Add a 'loyalty_points' number field to customers"
> "Add a rule: when a pedido is created, increment customer loyalty_points by 1"
3. Multi-agent collaboration via channels
// Agent A (data owner):
> "Publish my tenant as 'product-catalog' channel"
> "Define a tool 'search-products' using semantic search on products entity"
// Agent B (consumer):
> "Search channels tagged 'products'"
> "Execute 'search-products' on 'product-catalog' channel with query 'wireless headphones'"
Troubleshooting
| Problem | Solution |
|---|---|
Entity not found | Run list_entities to check entity names. Names are lowercase with underscores. |
Tenant not selected | Run select_tenant before any data operations. |
401 Unauthorized | Check your FYSO_API_KEY is correct and not expired. |
Business rule validation failed | Use test_business_rule to debug rules with sample data. |
| Login returns HTML instead of JSON | Use POST /api/auth/tenant/login (note the /api prefix). |
| Record fields are null | Access fields via record.data.fieldName, not record.fieldName. |