Skip to main content
Erstan’s MCP server lets an external coding agent build and publish Agent Builder workflows while people keep control of intent and review. The authoring tools expose the live node catalog and a concise builder guide, then let the client create or update a complete draft graph, validate it, and publish the exact reviewed revision.
For Claude and Codex, install the official Erstan plugin with browser-based OAuth and authorize Build access. Use the Advanced API-key setup only for automation or MCP clients that do not support the plugin flow. See Connect a Coding Agent.
publish_agent makes a validated draft live and therefore requires an explicit user request, both authoring scopes, the latest opaque revision, and normal live edit/team access. The backend does not expose archive or delete through these tools. test_agent can run a draft, uses real tools, and therefore additionally requires agents:run and normal approval policies.publish_agent_skill likewise requires an explicit publication step and the latest Skill currentVersion. create_agent_skill always creates a draft.

Backend-enforced guarantees

These restrictions are server controls, not prompt guardrails:
  • create_agent always creates a draft, and update_agent writes a draft while preserving any retained published version.
  • publish_agent validates the complete saved graph and publishes only the exact current revision/version. The authoring tool family exposes no archive or delete operation. test_agent runs the guarded current draft; run_agent is a separate capability that resolves only a retained published version.
  • Every call re-checks the connected user’s live workspace, team, and agent permissions. Advanced API keys use their creator’s live permissions.
  • update_agent and publish_agent require an opaque revision, and the backend atomically rejects stale revisions before mutation. The client handles that result by re-reading and reconciling; it cannot bypass the check by retrying.
  • validate_agent never mutates, publishes, or executes the draft.
  • Skill package validation never saves or executes code. Skill creation is draft-only, full-package updates require expectedVersion, and publication re-validates the current package.
  • User-authored Skill actions run only through the isolated E2B action runtime. Declaring sideEffects: "none" disables action-runtime network access, but does not make workspace-authored code trusted or bypass write confirmation.
Consequently, authoring clients can publish only a valid, current, manageable draft and cannot archive or delete through MCP. Draft testing remains an explicit, separately scoped operation; prompts and Skills cannot bypass those controls.

Authorize agent building

Install the plugin and authorize Build access for the normal interactive setup. This grants the connected-app permissions View agents, Build agents, Run agents, Publish agents, and View runs, plus read-only access to work, documents, and files. It does not grant task, document, or file writes.

Advanced API-key setup

For a non-OAuth client, create a workspace API key in Settings → API Keys with both authoring scopes: Scopes are exact and additive. create_agent needs agents:write; update_agent, validate_agent, and publish_agent require both agents:read and agents:write. A practical authoring key therefore needs both scopes. The existing agents:list and agents:run scopes remain separate and apply only to discovering and running retained published versions.

Access model

An OAuth connection acts as the user who approved it; an API key acts as the user who created it. Erstan evaluates that person’s live workspace, team, and agent permissions on every tool call:
  • get_agent can read only an agent the connection owner can normally see.
  • create_agent must target an accessible team in the connection owner’s workspace.
  • update_agent, validate_agent, and publish_agent require the connection owner’s normal edit permission for the target agent. Publishing also re-checks visibility of its current home team when one is assigned.
There is no separate agent allowlist. If the connection owner loses team membership or agent access, the connection loses it immediately. Disabled agents remain authorable when the connection owner still has normal workspace and team permission. Disabling prevents execution; it does not discard the draft. Archived agents cannot be updated or validated over MCP.

Tools

tools/list advertises a tool only when the OAuth grant holds the corresponding connected-app permission or an advanced API key holds every scope shown below. The plugin’s Build profile supplies the standard authoring permissions.
MCP get_agent reads authoring state, including drafts. list_agents under agents:list is intentionally different: it lists only retained published versions that can be run externally.

