mcpbeat

agent4.io MCP Server

io.agent4/agent4-tenant
answering

agent4.io is answering right now. Last checked 14 min ago. It exposes 47 tools.

Build and run grounded business agents over MCP: agents, knowledge bases, skills, Storylines.

Uptime history 41 hours of history · worst hour 75%
41 hours agonow
100.0%
Uptime 24h
91 of 91 checks
47
Tools
read from the server
580 ms
Response time
average over 24h
open, no key
Access
streamable-http

Connect this server

Endpoint below is the one we actually reach during checks — not the one copied from a README. Last verified 14 min ago.

run in your terminal
claude mcp add agent4-tenant --transport http https://api.agent4.io/v1/mcp
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "agent4-tenant": {
      "url": "https://api.agent4.io/v1/mcp"
    }
  }
}
~/.codex/config.toml
[mcp_servers.agent4-tenant]
url = "https://api.agent4.io/v1/mcp"
.cursor/mcp.json
{
  "mcpServers": {
    "agent4-tenant": {
      "url": "https://api.agent4.io/v1/mcp"
    }
  }
}
.vscode/mcp.json
{
  "mcpServers": {
    "agent4-tenant": {
      "url": "https://api.agent4.io/v1/mcp"
    }
  }
}

Available tools 47

Read directly from the server with tools/list, grouped by what they act on. If a tool disappears, we record the date.

