AALY
Server Details
Backend for AI build SAAS applications - auth, dynamo db, functions, file storage, etc
- Status
- Healthy
- Uptime
- 100.0% over the last 24 hours
- Last Tested
- Transport
- Streamable HTTP · MCP 2025-11-25
- URL
- ChatGPT
- –
- Claude
- AALY
TDQS
Scored across 47 tools
Most tools target a distinct resource+action, and descriptions carefully draw boundaries (e.g. create_field vs create_fields bulk, set_notification_channel vs set_notification_template, list_secrets vs list_variables, get_request_trace vs list_logs). A few relationships (endpoint vs function attachment, update_field/update_function/update_endpoint all-or-nothing rules) are subtle enough that an agent could occasionally pick wrong, but the docs mostly disambiguate.
Strong, predictable verb_noun pattern throughout: list_*, get_*, create_*, update_*, delete_*, set_*, plus file_feature_request/file_support_ticket used consistently for the 'file a report' concept. The lone outlier is whoami (no verb_noun), and 'file' as a verb is unconventional, but overall very consistent.
47 tools is well above the 25+ threshold and a heavy surface for an agent to navigate in one server, spanning projects, entities, fields, endpoints, functions, deployments, secrets, variables, notifications, logs, files, support and feature requests. The breadth is genuine, but many granular operations inflate the count well beyond a well-scoped set.
Near-complete lifecycle coverage across every sub-domain: CRUD for projects, entities, fields, endpoints and functions, plus deploy/list deployments, secrets, variables, notification channels/templates, tickets with comments, feature requests with voting, file upload, and logs/traces. Dead ends are handled (get via list, soft-delete semantics), leaving no obvious operational gaps.
Available Tools
47 toolsadd_commentAInspect
Add a reply to the comment thread of a support ticket or feature request you can already see (get_support_ticket / list_feature_requests). Use it to answer a question from the AALY team, add detail they asked for, or report that a fix did or did not work. It only ever appends a comment; it cannot change status or any other field.
The comment is attributed to the signed-in user and labelled as coming from an agent (pass client_name, e.g. 'Claude Code', to say which). Read the thread first with get_support_ticket so you don't repeat what's already there. A closed ticket takes no more comments - if it's still a problem, file a new ticket and mention the old id. A ticket or request with status 'on_hold' is parked on purpose; its holdReason says why - you can still comment.
Inputs: text (required), record_id (required), record_type (required), client_name.
create_endpointAInspect
Write-only schema tool: creates one route DEFINITION record in the project's schema. It does NOT call any API, send any HTTP request, or read or write application data — method below configures which verb the route being defined will answer, it is not a verb this tool performs. Use list_endpoints to read routes back.
What it defines: a custom, non-CRUD REST route attached to an entity, e.g. POST /orders/summary. This record IS the route's identity — its action word, HTTP method, auth mode and execution mode. It runs no code by itself: attach one or more Functions to it via create_function(entity_id=<this endpoint's returned id>, trigger_point='endpoint') — an endpoint's own id, not the entity's, is what a Function's entity_id must reference for that trigger point. Read the aaly://platform/functions resource before your first one.
auth: 'required' (default) behaves exactly like ordinary CRUD — callers need a valid token. 'public' accepts requests with NO Authorization header at all — there is no caller identity for its Functions to act as, so they typically call back into the project's own REST API using an API key stored via set_secret rather than an inherited token. There is no per-endpoint permission scoping yet: a public route is exactly as powerful as whatever key its Functions use, so treat a stored key backing a public route as a full-privilege service account and validate its input defensively (create_field with entity_id set to this endpoint's id, location 'body'/'query', turns on real request validation instead of accepting free-form JSON).
No nested paths: the URL is always /{entity}/{action}, exactly one path segment after the entity.
Inputs: action (required), method (required), entity_id (required), auth, +4 more.
create_entityAInspect
Define a new data entity under a project. CRUD endpoints at {base}/{customer_slug}/{project_slug}/{entity_name} activate immediately. The key must be a unique 3-character UPPERCASE string (e.g. 'ORD' for orders). Pass fields to create its fields in the same call (one bulk request) instead of a create_field per field.
Inputs: key (required), name (required), label, fields, +4 more.
create_fieldAInspect
Add a new field to an entity schema. CHOOSING A TYPE — to LINK records (entity-to-entity relationship), use type 'reference' with targets; for an ARRAY of linked records (e.g. participants, tags) use 'reference' with multiple: true — do NOT store related record IDs as 'text' or as a 'list'. Use 'list' only for arrays of primitives (strings/numbers/booleans), with valueType. For enum fields provide values. Decide type, cardinality (multiple), and targets carefully: they're permanent once set (see update_field's description for what's changeable later and what isn't). Also works against the built-in users entity — its base fields (name/email/password/...) are fixed, but you can add your own business fields (e.g. 'role', 'gender', 'department') exactly like on any other entity; get its entity id from list_entities or describe_project. COMPUTED/STORED — for a field whose value is set by server-side logic rather than the client (computed=true, excluded from the create/update request schema) and/or never persisted (stored=false, e.g. a value presigned/derived fresh on every read): both default to the ordinary case (computed=false, stored=true) and are permanent once set. stored=false cannot be combined with search or unique. A stored=false field only gets a real value if something (today: a platform hook) populates it — declaring one on your own entity is schema support for a capability that isn't available to customer-defined logic yet.
Inputs: name (required), type (required), entity_id (required), max, +17 more.
create_fieldsAInspect
Add MANY fields to one entity in a single call — one bulk POST /fields instead of one create_field per field. Each item takes exactly the attributes create_field takes (name, type, label, required, unique, search, targets, values, valueType, multiple, default_value, formula, computed, stored, ...), and the same type/cardinality/immutability guidance applies — read create_field's description first. PARTIAL SUCCESS IS NORMAL: the result carries a summary ({total, succeeded, failed, notAttempted}) and one entry per field in input order, each with _ref (the field name), status (the HTTP status that field's own create returned) and body (the created field record, or the error object with code/message). Fields that failed did not affect the ones that succeeded — read each failed entry's error, fix it, and call create_fields again with ONLY the failed ones. status: null with code NOT_ATTEMPTED means the request deadline hit before that field started; resubmit it as-is. Prefer this over repeated create_field calls whenever you are defining two or more fields on the same entity.
Inputs: fields (required), entity_id (required).
create_functionAInspect
Define a Function: customer Python that runs on an entity's request lifecycle. This creates METADATA ONLY and deploys nothing — the code comes from the project's bundle, uploaded separately and deployed with deploy_functions.
Read the aaly://platform/functions resource before your first one: it has the payload contract, the repo layout handler paths point into, and runnable examples.
Four axes decide behaviour. trigger_point: before-request can rewrite the payload or reject the request outright; after-request sees the response; endpoint IS the response for a custom-endpoint route (see create_endpoint) rather than wrapping a CRUD operation at all. execution_mode: synchronous blocks the request and shares the trigger's whole-chain budget (2s before, 5s after, 25s for a synchronous endpoint, which stays under API Gateway's 29s timeout); asynchronous is fire-and-forget (5 min budget) with failures visible only in CloudWatch. methods: which HTTP verbs trigger it — irrelevant for trigger_point 'endpoint', where the method lives once on the endpoint record itself. order: Functions on the same trigger run lowest-first in ONE invocation, each receiving the previous one's output.
Metadata edits take effect within 30s with no redeploy — only changing the code bundle requires deploy_functions.
Inputs: name (required), entity_id (required), trigger_point (required), label, +9 more.
create_projectAInspect
Create a new project under the platform customer. Returns the new project record with auto-generated id (e.g. 'PRJ3'). The project's DynamoDB data table is provisioned asynchronously by the engine (~30 seconds). Use this id for create_entity calls.
Inputs: name (required), slug, description, multiTenant, +1 more.
delete_endpointADestructiveIdempotentInspect
Soft-delete a custom endpoint. It stops routing within 30s; its attached Functions are untouched (and become unreachable until reattached to a different endpoint).
Inputs: endpoint_id (required).
delete_entityADestructiveIdempotentInspect
Soft-delete an entity schema. Existing data records are NOT deleted.
Inputs: entity_id (required).
delete_fieldADestructiveIdempotentInspect
Soft-delete a field. Existing records keep the stored values, but the field is excluded from validation and responses (and no longer accepted on writes). Refused with FIELD_IN_USE (409) while another field's formula reads it: a formula cannot be edited, so delete the formula field first, or keep the source and hide it with update_field(hidden=true). The name can be created again later only with the same definition it had (type, unique, search, multiple, targets, valueType, precision, computed, stored, formula); a different one is refused with FIELD_SHAPE_CONFLICT (409) because the old values are still stored under that name — use a new name and migrate the data (migrate-field prompt).
Inputs: field_id (required).
delete_functionADestructiveIdempotentInspect
Soft-delete a Function. It stops running within 30s; the deployed code bundle is untouched.
Inputs: function_id (required).
delete_notification_channelADestructiveIdempotentInspect
Delete a notification channel. Sends on that channel then fall back to the platform default for email, and stop delivering for slack and whatsapp. The secret it named is not touched — delete that separately with delete_secret if it is no longer needed.
Inputs: channel_id (required).
delete_notification_templateADestructiveIdempotentInspect
Delete a notification template. Sends naming it fall back to the platform's shipped default if one exists for that key, and otherwise fail with TEMPLATE_NOT_FOUND rather than sending an empty message.
Inputs: template_id (required).
delete_secretADestructiveIdempotentInspect
Delete a secret. This is a genuine, immediate deletion rather than the platform's usual soft delete — a revoked credential must not outlive its revocation.
Inputs: secret_id (required).
delete_variableBDestructiveIdempotentInspect
Delete a non-secret Function variable.
Inputs: variable_id (required).
deploy_functionsADestructiveInspect
Deploy a project's Function code bundle. Project-level, not per-Function — one zip holds every handler for the project, so the name is plural.
Upload the zip first with upload_file, then pass the file id here. The zip's own layout is preserved verbatim, so handler dotted paths point into it directly: a handler of 'orders.before.validate' needs orders/before.py in the zip. Dependencies must be vendored into the zip (pip install -r requirements.txt -t .) — the platform does not run pip on customer input.
Returns immediately with status 'deploying'. Poll list_deployments to see it settle to 'ready' or 'failed'. Rolling back is this same call with an earlier file id.
Inputs: code_file_id (required), project_id.
describe_projectARead-onlyIdempotentInspect
Return a single builder-facing overview of a project's capabilities: its tenant/data-sharing model (and what multiTenant enforces), every entity with its fields, the entity-to-entity relationships (reference fields), and which query parameters actually filter today. Call this to understand a project at a glance before writing app code, instead of piecing it together from list_entities + list_fields. For the full machine-readable REST contract, use generate_openapi_spec.
Inputs: project_id.
file_feature_requestAInspect
Request a capability the AALY platform does not have today. Call list_feature_requests FIRST to check whether the gap has already been filed — if so, prefer vote_feature_request over creating a duplicate.
This is the intended next step whenever aaly://platform/capabilities (or any other guide) tells you something is not implemented and you had to agree a workaround with the user: file the gap here so it shows up as real demand, tagged with what you were building. use_case (WHY you need this, not just what) is the single most useful field for prioritization — fill it in even when brief.
Inputs: title (required), description (required), area, tags, +9 more.
file_support_ticketAInspect
File a bug report, question, incident, or billing/access issue against the AALY platform. Use this instead of guessing around a problem or silently working around it — especially when you (an agent) hit an actual error, not just a documented capability gap (for a missing capability, use file_feature_request instead).
If the problem happened during a specific API call, pass request_id (from the error response or a prior list_logs/get_request_trace call) — it lets a human join straight to that request's full trace instead of reproducing blind. attachment_ids accepts file records from upload_file (screenshots, HAR exports, logs).
Inputs: type (required), title (required), description (required), area, +13 more.
generate_openapi_specAIdempotentInspect
Generate the OpenAPI 3.0 spec for all entities in a project and upload it to S3. Returns a presigned URL. The spec describes the project's REST API (auth + CRUD endpoints) that the generated app code will call directly — this MCP does not proxy data CRUD.
Inputs: project_id.
get_request_traceARead-onlyIdempotentInspect
Everything about ONE request in a single call: its own status/latency/payload, plus every Function invocation it triggered, in order, with each one's status, error text, and captured print() output. This is the tool for 'a request failed, was it my code' — pass the requestId you already have (from a client error, a support ticket, or list_logs) and get the whole story back at once.
request is the client's own top-level request. When a Function calls the project's API during it, those internal calls share the requestId and are listed in subRequests (oldest first, each with internal: true and parentRequestId), never as request.
Inputs: request_id (required), project_id.
get_support_ticketARead-onlyIdempotentInspect
Fetch one support ticket by id, including its full comment thread and attachments.
Inputs: ticket_id (required).
list_deploymentsARead-onlyIdempotentInspect
Deployment history for a project, newest first — status, failure message, bundle version, and who deployed it when. This is the 'did my deploy work' tool.
isLive: true marks the deployment the project is serving now — the newest one that reached 'ready'; at most one per project. A failed deployment does not disturb the previously-ready one, so the project keeps running its last good bundle and that one stays live. Rolling back is a new deployment, which becomes the live one once it is ready.
Inputs: limit, status, project_id.
list_endpointsARead-onlyIdempotentInspect
List custom, non-CRUD endpoint routes. Optionally filter by project_id or entity_id.
Inputs: limit, offset, entity_id, project_id.
list_entitiesARead-onlyIdempotentInspect
List entity schemas. Optionally filter by project_id to see only entities under a specific project.
Inputs: limit, offset, search, project_id.
list_feature_requestsARead-onlyIdempotentInspect
List feature requests, filtered by status/priority/area/project. Call this before file_feature_request to check for an existing match — vote for it instead of filing a duplicate.
Inputs: area, limit, status, blocking, +2 more.
list_fieldsARead-onlyIdempotentInspect
List field definitions for a specific entity. Returns field names, types, and validation rules (required, unique, search, min, max, enum values, reference targets).
Inputs: entity_id (required), limit, offset.
list_functionsARead-onlyIdempotentInspect
List Functions, optionally filtered by project, entity, trigger point or enabled state.
Inputs: limit, offset, enabled, entity_id, +2 more.
list_logsARead-onlyIdempotentInspect
Browse request and Function execution logs for a project — 'was it my engine or my Function code' debugging, with rich filtering.
log_type='requests' returns one row per API request (status, latency split into engine vs. Function time, redacted payload). log_type='function_logs' returns one row per Function invocation within a request's chain (status, duration, its own error text in full, and its captured print() output). The two share a requestId — use get_request_trace to fetch both sides of one request in a single call.
Filters: tenant_id, entity, http_method, and (function_logs only) function_id are exact-match and fast. At least one of those, an exact request_id, or a bounded created_after/created_before time range is required — an unfiltered, unbounded query is rejected, since requests rows never expire.
Inputs: log_type (required), limit, entity, status, +7 more.
list_notification_channelsBRead-onlyIdempotentInspect
List a project's notification channels. Returns each channel's config and the NAME of the secret it uses — never a credential value, because a channel does not store one.
Inputs: limit, project_id.
list_notification_templatesARead-onlyIdempotentInspect
List a project's notification templates, including their rendered-from Mustache source. Does not include the platform's own shipped defaults, which apply whenever no template here matches.
Inputs: limit, project_id, channel_type.
list_projectsBRead-onlyIdempotentInspect
List all projects under the platform customer. Returns project id, slug, name, multiTenant/publicSignup flags, provisionStatus, and _createdAt.
Inputs: limit, offset, search.
list_secretsARead-onlyIdempotentInspect
List a project's secrets. VALUES ARE NEVER RETURNED — each shows a masked preview and a fingerprint, which is enough to confirm whether a secret still matches what was set without exposing it.
Inputs: limit, project_id.
list_support_ticketsBRead-onlyIdempotentInspect
List support tickets, filtered by status/priority/area/type/project. Scoped to your own customer automatically.
Inputs: area, type, limit, status, +2 more.
list_variablesARead-onlyIdempotentInspect
List a project's non-secret Function variables, including their values — they are not secrets, so there is nothing to mask. Use list_secrets for credentials.
Inputs: limit, project_id.
set_notification_channelAIdempotentInspect
Configure how a project delivers notifications on one channel — the transport and sender identity, never the message text (that is set_notification_template).
To send from the project's OWN domain use provider 'smtp', not 'ses': 'ses' sends through AALY's role, which may only send as aaly.io, so any other address fails at send time. For smtp, config.username is the LOGIN name and defaults to from_address - set it explicitly for SendGrid ('apikey'), Postmark (server token), Mailgun or Amazon SES SMTP.
NO CREDENTIAL IS ACCEPTED HERE. credential_key is the NAME of a secret, so a live token never passes through this tool. To configure Slack: call set_secret to have a human enter the bot token, then name that key here.
One channel per channel_type: calling this again updates the existing one rather than failing, so it is safe to re-run.
Email is the only channel with a platform fallback — a project that configures nothing can still send email through AALY's own verified sender. Slack and WhatsApp send through accounts only you can own, so they do not deliver at all until configured here.
This sets the project DEFAULT. A tenant can override it for itself via the project's own REST API; those overrides are not reachable from here.
Inputs: provider (required), channel_type (required), config, enabled, +4 more.
set_notification_templateAIdempotentInspect
Set the message a notification sends, rendered with Mustache against the data passed on each send: 'Hi {{name}}' with data {"name": "Ada"} becomes 'Hi Ada'. {{value}} is HTML-escaped; use {{{value}}} only where raw markup is intended.
Templates are per (key, channel_type), so one key can carry a full HTML email and a one-line Slack message. Calling this again updates the existing template rather than failing.
What each channel needs: email — subject and body_text (body_html optional); slack and in_app — body_text; whatsapp — provider_config with templateName, because Meta only accepts templates it has already approved for a message a business initiates, and will refuse a body we compose.
The platform ships defaults for auth.verify_email and auth.password_reset, so those work before you set anything; a template you set here overrides them.
Inputs: key (required), channel_type (required), enabled, subject, +5 more.
set_secretARead-onlyIdempotentInspect
Register a credential a project's Functions read at runtime, as req.secrets['KEY'].
NO VALUE IS ACCEPTED HERE. This returns instructions for a human to enter the value in the AALY app, along with the exact key name to use — a live credential must not pass through an agent's context, this MCP's transport, or a conversation transcript. Call this to declare which secrets a Function needs, then hand the operator that list.
A secret may hold a single string (an API key) or a whole structured token set — an OAuth access token, refresh token and expiry together, so they rotate atomically in one write rather than tearing across separate records. The web app decides which when the value is entered.
This sets the project DEFAULT; a tenant overrides its own via the project's REST API.
Inputs: key (required), project_id, description.
set_variableAInspect
Set a NON-SECRET configuration value a project's Functions read at runtime, as req.env['KEY'].
Variables are stored and returned in plain text — that is the point of them not being secrets. Anything that must not be readable (an API key, an OAuth token) belongs in set_secret instead.
This sets the project DEFAULT. A tenant can override any key for itself by calling the project's own REST API; those overrides are not reachable from here, because this MCP is scoped to the platform project.
Inputs: key (required), value (required), project_id, description.
update_endpointAIdempotentInspect
Update a custom endpoint's auth mode, execution mode, enabled state, or metadata. entity_id, action and method are immutable — together they ARE the route's identity, so passing any rejects the whole call atomically, nothing applied — same all-or-nothing rule as update_field/update_function. To actually change one of those: create_endpoint with the shape you want, repoint its Functions (update_function's entity_id is also immutable, so this means create_function against the new endpoint's id and delete_function the old attachment), then delete_endpoint the old route.
Inputs: endpoint_id (required), auth, label, action, +5 more.
update_entityAIdempotentInspect
Update an entity's metadata (label, description, allowed methods). Does not affect field definitions.
Inputs: entity_id (required), label, methods, description, +1 more.
update_fieldAIdempotentInspect
Update a field's behavior or metadata. MUTABLE (change any time): label, description, default_value, required, hidden, min, max, pattern, values. IMMUTABLE: type, unique, search, targets, multiple, valueType, computed, stored, formula. Passing ANY of these — even mixed with mutable ones in the same call — rejects the WHOLE call atomically with NOTHING applied; update_field never silently drops or partially applies an immutable attribute, so only pass attributes you actually intend to change (don't echo back a full field record from list_fields). To actually change one: create a differently-named field with the correct shape and migrate data into it per-tenant via direct REST calls — do NOT delete_field + create_field under the same name, that leaves stale data readable under the old shape. Run the migrate-field prompt for the full step-by-step recipe, or see the aaly://platform/capabilities resource, 'Known footguns'. Note: there is no separate 'facet' attribute at all (create_field has no such param) — faceting is automatic whenever search:true is set on an eligible type, so it follows search's own immutability.
Inputs: field_id (required), max, min, label, +6 more.
update_functionAIdempotentInspect
Update a Function's mutable metadata: label, description, methods, execution_mode, handler, order, enabled, error_handling, timeout_ms. Takes effect within 30s with no redeploy.
entity_id, name, trigger_point and language are immutable — passing any of them rejects the whole call, with nothing applied.
Inputs: function_id (required), name, label, order, +10 more.
update_projectAIdempotentInspect
Update project metadata (name, description, multiTenant/publicSignup flags, email verification mode and email branding). logoUrl and brandColor can be removed by passing an empty string or null. Does not affect the project's data table or schema.
Inputs: name, logoUrl, brandColor, project_id, +4 more.
upload_fileAInspect
Upload a file into the platform project's own files entity. Works over any transport (local stdio or the hosted mcp.aaly.io endpoint) — no local filesystem access required. Platform-project only — for uploading into an end-customer's own project, call that project's own REST API (POST /files/presigned-url, then POST /files) directly, the same way the generated app does; this tool does not do that.
Three ways to use it, in order of preference:
Pass content_base64 (the file's bytes, base64-encoded) with filename and mime_type — this tool uploads and registers it in one call. Keep it under 8MB for this mode; base64 in a single tool-call argument gets unreliable well before that.
If you can perform your own HTTP request (e.g. a sandboxed curl/fetch capability) and the file is larger: call with filename, mime_type, and size only (no content_base64, no s3_key) to get back a presigned upload URL — POST the file directly to it yourself (uploadFields as form fields, the file's bytes as the LAST field, named 'file'), then call this tool again with s3_key set to the returned value (plus the same filename/mime_type/size) to register the record.
If neither is possible in your environment, don't force it — tell the user to upload the file directly through the AALY platform app instead.
100MB cap either way (enforced server-side at the presign step).
Inputs: filename (required), size, s3_key, mime_type, +1 more.
vote_feature_requestAInspect
Add one vote to an existing feature request — the 'me too' signal for something already filed, instead of creating a duplicate. Call once per distinct person/session you're voting on behalf of; there is currently no per-voter dedupe, so an agent must not call this repeatedly for the same requester to inflate the count.
Inputs: request_id (required).
whoamiARead-onlyIdempotentInspect
ALWAYS CALL THIS FIRST in any new conversation. Resolves your identity from the request token (API key when hosted, or the AALY_TOKEN JWT/API key when running locally), fetches the platform user record, and lists all projects under the platform customer. Returns user, projects (id, slug, name), the key's context object, default_project_id (from context.projectId, if the key was minted with one), and a hint telling you what to do next. When default_project_id is set, project_id can be omitted on create_entity/generate_openapi_spec/describe_project/update_project. No parameters.
Inputs: no named parameters.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceRemote MCP server that lets AI assistants read tracked competitive intelligence — competitor news, reviews, website changes, social posts and ads — and act on it by managing projects, competitors, battle cards, reports and canvases. Every answer carries a source and a date, and write actions only publish when explicitly shared.MIT
- AlicenseCqualityCmaintenanceCompetitor Monitor AI - MCP server providing AI-powered tools and automation by MEOK AI Labs112 npm29 PyPIMIT
- AlicenseAqualityDmaintenanceEnables brand visibility monitoring across major AI platforms like ChatGPT, Claude, Gemini, and Perplexity. It allows users to track visibility scores, analyze competitor data, and receive actionable insights to improve AI-generated brand recommendations.169 npm1MIT

industrylens-mcpofficial
AlicenseNot gradedqualityCmaintenanceBrowse IndustryLens's published competitive-intelligence reports and head-to-head competitor comparisons from any AI agent — real, source-backed data.MIT
Glama MCP Gateway
Add one secure layer between your agents and this server.