Skip to main content

MCP Quickstart

A step-by-step walkthrough of the core Fyso MCP workflow. Every tool call here is real -- you can copy-paste these into your MCP client and they will work.

1. Connect

Add Fyso to your MCP client config (claude_desktop_config.json or equivalent):

{
"mcpServers": {
"fyso": {
"command": "npx",
"args": ["-y", "@fyso/mcp-server"],
"env": {
"FYSO_API_KEY": "your-api-key",
"FYSO_API_URL": "https://api.fyso.dev/api",
"FYSO_TOOLS": "core"
}
}
}
}

FYSO_TOOLS controls which tools are available. core is the default and covers everything in this guide. See Tool Profiles for the full breakdown.

2. Select a Tenant

Every operation in Fyso happens inside a tenant. Start by listing your tenants, then select one.

List tenants:

list_tenants()

Response:

{
"success": true,
"tenants": [
{ "id": "uuid-1", "slug": "my-app", "name": "My App" },
{ "id": "uuid-2", "slug": "staging", "name": "Staging" }
]
}

Select a tenant:

select_tenant({ tenantSlug: "my-app" })

Response:

{
"success": true,
"message": "Tenant 'my-app' selected",
"tenant": { "id": "uuid-1", "slug": "my-app", "name": "My App" }
}

From this point on, all operations target my-app.

3. Create an Entity

Entities are your data tables. Use generate_entity to create one from a JSON definition.

generate_entity({
name: "tasks",
fields: [
{ "name": "title", "type": "text", "required": true },
{ "name": "description", "type": "long_text" },
{ "name": "status", "type": "select", "options": ["open", "in_progress", "done"] },
{ "name": "priority", "type": "select", "options": ["low", "medium", "high", "critical"] },
{ "name": "assignee", "type": "text" }
]
})

Response:

{
"success": true,
"message": "Entity 'tasks' created successfully",
"entity": {
"id": "uuid",
"name": "tasks",
"slug": "tasks",
"fields": [
{ "key": "title", "type": "text", "required": true },
{ "key": "description", "type": "long_text", "required": false },
{ "key": "status", "type": "select", "options": ["open", "in_progress", "done"] },
{ "key": "priority", "type": "select", "options": ["low", "medium", "high", "critical"] },
{ "key": "assignee", "type": "text", "required": false }
]
}
}

The entity is created as a draft. To make it live:

publish_entity({
entityName: "tasks",
message: "Initial version"
})

4. Create Records

Add data to your entity with create_record.

create_record({
entityName: "tasks",
data: {
"title": "Fix login bug",
"description": "Users get 500 error on login with special characters in password",
"status": "open",
"priority": "high",
"assignee": "alice@team.com"
}
})

Response:

{
"success": true,
"record": {
"id": "rec-uuid-1",
"entityId": "uuid",
"name": "Fix login bug",
"data": {
"title": "Fix login bug",
"description": "Users get 500 error on login with special characters in password",
"status": "open",
"priority": "high",
"assignee": "alice@team.com"
},
"createdAt": "2026-03-01T10:00:00Z",
"updatedAt": "2026-03-01T10:00:00Z"
}
}

Create a few more:

create_record({
entityName: "tasks",
data: {
"title": "Add dark mode",
"description": "Support system-level dark mode preference",
"status": "open",
"priority": "medium",
"assignee": "bob@team.com"
}
})

create_record({
entityName: "tasks",
data: {
"title": "Update dependencies",
"description": "Run npm audit fix and update major versions",
"status": "in_progress",
"priority": "low",
"assignee": "alice@team.com"
}
})

5. Query Records

query_records supports filters, pagination, sorting, and semantic search.

Simple filter

query_records({
entityName: "tasks",
filter: "status = open"
})

Compound filter

query_records({
entityName: "tasks",
filter: "status = open AND priority = high"
})

All filter operators

