MFS — register / update / re-sync data sources
1. What this skill does
Walks the user through getting a data source into MFS so it's searchable.
The work splits into:
- Picking the right connector scheme.
- Collecting credentials (preferring
env:VAR / file:/path indirection
over plaintext).
- Writing a connector TOML.
- Calling
mfs add <uri> --config <toml> and monitoring the returned job.
Each connector has its own field set, credential acquisition story, and
gotchas. Per-connector details live in
reference/connectors/<scheme>.md — read the matching one before
collecting fields for any scheme.
Step 0: Pre-flight (always run first)
mfs --version # missing? `cargo install mfs-cli` (see install row below)
mfs status # server reachable? connectors/jobs visible?
mfs config show # endpoint/profile/client id/server-info debugging
mfs connector list # what's already configured?
Branch on the result:
| Signal |
Action |
mfs not found |
install the CLI (Rust): cargo install mfs-cli, or the shell installer from the project's GitHub releases page. |
mfs status connection refused |
the configured server is down. Tell the user how to bring it up — pre-release, the server runs from source: git clone https://github.com/zilliztech/mfs.git && cd mfs/server/python && uv sync && uv run mfs-server setup && uv run mfs-server run — and wait. Work only through the configured endpoint rather than pointing the CLI at a different server. |
mfs status returns 401 unauthorized |
the user's MFS_API_TOKEN is missing/wrong. Use mfs config show to confirm the endpoint/profile, then set the intended token source and retry. |
server up + connector list empty |
first-ever connector; jump to §B (greenfield walk-through) when intent matches |
| server up + N connectors registered |
proceed to Step 1 intent classification |
Step 1: Classify intent (the central decision)
Read the user's most recent message. Pick exactly one row:
| User said... |
Intent |
Jump to |
| "add postgres prod-db to MFS" + credentials available (env / file / about to paste) |
A. Zero-friction add |
§A |
| "I want to add postgres / slack / X" (no specifics, vague) |
B. Greenfield walk-through |
§B |
| "re-sync github", "re-index slack", "pull latest from jira" |
C. Force re-ingest |
§C |
| "update my slack token", "change postgres host", "switch to new DSN" |
D. Edit existing config |
§D |
| "what connectors do I have", "list registered sources" |
E. List |
§E |
| "find X" / "search Y" / "grep Z" / "cat W" |
wrong skill |
redirect to mfs-find, stop |
| "is X indexed yet" / "did the sync finish" / "search returns nothing" |
wrong skill or boundary |
suggest mfs-find for query-side diagnosis; if user says it's an ingest issue, jump to §C or §F |
| Truly unclear after a re-read |
F. Clarify |
§F |
Mid-flow redirect
If at any point the user changes intent ("wait, just list what I have" /
"actually let me just re-sync the existing one"), abandon the current §
and jump to the new one. Don't insist on finishing the original branch.
§A. Zero-friction add
User knows what to add and has credentials handy. Aim for: ≤3 questions
to the user, then write toml + run mfs add.
Parse the URI from the user's message. Shape: <scheme>://<alias>.
Scheme is required and is the connector type (postgres, slack, …).
Alias is the human-readable instance ID — gets used as the toml
filename and the connector's row in metadata.
- If only
<scheme> was given (no alias), ASK: "What should I call
this instance? (free-form; appears as the URI host part, e.g.
postgres://**prod-db**)"
file takes a bare path, not an alias. The target is a local
path: mfs add /abs/path (the URI is derived as file://local/abs/path).
The path is client-side: on the same host the server reads it directly; on
a different host the CLI bundles and uploads the tree (--upload /
--no-upload to force).
Read the matching reference/connectors/<scheme>.md for the
required field set, and reference/credentials.md for how credentials
work. For each credential field, put a reference in the toml —
env:VAR_NAME or file:/abs/path — which the server resolves against its
own environment / filesystem at ingest time. Make sure that value is present
where the server runs (client and server share a machine on a loopback
endpoint; otherwise it lives on the server — ask the user if unsure).
Write the toml to a temp path:
# mfs-server connector config — <scheme>
# URI: <uri>
<field1> = "<value or env:VAR>"
<field2> = "<value>"
...
Use a path like /tmp/mfs-<alias>.toml so it doesn't pollute the
user's cwd.
Run mfs add in estimate-confirm mode for external sources where
cost matters (databases >100k rows, GitHub repos with many issues,
large Slack workspaces, full website crawls):
mfs add <uri> --config /tmp/mfs-<alias>.toml
For non-local targets, the current CLI automatically calls
/v1/connectors/estimate and prompts Continue? [y/N] unless --yes
is set. There is no standalone --estimate flag. Show the estimate to
the user and only answer yes when the user has approved.
For small / unambiguous sources (single repo of docs, one CRM with
<10k records, a defined Slack channel), the same command is still the
normal add path. Use --yes only when the user has already accepted
skipping the estimate confirmation.
Whole-account enumerators (gdrive = the entire Drive; feishu user-mode docs =
the entire My Space): if the estimate is large, don't just confirm a full index —
first propose narrowing by time. Re-estimate with a recent start date (POST /v1/connectors/estimate with a since field) to show the smaller count, then add
with that bound:
mfs add <uri> --config /tmp/mfs-<alias>.toml --since <date>
--since indexes only objects modified on/after <date>; older ones are left
untouched and never deleted, and can be pulled in later by lowering --since.
Capture the queued job id. If the step 4 command was approved at the
prompt, it already queued the job. For local targets, or when the user has
explicitly approved skipping the estimate confirmation, run:
mfs add <uri> --config /tmp/mfs-<alias>.toml
Capture the returned job_id. mfs add always returns after queueing;
use mfs job show or mfs job list to watch terminal state.
Follow the job until terminal state:
mfs job show <job_id>
# or polled (no jq needed — grep the JSON status field):
while ! mfs job show <job_id> | grep -qE '"status": *"(succeeded|failed|cancelled)"'; do
sleep 5
done
mfs job show <job_id>
Confirm result — report what's searchable, not just what was registered:
succeeded + succeeded_objects > 0 → run mfs connector inspect <uri>
and report both numbers: object_count (files registered) and
objects.indexed / chunk_count (files actually embedded and
semantically searchable). They often differ — only documents, code, and
(with a vision model on) images get embedded; data / config files
(.json .csv .yaml .log …) are listed and greppable but not
vector-searchable. Don't claim "all N indexed" when only some are. Then give
one example: "Try: mfs search '<sample query>' <uri>".
succeeded + succeeded_objects == 0 → check mfs ls <uri> —
either source genuinely empty, or wrong text_fields/scope.
Read reference/troubleshooting.md.
failed → read the job's error field, match against
reference/troubleshooting.md, propose a fix and ask user.
§B. Greenfield walk-through
User vague about what to add. Hand-hold through scheme picking, then
delegate to §A's steps 2-7 with the chosen scheme.
Pre-flight (Step 0 already covered this).
Ask: which kind of source? Group the 20 schemes by shape so the
choice is tractable:
Pick the source TYPE:
1. Database tables (postgres, mysql, snowflake, bigquery)
2. Document store (mongo)
3. Code repository (github)
4. Issue tracker / wiki (jira, linear, notion)
5. CRM (hubspot)
6. Support / help desk (zendesk)
7. Chat / messaging (slack, discord, gmail, feishu)
8. Cloud storage / files (s3, gdrive, file, web)
9. Other (specify)
Once user picks a group, narrow to the specific scheme (e.g. "Database
tables → postgres / mysql / snowflake / bigquery — which?").
Ask for an instance alias (host part of the URI; e.g. "prod-db",
"support-workspace", "main-repo").
Read reference/connectors/<scheme>.md — its top section
"How to obtain credentials" guides the user through fetching the
token/DSN/key from the source's own console. Walk them through one
step at a time, ask after each step ("Got the token? Paste it as
env:VAR_NAME if it's already exported, or paste the value here").
Continue with §A from step 2 (collect fields → write toml →
estimate-confirm/add → follow job → confirm).
§C. Force re-ingest
User wants to re-sync an existing connector — typically because the
source changed (new tickets, new PRs, new files) and the user doesn't
want to wait for the next scheduled sync.
Confirm the URI matches a registered connector:
mfs connector list | grep <alias-or-scheme>
If not found, redirect to §B.
Confirm with the user when it's a force-full re-index (re-embeds
everything, costs tokens):
"Re-syncing <uri>. Pick one:
• no flag pull changed data using the connector's normal sync path
• --since limit to changes since a date — only on connectors that
support it (currently gdrive, feishu); others return an error
• --full re-embed everything from scratch (re-bills embedding
API; only do this if you've changed text_fields,
the embedding model, or chunking config)"
Run:
mfs add <uri> # incremental: re-uses existing toml + caches
mfs add <uri> --full # full re-embed
mfs add <uri> --since <date> # only new content since date
Follow + confirm as in §A step 6-7.
§D. Edit existing config
User wants to change a registered connector — new token, different
text_fields, more channels, raise max_read_rows, etc.
Locate the existing toml:
ls -la $MFS_HOME/connectors/<alias>.toml
# OR (if MFS_HOME unset)
ls -la ~/.mfs/connectors/<alias>.toml
Read it so the user sees current state. ASK what they want to
change. Common edits and the right field:
| Want to change |
Field |
| Auth token |
token / api_key / access_token (scheme-dependent) |
| DSN / connection string |
dsn / uri |
| Which channels / projects / labels |
channels / projects / labels (multi-value) |
| Max records per object |
max_read_rows |
| Cap on per-object chunks |
chunk_max |
| Which columns to embed (DB / SaaS) |
[[objects]] text_fields |
| Make a previously-indexed object stop indexing |
[[objects]] indexable = false |
| Process some objects before others in this sync |
[[objects]] priority (lower = earlier; doesn't affect ordering across different connectors) |
See reference/connectors/<scheme>.md for the full field list.
Apply the minimum diff. Don't rewrite unrelated fields.
Run mfs connector update so the engine applies the new config
through the explicit update path:
mfs connector update <uri> --config $MFS_HOME/connectors/<alias>.toml
Follow + confirm as in §A step 6-7.
When does a config update re-embed?
| What changed |
Re-embed? |
| auth token, DSN host |
no — re-runs sync only |
max_read_rows increased |
partial — picks up newly visible records |
text_fields (which columns become content) |
yes, with --force-index (see below) |
embedding.* in server config |
yes (and affects ALL connectors) |
[[objects]] indexable = false |
drops that object from index |
[[objects]] priority |
no — only changes processing order for objects enumerated in a future sync, not already-succeeded ones |
Applying a text_fields change to existing objects needs
mfs add <uri> --force-index. A plain mfs connector update saves the new
config, but an incremental sync re-chunks an object only when its source content
changed — a config-only change leaves existing objects on their previous shape.
Run mfs add <uri> --force-index after the update to re-chunk them with the new
text_fields.
If the change forces re-embedding and the source is large, ask the user before
running it if the cost cannot be estimated from the CLI.
§E. List registered connectors
mfs connector list # via the running server (live state)
mfs-server connector list # on-disk tomls under $MFS_HOME/connectors/
The two views can differ:
mfs connector list shows what the server has registered in its
metadata DB.
mfs-server connector list shows the toml files on disk (admin spec).
If they diverge, the disk file is a saved spec the user can re-apply with
mfs add <uri> --config <toml>.
Format the output as a small table for the user. If they then ask about
one specific connector, switch to §C / §D as appropriate.
§F. Clarify intent
User's first message was too vague to pick a path. Ask one short
question, default to §B if they shrug:
"Want to (1) add a new source, (2) re-sync an existing one, (3) change
the config of one you've already added, or (4) just see what's
registered?"
After they answer, jump to the matching §.
Useful commands (cross-cutting)
Cheap reads any path may need:
mfs status # server + all connectors at a glance
mfs config show # endpoint/profile/client id/server info
mfs connector inspect <uri> # one connector's object/job summary
mfs ls <uri> --json # per-entry search_status
mfs connector list # live server view
mfs-server connector list # on-disk toml view (admin)
mfs job list # recent ingest jobs
mfs job show <job_id> # one job's state and error field
mfs job cancel <job_id> # cancel a queued/running job
mfs remove <root-uri> # drop a connector + its index data (DESTRUCTIVE)
mfs remove <root-uri> permanently removes that connector AND its indexed
chunks from Milvus. Use the registered connector root, not a child object path.
ALWAYS confirm with the user before running it.
Anti-patterns to flag back to the user
- Adding the same URI twice — second
mfs add <uri> updates the
existing connector, doesn't create a duplicate. If the user really
wants two postgres instances, give them different aliases
(postgres://prod-db vs postgres://staging-db).
- Cosmetically-different URIs that point to the same source — the
URI string IS the connector identity; MFS does NOT canonicalize
across the scheme-specific forms a host/database can take. So
postgres://h:5432/db and postgres://h/db register as two
separate connectors over the same physical DB, each with its own
job queue + collection state. Pick one form per source and stick
with it; if the user is mid-flow and you spot the drift, suggest
rolling back the duplicate with mfs connector remove.
- Pasting plaintext tokens into the toml when an env var exists —
suggest
env:VAR form, especially when the user mentions docker /
K8s / CI / shared host.
- Setting
text_fields blindly on a SaaS connector — most have a
built-in preset (see reference/connectors/<scheme>.md for what auto-
applies); user only needs [[objects]] for overrides.
--full re-embedding to "fix" a search problem — wastes tokens.
First diagnose with mfs-find (§12) whether the issue is index
config or query construction.
Reference routing
reference/credentials.md — WHEN about
to write a secret value into a toml. Covers env:VAR and file:/path
indirection syntax, security tradeoffs, and which env vars common SaaS
CLIs already export.
reference/update-flow.md — WHEN
walking §D and the user wants to change something that has knock-on
consequences (changing text_fields, switching embedding provider).
reference/troubleshooting.md —
WHEN mfs add failed, job state is failed, or succeeded but
succeeded_objects == 0. Maps common error messages to recovery steps.
reference/error-codes.md — WHEN an
mfs command returned --json error output with a code field.
reference/connectors/<scheme>.md — WHEN about to add or update a
specific scheme. REQUIRED reading before the credential-gathering
step. Schemes: postgres, mysql, mongo, snowflake, bigquery,
slack, discord, gmail, feishu, github, jira, linear,
notion, hubspot, zendesk, s3, gdrive, web, file.
The per-connector files cover credential acquisition, required toml
keys, optional knobs, and known pitfalls. Don't guess any of these from
training-data memory — the reference is the source of truth for this
codebase's connectors.
1---2name: mfs-ingest3description: Register, update, or re-sync data sources for MFS so they become searchable — postgres / mysql / mongo / snowflake / bigquery, github / jira / linear / notion / hubspot / zendesk, slack / discord / gmail / feishu, s3 / gdrive / web / file. Use whenever the user wants to ADD a new data source to MFS, change an existing connector's config, re-ingest / re-index a source, list registered connectors, or troubleshoot a sync that's not picking up data. Trigger phrases include "add X to MFS", "ingest my [postgres/slack/github/etc]", "register this repo / database / workspace", "make X searchable", "re-sync Y", "update the slack token", "what connectors do I have". Do NOT use for: searching / finding / reading content (use `mfs-find`); raw mutation of the source itself (MFS only reads).4---56# MFS — register / update / re-sync data sources78## 1. What this skill does910Walks the user through getting a data source into MFS so it's searchable.11The work splits into:12131. Picking the right connector scheme.142. Collecting credentials (preferring `env:VAR` / `file:/path` indirection15 over plaintext).163. Writing a connector TOML.174. Calling `mfs add <uri> --config <toml>` and monitoring the returned job.1819Each connector has its own field set, credential acquisition story, and20gotchas. Per-connector details live in21`reference/connectors/<scheme>.md` — **read the matching one before22collecting fields** for any scheme.2324## Step 0: Pre-flight (always run first)2526```bash27mfs --version # missing? `cargo install mfs-cli` (see install row below)28mfs status # server reachable? connectors/jobs visible?29mfs config show # endpoint/profile/client id/server-info debugging30mfs connector list # what's already configured?31```3233Branch on the result:3435| Signal | Action |36|---|---|37| `mfs` not found | install the CLI (Rust): `cargo install mfs-cli`, or the shell installer from the project's GitHub releases page. |38| `mfs status` connection refused | the configured server is down. Tell the user how to bring it up — pre-release, the server runs from source: `git clone https://github.com/zilliztech/mfs.git && cd mfs/server/python && uv sync && uv run mfs-server setup && uv run mfs-server run` — and wait. Work only through the configured endpoint rather than pointing the CLI at a different server. |39| `mfs status` returns 401 unauthorized | the user's `MFS_API_TOKEN` is missing/wrong. Use `mfs config show` to confirm the endpoint/profile, then set the intended token source and retry. |40| server up + `connector list` empty | first-ever connector; jump to **§B (greenfield walk-through)** when intent matches |41| server up + N connectors registered | proceed to Step 1 intent classification |4243## Step 1: Classify intent (the central decision)4445Read the user's most recent message. Pick exactly one row:4647| User said... | Intent | Jump to |48|---|---|---|49| "add postgres prod-db to MFS" + credentials available (env / file / about to paste) | **A. Zero-friction add** | §A |50| "I want to add postgres / slack / X" (no specifics, vague) | **B. Greenfield walk-through** | §B |51| "re-sync github", "re-index slack", "pull latest from jira" | **C. Force re-ingest** | §C |52| "update my slack token", "change postgres host", "switch to new DSN" | **D. Edit existing config** | §D |53| "what connectors do I have", "list registered sources" | **E. List** | §E |54| "find X" / "search Y" / "grep Z" / "cat W" | **wrong skill** | redirect to `mfs-find`, stop |55| "is X indexed yet" / "did the sync finish" / "search returns nothing" | **wrong skill or boundary** | suggest `mfs-find` for query-side diagnosis; if user says it's an ingest issue, jump to §C or §F |56| Truly unclear after a re-read | **F. Clarify** | §F |5758### Mid-flow redirect5960If at any point the user changes intent ("wait, just list what I have" /61"actually let me just re-sync the existing one"), abandon the current §62and jump to the new one. Don't insist on finishing the original branch.6364---6566## §A. Zero-friction add6768User knows what to add and has credentials handy. Aim for: ≤3 questions69to the user, then write toml + run `mfs add`.70711. **Parse the URI** from the user's message. Shape: `<scheme>://<alias>`.72 Scheme is required and is the connector type (`postgres`, `slack`, …).73 Alias is the human-readable instance ID — gets used as the toml74 filename and the connector's row in metadata.75 - If only `<scheme>` was given (no alias), ASK: "What should I call76 this instance? (free-form; appears as the URI host part, e.g.77 `postgres://**prod-db**`)"78 - **`file` takes a bare path, not an alias.** The target is a local79 path: `mfs add /abs/path` (the URI is derived as `file://local/abs/path`).80 The path is client-side: on the same host the server reads it directly; on81 a different host the CLI bundles and uploads the tree (`--upload` /82 `--no-upload` to force).83842. **Read the matching `reference/connectors/<scheme>.md`** for the85 required field set, and `reference/credentials.md` for how credentials86 work. For each credential field, put a **reference** in the toml —87 `env:VAR_NAME` or `file:/abs/path` — which the server resolves against its88 own environment / filesystem at ingest time. Make sure that value is present89 where the server runs (client and server share a machine on a loopback90 endpoint; otherwise it lives on the server — ask the user if unsure).91923. **Write the toml** to a temp path:93 ```toml94 # mfs-server connector config — <scheme>95 # URI: <uri>96 <field1> = "<value or env:VAR>"97 <field2> = "<value>"98 ...99 ```100 Use a path like `/tmp/mfs-<alias>.toml` so it doesn't pollute the101 user's cwd.1021034. **Run `mfs add` in estimate-confirm mode** for external sources where104 cost matters (databases >100k rows, GitHub repos with many issues,105 large Slack workspaces, full website crawls):106 ```bash107 mfs add <uri> --config /tmp/mfs-<alias>.toml108 ```109 For non-local targets, the current CLI automatically calls110 `/v1/connectors/estimate` and prompts `Continue? [y/N]` unless `--yes`111 is set. There is no standalone `--estimate` flag. Show the estimate to112 the user and only answer yes when the user has approved.113114 For small / unambiguous sources (single repo of docs, one CRM with115 <10k records, a defined Slack channel), the same command is still the116 normal add path. Use `--yes` only when the user has already accepted117 skipping the estimate confirmation.118119 **Whole-account enumerators** (gdrive = the entire Drive; feishu user-mode docs =120 the entire My Space): if the estimate is large, don't just confirm a full index —121 first propose narrowing by time. Re-estimate with a recent start date (`POST122 /v1/connectors/estimate` with a `since` field) to show the smaller count, then add123 with that bound:124 ```bash125 mfs add <uri> --config /tmp/mfs-<alias>.toml --since <date>126 ```127 `--since` indexes only objects modified on/after `<date>`; older ones are left128 untouched and never deleted, and can be pulled in later by lowering `--since`.1291305. **Capture the queued job id**. If the step 4 command was approved at the131 prompt, it already queued the job. For local targets, or when the user has132 explicitly approved skipping the estimate confirmation, run:133 ```bash134 mfs add <uri> --config /tmp/mfs-<alias>.toml135 ```136 Capture the returned `job_id`. `mfs add` always returns after queueing;137 use `mfs job show` or `mfs job list` to watch terminal state.1381396. **Follow the job** until terminal state:140 ```bash141 mfs job show <job_id>142 # or polled (no jq needed — grep the JSON status field):143 while ! mfs job show <job_id> | grep -qE '"status": *"(succeeded|failed|cancelled)"'; do144 sleep 5145 done146 mfs job show <job_id>147 ```1481497. **Confirm result** — report what's *searchable*, not just what was registered:150 - `succeeded` + `succeeded_objects > 0` → run `mfs connector inspect <uri>`151 and report both numbers: `object_count` (files registered) and152 `objects.indexed` / `chunk_count` (files actually embedded and153 semantically searchable). They often differ — only documents, code, and154 (with a vision model on) images get embedded; data / config files155 (`.json` `.csv` `.yaml` `.log` …) are listed and greppable but not156 vector-searchable. Don't claim "all N indexed" when only some are. Then give157 one example: "Try: `mfs search '<sample query>' <uri>`".158 - `succeeded` + `succeeded_objects == 0` → check `mfs ls <uri>` —159 either source genuinely empty, or wrong `text_fields`/scope.160 Read `reference/troubleshooting.md`.161 - `failed` → read the job's `error` field, match against162 `reference/troubleshooting.md`, propose a fix and ask user.163164---165166## §B. Greenfield walk-through167168User vague about what to add. Hand-hold through scheme picking, then169delegate to §A's steps 2-7 with the chosen scheme.1701711. **Pre-flight** (Step 0 already covered this).1721732. **Ask: which kind of source?** Group the 20 schemes by shape so the174 choice is tractable:175 ```176 Pick the source TYPE:177 1. Database tables (postgres, mysql, snowflake, bigquery)178 2. Document store (mongo)179 3. Code repository (github)180 4. Issue tracker / wiki (jira, linear, notion)181 5. CRM (hubspot)182 6. Support / help desk (zendesk)183 7. Chat / messaging (slack, discord, gmail, feishu)184 8. Cloud storage / files (s3, gdrive, file, web)185 9. Other (specify)186 ```187 Once user picks a group, narrow to the specific scheme (e.g. "Database188 tables → postgres / mysql / snowflake / bigquery — which?").1891903. **Ask for an instance alias** (host part of the URI; e.g. "prod-db",191 "support-workspace", "main-repo").1921934. **Read `reference/connectors/<scheme>.md`** — its top section194 "How to obtain credentials" guides the user through fetching the195 token/DSN/key from the source's own console. Walk them through one196 step at a time, ask after each step ("Got the token? Paste it as197 `env:VAR_NAME` if it's already exported, or paste the value here").1981995. **Continue with §A from step 2** (collect fields → write toml →200 estimate-confirm/add → follow job → confirm).201202---203204## §C. Force re-ingest205206User wants to re-sync an existing connector — typically because the207source changed (new tickets, new PRs, new files) and the user doesn't208want to wait for the next scheduled sync.2092101. **Confirm the URI** matches a registered connector:211 ```bash212 mfs connector list | grep <alias-or-scheme>213 ```214 If not found, redirect to §B.2152162. **Confirm with the user** when it's a force-full re-index (re-embeds217 everything, costs tokens):218 > "Re-syncing `<uri>`. Pick one:219 > • no flag pull changed data using the connector's normal sync path220 > • `--since` limit to changes since a date — only on connectors that221 > support it (currently gdrive, feishu); others return an error222 > • `--full` re-embed everything from scratch (re-bills embedding223 > API; only do this if you've changed `text_fields`,224 > the embedding model, or chunking config)"2252263. **Run**:227 ```bash228 mfs add <uri> # incremental: re-uses existing toml + caches229 mfs add <uri> --full # full re-embed230 mfs add <uri> --since <date> # only new content since date231 ```2322334. **Follow + confirm** as in §A step 6-7.234235---236237## §D. Edit existing config238239User wants to change a registered connector — new token, different240`text_fields`, more channels, raise `max_read_rows`, etc.2412421. **Locate the existing toml**:243 ```bash244 ls -la $MFS_HOME/connectors/<alias>.toml245 # OR (if MFS_HOME unset)246 ls -la ~/.mfs/connectors/<alias>.toml247 ```2482492. **Read it** so the user sees current state. ASK what they want to250 change. Common edits and the right field:251252 | Want to change | Field |253 |---|---|254 | Auth token | `token` / `api_key` / `access_token` (scheme-dependent) |255 | DSN / connection string | `dsn` / `uri` |256 | Which channels / projects / labels | `channels` / `projects` / `labels` (multi-value) |257 | Max records per object | `max_read_rows` |258 | Cap on per-object chunks | `chunk_max` |259 | Which columns to embed (DB / SaaS) | `[[objects]] text_fields` |260 | Make a previously-indexed object stop indexing | `[[objects]] indexable = false` |261 | Process some objects before others in this sync | `[[objects]] priority` (lower = earlier; doesn't affect ordering across different connectors) |262263 See `reference/connectors/<scheme>.md` for the full field list.2642653. **Apply the minimum diff**. Don't rewrite unrelated fields.2662674. **Run `mfs connector update`** so the engine applies the new config268 through the explicit update path:269 ```bash270 mfs connector update <uri> --config $MFS_HOME/connectors/<alias>.toml271 ```2722735. **Follow + confirm** as in §A step 6-7.274275### When does a config update re-embed?276277| What changed | Re-embed? |278|---|---|279| auth token, DSN host | no — re-runs sync only |280| `max_read_rows` increased | partial — picks up newly visible records |281| `text_fields` (which columns become content) | yes, with `--force-index` (see below) |282| `embedding.*` in server config | yes (and affects ALL connectors) |283| `[[objects]] indexable = false` | drops that object from index |284| `[[objects]] priority` | no — only changes processing order for objects enumerated in a future sync, not already-succeeded ones |285286**Applying a `text_fields` change to existing objects needs287`mfs add <uri> --force-index`.** A plain `mfs connector update` saves the new288config, but an incremental sync re-chunks an object only when its source content289changed — a config-only change leaves existing objects on their previous shape.290Run `mfs add <uri> --force-index` after the update to re-chunk them with the new291`text_fields`.292293If the change forces re-embedding and the source is large, ask the user before294running it if the cost cannot be estimated from the CLI.295296---297298## §E. List registered connectors299300```bash301mfs connector list # via the running server (live state)302mfs-server connector list # on-disk tomls under $MFS_HOME/connectors/303```304305The two views can differ:306- `mfs connector list` shows what the server has registered in its307 metadata DB.308- `mfs-server connector list` shows the toml files on disk (admin spec).309310If they diverge, the disk file is a saved spec the user can re-apply with311`mfs add <uri> --config <toml>`.312313Format the output as a small table for the user. If they then ask about314one specific connector, switch to §C / §D as appropriate.315316---317318## §F. Clarify intent319320User's first message was too vague to pick a path. Ask one short321question, default to §B if they shrug:322323> "Want to (1) add a new source, (2) re-sync an existing one, (3) change324> the config of one you've already added, or (4) just see what's325> registered?"326327After they answer, jump to the matching §.328329---330331## Useful commands (cross-cutting)332333Cheap reads any path may need:334335```bash336mfs status # server + all connectors at a glance337mfs config show # endpoint/profile/client id/server info338mfs connector inspect <uri> # one connector's object/job summary339mfs ls <uri> --json # per-entry search_status340mfs connector list # live server view341mfs-server connector list # on-disk toml view (admin)342mfs job list # recent ingest jobs343mfs job show <job_id> # one job's state and error field344mfs job cancel <job_id> # cancel a queued/running job345mfs remove <root-uri> # drop a connector + its index data (DESTRUCTIVE)346```347348`mfs remove <root-uri>` permanently removes that connector AND its indexed349chunks from Milvus. Use the registered connector root, not a child object path.350ALWAYS confirm with the user before running it.351352## Anti-patterns to flag back to the user353354- **Adding the same URI twice** — second `mfs add <uri>` updates the355 existing connector, doesn't create a duplicate. If the user really356 wants two postgres instances, give them different aliases357 (`postgres://prod-db` vs `postgres://staging-db`).358- **Cosmetically-different URIs that point to the same source** — the359 URI string IS the connector identity; MFS does NOT canonicalize360 across the scheme-specific forms a host/database can take. So361 `postgres://h:5432/db` and `postgres://h/db` register as two362 separate connectors over the same physical DB, each with its own363 job queue + collection state. Pick one form per source and stick364 with it; if the user is mid-flow and you spot the drift, suggest365 rolling back the duplicate with `mfs connector remove`.366- **Pasting plaintext tokens into the toml when an env var exists** —367 suggest `env:VAR` form, especially when the user mentions docker /368 K8s / CI / shared host.369- **Setting `text_fields` blindly on a SaaS connector** — most have a370 built-in preset (see `reference/connectors/<scheme>.md` for what auto-371 applies); user only needs `[[objects]]` for overrides.372- **`--full` re-embedding to "fix" a search problem** — wastes tokens.373 First diagnose with `mfs-find` (§12) whether the issue is index374 config or query construction.375376## Reference routing377378- **[`reference/credentials.md`](reference/credentials.md)** — WHEN about379 to write a secret value into a toml. Covers `env:VAR` and `file:/path`380 indirection syntax, security tradeoffs, and which env vars common SaaS381 CLIs already export.382383- **[`reference/update-flow.md`](reference/update-flow.md)** — WHEN384 walking §D and the user wants to change something that has knock-on385 consequences (changing `text_fields`, switching embedding provider).386387- **[`reference/troubleshooting.md`](reference/troubleshooting.md)** —388 WHEN `mfs add` failed, job state is `failed`, or `succeeded` but389 `succeeded_objects == 0`. Maps common error messages to recovery steps.390391- **[`reference/error-codes.md`](reference/error-codes.md)** — WHEN an392 `mfs` command returned `--json` error output with a `code` field.393394- **`reference/connectors/<scheme>.md`** — WHEN about to add or update a395 specific scheme. REQUIRED reading before the credential-gathering396 step. Schemes: `postgres`, `mysql`, `mongo`, `snowflake`, `bigquery`,397 `slack`, `discord`, `gmail`, `feishu`, `github`, `jira`, `linear`,398 `notion`, `hubspot`, `zendesk`, `s3`, `gdrive`, `web`, `file`.399400The per-connector files cover credential acquisition, required toml401keys, optional knobs, and known pitfalls. Don't guess any of these from402training-data memory — the reference is the source of truth for this403codebase's connectors.