Files
mcpctl/docs/chat.md
Michal a5cab5a096
Some checks failed
CI/CD / lint (pull_request) Successful in 1m2s
CI/CD / typecheck (pull_request) Successful in 2m10s
CI/CD / test (pull_request) Successful in 1m17s
CI/CD / smoke (pull_request) Failing after 1m49s
CI/CD / build (pull_request) Successful in 2m8s
CI/CD / publish (pull_request) Has been skipped
feat(chat): project-scoped chat — mcpctl chat --project <name>
Chat directly with a Project (no Agent needed): its Prompts become the system
context, its MCP-server tools are callable, its llmProvider/llmModel drive the
LLM, and (opt-in) the model can read secret values. History is saved inside the
project, attributed per user, resumable, and deletable (RBAC-permitting) — "use
it like Claude, scoped to the project".

Backend (reuses the agent-chat orchestrator):
- ChatThread is now agent-XOR-project (schema + migration + CHECK constraint);
  new listThreadsByProject / deleteThread on the repo.
- ChatService: prepareProjectContext (project prompt + Prompts by priority,
  llm from llmProvider with llmModel override, project tools), shared
  runChatLoop/runChatStreamLoop, project thread CRUD with owner enforcement
  (404-not-403 on foreign threads), admin-override delete.
- Gated get_secret virtual tool: offered only with --allow-secrets AND the
  caller's view:secrets; resolves via SecretService, never routes to a server.
- routes/project-chat.ts (chat SSE+non-stream, threads create/list/delete);
  RBAC run:projects:<name>.

CLI:
- `mcpctl chat --project <name>` (+ --allow-secrets), one-shot/REPL/resume.
- REPL /threads, /resume <id>, /delete <id>; project-aware header + /tools.
- `mcpctl get threads --project <name>`, `mcpctl delete thread <id> --project`.
- completions regenerated (--project completes project names).

Tests: 8 new project-chat unit tests; full mcpd (945) + CLI (508) green;
schema validated against Postgres. Docs: docs/chat.md "Project chat" section.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-18 10:34:21 +01:00

6.1 KiB

mcpctl chat

Open an interactive chat session with an Agent, or send a single message in one shot. See agents.md for what an Agent is and how to create one.

Modes

mcpctl chat <agent>                 # interactive REPL, new thread
mcpctl chat <agent> --thread <id>   # interactive REPL, resume thread
mcpctl chat <agent> -m "hi"         # one-shot, prints reply, no REPL
mcpctl chat <agent> -m "hi" --no-stream  # one-shot, single JSON response (no SSE)

Streaming is on by default. Text deltas land on stdout as they arrive; tool calls and tool results print to stderr in dim brackets so the chat output stays clean.

Project chat

Chat directly with a project — no Agent needed. The session sees the project's Prompts as system context, can call every tool from the project's attached MCP servers, and uses the project's own LLM (llmProvider, with llmModel as an optional served-model override).

mcpctl chat --project sre                 # REPL scoped to project "sre"
mcpctl chat --project sre -m "what alerts fired overnight?"
mcpctl chat --project sre --thread <id>   # resume a past conversation
  • Prompts + tools come from the project and stay current — anything you add to the project later shows up automatically in the next turn.
  • LLM: set it once with mcpctl patch project sre llmProvider=<llm-name> (and optionally llmModel=<served-model>). Chat errors clearly if unset.
  • History is saved inside the project, attributed to you. List and resume:
    mcpctl get threads --project sre         # your threads for this project
    mcpctl chat --project sre --thread <id>
    
    Delete one you own (admins with delete:projects can delete anyone's):
    mcpctl delete thread <id> --project sre
    

Reading secrets (--allow-secrets)

By default the model cannot read secret values — it only benefits from them indirectly (the project's tools run authenticated). Opt in with --allow-secrets to expose a get_secret tool the model can call:

mcpctl chat --project sre --allow-secrets

This is gated: it requires the flag and your view:secrets permission, and it is off by default. Secret values the model reads land in the chat context and thread history, so use it deliberately.

RBAC: project chat and its threads route through run:projects:<name>.

Per-call flags

All optional. They override the agent's defaultParams for this session only — use the in-REPL /save slash-command to persist the current set back to the agent.

--system <text>              # replace agent.systemPrompt for this session
--system-file <path>         # read --system text from a file
--system-append <text>       # append to the agent system block (after project Prompts)
--personality <name>         # apply a personality overlay for this turn
                             # (additive — see docs/personalities.md)
--temperature <n>            # 0..2
--top-p <n>                  # 0..1
--top-k <n>                  # integer; Anthropic-only, OpenAI ignores
--max-tokens <n>             # cap on assistant tokens
--seed <n>                   # reproducibility (provider-dependent)
--stop <text>                # stop sequence (repeatable, up to 4)
--allow-tool <name>          # repeat to allowlist project MCP tools
--extra <key=value>          # provider-specific knob (repeatable)
--no-stream                  # disable SSE; single JSON response

--extra is the LiteLLM-style escape hatch: pass anything the underlying adapter understands. Numeric values are auto-parsed (--extra repetition_penalty=1.1); strings stay strings.

In-REPL slash-commands

/set KEY VALUE      adjust an override for the rest of the session
                    (temperature, top-p, top-k, max-tokens, seed, stop,
                     or any provider-specific knob — unknown keys go
                     into `extra`)
/system <text>      set systemAppend for this turn onward (empty = clear)
/tools              list MCP servers the agent can call as tools
/clear              start a fresh thread (same agent)
/save               PATCH agent.defaultParams = current overrides
                    (systemOverride / systemAppend are NOT persisted)
/quit, /exit        leave the REPL (Ctrl-D works too)

Threads

Threads persist server-side. To resume:

mcpctl get threads --agent reviewer
mcpctl chat reviewer --thread <id>

A mcpctl get thread <id> reads the message log:

mcpctl get thread c0abc… -o yaml

Examples

Quick gut-check on a deploy:

$ mcpctl chat reviewer -m "is fulldeploy.sh safe to run on the current branch?"
Yes — I checked: tests are green on commit 727e7d6 and there's no
in-flight migration. The k8s context is worker0-k8s0 (production); confirm
that's intended before running.
(thread: cm9k…)

Resuming with overrides:

$ mcpctl chat deployer --thread cm9k… --temperature 0.0 --max-tokens 256
> walk me through what changed since the last deploy
…

Pinning sampling defaults to the agent:

$ mcpctl chat deployer --temperature 0.0 --max-tokens 8000
> /save
(saved current overrides as agent.defaultParams)
> /quit

Troubleshooting

  • No agents appear in tools/list — check the agent has a project attach (mcpctl describe agent <name>). The mcplocal plugin only exposes agents on their attached project's session.

  • Tool calls fail with Project not found — the agent has no project attach. Either attach it (mcpctl edit agent <name> and set the project field), or expect text-only chat.

  • Anthropic agents can't call tools — known limitation; the Anthropic adapter doesn't translate OpenAI tool format yet. Use LiteLLM or a direct OpenAI-compatible provider for tool-using agents until the translator ships.

  • mcpctl chat <agent> returns 404 — the agent name doesn't resolve. mcpctl get agents to confirm spelling.

  • REPL feels stuck — agent tool calls can take minutes (e.g. running a Grafana query). Watch stderr for [tool_call: …] / [tool_result: …] brackets; those tell you the loop is alive.