Arroway

Arroway orchestrates people and AI agents around the decisions in force.

Should I use this

Quality & Safety

A
Description quality
96%
Schema completeness
99%
Naming quality
80%
Poisoning risk
80%
Permission match
100%
Protocol compliance
100%

Findings (2)

  • HIGHTool poisoning patterns detected
  • MEDIUMTool description contains suspicious base64-like encoded stringin arroway_remember

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~5,411Tokens (tool definitions)
~2.4 KBTypical response size
Significant attention impact (4.23% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "arroway": {
      "url": "https://www.arroway.app/api/mcp"
    }
  }
}

Remote endpoints

https://www.arroway.app/api/mcpstreamable-http

What it can do

Tool inventory

Tools (19)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢arroway_read(project, include, task_context, handoff, since)

Read Arroway for a project BEFORE acting on any task related to it. It serves the authored essence of memories, dated-log entries and handoffs by default; name a #handle in include to recover that object's full body.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug, e.g. 'seven50'",
      "maxLength": 63
    },
    "include": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 8,
        "maxLength": 36
      },
      "description": "#handles whose full body you need; they come first, so others fall out — it chooses, it does not add.",
      "minItems": 1,
      "maxItems": 10,
      "uniqueItems": true
    },
    "task_context": {
      "type": "string",
      "description": "Optional: what you are about to do; it ranks results. The declaration alone is NOT evidence of use: a matching completion residue from the same session must corroborate it.",
      "maxLength": 16384
    },
    "handoff": {
      "type": "string",
      "description": "Optional: #handle of an OPEN handoff you are continuing; the read is built from its reading list (none: falls back to the normal read). Cannot be combined with include."
    },
    "since": {
      "type": "string",
      "description": "Optional: checkpoint from a previous read of THIS project, so standing rules are not reprinted. Omit after compaction or in a new conversation."
    }
  },
  "required": [
    "project"
  ],
  "additionalProperties": false
}
🟢arroway_continue(read_id, receipt)

Fetch the next part of a read that did not fit in one response (read_id and receipt of the preceding part). OPTIONAL: the first part already counts as delivered and names what later parts hold.

Input Schema

{
  "type": "object",
  "properties": {
    "read_id": {
      "type": "string",
      "description": "Opaque id returned by the incomplete arroway_read response."
    },
    "receipt": {
      "type": "string",
      "description": "Opaque receipt returned by the immediately preceding part."
    }
  },
  "required": [
    "read_id",
    "receipt"
  ],
  "additionalProperties": false
}
🟢arroway_complete_read(read_id, receipt)

Acknowledge the final part of a multi-part Arroway read with its read_id and receipt, closing the sequence. It is not a precondition for working.

Input Schema

{
  "type": "object",
  "properties": {
    "read_id": {
      "type": "string",
      "description": "Opaque id returned by the incomplete arroway_read response."
    },
    "receipt": {
      "type": "string",
      "description": "Opaque receipt returned by the final part."
    }
  },
  "required": [
    "read_id",
    "receipt"
  ],
  "additionalProperties": false
}
🟢arroway_catch_up(days)

Call ONCE at the START of a session, before there is a task: what happened recently across all of this person's projects, opening with the roster of their projects (slug and purpose) and open handoffs.

Input Schema

{
  "type": "object",
  "properties": {
    "days": {
      "type": "integer",
      "description": "Days back, counting today. Default 2; more only when picking up work after being away.",
      "minimum": 1,
      "maximum": 30
    }
  },
  "required": [],
  "additionalProperties": false
}
🟢arroway_search_log(query, project)

Find WHERE a literal term or phrase appeared in the recent dated log (essence and body), across every project of this person or one. Returns short excerpts anchored by project, date and entry. It searches what happened, not curated memory.

Input Schema

{
  "type": "object",
  "properties": {
    "query": {
      "type": "string",
      "maxLength": 200,
      "description": "Literal term or phrase; case-insensitive."
    },
    "project": {
      "type": "string",
      "description": "Optional project slug; omit to search them all.",
      "maxLength": 63
    }
  },
  "required": [
    "query"
  ],
  "additionalProperties": false
}
🟢arroway_norms(project, since, draft)

