Skip to content
Start your 14-day trial →

MCP Tools Reference

Complete reference for Nexus-Catalyst MCP tools exposed via tools/list: six discrete memory tools and two Linear integration tools, split by read/write.


Nexus-Catalyst exposes 8 client-facing MCP tools. Models call them directly by name; action is only used on the two integration tools, which each cover several related Linear operations.

Tool Type Purpose
recall_context Discrete Session-start semantic recall + persona hint
get_persona_definition Discrete Load a specialized AI persona
search_memories Discrete Mid-session ad-hoc memory search
get_memory_detail Discrete Fetch full content for a specific memory
store_context Discrete Save session memory at end of turn
update_user_facts Discrete Update the durable user facts document
integration_query Read-only Fetch Linear issues, projects, teams, labels, comments
integration_mutate Write Create or modify Linear issues, projects, labels, comments

Every session should follow this pattern:

1. recall_context → search memories, get persona_hint
2. get_persona_definition → only if persona_hint returned
3. [work happens — search_memories / get_memory_detail as needed]
4. store_context → persist what was decided
5. update_user_facts → only if a durable fact about the user surfaced

integration_query / integration_mutate are used when you need Linear — for example searching for a related issue, or creating one from a debugging session.


Always call first at the start of every session, before responding.

Performs semantic search of your NC memory store and returns truncated summaries plus an optional persona_hint.

Parameter Required Description
query Yes Short topic/keywords for the request — the fallback search term when user_query_full is absent
user_query_full No (recommended) The user’s complete, verbatim message for this turn, untruncated. When provided, recall matches on it instead of query for materially better retrieval on long or detailed requests
use_full_query No Whether to search on user_query_full when present. Defaults true — you normally don’t set this
topics No Comma-separated distinct topics (each ≤10 words). A hint, not a switch — see Topic fan-out below. Only send topics that are genuinely distinct
conversation_id No Thread ID, format: nc-[topic]-[YYYYMMDD]. Reuse across turns in the same session
program_tool No Client identifier: claude-desktop, cursor, claude-code, web-interface, api-direct

Topic fan-out: when a request is genuinely broad, recall runs one focused search per topic instead of a single blurred one.

It triggers only when the query is at least 200 characters and either carries 2+ distinct topics or exceeds the length threshold. Sending several topics on a short question does not fan out — the hint alone cannot trigger it.

memories is always the flat, deduplicated result set. When a request fans out, the response adds:

"fanned_out": true,
"topic_count": 3,
"topic_groups": [
{ "topic": "bearer auth", "memory_ids": ["mem_abc123", "mem_def456"] },
{ "topic": "deploy", "memory_ids": ["mem_def456"] }
]

topic_groups carries ids only — join them against memories, which holds the objects. A memory relevant to two topics appears in both groups but exactly once in memories.

Results scale with the number of topics, deduplicated:

Branches Per topic Max total
1 (no fan-out) 10 10
2 8 16
3 7 21
4 6 24
5 (ceiling) 6 30
What database setup did we decide on for the e-commerce project?

Tool call:

{
"query": "e-commerce database setup decision",
"user_query_full": "What database setup did we decide on for the e-commerce project?",
"conversation_id": "nc-ecommerce-db-20260529",
"program_tool": "cursor"
}

Response (shape):

{
"memories": [
{
"memory_id": "mem_abc123",
"summary": "Database: PostgreSQL 15 with Prisma ORM",
"confidence": 0.95
}
],
"persona_hint": "jack"
}

If persona_hint is present → call get_persona_definition next. Use returned memory_id values with get_memory_detail when summaries are not enough.


Retrieves the full definition, communication style, and behavioral guidelines for a recommended persona.

Only call when recall_context returns a persona_hint in the current session.

Parameter Required Description
persona_name Yes Persona to load (e.g. jack, betty, nora)
{
"persona_name": "jack"
}

