Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault

No arguments

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": true
}
prompts
{
  "listChanged": true
}
resources
{
  "listChanged": true
}

Tools

Functions exposed to the LLM to take actions

NameDescription
deploy_app

Deploy a v2 app: an HTML document + a capability manifest, hosted at its own URL. The manifest has eight extension keys: app metadata; collections (+ per-collection write/read/delete role lists); externalHosts (fetch allowlist); cdn (allow CDN scripts/styles); capabilities (Permissions-Policy opt-ins); embeds (iframe frame-src allowlist); notify (email-on-row rules); webhooks (signed HTTP POST on-row rules). Pass EITHER no app_id (create, mints a slug + URL) OR app_id (redeploy an existing app with new content). Supply the HTML as INLINE html OR as html_path (an absolute path read on the MCP-SERVER host, which is the relay for a hosted connector or your CLI host for a locally-run one, NOT the remote agent's machine; use it to avoid retransmitting a large HTML file every deploy, but only a locally-run connector can read it, and if both are given inline html wins). Pass dry_run:true (alias check) to VALIDATE ONLY: it runs the full manifest + asset-shape validation, the redeploy compat gate, and the schedule-timezone advisory, then returns { ok, warnings, compat?, breaks? } WITHOUT creating a version or mutating anything. A redeploy that NARROWS the manifest (drops a collection, tightens a schema, revokes a role) is refused with manifest_incompatible_redeploy unless force:true; a narrowed collection is then detached, never deleted. Ship images/fonts/audio/video/data FILES with the app in the SAME call via assets[]: each is validated + stored app-scoped and served at its path on the app's own origin, so the HTML references it by a stable same-origin path (<img src="frames/000.jpg">, <video src="media/clip.mp4">), media and font paths support HTTP Range for seeking. A redeploy's assets replace the previous version's set. BEFORE authoring: call get_skill for the manifest grammar. Returns { app_id, slug, url, version, visibility, created } (create) or { app_id, version, compat, breaks? } (redeploy).

list_rows

List rows in a v2 app's mutable collection. This also doubles as the POLL for a collection's current state (no streaming in MCP): pass the prior next_cursor as since to fetch only newer/changed rows. Returns { rows, next_cursor, has_more }.

get_row

Fetch a single row by its key from a v2 app collection (a dedicated relay route — not a client-side scan). Returns { row } or an isError row_not_found.

upsert_row

Create a row in a v2 app's collection, or return the existing row if key is already present (deduped:true) — the ONLY create-shaped verb for app rows (no separate strict create). Omit key to add a new row (server-generates one); pass key to ensure a row exists at that key. The collection must be declared in the app's manifest with 'agent' allowed to write. Returns { row, deduped? }.

update_row

Update an existing row in a v2 app's collection (replaces its data). Pass if_match with the row's current version for an optimistic-locked update — on a version mismatch the relay returns the current row so you can retry. Returns { row }.

delete_row

Soft-delete a row from a v2 app's collection. A watcher sees the deletion live (op:delete on the change feed). Pass if_match for an optimistic-locked delete. Returns { deleted: true }.

get_feed_events

Poll a v2 app's change feed for what happened (row creates/updates/deletes, from any writer — agent or human). This is the long-poll analogue of homespun apps watch — there is no streaming in MCP. Poll loop: call with no since first; process the returned entries; remember cursor; call again passing it as since to get only newer entries. To WAIT for activity, pass wait (~25) so the relay holds the request open until an entry arrives or it times out. A since older than the retention floor returns resync_required — re-list the collection(s) with list_rows instead. Returns { entries, cursor, truncated }.

apps

Manage v2 app lifecycle (deploy_app creates/redeploys; this tool covers the rest). ONE tool with an action enum: list (YOUR owning human's apps) | show (full detail incl. manifest, timezone, has_share_token) | update (visibility and/or timezone - slug is immutable; switching TO 'link' returns a share_url once) | share_link_rotate (rotate a 'link' app's share token, returning a new share_url and revoking the old link; also generates one if the app has none) | delete (soft-delete, idempotent) | wake (a dormant app; a no-op reporting the actual status otherwise) | domain_set (bind ONE custom domain; returns the DNS records the domain owner must publish) | domain_status (the domain record, live-refreshed against Cloudflare when enabled; inspect last_error when it is not activating) | domain_remove (unbind the domain, idempotent).

members

Manage a v2 app's membership (auth spec §6) — who besides the app's owner can sign in to a private app / write to member-scoped collections. ONE tool with an action enum: add (invite-or-attach a member by email — attaches immediately if the email already has a Human, otherwise the relay emails a magic-link invite) | list (the app's owner + members) | set_role (change an existing member's declared custom role in place, or null to clear it — does NOT revoke their sessions, so use this rather than remove-then-add to re-role someone) | remove (idempotent; also revokes the human's live sessions on this app — the app owner cannot be removed) | roles (the derived roles summary: per declared role and collection, the EFFECTIVE access a holder actually has, reported separately for signed-in members and for grant-link holders since their role floors differ, plus member and active-grant-link counts).

grants

Manage a v2 app's grant links (M5). A grant link is a capability URL that confers a DECLARED custom role (x-homespun-manifest.roles) on a stable, per-holder anonymous identity, so the holder's own rows are isolated by author/:own scoping. A grant NEVER escalates to owner/member/agent. ONE tool with an action enum: mint (create a link; returns a grant_url carrying the token in its #g= fragment, shown ONCE, never recoverable) | list (the app's links, never any token) | revoke (idempotent). mode once = one-time (first-browser-claims), multi = shared (capped by max_uses within expiry). An optional pin (pin_row_key OR pin_where) NARROWS the holder to specific rows, never widens. Note: a write-only grant pinned to a single row key can still read that row's existing data back via create dedup, so a 'write-only to slot X' grant exposes slot X's current contents to the holder.

ingest

Manage a v2 app's inbound catch-hooks (inbound-webhooks). A catch-hook lets an EXTERNAL system (Stripe, Zapier, Make, Home Assistant, an email router) POST JSON to a secret URL that writes into a declared collection, so the app receives data even with no agent online. Hooks are DECLARED IN THE MANIFEST (x-homespun-manifest.ingest) and materialized at deploy, so this tool has no create/delete: use it to READ BACK the URL, rotate a leaked one, and manage the opt-in signing secret. ONE tool with an action enum: list (the app's hooks, each with its full secret URL, current rule collection/mode/wake/handshake, per-status delivery counts, and signing-secret state) | rotate (mint a fresh URL secret for one hook by name and return its NEW url once; the old url stops working immediately, no redeploy needed) | set_signing_secret (provision/rotate a hook's signing secret, a DIFFERENT secret from the URL: what a provider HMACs the body with; omit secret to mint one returned ONCE, or pass secret to store a provider value verbatim, never echoed) | clear_signing_secret (remove it). Signature verification ships DARK for now: nothing verifies a signature yet. After deploying a manifest that declares a hook, run list and tell the owner the exact url to paste into the external system.

attachments

Binary attachments (images, PDFs, audio, video) referenced from event payloads / input_data via format: homespun-attachment-id. ONE tool with an action enum: upload | fetch | presign | finalize | download | show | list | delete | mint_token | revoke_token | list_tokens. TOKEN COST, READ FIRST: an inline upload with content_base64 carries the bytes in the tool-call arguments, so they enter the MODEL CONTEXT and cost tokens PROPORTIONAL TO FILE SIZE (a few-hundred-KB image is already very costly, worse on every retry). For ANY real image or media (anything beyond a tiny icon) use a ZERO-CONTEXT path instead: fetch when you have a URL (the relay downloads it server-side, you send only the URL string), or presign + finalize when the client can PUT the raw bytes out-of-band. fetch: { source_url (https), scope } — the relay downloads the URL itself behind an SSRF guard (https only, no private/loopback/metadata hosts, DNS pinned, redirects refused, size-capped, timed out) and runs the same byte-sniff + allowlist + size + quota + scan checks as any upload; works on any storage backend. upload (inline) takes EITHER content_base64 (base64 bytes, no filesystem; last-resort for small assets or clients with neither a URL nor an out-of-band PUT) OR file_path (ABSOLUTE path read on the RELAY host, only usable when the file is local to the relay). presign + finalize (token-free, for images/video/big audio): (1) presign with { mime, size, sha256, scope } returns { put_url, attachment_id }; (2) YOU PUT the raw bytes to put_url over plain HTTP out-of-band; (3) finalize with the attachment_id. At finalize the relay re-reads the stored bytes, BYTE-SNIFFS the real type, and enforces the same allowlist + size + sha256 + quota + scan checks as any upload, so a presign that lies about its mime is caught and never served inline. The presigned path requires the Azure storage backend; a filesystem self-host returns a clear not-supported error (use fetch or inline upload there). download writes to an ABSOLUTE out_path (or returns base64). Scope an upload to agent (default, reusable) or app. mint_token returns a /b/ capability URL (ONCE) a browser can GET without your API key.

taste

Read / write / clear the agent's freeform UI taste notes (a small markdown document of presentation preferences learned from human feedback — 'denser layout', 'no rounded corners'). ONE tool with an action enum: get | set | clear. Call get BEFORE generating an app so prior feedback shapes the output; set does a whole-document replace (not append). Keep entries about UI/presentation only.

key

Inspect, mint, or revoke the calling agent's API key. ONE tool with an action enum: list (key info: agent_id, key_prefix, timestamps) | mint (mint a NEW sibling API key for YOUR OWN agent identity, same scope/ownership, and return its raw value ONCE, the way an MCP-driven agent bootstraps a CLI/child-process credential; the raw key is never retrievable again, the sibling appears in a list made WITH it, and the owner can revoke it) | revoke (self-destruct the agent's OWN key; it stops working immediately and is irreversible, so pass confirm:true). The relay derives identity from the caller's token, so every action acts only on the caller's own agent, and mint can never target another agent's id.

feedback

Send or list feedback to the relay operator. ONE tool with an action enum: create (a bug|feature|note with a message, optional app_id) | list (the agent's own submissions, newest first, paginated by before).

agent

Agent identity + binding. ONE tool with an action enum: whoami (the resolved relay URL, active profile, whether a key is configured — no network, no secrets) | claim (bind this agent to a human via a one-shot claim code from their Settings UI; one-way) | logout (clear the locally-saved key/profile; does NOT revoke it on the relay — use the key tool's revoke for that).

community

Publish an app you own as a COMMUNITY TEMPLATE, install a template into your own account, and (relay operators only) review submissions. ONE tool with an action enum: publish | get_config_contract | install | list_pending | get_submission | approve | reject | set_trust_level. publish captures your live app (html + manifest + the seed rows of its seedOnInstall collections + listing metadata) into a PENDING template - installable by the returned direct link but NOT listed in the public gallery until an operator approves it; you must have a verified email and at most a few pending submissions at once. PRIVACY: an approved template's content AND its captured seed rows become PUBLIC to every platform user, so never publish an app whose seedOnInstall collections hold real personal data - seed data must be example-only. Pass attest_example_only:true to attest you checked this. Optionally give the template a per-publisher slug (namespaced id /) and a semver version (default 1.0.0): a republish under the same slug must bump the version. get_config_contract reads what a template needs at install (its settings collection + ordered config/upload steps) by ref; install creates a fresh PRIVATE copy of a template for YOUR owning human, passing the answers as config (a 'config' value is a string, an 'upload' value is a pre-uploaded attachment id from the attachments tool). The review actions are limited to the relay's configured community reviewers: list_pending (the queue), get_submission (a submission's full content by snapshot_id), approve (list it in the gallery; a re-publish supersedes your app's prior approved version), reject (with a required note that lands in the publisher's app feed).

publisher

Manage YOUR community publisher identity: the @-handle and public profile you present in the template gallery. ONE tool with an action enum: claim | get | update. get returns your profile (handle, whether it is claimed yet, tenure, and the rating/template counters). claim sets your handle exactly ONCE (it is permanent afterwards) from a lowercase 3-to-32-char string; a handle that is reserved (platform or role words) or already taken is refused. update changes your public display_name, bio, or url at any time. claim and update require a verified email; an existing publisher may already have a provisional maker-... handle (auto-assigned) that claim renames the one allowed time.

review

Rate and review community templates you have USED, respond to reviews of your own templates, and (relay operators only) moderate. ONE tool with an action enum: create | respond | report | remove | unhold. create leaves a 1-to-5 star rating plus an optional written body on a template you have installed - identify the template by template ("/") or by handle+slug; you need a verified email, and each install yields exactly one review (the aggregate carries across template versions). A body that contains a link or a contact email is AUTO-HELD for a moderator before it appears. respond replies to a review of YOUR OWN template line (review_id + response; null clears it), one editable response per review. report flags a review for the relay's moderators (review_id + reason), deduped per account. remove and unhold are limited to the relay's configured community reviewers: remove takes a review down and adjusts the rating aggregate; unhold publishes a previously auto-held review into the aggregate.

get_skill

Fetch the relay's auto-updating SKILL.md (the full Homespun usage guide) — UNAUTHENTICATED, needs no API key. Call this to self-teach the Homespun workflow (events vs records, schema grammars, the poll loop) before driving the other tools. Pass version_only:true to get just the relay's skill version string (to check if a cached copy is stale).

Prompts

Interactive templates invoked by user choice

NameDescription
homespun_guideInsert the app usage guide (MCP invocation + conceptual core) into the conversation so the model knows how to drive app's tools.

Resources

Contextual data attached and managed by the client

NameDescription
homespun_guideThe app conceptual guide for MCP clients: when to use app, events vs records, schema design, the house style, and the round-trip mental model — with MCP tool-call invocation grammar.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/homespunapps/homespun'

If you have feedback or need assistance with the MCP directory API, please join our Discord server