Tool reference
HTTP and stdio transports expose the same tool surface.
Identity & discovery
These three answer the bootstrap question: who am I, where am I, and what scopes do I have? Call them at the start of every session.
whoami
Verify auth and get bootstrap context. No inputs.
Returns:
| field | example | notes |
|---|---|---|
valid |
true |
False = key bad/expired |
keyType |
"workspace" / "user" |
iri_ws_* keys vs iri_* per-user keys |
username |
"angie" |
Owner's username |
displayName |
"Angie" or "Sports Warehouse (workspace)" |
UI-friendly label |
workspace |
{id, slug, name} |
The workspace this session is scoped to (default for user keys) |
agentId |
"sports-bot" or null |
Set when the key was provisioned with an agent identity |
sphereCount |
3 |
How many spheres the caller can see — call list_spheres to enumerate |
list_workspaces
List workspaces the caller belongs to. No inputs.
- Workspace-bound key (
iri_ws_*): returns only the bound workspace — workspace keys do not leak the creator's other memberships. - Personal user key (
iri_*) or session: returns every workspace the user is a member of.
list_spheres
List spheres (sub-team / project memory areas) the caller can access. No inputs.
- Workspace-bound key (
iri_ws_*): returns only spheres in the bound workspace. - Personal user key (
iri_*) or session: returns every sphere the user is a member of.
Each entry: {slug, name, description, visibility, role, memberCount}. Use slug for sphere_slug arguments on create_note, create_document, get_briefing, list_tasks, create_task, etc.
Workspace lifecycle
Top-level tenant management. See docs/concepts/workspaces.md for the full model.
create_workspace
Create a brand-new workspace. The caller becomes admin in the same transaction.
| arg | type | notes |
|---|---|---|
name |
string | Display name. |
slug |
string | Globally unique. Lowercase [a-z0-9-]. |
Returns the created workspace row ({id, slug, name, ownerId, plan, settings, createdAt}). 409 on slug collision.
delete_workspace
Destructive. Hard-delete a workspace. Multiple guards stack:
| arg | type | notes |
|---|---|---|
slug |
string | Slug of the target workspace. |
confirm_slug |
string | Must equal slug exactly. The MCP tool refuses before any API call when these differ; the server also re-checks against the resolved workspace's slug as defense in depth. |
Server-side preconditions (in addition to slug confirmation):
- Caller must be a workspace admin.
- Workspace must be empty — every owned table (
notes,atoms,documents,conversion_jobs, …) is FK'dON DELETE RESTRICT. Postgres rejects → 409Notepad is not empty. - Caller must belong to ≥ 1 other workspace. You cannot strand yourself → 409
Cannot delete your last notepad.
This op is irreversible at the application layer. Recovery requires a Neon point-in-time backup.
# Refusal — confirm_slug doesn't match
delete_workspace { slug: "iri-notes", confirm_slug: "iri_notes" }
→ ERROR: confirm_slug must equal slug exactly.
# Accepted — slug + confirmation align, server re-validates
delete_workspace { slug: "iri-notes", confirm_slug: "iri-notes" }
→ Deleted workspace "iri Notes" (iri-notes).
Sphere lifecycle
Sub-team / project space management inside a workspace. See docs/concepts/spheres.md for the full model.
create_sphere
Create a sphere in the workspace bound to this key. Caller becomes owner.
| arg | type | notes |
|---|---|---|
name |
string | Display name. |
slug |
string | 3–40 chars, [a-z0-9_-]. Globally unique. Reserved names (admin, dashboard, etc.) rejected. |
description |
string? | Optional. |
visibility |
"private" | "public" |
Default "private". Public spheres are readable by non-members; writes still need a sphere role. |
Returns the created sphere row. 409 on slug collision; 400 on bad slug or reserved name.
delete_sphere
Destructive — CASCADE. Hard-delete a sphere. Unlike workspace deletion, there is no "must be empty" guard. The delete cascades through every child table:
notes(every note in the sphere)folders+folder_memory_history(the whole folder tree, every memory.md, every revision)tasks(the sphere's task board)sphere_members,sphere_invitationsactivity,commentsapi_key_spheres
| arg | type | notes |
|---|---|---|
slug |
string | Slug of the target sphere. |
confirm_slug |
string | Must equal slug exactly. The MCP tool refuses before any API call when these differ; the server also re-checks against the resolved sphere's slug as defense in depth. |
Caller must be the sphere owner (canDeleteSphere). The same ?confirm=<slug> gate applies to direct REST/dashboard calls — SphereSettings.tsx sends it on the dashboard delete button.
delete_sphere { slug: "research-wiki", confirm_slug: "research_wiki" }
→ ERROR: confirm_slug must equal slug exactly.
delete_sphere { slug: "research-wiki", confirm_slug: "research-wiki" }
→ Deleted sphere "Research Wiki" (research-wiki). All child notes, folders, tasks, and members were cascaded.
Notes CRUD
list_notes
List notes in the workspace.
| arg | type | notes |
|---|---|---|
folder |
string? | Exact match |
tag |
string? | Exact match |
vault |
string? | Obsidian / Apple Notes / Notion / etc. |
sort |
"recent" | "updated" | "published" |
Default published (published_at desc). Use recent for "what was just touched". |
limit |
number | Default 200, hard cap 500 |
Use this when you want the most-recent / most-relevant-by-time notes. For semantic relevance to a topic, use search_notes instead.
read_note
Return the full note body + frontmatter for a slug. Soft-deleted notes return isError: true.
list_sphere_notes
List published notes inside a sphere by slug or UUID. Use this when you specifically want a sphere's shared project/team notes; list_notes returns workspace-level notes.
search_notes
Semantic hybrid search (Postgres FTS + vector). Returns ranked notes with the best matching chunk heading/snippet when available. query required.
create_note
Create a lightweight note. Server slugifies from title.
| arg | required |
|---|---|
title |
✓ |
body |
✓ |
tags, folder, draft |
optional |
sphere_slug / sphere_id |
optional — drop into a specific sphere |
update_note
Partial update — missing fields are preserved. folder: null clears the folder.
delete_note
Soft-delete by slug. Reversible via the web dashboard.
move_note
Move a note to a different sphere and/or folder. Note keeps its slug and id; sphere_id, workspace_id, and folder are rewritten in place along with chunks, atoms, evidence, and attachments. Caller needs writer access on both source and target spheres.
| Field | Required | Notes |
|---|---|---|
slug |
✓ | Note slug to move |
sphere_id |
✓ | Target sphere — accepts UUID or slug |
folder_id |
optional | Target folder UUID; null/omit = sphere root |
Agent write-back
create_document
The proper agent path — stricter, versioned, flows into the Layer 2 extraction pipeline. Same (agent, task) pair produces a new version instead of a duplicate.
{
title: string,
body: string, // Markdown; use [[slug]] to cite other notes
frontmatter: {
type: string, // "research" | "analysis" | "review" | "summary" | ...
agent: string, // Your agent's identifier (free-form, consistent)
task: string, // Same agent + same task = new version
inputs?: string[], // Source slugs this doc is built on
status?: 'draft' | 'complete' | 'needs_review',
next_steps?: string[],
citations?: string[],
},
tags?: string[],
folder?: string,
sphere_slug?: string, // Project/team sphere to write into
sphere_id?: string,
}
Knowledge graph
get_briefing
The headline tool. Given a topic, returns a curated briefing (not raw search hits).
| arg | notes |
|---|---|
query |
required |
depth |
quick (default) / deep |
format |
structured JSON (default) / narrative prose via Haiku (~$0.001) |
sphere_slug / sphere_id |
optional project/team scope |
query_atoms
Query the atoms layer directly. Filter by entity, type, relationship, limit.
get_contradictions
List open or resolved contradictions.
explore_entity
Deep-dive on a single entity — atoms, contradictions, related entities, metadata.
Task board
create_task
Post a task for humans or agents to claim. Use sphere_slug or sphere_id to target a project/team sphere. Most tasks should be left unassigned.
list_tasks
List open tasks. Filters: sphere_slug, sphere_id, status, needs, claimed_by, assigned_to, involving (= "my inbox"), limit.
update_task
Update without claiming. PM/triage path: change priority, due date, assignee, source docs, next steps.
claim_task
Atomically claim a pending task. Race-safe at the DB level; only one claimer wins.
start_task
Move a task you claimed into in_progress.
complete_task
Mark a claimed task done. Pass resolution (1-3 sentences, replays as the closing comment in Linear/GitHub) and optional result_note_id linking to the doc you produced.
assign_task
Set or clear a soft assignee. Does not lock claim — anyone can still claim.
release_task
Release a claimed task back to pending so someone else can pick it up.
cancel_task
Cancel a task that is no longer needed. Anyone with workspace access can cancel.
Folder memory
get_folder_memory
Read the agent-facing memory attached to a folder. Returns the markdown blob plus metadata so an agent can reorient itself before working in that folder.
update_folder_memory
Replace or patch the folder's agent memory. Use to record durable facts about the folder's purpose, conventions, or gotchas — separate from individual notes.
Quick end-to-end
Curl against the hosted HTTP endpoint:
KEY=iri_ws_…
URL=https://notes.iri-ai.com/api/mcp
# whoami — bootstrap
curl -s -X POST "$URL" \
-H "content-type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "x-write-key: $KEY" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"whoami","arguments":{}}}'
# list spheres
curl -s -X POST "$URL" \
-H "content-type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "x-write-key: $KEY" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"list_spheres","arguments":{}}}'
# most recently touched notes
curl -s -X POST "$URL" \
-H "content-type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "x-write-key: $KEY" \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"list_notes","arguments":{"sort":"recent","limit":20}}}'
# semantic search
curl -s -X POST "$URL" \
-H "content-type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "x-write-key: $KEY" \
-d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"search_notes","arguments":{"query":"warehouse capacity"}}}'
Responses come back as SSE frames (event: message + data: { … }). Drop-in MCP clients parse these automatically.