OperatorDescriptionExample
=Equals (case-insensitive)status = open
!=Not equalstatus != done
>Greater than (numeric)score > 80
<Less than (numeric)score < 50
>=Greater than or equalpriority >= high
<=Less than or equalcount <= 10
containsContains text (case-insensitive)title contains login

String values don't need quotes, but you can use them: assignee = "alice@team.com".

Pagination

query_records({
entityName: "tasks",
limit: 10,
offset: 0
})

Sorting

query_records({
entityName: "tasks",
orderBy: "priority",
orderDir: "desc"
})

Find records by meaning, not exact text match:

query_records({
entityName: "tasks",
semantic: "authentication issues",
minSimilarity: 0.6,
limit: 5
})

This would match "Fix login bug" even though the query doesn't contain the word "login".

Combining filters

You can combine filter with semantic -- the filter is applied as a post-filter on semantic results:

query_records({
entityName: "tasks",
semantic: "UI improvements",
filter: "status = open",
limit: 10
})

Response shape

{
"success": true,
"records": [
{
"id": "rec-uuid-1",
"name": "Fix login bug",
"data": {
"title": "Fix login bug",
"status": "open",
"priority": "high",
"assignee": "alice@team.com"
}
}
],
"total": 1,
"limit": 20,
"offset": 0
}

6. Add a Business Rule

Business rules run automatically when records are created, updated, or queried. Use generate_business_rule with a natural language prompt.

generate_business_rule({
entityName: "tasks",
prompt: "When a task is created, if no priority is set, default it to 'medium'"
})

Response:

{
"success": true,
"rule": {
"id": "rule-uuid",
"name": "default-priority-on-create",
"entityName": "tasks",
"trigger": "on_create",
"status": "draft",
"dsl": {
"validate": [
{
"condition": "priority == null",
"action": "set_field",
"field": "priority",
"value": "medium"
}
]
}
}
}

The rule is created as a draft. Publish it to make it active:

publish_business_rule({
ruleId: "rule-uuid"
})

Only published rules execute. You can test before publishing:

test_business_rule({
ruleId: "rule-uuid",
testData: {
"title": "New task without priority",
"status": "open"
}
})

7. Create a User

Create tenant users with specific roles and per-entity permissions.

create_user({
tenantSlug: "my-app",
email: "dev@team.com",
password: "securepass123",
name: "Dev User",
role: "member",
permissions: {
entities: {
"tasks": ["create", "read", "update"]
}
}
})

Response:

{
"success": true,
"user": {
"id": "user-uuid",
"email": "dev@team.com",
"name": "Dev User",
"role": "member",
"isActive": true
}
}

Available roles

RoleAccess level
ownerFull control over everything
adminManage users and settings
memberCreate and edit records
viewerRead only

Per-entity permissions

Permissions are create, read, update, delete per entity:

{
"entities": {
"tasks": ["create", "read", "update", "delete"],
"reports": ["read"]
},
"canManageUsers": false,
"canManageSettings": false
}

8. Deploy a Static Site

Deploy any static site (Astro, Vite, Next.js export, plain HTML) to a Fyso subdomain.

deploy_static_site({
subdomain: "my-app",
path: "/path/to/dist"
})

Response:

{
"success": true,
"message": "Site deployed successfully",
"data": {
"url": "https://my-app-sites.fyso.dev",
"subdomain": "my-app"
}
}

Your site is live at https://my-app-sites.fyso.dev.

If the MCP server can't access your filesystem directly, it returns a curl command to run manually -- just execute it and the deploy completes.

List deployed sites

list_static_sites()

Generate a deploy token for CI/CD

generate_deploy_token({ subdomain: "my-app" })

Returns a one-time token (expires in 5 minutes) for use in GitHub Actions or other CI pipelines. See GitHub Actions Deployment for a full workflow.


What's Next

You now know the core workflow: connect, model data, query it, add rules, create users, and deploy.

Next: See Building a Complete App for a full end-to-end example that puts all of these pieces together.