Argument and response summary

  • get_agent_node_catalog accepts optional nodeType, builderSection, and includeFieldDetails filters. Set includeActionTypes to true to include valid action types and optionally set maxActionTypes from 10 to 500 (default 120). Its versioned, builder-visible response is the source of truth; hidden/internal nodes, event triggers, raw HTTP categories, and unsafe action names are filtered out.
  • get_agent_builder_guide takes no arguments and returns versioned builder guidance, including the external tool-policy and baseline-tool rules below.
  • get_agent takes agentId and an optional positive integer version. It returns { "agent": { ... }, "builderUrl": "..." }; agent.revision is the current opaque write token. An explicit historical version also adds top-level selectedVersion, while agent.currentVersion still identifies the actual current graph version.
  • create_agent requires teamId, name, nodes, and edges. Optional metadata includes description, category, tags, difficulty, estimatedTime, and behaviorType (interactive or pipeline). The new agent is shared with the selected team, and its response includes the first opaque revision.
  • update_agent requires agentId, the latest opaque revision, and at least one metadata or graph change. version is an optional additional guard against editing a different current graph version. It does not move an agent to another team. Never decode, synthesize, or reuse an old revision.
  • validate_agent can validate a saved draft by agentId, or validate proposed name, behaviorType, nodes, and edges before creation. Optional proposed fields overlay the saved graph when agentId is present. Its response includes agentId, version, valid, and structured diagnostics with severity, code, message, and relevant graph paths or IDs.
  • publish_agent requires agentId and the latest opaque revision; pass currentVersion as optional version for a second guard. It returns the published authoring state plus published: true and alreadyPublished. A current already-published version is a validated no-op. If a response is lost, call get_agent: matching status: "published", currentVersion, and publishedVersion confirms success; otherwise do not retry with the stale pre-publish revision.
  • A canonical Skill package is { "version": 1, "entryPath": "SKILL.md", "files": [...], "actions": [...] }. Every action points to an included file and declares runtime: "e2b", language, and sideEffects (none or external).
  • validate_agent_skill and create_agent_skill accept the complete object as either package or packageJson. Create also requires a display name and always returns a draft.
  • get_agent_skill returns the complete package as skill.packageJson. Send that complete package to update_agent_skill with the latest skill.currentVersion as expectedVersion; do not send only changed files.
  • publish_agent_skill accepts skillId and the latest expectedVersion. A stale version returns skill_version_conflict; re-read and reconcile instead of overwriting newer work.
  1. Call get_agent_builder_guide once at the start of the build.
  2. Call get_agent_node_catalog and choose only node types and fields present in the returned live catalog.
  3. Construct the complete directed graph and call create_agent with the target teamId.
  4. Keep the returned agent ID, opaque revision, currentVersion, and builderUrl.
  5. Call validate_agent. The backend requires the complete proposed definition to pass validation. If an existing agent has unrelated pre-existing errors, stop before writing and ask whether the user wants to expand the change to repair them.
  6. Use get_agent to re-read the persisted draft. For every update, pass its latest opaque revision; optionally pass currentVersion as version for an additional graph-version guard. Replace the stored revision with the new value returned by each successful update.
  7. Use test_agent with the current draft version when an execution test is authorized, then inspect the returned run. After the user explicitly asks to make the validated draft live, call publish_agent with the latest revision and optional current version.

Manage a Skill package

Use the same authorized connection for reusable Skill packages:
  1. Build the complete package, including SKILL.md, every referenced text file or script, and action metadata.
  2. Call validate_agent_skill and resolve every error. Validation does not save or run the package.
  3. Call create_agent_skill; it always creates a draft. Review the returned skill.packageJson.
  4. For later changes, call get_agent_skill, apply the intended edit to the complete package, and call update_agent_skill with its latest currentVersion as expectedVersion. Omit status to preserve it. A published Skill has no separate retained draft pointer, so an update to one changes its live package.
  5. Publish only when explicitly requested by calling publish_agent_skill with the newly returned currentVersion.
ZIP import/export preserves action metadata in .erstan/skill-package.json; older SKILL.md-only archives remain valid. The manifest is transport metadata and is not included in packageJson.files.

Agent Builder skill

The official plugin installs and versions this Skill automatically. The reference below is for advanced MCP clients that cannot install the plugin; Claude and Codex plugin users should not paste a separate copy into their projects. It teaches other clients how to use the backend-enforced authoring workflow without treating prompt instructions as the security boundary.

Create a draft

The exact argument schema is available through MCP tools/list. A create call includes the target team, agent metadata, and the complete node-and-edge graph:
Creation always returns a draft. Save its returned revision for the next update. currentVersion may be passed as the optional version guard on update or validation, but it does not replace the required revision token for updates. A decoded create response has this stable shape:

Update and validate