Call in the seconds BEFORE you tell the person something or propose a course of action: returns what is already decided (the project's and this person's own) AND THEN A MAP of the titles and handles of everything else. arroway_read include GUARANTEES a mapped one in full; it does not make that read any cheaper, so use it to be sure, never to pay less. Before publishing text for others, pass it as draft: what it touches comes back in full.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug the claim is about.",
      "maxLength": 63
    },
    "since": {
      "type": "string",
      "description": "Optional: checkpoint from a previous arroway_norms call for THIS project (not the read's). Omit after compaction or in a new conversation."
    },
    "draft": {
      "type": "string",
      "description": "Optional: the text you will publish or say (PR, comment, message, page), ending with one line in the project's language on what it claims, recommends and names.",
      "maxLength": 20000
    }
  },
  "required": [
    "project"
  ],
  "additionalProperties": false
}
🟡arroway_log(project, content, essence, topic, source, ...)

Record the durable residue of a COMPLETED task in the team-visible daily log: what someone arriving later needs in order not to redo it, dated state included. ALWAYS write the authored essence (only a frozen catalog without that field may omit it). If the person corrected you for re-litigating a decision, say so. If this work made a read memory's 'dies when' true, name it in fulfills and it is retired with this entry.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug. Not from the person or a read this session? It is a guess: check the arroway_catch_up roster.",
      "maxLength": 63
    },
    "content": {
      "type": "string",
      "description": "What was decided, found or changed, and what it cost. You judge the length.",
      "maxLength": 65536
    },
    "essence": {
      "type": "string",
      "description": "One authored line with the operative result; never the opening of the body.",
      "maxLength": 280
    },
    "topic": {
      "type": "string",
      "description": "Optional free tag (e.g. 'marketing')",
      "maxLength": 120
    },
    "source": {
      "type": "string",
      "description": "Optional pointer to a living source (URL, doc, CRM id)",
      "maxLength": 2048
    },
    "operational": {
      "type": "boolean",
      "description": "true for HOW the work went (failures, measurements, self-corrections): kept for catch-up, out of task reads."
    },
    "backfilled": {
      "type": "boolean",
      "description": "true for history from BEFORE Arroway existed, not today's work."
    },
    "keep_whole": {
      "type": "boolean",
      "description": "true only after you considered cutting an indivisible oversized residue."
    },
    "fulfills": {
      "type": "array",
      "description": "Memories whose 'dies when' this work made true (decision/fact/reference received in full in a read). Never one that merely looks old.",
      "items": {
        "type": "object",
        "properties": {
          "memory": {
            "type": "string",
            "description": "The #handle from the read, or the full id.",
            "maxLength": 36
          },
          "how": {
            "type": "string",
            "description": "What met the kill condition, in one sentence.",
            "maxLength": 1000
          }
        },
        "required": [
          "memory",
          "how"
        ],
        "additionalProperties": false
      },
      "minItems": 1,
      "maxItems": 20
    }
  },
  "required": [
    "project",
    "content"
  ],
  "additionalProperties": false
}
🟡arroway_remember(project, type, treatment, treatment_justification, title, ...)

