Skip to content

Project Server ​

The project server (servers/research/) provides structured project management with support for different project types, source tracking, APA citation generation, bibliography output, and data backend registration.

Renamed from Research Server

This server was previously called "crow-research." The server name is now crow-projects, and the factory function is createProjectServer (the old createResearchServer name still works as a backward-compatible alias). The gateway mounts at /projects/mcp (primary) and /research/mcp (legacy alias).

Project Types ​

Projects have a type field that determines their purpose:

TypeDescription
researchTraditional research projects with sources, citations, and bibliography (default)
data_connectorProjects that connect to external data through registered backends

The type is set when creating a project and determines which tools and workflows are relevant.

Tools ​

crow_create_project ​

Create a new project.

ParameterTypeRequiredDescription
namestringYesProject name
descriptionstringNoProject description and goals
tagsstringNoComma-separated tags
typestringNoProject type: research (default) or data_connector

crow_list_projects ​

List all projects with optional status filter.

ParameterTypeRequiredDescription
statusstringNoFilter by status

crow_update_project ​

Update a project's name, description, status, or tags.

ParameterTypeRequiredDescription
idnumberYesProject ID
namestringNoNew name
descriptionstringNoNew description
statusstringNoNew status (active, paused, completed, archived)
tagsstringNoNew tags

crow_add_source ​

Add a source to a project. Automatically generates an APA citation if none is provided. Most commonly used with research type projects.

ParameterTypeRequiredDescription
titlestringYesSource title
source_typestringYesType (see list below)
project_idnumberNoAssociate with a project
urlstringNoURL where the source was found
authorsstringNoAuthor(s) in "Last, F. M." format
publication_datestringNoPublication date (YYYY-MM-DD or YYYY)
publisherstringNoPublisher or website name
doistringNoDOI (for academic papers)
isbnstringNoISBN (for books)
abstractstringNoAbstract or brief description
content_summarystringNoSummary of key points and findings
full_textstringNoFull text content if available
citation_apastringNoManual APA citation (auto-generated if omitted)
retrieval_methodstringNoHow the source was obtained
tagsstringNoComma-separated tags
relevance_scorenumberNoHow relevant to the project, 1-10 (default: 5)

Source types: web_article, academic_paper, book, interview, web_search, web_scrape, api_data, document, video, podcast, social_media, government_doc, dataset, other

Search the web through the Brave Search API (servers/shared/brave-search.js, key BRAVE_API_KEY, 10-second timeout). Nothing is fetched or stored. Each result carries the stamp SNIPPET, not a source: open it with crow_add_source before citing, and results are cut to whole entries so the reply fits the voice result cap. Without an API key the tool says search is not configured and suggests opening a known URL with crow_add_source.

ParameterTypeRequiredDescription
querystringYesSearch query (up to 400 characters)
countnumberNoNumber of results, 1-10 (default: 5)

crow_fetch_source ​

Open a stored source's URL again (needs the write_sources capability on its project). Use it to retry a failed fetch or refresh an old copy. See Fetch before cite.

  • A source with no URL has nothing to fetch.
  • A fetch that fails or finds no readable text keeps an earlier copy that has text, and the source stays citable.
  • An unchanged page (same content hash) only updates fetched_at.
  • A changed page is not stored while quote notes that passed their check rely on the old text, unless the owner passes force: true.
  • When new text is stored, the source's quote notes are re-checked, and a quotes_checked verification is cleared if a quote is no longer on the page.
ParameterTypeRequiredDescription
idnumberYesSource ID
forcebooleanNoOwner only: replace the stored page text even when passing quote checks rely on it

crow_search_sources ​

Search sources using full-text search.

ParameterTypeRequiredDescription
querystringYesSearch query
source_typestringNoFilter by type
project_idnumberNoFilter by project
limitnumberNoMax results

crow_get_source ​

Get full details of a specific source.

ParameterTypeRequiredDescription
idnumberYesSource ID

crow_verify_source ​

Verify a source, or clear its verification. With quotes_checked the source is marked verified only when it has at least one quote note and every quote is found on the page Crow fetched. See Verifying a source.