Ad-hoc semantic search mid-session. Use when you need something specific that was not returned by recall_context at session start.

Returns truncated summaries and memory_id values — use get_memory_detail for full content.

Parameter Required Description
query Yes Search query (fallback when user_query_full is absent)
user_query_full No (recommended) The user’s complete, verbatim request. When provided, search matches on it instead of query
conversation_id No Thread identifier
max_results No Max results (default 5, max 20)
Search for authentication decisions in the last month
{
"query": "authentication JWT refresh token decisions",
"user_query_full": "Search for authentication decisions in the last month",
"max_results": 10
}

Fetch the full content of a specific memory by memory_id. Second step of the recall → detail pattern.

Parameter Required Description
memory_id Yes ID returned by recall_context or search_memories
{
"memory_id": "mem_abc123"
}

Returns full fields: summary, context (untruncated), conversation_id, timestamp, persona, artifact_url, company_client, client_project.

recall_context returns each memory’s summary capped at 1200 characters — enough to answer most questions without a follow-up. Call get_memory_detail(memory_id) when you need the untruncated context; that is the division of labour, so recall stays cheap for the caller’s context window.


Call at the end of every session to record what was discussed. The model generates summary and context — do not ask the user to provide them.

Parameter Required Description
summary Yes What was asked and decided. 50–75 tokens max
context Yes Full technical detail. Target 2000–8000 tokens; do not truncate errors, paths, or commands
conversation_id Yes Must match the ID used in recall_context this session
user_query No User’s verbatim opening question — improves future recall matching
persona No Persona used this session
billable No Mark as billable client work
company_client No Client name
client_project No Project name
artifact_url No Associated artifact URL (nc-doc://… or https://…)
{
"summary": "Decided on PostgreSQL 15 with Prisma ORM for e-commerce API.",
"user_query": "What ORM should we use with Postgres for the e-commerce project?",
"context": "Evaluated Prisma vs Drizzle. Chose Prisma for migration tooling and team familiarity. Connection string in .env as DATABASE_URL. Schema lives in prisma/schema.prisma.",
"conversation_id": "nc-ecommerce-db-20260529",
"client_project": "e-commerce"
}

Update the user’s durable facts document — a JSON merge patch (set paths to values; null deletes a path). The merged document is auto-injected into the first recall_context of every new conversation, so quality matters more than completeness.

Write ONLY when all three hold — see the fact-write gate for the full rule:

  1. Durable, not situational — a truth about the user, their people, businesses, or infrastructure, not a session outcome.
  2. Data, not a rule — wife.name: Nicole is a fact; “never fabricate a last name” is an instruction and must never be stored here.
  3. Correct over append — on conflict, overwrite or delete the stale path rather than accreting variants.
Parameter Required Description
facts_patch Yes JSON merge patch object. Nested objects merge; scalars/arrays replace; null deletes a path
{ "facts_patch": { "family": { "wife": { "name": "Nicole" } } } }

The merged document is hard-capped at ~4KB; an oversize write is rejected — prune stale paths first. Facts are always private to the user and never enter team recall or any shared surface.


Read-only Linear queries: fetch issues, projects, teams, labels, statuses, users and comments. This tool never creates or modifies anything — use integration_mutate for that.

An action parameter selects the operation; everything else is passed as a top-level parameter.

Every response uses the standard envelope:

{ "success": true, "message": "Linear issues retrieved", "data": { "…": "…" } }

Nexus-Catalyst stores one Linear API key per organization, labelled ("AV", "JL", …) when you connect it.

  • One org connectedworkspace is optional and ignored.
  • Two or more — pass workspace on every call. Omitting it returns a disambiguation response rather than an error: success: true with disambiguation_required: true, available_workspaces, and a message naming the valid labels. An unrecognised label returns the same shape. Matching is case-insensitive.

This is what lets one conversation read and write across separate Linear organizations without re-authenticating — see Nexus-Catalyst and Linear’s own MCP.

Action Required Returns
get_linear_teams teams[], total
get_linear_projects projects[], total
get_linear_issue issue_id issue — full description, no excerpting
search_linear_issues query or team_id see Searching issues
get_linear_project_detail project_id project with members, teams, labels, issue_count
get_linear_team_detail team_id team with members, states, labels, issue_count
list_linear_labels labels[] — workspace-wide, see Labels
list_linear_project_labels project_id labels[]
list_linear_statuses team_id statuses[] — workflow state UUIDs
list_linear_users users[] — assignee UUIDs
list_linear_comments issue_id comments[] (first 50, excerpted)
get_linear_comment_detail issue_id Full, unexcerpted comment thread — the drill-in from list_linear_comments
get_project_context project_id or team_id issues + linked memories, see get_project_context

search_linear_issues requires at least one of query or team_id — a filter alone is not enough to scope a search.

Parameter Description
query Matches the issue title only, case-insensitively, first 100 characters of the term. It does not search descriptions or comments
team_id Restrict to one team
limit Default 25, max 100
description_chars Excerpt length for descriptions, default 200, 0 to omit — see Description excerpts
search_filters { state, label, project } — nothing else

search_filters

Key Value
state open (started + unstarted), closed (completed + cancelled), or a specific one: active, in_progress, started, todo, unstarted, done, completed, cancelled, backlog, triage
label Label name, exact and case-sensitive. Matches issues carrying it among other labels. "Launch-Critical" finds nothing when the label is launch-critical
project Project UUID from get_linear_projects

Response

Field Meaning
issues The matches
returned_issues How many issues are in this response
total The same number. Kept for older callers; it is the count returned, not the count matching
may_be_truncated true when the result filled the limit, so more may exist
applied_filters The filter keys that were actually used — read this back
detail_hint Present when descriptions were shortened; names the drill-in call
query, team_id Echoed back when supplied

Issue descriptions dominate the payload of a multi-issue response — on one real project, 94KB of 123KB. Both search_linear_issues and get_project_context therefore excerpt them, and always say so.

description_chars — default 200, maximum 2000, clamped rather than trusted. 0 omits descriptions entirely.

Per issue, the response then carries:

  • description — the excerpt (absent when description_chars: 0)
  • description_truncated: true — when the body was cut
  • description_chars_available — the full length, so you can tell an omitted body from an empty one

Use get_linear_issue with the identifier for one issue’s complete description. It never excerpts.

Issues plus the Nexus-Catalyst memories linked to them, scoped by project_id or team_id.

Parameter Description
project_id / team_id One of the two is required
include_closed Default false
description_chars As above
Response field Meaning
scoped_by "team" or "project" — which one answered
issues Up to 50, description-trimmed
returned_issues How many came back
issues_may_be_truncated true when the 50-issue cap was hit
related_memories, total_memories Memories linked to the first 20 issues
patterns Aggregate signal across the issues
detail_hint As above

list_linear_labels returns every label in the organization, including workspace-level ones. It takes team_id only to echo it back — workspace-level labels have no team association, so filtering by team would hide the labels most issues actually use.

Example — find open issues carrying a label

Section titled “Example — find open issues carrying a label”
{
"action": "search_linear_issues",
"workspace": "AV",
"team_id": "a0a14518-cdb4-4a17-912e-6d28e77a8d01",
"search_filters": { "state": "open", "label": "launch-critical" },
"description_chars": 0,
"limit": 100
}

Linear actions that create or modify records: issues, projects, labels, comments, and the memory↔issue cross-reference rows. Every action here writes — use integration_query for reads.

An action parameter selects the operation; everything else is passed as a top-level parameter. Same response envelope and workspace selection as integration_query.

Action Required Notes
create_linear_issue title, team_id Alias of save_linear_issue without an issue_id
save_linear_issue issue_id to update; title + team_id to create See Writing issues
auto_create_linear_issue title, team_id Legacy alias of create_linear_issue — prefer create_linear_issue
create_linear_project name, team_ids or team_id Projects belong to one or more teams, so this one takes an array
create_linear_label name team_id optional and meaningful — see Creating and renaming labels
update_linear_label id + one of name / color / description Rename preserves the label id and every attachment
create_linear_comment issue_id, body
link_memory_to_linear_issue memory_id, issue_id Stores the link and stamps the memory
cross_reference_linear_memory memory_id Finds issues related to a memory and links them
update_ticket_from_memory issue_id, memory_id update_type: add_comment (default) or update_description

Pass write fields at the top level — never inside search_filters.

Parameter Applies to Description
title create / update Required to create
description create / update Markdown body
team_id create / update Team UUID from get_linear_teams. Required to create. On an update this MOVES the issue — see below
project_id create / update Project UUID from get_linear_projects
priority create / update 1 Urgent, 2 High, 3 Medium, 4 Low. Defaults to 3 on create
state_id create / update Workflow state UUID from list_linear_statuses. This is how you close an issue
assignee_id create / update User UUID from list_linear_users
labels create / update Array of label UUIDs, not names. See the replacement warning below
issue_id update UUID or human identifier (NC-103); an identifier is resolved for you

An update that supplies no recognised field is refused rather than reported as a success. Linear’s issueUpdate answers success: true for an empty input, so a typo’d parameter name would otherwise look exactly like a completed write.

create_linear_label — the team_id parameter decides the label’s scope, permanently in practice:

  • omit team_id → a workspace-level label every team can use
  • supply team_id → a team-scoped label. Linear refuses to put it on another team’s issue

The response reports scope as "workspace" or "team", read back from Linear rather than echoed from the request.

update_linear_label renames or recolours a label in place. The id survives, so every issue already carrying it keeps it. Linear label names are case-sensitive and it does not dedupe on case, so a rename is the right fix for a casing mistake — creating the lowercase one alongside leaves you with two.

{
"action": "create_linear_issue",
"workspace": "AV",
"title": "CORS error from localhost",
"description": "API returns CORS failure when the frontend calls from localhost:3000",
"team_id": "a0a14518-cdb4-4a17-912e-6d28e77a8d01",
"priority": 2,
"labels": ["bdddef24-39ce-45f9-bc2b-7497ffd8e6d5"]
}
{
"action": "save_linear_issue",
"workspace": "AV",
"issue_id": "NC-103",
"state_id": "61eb3529-20a8-44cc-b0a6-d773e3d74ad5"
}

Resolve the state UUID with list_linear_statuses first. Writing “Closes NC-103” in a commit message does nothing here.

{
"action": "link_memory_to_linear_issue",
"workspace": "AV",
"memory_id": "mem_abc123",
"issue_id": "NC-103"
}

Bug reported
→ recall_context (similar past bugs)
→ search_memories (narrow search if needed)
→ get_memory_detail (full prior fix write-up)
→ integration_mutate.create_linear_issue (track bug)
→ store_context (save resolution workflow)
recall_context or search_memories → summaries + memory_ids
get_memory_detail → full preserved conversation

All tools return a consistent error shape:

{
"error": true,
"message": "Descriptive error message",
"code": "ERROR_CODE",
"suggestion": "How to fix the issue"
}

Use natural language — let the client choose the right tool:

✅ "What did we discuss about authentication?"
❌ "Execute recall_context with query authentication"

Follow the session workflowrecall_context first, store_context last.

Use get_memory_detail when summaries are insufficient — don’t guess from truncated text.

Don’t skip recall at session start — context from prior sessions won’t load automatically otherwise.

Don’t nest Linear write fields in search_filters — pass title, team_id, etc. at the top level.

Don’t call get_persona_definition without a persona_hint — wastes a tool call.


Back to: Documentation Home