For an agent that has never been published, update_agent accepts editable metadata patches and optional complete replacement nodes and edges. Always pass the most recently returned revision; version is optional:
Then validate the persisted draft:
A successful tool call can still report "valid": false; inspect diagnostics for graph or configuration errors. Validation never publishes and does not make the draft externally runnable.

Publish a validated draft

Publishing re-runs the external-authoring validation and the normal workflow publish checks before changing lifecycle state:
The revision must still match when the publish transaction claims the workflow row. A concurrent update returns agent_revision_conflict and publishes nothing. Re-read, reconcile the user’s intent, validate again, and ask before publishing a changed graph. Repeating publish_agent with the current revision after the version is already live returns alreadyPublished: true without creating another version.

External-authoring boundaries

The catalog and validation contract deliberately expose only builder-visible nodes and tools.

Triggers

Externally authored start nodes may use input_form, chat, schedule, or webhook. triggerType: "event" is not externally authorable at all. In particular, email.received remains app-only. To receive a webhook, use triggerType: "webhook" rather than an event trigger.

AI nodes and tool selection

Every externally authored AI/tool-capable node must explicitly set canonical top-level data.toolPolicy to a value advertised for that node by get_agent_node_catalog. AI Respond, AI Think, and AI Plan & Execute support auto_discover, pinned_only, and none. Other internal model and fixed-action AI nodes advertise only pinned_only and none. The saved top-level field is authoritative. Legacy or nested selection aliases such as input.toolPolicy, toolMode, toolsMode, autoSelectTools, and autoToolDomainSelection are rejected for external authoring; runtime and nested inputs can only narrow a saved policy and never promote it. Use none when the model needs no tools; none exposes zero model tools in every run: no platform baseline, pinned, provider, discovered, workflow-edge, Task/artifact, or executable-skill tools. Attached Skill metadata may remain in context, but full Skill instructions never do. AI Respond retains its existing conversational pinned baseline under pinned_only. AI Think and AI Plan & Execute are stricter: outside an authorized assigned-Task run, pinned_only gives them canonical persisted agentTools or Plan & Execute selectedActions pins plus skill_execute for saved executable skillIds, plus the always-on Platform Internal Runtime tier (run plan ledger write_todos, bounded tool-result reads, isolated Workbench). A legacy saved Think or Plan node with no top-level policy is runtime-clamped to that same bounded surface, while new external definitions cannot omit the field. Across all capability profiles, any authorized assigned-Task run whose effective policy is not none may additionally restore only its Task/artifact model tools so it can service the bound task; this never grants Tool Hub discovery/meta tools or default Skill discovery. Use auto_discover only for exploratory or low-risk general assistance. For AI Think and AI Plan & Execute, only an explicitly saved canonical top-level data.toolPolicy: "auto_discover" enables the expanded platform baseline, Tool Hub, and default Skill discovery. Default Skill discovery on those nodes also requires skillPolicy: "auto_discover"; skillPolicy never raises the tool-policy ceiling. Explicit pins remain available, and every discovered write retains the workspace execution policy. Pin any tool the workflow must have and retain its individual governance settings. auto_discover controls discovery only; it never changes an explicit per-tool writePolicy. Only a server-owned platformMinimumWritePolicy may make the effective execution policy stricter. Use pinned_only for deterministic, production, ERP/accounting, NetSuite, or write-capable work. Attached skillIds are metadata-only candidates under both active Skill policies. With skillPolicy: "auto_discover", skill_search, skill_describe, and skill_read_file can access the full readable Skill catalog. With skillPolicy: "pinned_only", those Skill tools are restricted to the attached set. Full instructions load on demand through skill_describe; attaching a Skill never eagerly injects its full instructions. skillPolicy: "none" continues to disable Skill tools and discovery. selectedActions remain explicit Plan & Execute pins. They can coexist with additional agentTools and with toolPolicy: "auto_discover"; selecting or removing an action does not replace an explicit node policy. Each selected action may carry its own writePolicy (allow, require_approval, or deny) in-app. External authors should omit that field to inherit the catalog default or use an accepted stricter override. Conversational Agent nodes declare pins in agentTools. Do not combine toolPolicy: "auto_discover" with a non-empty selectedActions array on AI Respond: selectedActions is legacy pinned-only state there, so the external API rejects that contradictory shape instead of letting persistence silently change the policy. Use selectedActions only on node types whose live catalog advertises it, such as Action or AI Plan & Execute. With pinned_only or auto_discover, every explicit pinned tool must be visible in the live catalog returned for the connection owner:
  • Every Erstan er_* binding must explicitly set source: "erstan"; Erstan source is never inferred. The name must be catalog-visible. Hidden/internal names, including er_agent_builder_*, are denied even when disguised with function prefixes, aliases, nested selectedActions, or toolKeys.
  • Connector source names, tool names, and explicit connectionId values must all be visible to the connection owner in the current workspace.
  • Within one node, normally pin each canonical runtime tool name once. The only accepted duplicate is one agentTools occurrence mirrored by one legacy selectedActions occurrence with the same trimmed/lowercased exact raw identity, the same explicit normalized source, and no conflicting connectionId (identical when both are set). Function prefixes are not ignored for compatibility: functions.foo and foo are different raw aliases. Duplicates within either array, different raw aliases that canonicalize to one runtime name, conflicting connections, and different sources are rejected. Source conflicts use pinned_tool_runtime_name_source_conflict; all other incompatible duplicates use pinned_tool_runtime_name_duplicate_conflict.
  • The runtime-owned Tool Hub and skill meta names tool_search, catalog_search, tool_describe, tool_invoke, tool_batch_invoke, skill_search, skill_describe, skill_read_file, and skill_execute cannot be externally pinned under any connector source. Validation returns pinned_tool_runtime_name_reserved before consulting the connector catalog.
  • providerTools is unavailable for external authoring at both node and nested-input level. Use validated agentTools bindings on conversational Agents, or selectedActions only on node types whose live catalog advertises that field.
  • Both actionCategory: "http" and the integration alias webhook_outbound are raw HTTP actions and are denied.
  • If supplied, a pinned tool’s writePolicy may be require_approval or deny. External authoring cannot introduce writePolicy: "allow", automatic-write flags, or autoApproveWrites. An update or publish may preserve an identical existing allow binding configured in Erstan, but cannot add, move, or duplicate one.
