Create a grounded support agent
Create an agent with a soul, a task with boundaries, tools and a knowledge base — over MCP.
list_toolslist_knowledge_basescreate_agentget_agentcreate_shareBefore you build — discover, don't run this cold. Interview the tenant about their job, their material, the procedures it runs and the systems it must touch; plan the whole setup (agent + knowledge base + skills + MCP as needed) and play it back before creating anything. The steps below are what you run after that — see Discover before you build.
Principle — one agent, one job. Give this agent a single, clearly bounded task. If the business has three jobs (support and sales and scheduling), build three agents — a "does everything" agent answers each thing worse. More in Design principles.
An agent is soul + task + tools + skills + knowledge_bases. soul is identity and voice; task is
the job and its boundaries — both go into the fixed prefix of the system prompt.
1. See what you can attach
list_tools() # tools available to this tenant (including connected MCP tools)
list_knowledge_bases() # knowledge bases you can mount2. Create it
On by default, so you don't have to ask for them. A new agent can already reply with a tappable single/multi-choice form (
ask_forms) when it needs two or three facts before it can answer, and can already draw a chart (compute_chartis in the default tool list). Both were off by default until 2026-08-03, and the create call had no parameter for the first — so agents built before then have neither, andupdate_agent(ask_forms=True, add_tools=["compute_chart"])is how you bring one up to date.Passing
tools=[...]replaces the default list rather than adding to it, so includecompute_chartyourself whenever you pass tools at all.
Names are lower-case. The name is not only what you see — eleven tables reference an agent by it (shares, sessions, storylines, channel bindings, usage), so
Pipandpipare two different agents to all of them and the same one to you. New names are lower-cased on save; write them that way and there is nothing to reconcile. It is also not the public URL — that isalias.
create_agent(
name="support", # lower-case; the platform lower-cases it anyway
alias="support", # public human-readable URL slug — set one (url-safe, lowercase)
soul="You are the support assistant for Acme Loans. Professional and warm.",
task="Answer questions about mortgage products and the application process. "
"Never promise a disbursement date; never give legal or tax advice; "
"for any specific quote, call a tool — do not answer from memory.",
tools=["web_search"],
knowledge_bases=["company-policy"], # use the KB's returned slug name (see below)
published=True,
)aliasis the agent's public human-readable address segment ({public_base}/t/<tenant>/<alias>) — set it so you can hand people a memorable link. It's normalised to a url-safe slug; a clash comes back inalias_result.- System tools are on by default. New agents automatically get
current_time,ip_geoandweather(the built-insystemMCP) — you don't list them;toolsis for the extra ones. - Names in URLs are slugged. A knowledge base name becomes a url-safe slug on creation
(
"Company Policy"→company-policy); attach it by the returned name, not what you typed.
3. Confirm what landed
get_agent(name="Support") # writing it doesn't mean it looks the way you intendedpublished=True means visible, not reachable. End users can't get to the agent until you create
a share (step 4). Don't stop at "published".
Boundaries belong in task — negative constraints ("never promise…") stop drift better than positive
description. Don't put safety rules in soul; the platform appends global moderation automatically. To
change one field later, use update_agent(name, field=…) — it merges, so it won't blank the rest.
4. Publish it — ask how, then make it reachable
Before you say "done", ask the tenant how their customers should reach it, then wire that channel with
create_share (it returns a real, openable link — hand that back, not "it's published"):
create_share(agent_name="Support", label="Website widget")
# → { token, chat_url, qr_url, embed_snippet, pretty_url, … }If the response carries pretty_url (…/t/<tenant-alias>/<agent-alias>), that's the link for
humans — readable and stable across token rotation. If it's null, set the missing alias
(create_agent(alias=…) / PUT /agents/{name}/alias; tenant alias in console → Settings) rather
than shipping the token link. chat_url remains right for embeds and QR codes.
- No website — just a link or a QR (a freelancer, a shop, a flyer, a business card): hand back
chat_url(a full-screen hosted chat page — no site needed) andqr_url(a QR they can print). It's anonymous: no login, and each visitor is remembered by their browser, so regulars are recognised. - Their own website: give them
embed_snippet(one line before</body>for a floating widget), orchat_urlto link / iframe. - Telegram / WhatsApp: set up per-channel in the console (Agent → Integration → Telegram / WhatsApp); point them there.
Report back. Hand back the actual link they can open and test right now (
chat_url, andqr_urlif they have no site), plus the agent's console page to review it —https://console.agent4.io/#/agents/Support. Not "it's published" — the link.