Save a durable memory (decision/rule/fact/preference/reference/identity): only what would change what someone does on a DIFFERENT task. Unsanctioned in THIS conversation, it is a PROPOSAL — never present it as a decision. 'identity' is WHO someone is: the user's circle goes in their personal project, a business's people in that business's project. A sourced fact or reference that only informs can be a finding, which cannot replace a sanctioned memory.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug. Not from the person or a read this session? It is a guess: check the arroway_catch_up roster.",
      "maxLength": 63
    },
    "type": {
      "type": "string",
      "enum": [
        "rule",
        "decision",
        "fact",
        "preference",
        "identity",
        "reference"
      ],
      "description": "Kind of memory."
    },
    "treatment": {
      "type": "string",
      "enum": [
        "governed",
        "finding"
      ],
      "description": "`governed` enters the person's review queue, a real cost to them; `finding` costs nobody a review and is never a norm. Does it GOVERN what someone may or must do, or only INFORM? Informs, with a source an agent can reopen and compare: finding (only fact and reference qualify)."
    },
    "treatment_justification": {
      "type": "string",
      "description": "Required for a finding: why it is verifiable context, not policy."
    },
    "title": {
      "type": "string",
      "description": "Short, unique within the project",
      "maxLength": 200
    },
    "content": {
      "type": "string",
      "description": "The norm ITSELF, as if true today, in the shortest form that still governs correctly. Biography (who, when, quotes, dated numbers) goes in why_source; a specific case in example.",
      "maxLength": 65536
    },
    "essence": {
      "type": "string",
      "description": "The operative norm or fact in ONE line.",
      "maxLength": 280
    },
    "why_source": {
      "type": "string",
      "description": "Where it came from: the ONLY place for biography. This does NOT travel in reads; it is shown in the panel.",
      "maxLength": 16384
    },
    "example": {
      "type": "string",
      "description": "A case illustrating the rule, shown in the panel; it NEVER travels in reads, so any criterion goes in content.",
      "maxLength": 16384
    },
    "source_ptr": {
      "type": "string",
      "description": "Pointer to the living source, when verifiable",
      "maxLength": 2048
    },
    "topic": {
      "type": "string",
      "description": "Optional free tag (e.g. 'marketing').",
      "maxLength": 120
    },
    "decided_by_human": {
      "type": "boolean",
      "description": "true ONLY if the person stated or sanctioned it in THIS conversation; else a proposal. A proposal is never free: it costs that person a review. Then only a PINNED memory travels in every read; a normal one competes for space in the block relevant to each task. Never write an instruction to check, verify, be careful or look at the source, a step of a routine, or anything here only because something went wrong once."
    },
    "kill_condition": {
      "type": "string",
      "description": "Mandatory: explicit revocation / named trigger / review date"
    },
    "review_at": {
      "type": "string",
      "description": "YYYY-MM-DD when this stops being true on its own. REQUIRED for a fact, which leaves reads after it.",
      "maxLength": 10,
      "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
      "format": "date"
    },
    "expires": {
      "type": "boolean",
      "description": "true ONLY for a dated STATUS that would be stale after review_at. If unsure, omit."
    },
    "supersedes_id": {
      "type": "string",
      "description": "#handle of the memory this replaces, only for the SAME point: acting on either would already satisfy or violate the other. A shared topic is not enough.",
      "maxLength": 36
    },
    "contradiction": {
      "type": "string",
      "description": "Required with supersedes_id: what this changes in the earlier memory."
    },
    "split_considered": {
      "type": "boolean",
      "description": "true only after looking for seams; splitting is the default."
    },
    "related_checked": {
      "type": "boolean",
      "description": "Second call only: true after reading the related memories shown."
    },
    "related_check_token": {
      "type": "string",
      "description": "Second call only: token returned with the related memories."
    },
    "revoked_reconsideration": {
      "type": "string",
      "description": "Second call only: the person's words in THIS conversation reconsidering a revoked finding."
    },
    "example_considered": {
      "type": "boolean",
      "description": "Second call only: true if the flagged example is criterion the rule needs."
    },
    "pin_suggested": {
      "type": "boolean",
      "description": "Your judgement on pinning (travels in EVERY read). There is no default: required on a rule's second call. Above the ceiling it becomes a proposal of the pin alone."
    },
    "pin_requested_by_human": {
      "type": "boolean",
      "description": "true ONLY if the person told you in THIS conversation to keep it in every session. Sanctioning the CONTENT is not asking for the pin. Pins above any ceiling."
    },
    "pin_decision_token": {
      "type": "string",
      "description": "Second call only: the first call's token, unchanged."
    },
    "backfilled": {
      "type": "boolean",
      "description": "true for sourced HISTORY from before Arroway, on the topic just worked on; never a dump."
    }
  },
  "required": [
    "project",
    "type",
    "title",
    "content",
    "essence",
    "decided_by_human",
    "kill_condition"
  ],
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "properties": {
          "type": {
            "const": "fact"
          }
        },
        "required": [
          "type"
        ]
      },
      "then": {
        "required": [
          "review_at"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "expires": {
            "const": true
          }
        },
        "required": [
          "expires"
        ]
      },
      "then": {
        "required": [
          "review_at"
        ]
      }
    }
  ]
}
🔴arroway_verify(project, memory, outcome, note)

Record what a memory's source says when your work ALREADY took you there — never go verifying memories as a task, never guess an outcome. A FACT proven gone is retired at once; a conflicting one when you propose the correction with arroway_remember supersedes_id. On a FINDING, source_gone archives it and a conflict is corrected in place. Rules and decisions are only marked.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug.",
      "maxLength": 63
    },
    "memory": {
      "type": "string",
      "description": "The #handle from the read, or the full id.",
      "maxLength": 36
    },
    "outcome": {
      "type": "string",
      "enum": [
        "matches",
        "source_gone",
        "conflicts"
      ],
      "description": "source_gone = PROVEN removed (404, file deleted, record gone), never mere unavailability (timeout, login wall, outage). conflicts = the source says something different."
    },
    "note": {
      "type": "string",
      "description": "Required for conflicts (what the source says) and source_gone (what proves removal).",
      "maxLength": 16384
    }
  },
  "required": [
    "project",
    "memory",
    "outcome"
  ],
  "additionalProperties": false,
  "allOf": [
    {
      "if": {
        "properties": {
          "outcome": {
            "const": "conflicts"
          }
        },
        "required": [
          "outcome"
        ]
      },
      "then": {
        "required": [
          "note"
        ]
      }
    },
    {
      "if": {
        "properties": {
          "outcome": {
            "const": "source_gone"
          }
        },
        "required": [
          "outcome"
        ]
      },
      "then": {
        "required": [
          "note"
        ]
      }
    }
  ]
}
⚪arroway_start_project(slug, name, scope, update)