knowledge
add_knowledge_file
Add a local file's content to a knowledge base (txt/md/html/pdf/docx). **This MCP runs on the platform server and cannot read paths on YOUR machine.** For text files, read the content yourself and call `add_knowledge_text`; for binaries (pdf/docx), upload via the console, or curl `/knowledge-bases/{name}/documents/upload`. **To ingest a whole folder, zip it and send that one endpoint** — subdirectories are walked, md/txt/pdf/html/docx are ingested one by one, and document names use the in-archive relative path (`2025/rates.pdf` vs `2026/rates.pdf` therefore never collide). Images, `.DS_Store` etc. inside the zip are ignored; if the archive contains an encrypted, corrupt or abnormally high-compression file, **the whole archive is rejected** naming the offending entry.
add_knowledge_text
Add a **text** document to a knowledge base (chunking + embedding happen synchronously; returns the real chunk count). For **local files** (pdf/docx…) see `add_knowledge_file`.
create_knowledge_base
Create a knowledge base. **Write `instructions` at creation time — do not leave it blank.** It is injected next to this KB's excerpts whenever they are retrieved. It does NOT affect recall (recall is vector search + max_distance); it governs how the model USES what was retrieved. Derive it from the expected usage, one line each: - Scope: what it covers / does not, and what to do when out of scope ("Covers residential mortgages only; for car or personal loans, say so and hand off"). - Authority: where it ranks ("Current company policy; overrides industry norms"). - Usage rules specific to this content ("Any quoted rate must state its effective date"). The generic "answer from the excerpts; say when not covered" is built into the platform — never repeat it here. Blank is acceptable only for generic reference material with no special rules. Worked examples: search_agent4_docs("knowledge base instructions examples"). max_distance is the relevance cutoff (blank = global default 0.6); tighten for regulatory content, and calibrate against real queries rather than guessing.
get_knowledge_base
Get one knowledge base's configuration (including the full instructions text shown to the model).
list_knowledge_bases
List this tenant's knowledge bases (with doc/chunk counts and relevance cutoff).
search_knowledge_base
Search this knowledge base; returns matching chunks with distances. Uses **exactly the same retrieval path as real conversations** — use it to validate the cutoff and chunking: an empty result means this question will be judged "not covered" and the agent will answer "not in the knowledge base".
update_knowledge_base
Update part of a knowledge base — fields you don't pass stay as they are (server-side PATCH merge).
agent
create_agent
Create an agent. `name` is lower-cased on save — it is a key, not a display name. soul = persona/identity; task = duties and boundaries; tools = tool-name whitelist (check list_tools first; the system tools time/geo/weather **and `compute_chart`** are **auto-enabled by default**, no need to list them — but note that passing `tools` at all replaces that default list, so include them yourself if you pass any); knowledge_bases = attached knowledge base names (once attached, retrieval is injected automatically every turn). `ask_forms` (**on by default**) lets the agent reply with a tappable single/multi-choice form instead of a paragraph of questions — the natural move when it needs two or three facts before it can answer. `compute_chart`, on by default too, is what lets it draw a chart; it computes shares / growth / running totals / projections in code from numbers already in the material, so the model never does the arithmetic. Pass `ask_forms=False` for an agent that should only ever answer in prose. alias = the **public human-readable slug** — strongly recommended: it becomes the memorable URL segment for this agent (`{public_base}/t/<tenant>/<alias>`), the link you hand to people. Use a URL-safe lowercase-hyphen name (`booking`, `suchka-venue`); it is normalised automatically. Collisions / invalid names are reported in alias_result.
get_agent
Get one agent's full configuration (soul/task/tools/skills/knowledge_bases/model/params).
update_agent
Update **part** of an agent — fields you don't pass stay as they are. ⚠️ List-field semantics, don't mix them up: `tools=[...]` / `skills=[...]` / `knowledge_bases=[...]` are **full-list replacement** — items you didn't read first get pushed out. To "add one / remove one", use `add_tools` / `remove_tools` (and add_/remove_skills, add_/remove_knowledge_bases): incremental, idempotent, leaves the rest untouched. After the call, **read the response** to verify the final list — don't announce "enabled" just because the call succeeded. Also: tools can ride on a skill (the tools field of create_skill/update_skill) — once the skill is attached to an agent, its bound tools join the chat-time whitelist automatically, but they **do not appear in the agent's own tools list**.
skill
create_skill
Create a skill. description = "when to use" (goes into the system prompt, keep it short); instructions = the detailed guide (fetched on demand via load_skill). The paradigm (important): instructions are visible only AFTER the model calls load_skill — if calling some tool is **mandatory** ("user gives a phone number → must call save_contact"), the trigger must be written into description, otherwise models often answer directly without loading the skill and the rule never takes effect. Also never promise return values a tool doesn't produce (ticket numbers / IDs) — the model will fabricate them. The returned warnings field flags both patterns.
get_skill
Get one skill's full content (including the complete instructions text).
update_skill
Update part of a skill — fields you don't pass stay as they are (server-side PATCH merge, no GET+PUT round-trip). ⚠️ `tools=[...]` is **full-list replacement**; to add/remove one use `add_tools`/`remove_tools` (incremental, idempotent). Tools bound to a skill take effect automatically at chat time on any agent the skill is attached to — no need to also add them to the agent's tools.
storyline
create_storyline
Create a storyline draft. After creating, self-check with validate_storyline, then publish_storyline. user_visibility — what the end user sees of their own run: "invisible" (default, no UI), "named" (a banner with the storyline name only), "trail" (banner + read-only view where untaken branches and future steps are redacted grey blocks), "full" (banner with step x/y + full read-only map). `learner_visibility` is the deprecated old name (legacy values hidden/completed_only still accepted and mapped). concurrency — who the progress follows: "user" (default) = progress belongs to the person, all of that user's sessions share one run — fits curricula / onboarding / KYC; "session" = progress belongs to the case, each session gets its own run, a new conversation = a new application — fits licence applications / tickets / per-product flows. Case state goes to the blackboard (travels with the run); facts about the person go to profile dimensions (shared across runs). graph = {"nodes":[Node,...], "edges":[]} (edges are derived from exits, may be left empty). Node = { node_key: stable uuid (unchanged across edits; exits/funnels reference it), title, task (may interpolate {dimension}/{blackboard.key}), type: "task"(default) | "document_review"(visual pre-review of uploads) | "export"(structured report) | "parallel"(parallel branches / AND-join), review: {"checkpoints":[str]} — type=document_review: per-item visual checkpoints, export: {"sections":[str]} — type=export: report sections, parallel: {"branches":[{"key":str,"label":str,"to_node_key":str},...]} — type=parallel: declares required branches, each pointing at a sub-flow entry; the user may do them in any order, the engine tracks completion, and only when ALL are done does the node take its single join exit (put it at exits[0]). A branch sub-flow's last step just exits back to this parallel node — no hand-written completion flags. flags: {"is_entry":bool, "is_terminal":bool}, on_enter_opening: something to say proactively on entry (empty = silent transition), ai_eval_trigger: natural-language condition for when to run AI evaluation (empty = every turn), callback: {"mode":"none"|"backend"|"ui_redirect", "wait_timeout_secs":int, "signal_name":str}, profile_writes: [{"dim":str, "source":"ai"|"rule"|"callback"}] — dimensions this node writes, resources: {"skills":[str],"knowledge_bases":[str],"tools":[str], "resource_mode":"additive"|"replace"}, exits: [Exit,...] (list order = priority; deterministic rule/callback/user_choice are evaluated first, ai last) } Exit = {"kind":..., "label":str, "to_node_key":str, "ai_criteria":str — kind=ai: one natural-language criterion, "user_choice":{"button_text":str} — kind=user_choice, "rule_ast":RuleAst — kind=rule (see below; an AST, not a string), "callback_signal":"done"|"timeout"|"canceled" — kind=callback, "target_storyline_id":str, — kind=goto_storyline "writes":[{"ref":"dim"|"blackboard","key":str,"op":"set"|"inc","value":<num|str|bool>},...]} — deterministic state writes when this exit is taken (this is how profile_writes with source='rule' actually land): set = assign (completion flags / branch flags), inc = increment (loop/retry counters, value defaults to 1). dim writes are constrained by profile_schema. kind ∈ ai|user_choice|rule|callback|goto_storyline. Common control flow composes deterministically (never bet on the LLM): if/else/switch = several rule exits on one node (order = priority); loop/retry = a back-edge + an inc counter in writes + a rule cap gate; AND-join = a parallel node, or hub + completion flags + an "and" rule. RuleAst is one of: comparison {"op":">="|">"|"<="|"<"|"=="|"!=", "left":{"ref":"dim"|"blackboard","key":str}, "right":{"value":<num|str|bool>}} boolean {"op":"and"|"or", "clauses":[RuleAst,...]} profile_schema = dimension definitions, e.g. {"listening":{"type":"int","min":0,"max":100,"visible_to_user":true}}. on_complete="goto_next" requires next_storyline_id (validate/publish reject otherwise). Enrolment (who enters this line, when): is_default=true auto-enrols on first conversation (at most one per agent); allow_agent_enroll=true lets the agent enrol users mid-conversation — in that case ALWAYS write enroll_trigger (one natural-language "enter when", e.g. "the visitor says they want to apply for a loan"), otherwise the agent has no trigger basis and almost never enrols; takes effect after publishing, independent of is_default and manual assignment. See /docs/tenant-guide/storylines.
get_storyline
Get one storyline's full definition (whole graph + profile_schema + top-level fields).
update_storyline
Update **part** of a storyline draft — fields you don't pass stay as they are (GET-then-merge on top of a full PUT underneath). concurrency: "user" = progress belongs to the person (shared across sessions); "session" = progress belongs to the case (one run per session). Changes affect only **future** enrolments; in-flight runs are not migrated. ⚠️ Especially `graph`: not passing it = keep the existing graph. (This tool once treated "no graph" as replace-with-empty — renaming a storyline wiped its whole flow. Semantics are now partial; to truly clear the graph, pass `{"nodes":[],"edges":[]}` explicitly.) graph/Node/Exit/RuleAst structures: see create_storyline. Pass expected_version for optimistic locking. Read the response to verify, then validate_storyline.
end
get_end_user
Get one end user's detail: basic profile (name, contact email/phone, city, timezone) + their spaces. Never any conversation content. Carries a `console_url` to the user's detail page.
list_end_users
List this tenant's **end users** (the people chatting with your agents) — roster only, never any conversation content. Each user carries: display name, login method (email / oauth:* / proxy), email (if any), space/session/document counts, last-24h token usage, and a `console_url` (click through for detail). q filters by name or external id; sort ∈ recent (default) | tokens24h (descending 24h usage). Pagination: pass the returned next_cursor back as cursor. Typical: list_end_users(sort="tokens24h") to find the most active / most expensive users.
page
list_page_contexts
List all page playbooks of this tenant (with match rules, greeting mode, position).
page_context_stats
Open counts and suggested-question click counts per playbook — find copy nobody clicks.
test
test_planner_trigger
Dry-run the Dynamic Planner's escalation judge: would these messages be offered a step-by-step plan? Use it after editing the agent's `task`, since the task text is the **business-domain gate** — a vague task lets out-of-domain requests through, a narrow one turns real customers away. messages: the user's turns in order; the LAST one is treated as the current turn and the rest as that user's earlier messages (same window the live judge sees). samples>1 re-runs the judge to show stability (it is a probabilistic call). expect: pass true/false to get `matched`. Nothing is stored — no session, no enrollment. Tokens count toward the tenant quota (kind=planner). Returns {triggered, samples, goals[], domain, matched}. Reads the judge only: whether the user then ACCEPTS the offer is a separate, user-controlled step.
test_skill_trigger
Reality-check whether your prompts actually trigger tool calls (dry-run) — run this after writing/changing a skill instead of counting corpses in production. Replays your messages N times against the **production** system-prompt assembly, tool schemas and this tenant's actual model routing, capturing only the model's tool-call decision: **tool side effects are NOT executed**, no session is stored. Tokens count toward the tenant quota (messages≤5, samples≤5, at most 25 calls per invocation — pick test messages carefully). Two modes for the skill's two battlefields: - loaded=false (default): first turn, skill not loaded — tests whether the trigger in description works; - loaded=true: simulates post-load_skill — tests the quality of instructions (incl. few-shot examples). Returns per-message hit counts plus claimed_without_call (the model said "noted" WITHOUT calling the tool — the worst failure, fix first). Cover edge cases in your test messages: numbers with spaces, buried in long questions, corrections, email-only. The loop: create_skill → check warnings (static lint) → test_skill_trigger (dynamic reality check) → adjust description / add examples → re-test until the hit rate holds.
agent4
search_agent4_docs
Search agent4.io's own product docs — concepts (what a thing *is*) and cookbook recipes (which tool to *call*). Use when you're unsure how an agent4.io feature works, what a term means, or how to build something on the platform. Returns top passages with title, layer ("concept"|"ops"), url and a snippet. Public content; no tenant data involved.
agents
list_agents
List all agents in this tenant (name + published state).
clone
clone_storyline
Clone a storyline into a new draft (new key, unpublished, doesn't claim default, no chain pointer) for tweaking.
configure
configure_share
Configure this share — its name and its **appearance** — fields you don't pass stay as they are (server-side partial merge). - `label`: the name at the top of the chat page, and the browser tab's title. **Renaming a share is this call**; you never need to create a replacement and delete the old one. That would mint a new token, so the link already embedded in the client's site would stop working — the visible name and the address are not the same thing. - `theme_color`: the brand colour, `#RGB` or `#RRGGBB`. **This one colour is all you give** — its foregrounds are derived on save. - `highlight_color`: **only if the brand actually has a second colour.** Most don't; leave it out and nothing changes anywhere. When set, it is used where something should be visible without competing with the primary action: the second series in a chart, and citation markers. Buttons, the current storyline step and user bubbles stay on `theme_color` — two colours fighting over the same element is how a two-colour palette goes wrong. Foregrounds are derived from it the same way. Text/foreground colours are derived server-side to WCAG contrast and stored (a light brand colour automatically gets dark text instead of white) — **do not compute a palette yourself and do not try to set text colours**; they would be overridden. - `logo_url`: absolute URL. The header scales by height, any aspect ratio fits; **the collapsed launcher bubble is square**, so only near-square images (aspect 0.74–1.35) are used on the bubble — a wide wordmark falls back to the platform icon there. Want your mark in both places? Provide a square variant too. - `input_mode`: `text` (text box, default) or `voice` (opens in push-to-talk). Requires the platform's voice backend. - `launcher`: hover tooltip text for the bubble. `theme`: `light` / `dark` / empty = follow the visitor. - `custom_css`: the escape hatch for strict brand guidelines — the injected stylesheet can override our CSS variables (`--acc` / `--acc-fg` / `--acc-text-l` / `--acc-text-d` / `--bg` / `--surface` / `--text` / `--border`); write light values under `:root{…}` and dark under `html[data-theme="dark"]{…}`. **Prefer theme_color**: it carries a readability guarantee, with custom_css the contrast is on you. Get the token from `list_shares` first. Full examples in the Cookbook's configure-branding.
custom
set_custom_domain
Bind the client's own domain to this tenant's chat pages: `https://chat.client.com/` serves the tenant's branded page (or a specific agent's chat), the address bar keeps the client's domain, and the TLS certificate is issued automatically. **Have the client configure DNS first**: add a CNAME at their DNS provider pointing to the `cname_target` in the response (`endpoint.agent4.io`). Key points: - **Subdomains only** (`chat.client.com`). An apex domain (`client.com`) cannot carry a CNAME — have the client use a subdomain, or a DNS provider with CNAME flattening (Cloudflare etc.). - **Cloudflare users must set the record to DNS only (grey cloud)**. With the proxy on (orange cloud) the name resolves to Cloudflare's addresses, verification fails, and `last_error` says so. - Verification is **asynchronous**: checked once immediately on binding; if DNS hasn't propagated it stays `pending` and is re-checked every 10 minutes (calling this tool again also re-triggers). `status` = `active` means live; the certificate is issued on first visit. - **One** domain per tenant; changing the domain re-runs verification, changing only `agent_alias` does not. - Requires a plan that includes custom domains (403 = upgrade needed). `agent_alias` empty → the domain lands on the tenant's branded page (listing available agents); set to an agent's public alias → lands directly on that agent's chat page.
diagnose
diagnose_prompt
Read a field and return a list of **specific** improvement suggestions (string array). field: same values as improve_prompt. current = the text to diagnose (required — an empty text has nothing to diagnose). Typical flow: diagnose_prompt first, pick the suggestions you want, then fold them into improve_prompt's hint.
export
export_storyline
Export a portable storyline JSON (schema_version + definition; no tenant/version/id) for backup, migration or re-import.
import
import_storyline
Import an exported storyline JSON as a draft. **Artifacts like "generate a storyline from a novel / source material" land here.** payload = the structure returned by export_storyline (schema_version + graph + profile_schema + top-level fields). Version-aware: payloads newer than the system supports are rejected. Always creates new, never claims default, key collisions auto-rename. override_agent_name rebinds the imported line to an agent that exists in the target tenant.
improve
improve_prompt
Rewrite a field's text to work better as an AI system prompt; returns the improved text. field ∈ persona | task | greeting | storyline_task | storyline_opening | storyline_ai_trigger | storyline_ai_criteria | skill_description | skill_instructions | kb_description | kb_instructions — determines the rewrite target (a Task should read like commands, a KB description says "what's inside / when it's relevant", a skill description says "when to use" in one line, …). current = the current text (empty = draft from scratch); hint = the direction you want this time (empty = general polish); context = on-site context (which KB is being edited, values of sibling fields) — the more specific, the better the fit. Returns only the improved text, no explanation, no wrapper — the caller places it next to the original for a human to accept or reject.
mcp
list_mcp_servers
List the MCP servers connected in this tenant's tool library (read-only; secret fields omitted).
preview
preview_plan
Generate a plan for a goal and return it for review **without persisting anything** — no temporary storyline, no enrollment, no user affected. Use it to inspect plan quality before trusting the feature in production, or to see how the agent's `task` constrains the steps. Returns {plan, backend, warnings}. `warnings` flags machine-detectable smells, notably checklist items that are the AGENT's own deliverable ("produce a summary") — those can never be ticked off, because ticking is judged from what the USER provides, so the step would stall forever.
publish
publish_storyline
Publish a storyline: validates first (blocking errors → 422), then freezes an immutable version and marks it published.
pwa
set_pwa_branding
Configure a specific **agent's** PWA branding and install experience (applies to that agent's `/s/` standalone chat pages — what gets installed to the home screen is one agent's entry page, so each agent is its own app). - `agent`: the agent name whose install branding to configure (required). - `icon_source_url`: public URL of one master image (PNG/JPG/WebP ≥192×192, ideally a square logo). The server derives the full set: browser-tab favicon(48) + install icons 192/512 + Android maskable(512). Non-square images are centre-cropped. Once set, "Add to Home Screen" installs this agent's own icon. - `install_prompt`: prompt style — `banner` (a dismissible slim bar inside the chat page, default), `card` (a card shown on first visit; more visible, more intrusive), `off` (no prompt). Android/Chrome uses the system install dialog; iOS automatically switches to a "Share → Add to Home Screen" illustrated guide. Icon/prompt params optional, settable independently. Returns the final config (icon URLs + install_prompt). Full walkthrough in the Cookbook's configure-branding.
resolve
resolve_page_context
Given a URL (or key), show which playbook it resolves to — always verify after writing a match rule. Globs make it easy to write rules that "look right but never match" (one `*` short, one path level too many) — and in production the only symptom is visitors silently getting the default playbook, with no error anywhere.
share
create_share
Create a **share / integration entry point** for an agent — this is how end users actually reach it. **`published=True` only means "visible", not "reachable"**: for end users to talk to the agent you must create a share. The response carries a directly openable chat link (`{public_base}/s/<token>`) and the website embed URL (`{public_base}/embed/<token>`). For a website widget, paste one line before </body>: `<script src="{public_base}/embed.js" data-token="<token>"></script>`. label names this entry point ("website widget", "support link"). Telegram/WhatsApp and other channels are connected separately on the agent's Integration page in the console. **No website?** Hand the returned `chat_url` or `qr_url` (QR code) straight to the tenant: print it on business cards / flyers / in-store; scanning opens a full-page chat, no login, returning visitors are remembered per browser. **For links you give to humans, prefer `pretty_url`** (when present in the response): `{public_base}/t/<tenant alias>/<agent alias>` — memorable, printable, survives token rotation. No pretty_url = aliases not fully set — **fix that proactively**: agent alias via `create_agent`'s alias param or `PUT /agents/{name}/alias`; tenant alias in console → Settings. The `/s/<token>` link still works, but it is the machine/embed form, not one to read out to a person.
shares
list_shares
List an agent's shares (token / label / disabled / chat link / embed URL / appearance config). When the top-level `pretty_url` is non-empty it is the preferred link to give humans (see create_share).
skills
list_skills
List this tenant's skills.
storylines
list_storylines
List this tenant's storylines (optionally filtered by agent). Includes state, version, default flag.
tenant
tenant_info
This tenant's basic info and quota (plus custom-domain binding status, if any).
tools
list_tools
List tool names assignable to agents, with their descriptions (incl. the tenant's connected MCP tools).
unpublish
unpublish_storyline
Unpublish (archive): no more auto-enrolment; in-flight users silently degrade to the plain agent on their next turn (progress kept — re-publishing resumes it).
upsert
upsert_page_context
Create or fully replace a page playbook. `context` is the page background the **server** injects for the agent — write "who lands on this page, what they are deciding, what they usually worry about"; do NOT write facts like prices or quotas (those belong in a knowledge base, which also ranks higher in authority). `url_pattern` is a glob (`*/pricing`, `*/solutions/*`), matches the path only, ignores query strings and trailing slashes; without it the page must report the key explicitly. Resolution order: explicit key > url_pattern > default. `greeting_mode="generated"` produces the greeting and suggested questions on the fly in the visitor's language (recommended); `"static"` uses your fixed `greeting` / `questions`. **This is a full replace**: fields you don't pass fall back to defaults rather than staying as they are. To change one field, `list_page_contexts` first, merge, then send.
usage
usage_stats
Usage statistics. group ∈ total | agent | user | space | day | model. Metadata only — token counts and event counts, never any conversation content. Use group="user" to see who uses the most, group="agent" for the busiest agent.
user
list_user_sessions
List one end user's **sessions** — metadata only: agent, title (AI summary), message count, tokens, timestamps. **Message bodies are not returned.** Transcripts are rendered in the console: each session carries a `console_url` that **deep-links straight to that conversation, auto-opened** (no digging through the detail page when there are many), plus `user_console_url` to the user's detail page as the general entry. Hand the link to the tenant — a human reads the original there. Pagination: pass next_cursor back as cursor.
validate
validate_storyline
Validate the storyline graph (entry / dead ends / unreachable / dangling / cross-line targets / rule dimensions). Returns {ok, errors}. Must pass before publishing.

Endpoints

URLTransportStateLatencyChecked
https://api.agent4.io/v1/mcp streamable-http answering 582 ms 14 min ago

agent4.io — questions

Answers built from our own checks of this server.

What can agent4.io do?
It exposes 47 tools, read directly from the server on our last check. Among them: add_knowledge_file, add_knowledge_text, clone_storyline, configure_share, create_agent, create_knowledge_base and 41 more. The full list with descriptions is on this page — we take it from the server itself via tools/list, not from a README. How MCP servers expose tools in the first place →
What is agent4.io mostly used for?
Its tools cluster around knowledge, storyline and skill. That is what this server is built to work with — the grouping comes from the actual tool names, not from a category we assigned.
Is agent4.io working right now?
We send a real MCP handshake every 15 minutes. Over the last 24 hours 91 of 91 checks got a reply (100.0%), average response time 580 ms. The bar chart above shows every period we have measured.
How do I connect agent4.io?
Copy the ready config from this page — we generate it for Claude Code, Claude Desktop, Codex, Cursor and VS Code, each with the file path that client actually reads. It is a remote server, so there is nothing to install — the client connects to the address.
Does agent4.io need an API key?
No. agent4.io completed a full MCP handshake with us as an anonymous client and listed its tools without asking for anything. All 47 of them are readable on this page. This is what we observed, not what the docs claim.
How fast is agent4.io?
It answers our handshake in 580 ms on average, which is faster than 18% of all working MCP servers we measure. That is on the slow side — worth knowing if the tool sits inside an interactive loop. The comparison comes from our own checks across the whole registry, every 15 minutes.