iri docs

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'd ON DELETE RESTRICT. Postgres rejects → 409 Notepad 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_invitations
  • activity, comments
  • api_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.