Open a NEW project when the work at hand has no home in Arroway. Propose the name and scope to the person FIRST and call only once they agree. update=true renames a project you own and rewrites its scope, when the person asks or the scope is wrong; the slug stays.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "description": "Short, lowercase, hyphenated, unique — e.g. 'trading-solana'",
      "maxLength": 63
    },
    "name": {
      "type": "string",
      "description": "How people will call it",
      "maxLength": 120
    },
    "scope": {
      "type": "string",
      "description": "What belongs here and what does not: the subject AND what is out.",
      "maxLength": 8192
    },
    "update": {
      "type": "boolean",
      "description": "true: change name and scope of the existing project at slug."
    }
  },
  "required": [
    "slug",
    "name",
    "scope"
  ],
  "additionalProperties": false
}
🟡arroway_withdraw(project, memory, why, other_author_confirmed)

Take back a pending PROPOSAL that turned out to be wrong, usually because the person corrected you. Not for sanctioned memories. It is kept as withdrawn, with your reason. If the corrected version is durable, also write it with arroway_remember.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug.",
      "maxLength": 63
    },
    "memory": {
      "type": "string",
      "description": "#handle of the proposal, from a read",
      "maxLength": 36
    },
    "why": {
      "type": "string",
      "description": "What made it wrong — usually what the person said.",
      "maxLength": 16384
    },
    "other_author_confirmed": {
      "type": "boolean",
      "description": "Second call only, after Arroway said someone else's AI wrote the proposal: true to go ahead."
    }
  },
  "required": [
    "project",
    "memory",
    "why"
  ],
  "additionalProperties": false
}
🔴arroway_retire(project, memory, why, decided_by_human)

Retire a SANCTIONED memory when the person told you in this conversation to remove it and nothing replaces it. Archived, never deleted. With a corrected version, use arroway_remember supersedes_id; for your own pending proposal, arroway_withdraw.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug.",
      "maxLength": 63
    },
    "memory": {
      "type": "string",
      "description": "The memory to retire — the #handle from a read is enough.",
      "maxLength": 36
    },
    "why": {
      "type": "string",
      "description": "Optional: what the person said made it obsolete, in their terms.",
      "maxLength": 16384
    },
    "decided_by_human": {
      "type": "boolean",
      "description": "Must be true, and only when the person explicitly told you to remove it IN THIS CONVERSATION."
    }
  },
  "required": [
    "project",
    "memory",
    "decided_by_human"
  ],
  "additionalProperties": false,
  "allOf": [
    {
      "properties": {
        "decided_by_human": {
          "const": true
        }
      }
    }
  ]
}
🟢arroway_export(project, name, description, topic)

Export OUT of a project what it has DECIDED, as a portable memory pack for another team or project. Only sanctioned, live memories travel: a FINDING never was one, so findings stay and the answer tells you how many did. Nothing about people travels.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Slug of the project whose norms you are exporting",
      "maxLength": 63
    },
    "name": {
      "type": "string",
      "description": "What this pack IS, in a few words: the first thing the other side reads.",
      "maxLength": 120
    },
    "description": {
      "type": "string",
      "description": "Optional: who it is for, what it assumes."
    },
    "topic": {
      "type": "string",
      "description": "Optional: export only the memories carrying this topic.",
      "maxLength": 120
    }
  },
  "required": [
    "project",
    "name"
  ],
  "additionalProperties": false
}
⚪arroway_import(project, pack)

Bring a memory pack made by arroway_export INTO a project. Everything lands as a PROPOSAL for the person's review and nothing is pinned, whatever the pack says. If any part is malformed, nothing is imported.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug. Not from the person or a read this session? It is a guess: check the arroway_catch_up roster.",
      "maxLength": 63
    },
    "pack": {
      "type": "object",
      "description": "The pack document itself; this server does not fetch URLs."
    }
  },
  "required": [
    "project",
    "pack"
  ],
  "additionalProperties": false
}
🟡arroway_move(project, memory, target, why)

