Appearance
Agent Management Tools โ
All tools use gnosari_id (not agent_id) as the identifier parameter. They call core services directly โ no HTTP proxy to the Gnosari API.
Errors propagate as MCP-level isError: true responses, not as success: false dicts.
gnosari_create โ
Create a new private agent with sensible defaults.
Annotations: readOnlyHint: false ยท destructiveHint: false ยท idempotentHint: false ยท openWorldHint: false
Parameters โ
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name shown in chat and dashboard |
instructions | string | Yes | System prompt defining the agent's behavior and goals |
description | string | No | Agent purpose description for the dashboard |
Returns โ
AgentSummaryWithHints:
| Field | Type | Description |
|---|---|---|
agent | AgentSummaryRead | Summary with gnosari_id, name, access_level, model |
hints | list[str] | Maximum hints โ bare agent needs full configuration |
Example โ
python
result = gnosari_create(
name="Product Support Bot",
instructions="You help customers with product questions and troubleshooting."
)
gnosari_id = result.agent.gnosari_id
print(result.hints)
# ["Set instructions with gnosari_manage_instructions...",
# "Make public with gnosari_manage_access...",
# "Add knowledge with gnosari_manage_knowledge...", ...]gnosari_get โ
Get a complete overview of an agent's configuration.
Annotations: readOnlyHint: true ยท destructiveHint: false ยท idempotentHint: true ยท openWorldHint: false
Parameters โ
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
gnosari_id | integer | Yes | - | ID of the agent to retrieve |
include_instructions | boolean | No | false | Include full instructions text (default false to reduce token cost) |
Returns โ
GnosariOverview โ organized into logical sections:
| Section | Fields |
|---|---|
| Identity | gnosari_id, name, description, model, temperature, reasoning_effort |
| Instructions | instructions_length, instructions_preview, instructions_version, instructions (if requested) |
| Access | access_level, uri, domain_name, domain_id, public_url |
| Appearance | greeting, empty_state_title, empty_state_description, suggested_prompts, theme_id, image_url |
| Knowledge | sources (list of KnowledgeSourceSummaryRead) |
| Traits | traits (list of TraitSummaryRead) |
| Data Collection | templates (list of _DataCollectionItem with id, name, collection_mode) |
| Collection Summary | collection (CollectionSummaryOut | null) โ record_count, new_count, last_capture for this agent (null if no records collected) |
| Hints | hints (empty when fully configured) |
Example โ
python
overview = gnosari_get(gnosari_id=123)
print(f"Agent: {overview.name}")
print(f"Access: {overview.access_level}")
print(f"Public URL: {overview.public_url}")
print(f"Knowledge sources: {len(overview.sources)}")
print(f"Instructions preview: {overview.instructions_preview}")
# Get full instructions
overview_full = gnosari_get(gnosari_id=123, include_instructions=True)
print(overview_full.instructions)gnosari_update โ
Update an agent's identity and model settings. Only modifies provided fields.
For instructions, access, appearance, knowledge, traits, and data collection โ use the dedicated tools.
Annotations: readOnlyHint: false ยท destructiveHint: false ยท idempotentHint: false ยท openWorldHint: false
Parameters โ
| Name | Type | Required | Description |
|---|---|---|---|
gnosari_id | integer | Yes | ID of the agent to update |
name | string | No | New display name |
description | string | No | New purpose description |
model | string | No | LLM model (e.g. gpt-5.4-mini, gpt-5.4, claude-sonnet-4); omitted โ the deployment's GNOSARI_DEFAULT_MODEL |
temperature | float | No | Creativity 0.0โ2.0 |
reasoning_effort | string | No | Depth: low, medium, high (Claude models only) |
clear_fields | list of string | No | Fields to reset to NULL โ interactive_buttons_behavior (reverts to the canonical default) or instructions (empties the system prompt; this is the only instructions write that lives here โ everything else goes through gnosari_manage_instructions). Passing a field here and as a value param in the same call is rejected |
At least one field must be provided. If none are provided, raises ValueError.
Returns โ
AgentSummaryWithHints with hints reflecting current configuration state.
Example โ
python
# Change model and temperature
result = gnosari_update(
gnosari_id=123,
model="gpt-5",
temperature=0.5
)
print(result.agent.model) # "gpt-5"gnosari_delete โ
Delete an agent and all its associated data. Two-phase: preview first, confirm second.
Annotations: readOnlyHint: false ยท destructiveHint: true ยท idempotentHint: true ยท openWorldHint: false
Parameters โ
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
gnosari_id | integer | Yes | - | ID of the agent to delete |
confirmed | boolean | No | false | Must be true to delete. When false, returns warning details |
Returns โ
confirmed=falseโDeleteConfirmationResponse: includes agent name, access level, warning message, and instruction for confirmingconfirmed=trueโDeletedResponse:{"gnosari_id": 123, "message": "Agent 123 permanently deleted."}
Example โ
python
# Phase 1: Preview
preview = gnosari_delete(gnosari_id=123)
print(preview.warning)
# "Deleting 'Support Bot' will permanently remove the agent,
# its joina.chat link, collected data, knowledge, traits, and config."
# Phase 2: Confirm (after user approval)
result = gnosari_delete(gnosari_id=123, confirmed=True)
print(result.message) # "Agent 123 permanently deleted."gnosari_manage_instructions โ
Update an agent's system instructions โ anchored partial edits, or a whole-text replace, append or prepend.
Annotations: readOnlyHint: false ยท destructiveHint: false ยท idempotentHint: false ยท openWorldHint: false
Parameters โ
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
gnosari_id | integer | Yes | - | ID of the agent to update |
action | string | Yes | - | edit, replace, append, or prepend |
content | string | No | null | Whole-text payload for replace, append, prepend. Required for those three; never combine with edits |
edits | list[TextEdit] | No | null | Anchored partial edits. Required for action="edit", rejected on the other actions. Maximum 20 per call |
expected_version | string | No | null | The instructions_version from your last read (or from the previous write's response). If the stored text changed underneath you, the call is refused with CONFLICT and nothing is written |
confirm_replace | boolean | No | false | Deliberate-overwrite flag. Required when action="replace" would discard more than 2000 stored characters; ignored on every other action |
| Action | Effect |
|---|---|
edit | Applies the anchored edits in order, all-or-nothing. Everything outside the anchors stays byte-identical. Prefer this for any change to existing text |
replace | Overwrites all current instructions |
append | Adds content to the end of existing instructions |
prepend | Adds content to the beginning of existing instructions |
TextEdit โ
Each entry in edits:
| Field | Type | Required | Description |
|---|---|---|---|
op | string | Yes | replace, insert_before, insert_after, delete, append, or prepend |
old | string | For replace, insert_before, insert_after, delete | Exact anchor substring, matched byte-for-byte and whitespace-significant. Must occur exactly once unless replace_all=True; widen it with surrounding lines if it is ambiguous |
new | string | For replace, insert_before, insert_after, append, prepend | The text to write. No newline is ever added implicitly โ write it yourself |
replace_all | boolean | No (default false) | Apply to every occurrence instead of requiring uniqueness. Valid for replace and delete only |
Returns โ
InstructionsResult:
| Field | Type | Description |
|---|---|---|
gnosari_id | int | Agent ID |
instructions_length | int | Character count after operation |
preview | str | First 200 characters |
action_performed | str | What was done: replace, append, prepend, or edit |
instructions_version | str | Content hash of the instructions after this write (16 lowercase hex), read back from storage. Pass it as the next call's expected_version |
applied | list[AppliedEdit] | One entry per anchored edit, in submitted order โ index, op, excerpt |
readiness | Readiness | Configuration completeness: machine-readable missing keys and prioritized next steps |
applied is populated for edit (one entry per edit) and for a non-empty append/prepend (one entry). It is empty for replace, which is not an anchored operation, and for an append/prepend with empty content, which is a silent no-op.
excerpt comes from the edit engine, not from this tool: it is the text around the change in the post-edit document. On a short instruction set that window can cover the whole document, so do not assume the excerpt is a small localized snippet.
Example โ
Read the version, edit one anchored span, verify from the response โ no second read:
python
overview = gnosari_get(gnosari_id=123, include_instructions=True)
print(overview.instructions_version) # "db42c544020661e8"
result = gnosari_manage_instructions(
gnosari_id=123,
action="edit",
edits=[
{
"op": "replace",
"old": "Always answer in English.",
"new": "Always answer in the language the visitor used.",
},
{
"op": "insert_after",
"old": "## Escalation",
"new": "\nHand off to a human after two failed attempts.",
},
],
expected_version=overview.instructions_version,
)
print(result.action_performed) # "edit"
print(result.instructions_version) # "c99c55daf9809044" โ use this next time
for entry in result.applied:
print(entry.index, entry.op, entry.excerpt)Whole-text actions still work unchanged:
python
# Write a brand new instruction set
gnosari_manage_instructions(
gnosari_id=123,
action="replace",
content="You are a helpful customer support agent for Acme Corp...",
)
# Add a rule at the end
gnosari_manage_instructions(
gnosari_id=123,
action="append",
content="\n\nAlways end responses with: 'Is there anything else I can help you with?'",
)Refusals โ
Refusals raise (isError: true) and write nothing. The message carries the code, the failing edit index when there is one, and every detail key:
CONFLICT: the text changed since it was read; re-read it and retry
current_version: c99c55daf9809044
current_length: 207| Code | Cause | Fix |
|---|---|---|
VALIDATION_ERROR | content and edits combined; edits missing or empty on action="edit"; content missing; an edit whose old equals its new; more than 20 edits; empty content on action="replace"; an over-threshold replace without confirm_replace | Follow the redirect in the message โ every problem found is named in one refusal |
ANCHOR_NOT_FOUND | old does not occur in the stored text | Re-read the instructions and copy the anchor exactly, whitespace included |
ANCHOR_AMBIGUOUS | old matched more than once and replace_all=False | Widen old with surrounding lines (the message lists match_count and one excerpt per match), or set replace_all=True |
CONFLICT | expected_version does not match the stored hash | Re-read, re-anchor against the current text, retry with the current_version from the message |
Two refusals are specific to action="replace":
- Over-threshold overwrite. Replacing more than 2000 stored characters โ the text that would be discarded, never the size of the incoming payload โ requires
confirm_replace=True. Preferaction="edit"instead of confirming. - Empty content.
content=""onaction="replace"is refused: it does not clear instructions. To clear them, callgnosari_update(gnosari_id=123, clear_fields=["instructions"]).append/prependwith emptycontentare not refused โ they are a no-op withapplied=[].
gnosari_manage_access โ
Configure an agent's access level and public URL.
Annotations: readOnlyHint: false ยท destructiveHint: false ยท idempotentHint: false ยท openWorldHint: false
Parameters โ
| Name | Type | Required | Description |
|---|---|---|---|
gnosari_id | integer | Yes | ID of the agent to update |
access_level | string | Yes | PUBLIC, PRIVATE, or PASSWORD_PROTECTED |
uri | string | No | URL path for joina.chat/{uri}. Required for PUBLIC/PASSWORD_PROTECTED |
domain | string | No | Domain name to publish on (resolved to domain_id) |
domain_id | integer | No | Domain ID (takes precedence over domain if both provided) |
password | string | No | Password for PASSWORD_PROTECTED access (min 8 chars) |
| Access Level | Who can access |
|---|---|
PUBLIC | Anyone with the joina.chat link |
PASSWORD_PROTECTED | Anyone with the link + password |
PRIVATE | API/embed access only (no public URL) |
Returns โ
AgentSummaryWithHints. The agent.public_url field is populated when access level is PUBLIC or PASSWORD_PROTECTED.
Examples โ
python
# Make agent public
result = gnosari_manage_access(
gnosari_id=123,
access_level="PUBLIC",
uri="support-bot"
)
print(result.agent.public_url) # "https://joina.chat/acme/support-bot"
# Password-protected
gnosari_manage_access(
gnosari_id=123,
access_level="PASSWORD_PROTECTED",
uri="internal-bot",
password="secret2024"
)
# Revert to private
gnosari_manage_access(gnosari_id=123, access_level="PRIVATE")gnosari_manage_appearance โ
Configure an agent's visual appearance and welcome experience. This is the primary surface for theming a chat โ the schema alone is enough to apply a complete visual identity.
Annotations: readOnlyHint: false ยท destructiveHint: false ยท idempotentHint: false ยท openWorldHint: false
At least one field must be provided.
The two config layers โ
Chat appearance resolves from two layers:
| Layer | Where it lives | What it holds | Set via |
|---|---|---|---|
| 1. Agent chat UI (CONTENT) | Agent.configuration.chat_ui | Per-agent greeting, empty-state, suggested prompts. | greeting, empty_state_*, suggested_prompts |
| 2. Chat theme (VISUAL identity) | chat_theme.configuration (canonical v2) | Reusable branding โ color preset + background pattern. Branding is theme-only โ agents never override it per chat. | style_preset |
Visual identity is chosen with ONE curated style_preset (see below). The preset resolves to a color preset + background pattern and is written to the agent's chat theme. Theme writes reuse the agent's existing theme in place (one row) โ repeated calls never create duplicate theme rows.
Parameters โ
| Name | Type | Required | Description |
|---|---|---|---|
gnosari_id | integer | Yes | ID of the agent to update |
greeting | string | No | First message shown when a user opens a new chat (layer 1) |
empty_state_title | string | No | Large title text for the welcome screen (layer 1) |
empty_state_description | string | No | Supporting text below the welcome title (layer 1) |
suggested_prompts | list[SuggestedPromptInput] | No | Clickable prompt buttons (max 8). Replaces all existing (layer 1) |
style_preset | string (enum) | No | ONE curated visual identity โ color preset + background pattern (layer 2). One of the 12 values below |
image_url | string | No | Agent avatar/logo URL (max 500 chars, publicly accessible) |
SuggestedPromptInput format:
python
{"title": "Button label", "prompt": "Full prompt text sent on click"}style_preset โ
A style_preset is a single curated combo that covers BOTH the color palette and the background pattern โ pick one by the agent's purpose/brand. It is a type-locked enum: only the 12 values below are accepted, and there is no raw-hex or font input from this tool. Applying a preset writes (or updates in place) the agent's chat theme and echoes the applied id back in the result.
style_preset | Color | Pattern | Use it for |
|---|---|---|---|
plain | sky | none | No pattern, clean sky accent. Corporate/formal, or let content lead. |
clean-dots | sky | fine-dots | Minimal sky-blue, faint dots. SaaS, B2B, dashboards. |
ocean-waves | ocean | waves | Calm blue, flowing waves. Wellness, travel, spa, relaxed brands. |
forest-topo | forest | topography | Green, contour lines. Outdoors, sustainability, nature, eco. |
blueprint | blue | blueprint | Technical blue grid. Engineering, dev tools, architecture. |
graph-paper | indigo | graph-paper | Indigo grid. Education, finance, data, analytical tone. |
circuit | teal | circuit | Teal circuit lines. Tech, hardware, AI, electronics. |
soft-bubbles | rose | bubbles | Warm rose, soft bubbles. Friendly, lifestyle, community, care. |
sunset-glow | sunset | organic-blobs | Vibrant sunset, organic blobs. Creative, marketing, bold consumer. |
emerald-grid | emerald | subtle-grid | Fresh emerald, subtle grid. Health, growth, productivity. |
confetti | fuchsia | confetti | Energetic fuchsia, confetti. Events, kids, playful/fun brands. |
mono-noise | violet | noise | Editorial violet, subtle grain. Media, publishing, premium/minimal. |
Returns โ
AppearanceResult:
| Field | Type | Description |
|---|---|---|
gnosari_id | int | Agent ID |
greeting | str | Current greeting |
empty_state_title | str | Current title |
empty_state_description | str | Current description |
suggested_prompts_count | int | Number of prompts configured |
chat_theme_id | int | null | Current theme ID (the DB row id; echoed so you can confirm the in-place reuse) |
style_preset | str | null | The style_preset id applied on this call (echoed back), or null if none |
image_url | str | Current avatar URL |
note | str | Advisory note (e.g. greeting hides the welcome screen) |
readiness | Readiness | Configuration completeness with missing keys and next steps |
Examples โ
Welcome content + a curated visual identity:
python
result = gnosari_manage_appearance(
gnosari_id=123,
greeting="Hi! How can I help you today?",
empty_state_title="Acme Support",
empty_state_description="Ask questions about our products and services.",
suggested_prompts=[
{"title": "What's included?", "prompt": "What's included in the Pro plan?"},
{"title": "How do I get started?", "prompt": "Walk me through getting started"}
],
style_preset="clean-dots",
image_url="https://example.com/avatar.png"
)
print(f"Prompts configured: {result.suggested_prompts_count}")
print(f"Style preset applied: {result.style_preset}")Change just the visual identity (reuses the agent's theme row in place):
python
result = gnosari_manage_appearance(
gnosari_id=123,
style_preset="ocean-waves",
)
print(f"Theme assigned: {result.chat_theme_id} โ preset {result.style_preset}")gnosari_health_check โ
Health check for monitoring server status.
Annotations: readOnlyHint: true ยท destructiveHint: false ยท idempotentHint: true ยท openWorldHint: false
No parameters. No authentication required.
Returns โ
python
{
"status": "healthy",
"server": "gnosari-mcp",
"version": "x.x.x",
"api_url": "http://gnosari-api.localhost"
}Example โ
python
health = gnosari_health_check()
print(health["status"]) # "healthy"
print(health["version"]) # "2.1.0"Common Errors โ
| Error | Cause | Solution |
|---|---|---|
AgentNotFoundError | gnosari_id does not exist | Verify ID with gnosari_search |
AgentAccessDeniedError | Agent belongs to a different account | Confirm the ID belongs to your account |
AgentValidationError | URI already taken on the domain | Check with gnosari_check_uri first |
ValueError (no update fields) | Called gnosari_update with no fields | Provide at least one field to update |
ValueError (no appearance fields) | Called gnosari_manage_appearance with no fields | Provide at least one appearance field |
Next Steps โ
- Manage Resource Tools - Traits, knowledge, data collection
- Discovery Tools - Search and URI check
- Agent Creation Flow - Atomic decomposition walkthrough