ParameterTypeRequiredDescription
idnumberYesSource ID
verifiedbooleanNotrue to verify (default), false to clear verification
methodstringNoquotes_checked (default) or manual_owner (the owner only; bots cannot)
notesstringNoVerification notes

crow_list_sources ​

List sources with optional filtering.

ParameterTypeRequiredDescription
project_idnumberNoFilter by project
source_typestringNoFilter by type
verifiedbooleanNoFilter by verification status
limitnumberNoMax results

crow_add_note ​

Add a note, optionally linked to a project or source.

ParameterTypeRequiredDescription
contentstringYesNote content
note_typestringNoType: note, quote, summary, analysis, question, insight (default: note)
provenancestringNoWhere the claim comes from: fetched, snippet or derived. Required for quote and summary notes; analysis and insight notes default to derived. See Note provenance
locatorstringNoWhere in the source (page, section, timestamp)
project_idnumberNoAssociated project
source_idnumberNoAssociated source
titlestringNoNote title
tagsstringNoComma-separated tags

crow_withdraw_note ​

Withdraw a note that is wrong, such as a quote that is not on the page. The note is kept and marked withdrawn (when, by whom, and why); it no longer counts toward verification, quote counts or note counts. It cannot be undone, and it is audited as note.withdraw.

ParameterTypeRequiredDescription
idnumberYesNote ID
reasonstringYesWhy the note is wrong (1 to 500 characters, kept on record)

Who may call it: the owner can withdraw any note. A bot can withdraw only a note it wrote. Peer and unknown callers never can, and a note with no recorded author counts as the owner's. The caller also needs write_notes on the note's project.

The author is recorded by crow_add_note as created_by. For a bot that is the bot id the bot states about itself in its call; Crow accepts it as given, so it keeps well-behaved bots from withdrawing each other's notes but is not a security boundary against a bot that lies. Withdrawing the last live quote note of a source clears a quotes_checked verification. The withdrawal columns stay local to each instance: they are never synced to peers, and inbound notes cannot set them.

crow_search_notes ​

Search notes by content.

ParameterTypeRequiredDescription
querystringYesSearch terms
project_idnumberNoFilter by project
note_typestringNoFilter by type (note, quote, summary, analysis, question, insight)
limitnumberNoMax results (default: 10)

crow_generate_bibliography ​

Generate a formatted APA bibliography for a project or filtered set of sources.

ParameterTypeRequiredDescription
project_idnumberNoGenerate bibliography for this project
tagstringNoFilter by tag
verified_onlybooleanNoOnly include verified sources (default: false)

crow_project_stats ​

Get statistics about projects and the research pipeline. No parameters.

Data Backend Tools ​

These tools manage external data connections for data_connector type projects.

crow_register_backend ​

Register an external MCP server as a data backend.

ParameterTypeRequiredDescription
namestringYesBackend name
server_urlstringYesMCP server URL
descriptionstringNoWhat data this backend provides

crow_list_backends ​

List all registered data backends. No parameters.

crow_remove_backend ​

Remove a registered data backend.

ParameterTypeRequiredDescription
backend_idnumberYesBackend ID

crow_backend_schema ​

Get the schema (available tools) from a registered backend.

ParameterTypeRequiredDescription
backend_idnumberYesBackend ID

Resources ​

research://projects ​

Returns the list of all projects.

APA Citation Generation ​

The server automatically generates APA citations when adding sources. The citation format varies by source type:

  • Academic papers: Author (Year). Title. Publisher. DOI/URL
  • Books: Author (Year). *Title*. Publisher.
  • Web articles: Author (Year). Title. Site Name. URL
  • Other types: Standard APA format with available fields

Fetch before cite ​

Crow opens a source's page itself before the source counts as citable. A bot's claim that it read a page is never taken on trust.

Fetch statuses ​

research_sources.fetch_status is one of:

StatusMeaning
fetchedCrow opened the page and stored its readable text
fetched_no_textCrow opened the page but found no readable text (a PDF, an image, a script-only page)
failedCrow could not open the page; the reason is stored in fetch_error
not_applicableThe source has no URL (a book, an interview), so there is nothing to fetch
legacyThe source predates fetching; shown as "legacy, unchecked"
NULLThe row arrived from a peer, a share or a clone; it was never checked here and is not citable here