Move something to the project it belongs in. A memory is only PROPOSED: the change waits for the person's review, because moving changes who sees it. A log entry you wrote moves at once, text unchanged.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Slug of the project it is in TODAY",
      "maxLength": 63
    },
    "memory": {
      "type": "string",
      "description": "#handle of the memory or log entry, from a read or arroway_search_log",
      "maxLength": 36
    },
    "target": {
      "type": "string",
      "description": "Slug of the project you believe it belongs to",
      "maxLength": 63
    },
    "why": {
      "type": "string",
      "description": "Why it belongs there and not here. For a memory, the person decides on this sentence.",
      "maxLength": 16384
    }
  },
  "required": [
    "project",
    "memory",
    "target",
    "why"
  ],
  "additionalProperties": false
}
🟡arroway_pass(project, where_stopped, next_step, essence, do_not_redo, ...)

Call when you STOP with the task unfinished (out of time, blocked, told to stop): it leaves a HANDOFF served at the top of every read until someone closes it; a completed task ends in arroway_log instead. ALWAYS write the authored essence (only a frozen catalog without that field may omit it). Write what the next session needs to continue, never a dump.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug.",
      "maxLength": 63
    },
    "where_stopped": {
      "type": "string",
      "description": "What is done and verified, what is half-done."
    },
    "next_step": {
      "type": "string",
      "description": "The single concrete next step. Not a plan: the step."
    },
    "essence": {
      "type": "string",
      "description": "One authored line with the operative in-flight state.",
      "maxLength": 280
    },
    "do_not_redo": {
      "type": "string",
      "description": "What must NOT be redone or re-litigated."
    },
    "open_risk": {
      "type": "string",
      "description": "The risk left open."
    },
    "card": {
      "type": "string",
      "description": "Card, issue or PR, when one exists."
    },
    "addressed_to": {
      "type": "string",
      "description": "Optional person or routine it is meant for; never a lock."
    },
    "supersedes": {
      "type": "string",
      "description": "#handle of the OPEN handoff this one replaces, from a read."
    },
    "read_handles": {
      "type": "array",
      "description": "The reading list: #handles of THIS project the next session must read in full, in order. Only what is required.",
      "maxItems": 10,
      "uniqueItems": true,
      "items": {
        "type": "string",
        "minLength": 8,
        "maxLength": 36
      }
    }
  },
  "required": [
    "project",
    "where_stopped",
    "next_step"
  ],
  "additionalProperties": false
}
⚪arroway_claim(project, handoff, note)

Mark that you are taking an open handoff BEFORE working on it, so parallel sessions do not duplicate it. A claim is a mark, never a lock. Addressing rule: addressed to YOUR user — take it; to someone else — only a human in this conversation can decide to take it, and an autonomous session must leave it.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug.",
      "maxLength": 63
    },
    "handoff": {
      "type": "string",
      "description": "The #handle from the read, or the full id."
    },
    "note": {
      "type": "string",
      "description": "Who is taking it — a routine names itself here.",
      "maxLength": 16384
    }
  },
  "required": [
    "project",
    "handoff"
  ],
  "additionalProperties": false
}
⚪arroway_close(project, handoff, note)

Close an open handoff when its work is DONE, alongside the arroway_log entry that records the residue. Work that removes what an open handoff exists to fix closes that handoff in the same pass — even when the handoff is someone else's. So this is also the call for someone ELSE's handoff, with a note naming what emptied it. A handoff that still carries real work, which a passer-by must never close, stays open; discarding a handoff is the human's gesture, in the panel.

Input Schema

{
  "type": "object",
  "properties": {
    "project": {
      "type": "string",
      "description": "Project slug.",
      "maxLength": 63
    },
    "handoff": {
      "type": "string",
      "description": "The #handle from the read, or the full id."
    },
    "note": {
      "type": "string",
      "description": "One line on what landed; it points at the residue.",
      "maxLength": 16384
    }
  },
  "required": [
    "project",
    "handoff"
  ],
  "additionalProperties": false
}
⚪arroway_configure_referrer(domain, source, channel)

Product administrators only: map an external referrer domain to a source and channel in Arroway's acquisition view, when an administrator asks. Stores only the domain and two labels; calling again replaces the mapping.

Input Schema

{
  "type": "object",
  "properties": {
    "domain": {
      "type": "string",
      "description": "External hostname only, such as linkedin.com."
    },
    "source": {
      "type": "string",
      "description": "Short source label, such as linkedin.",
      "maxLength": 2048
    },
    "channel": {
      "type": "string",
      "description": "Short channel label, such as organic-social or directory."
    }
  },
  "required": [
    "domain",
    "source",
    "channel"
  ],
  "additionalProperties": false
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded19 tools
verifiedversion not recorded19 tools
auth requiredversion not recorded—