Call get_agent_node_catalog with includeActionTypes: true when selecting an action node. Do not invent an actionType that is absent from its bounded response.

Canonical graph fields

node.type and data.nodeType must resolve to the same canonical node type. For direct action nodes, actionType is authoritative: a legacy selectedTool value cannot override it or name a hidden tool. Hidden node types, deprecated group containers, unknown action types, and invalid graph shapes are also rejected. Aliases returned by the node catalog may be accepted as input, but they are canonicalized before persistence. Subsequent get_agent responses return the canonical node.type and matching canonical data.nodeType when that field is present.

Child agent references

An ai-agent node uses targetWorkflowId to invoke another saved agent. The referenced child must be currently readable by the connection owner and belong to the same workspace as the parent. Self-reference is denied. For a public or automated parent run, Erstan executes the retained published child snapshot. A newer child draft is not exposed to that run, and a child with no published version cannot be invoked from that surface. Test child changes as appropriate, then publish the validated revision in the app or with publish_agent before relying on it from an external or automated parent.

Resource limits

Limits are checked before persistence or connector-catalog loading: validate_agent returns at most 200 normal diagnostics plus a final diagnostics_truncated marker when more problems exist.

Published agents and drafts

Updating a live agent does not replace its public version. Erstan preserves the last published snapshot for normal agents:list and agents:run calls while the newer draft is edited. Draft nodes and prompts are not exposed to public runs until the exact validated revision is published in the app or through publish_agent. After an agent has ever been published, its MCP metadata is immutable: name, description, category, tags, difficulty, estimatedTime, and behaviorType cannot be changed externally. update_agent accepts graph-only nodes and/or edges changes, atomically forks a draft when necessary, and returns a fresh revision. Make metadata changes in the Erstan app; validate and publish graph drafts with the guarded MCP flow above. Stale or malformed revisions fail with validation_failed and an agent_revision_conflict or agent_revision_invalid message. Re-read with get_agent instead of retrying with the stale token. Published metadata changes fail with agent_published_metadata_immutable. Inaccessible or cross-workspace teams and agents return not_found without revealing whether the target exists.

Next steps

Connect an MCP client

Install the plugin and authorize Build access.

Agent Builder

Review and edit the generated graph in Erstan.

Preview, publish & versions

Test and publish the draft when it is ready.

API keys

Scope and permission details.