A source is citable when its status is fetched, fetched_no_text or legacy, or when it is not_applicable and the owner verified it by hand (manual_owner). Bibliographies cite only citable sources and say how many were left out; include_unfetched lists the rest, marked [NOT FETCHED: ...].

crow_add_source with a URL fetches the page first (through the shared SSRF-guarded fetcher in servers/shared/fetch-page.js) and stores the final URL, HTTP status, a content hash and the page text. crow_fetch_source refreshes a stored copy. A refresh that finds no readable text keeps the earlier copy, and a refresh whose new text would break a passing quote check keeps the old text unless the owner passes force: true.

Note provenance ​

Quote and summary notes state where the claim comes from: fetched (backed by a page Crow opened), snippet (only a search-result snippet, so not citable in prose yet) or derived (the writer's own reasoning). Analysis and insight notes default to derived. A quote note on a fetched source is checked against the page text and records quote_found (1, 0, or NULL when the check could not decide) and a locator. Provenance, quote_found and locator stay local: they are in EXCLUDED_COLUMNS (and dropped from inbound rows) in servers/sharing/instance-sync.js, because each is a judgment about this instance's own copy of the page.

A wrong quote note is withdrawn with crow_withdraw_note rather than edited or deleted. A withdrawn note stays on record but is skipped by verification, by crow_verify_source quote checks and by the Projects panel's note and quote counts and notes list.

Verifying a source ​

crow_verify_source records how a source was verified in verification_method:

  • quotes_checked (default): the source needs at least one quote note, and every quote must be found on the stored page. If the stored copy is over 30 days old, Crow re-opens the page first and adopts the new text only when every quote still matches. A quote that later fails its check clears a quotes_checked verification; the audit log records it as invalidated.
  • manual_owner: the owner verifies by hand. Bots cannot. This is the only way to verify a not_applicable source.
  • legacy_flag: set once by the migration on rows that were already marked verified. It was never checked against a page, so it is not shown as [V].

Who is the owner ​

The project server decides the caller's identity when it is built, and the owner has to be explicit. npm run mcp-config marks the generated crow-projects entry CROW_ACTOR_KIND=owner; a hand-written client config needs the same env to verify by hand over stdio. Gateway mounts started with --no-auth, bots, peer instances and callers that say nothing are never the owner. A bot's HTTP calls to the gateway's router, projects, research and tools mounts are blocked by the pi-bots url guard, so a bot cannot reach the owner path through the gateway.

Quote matching ​

servers/research/quote-match.js decides whether a quote is on the page. A quote counts as found only when its exact wording appears on the page. Crow never reconstructs an edited quote.

  • Normalization: both sides are folded the same way: Unicode NFKC, whitespace, soft hyphens and zero-width characters, case, and the styles of quotes, dashes and apostrophes. Outer quote marks and a trailing . , ; : on the quote are trimmed; ? and ! are kept, because they change what the sentence says.
  • Word boundaries: a match must start and end on a word boundary. Hyphenated words and numbers such as 2.5 or 1,500 count as whole words.
  • Where it looks: the Readability text first, then the full page body. A result reports body when the match came from the full body.
  • Allowed edits in a quote: [sic], [citation needed], and a single capital-letter bracket that starts a word ([I]t). Any ellipsis or any other bracket makes the check "couldn't check exactly": quote the passage without cuts, or tell the owner. Footnote markers such as [3] are ignored on the page side only.
  • Couldn't check: a quote over 2,000 characters, under 4 characters, or with too many possible placements on the page. A page that was cut off at the size cap and has no match is also "couldn't check", never "not on the page".
  • Attribution: the full quote is tried first. Only if it is not found is a trailing dash or after-quote tail dropped, and only when the tail looks like a name: two or more capitalized words, not starting with words such as The, Never or Not, with an optional , Title. Put the speaker or publication in your own sentence, not inside the quote.
  • Result: found (1), not found (0), or couldn't check (NULL).

Known limits: substring matching cannot tell when the page itself denies the quoted sentence, or when a match comes from page furniture such as a menu or footer (the result then reports body).

Released under the MIT License.