@zokizuan/satori-mcp 4.10.0 → 4.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,62 +1,60 @@
1
1
  # @zokizuan/satori-mcp
2
2
 
3
- MCP server for Satori agent-safe semantic code search and indexing.
4
-
5
- ## Features
6
-
7
- - Capability-driven execution via `CapabilityResolver`
8
- - Runtime-first `search_codebase` with explicit `scope`, `resultMode`, `groupBy`, and optional `debug` traces
9
- - Deterministic query-prefix operators in `search_codebase` (`lang:`, `path:`, `-path:`, `must:`, `exclude:`)
10
- - Default grouped-result diversity and auto changed-files ranking (`rankingMode="auto_changed_first"`)
11
- - First-class `call_graph` tool with deterministic node/edge sorting and capability-driven language support (currently TS/JS/Python)
12
- - Sidecar-backed `file_outline` tool for per-file symbol navigation and direct call_graph jump handles
13
- - Snapshot v3 safety with index fingerprints and strict `requires_reindex` access gates
14
- - Deterministic train-in-the-error responses for incompatible or legacy index states
15
- - Query-time exclusion support with `.gitignore`-style matching
16
- - Structured search telemetry logs (`[TELEMETRY]` JSON to `stderr`)
17
- - Zod-first tool schemas converted to MCP JSON Schema for `ListTools`
18
- - Auto-generated tool docs from live tool schemas
19
- - `read_file` line-range retrieval with default large-file truncation guard and optional `mode="annotated"` metadata envelope
20
- - Optional proactive sync watcher mode (debounced filesystem events for explicitly touched roots in the current session)
21
- - Index-time AST scope breadcrumbs (TS/JS/Python) rendered in search output as `🧬 Scope`
22
- - Fingerprint schema `dense_v3`/`hybrid_v3` with hard gate for all pre-v3 indexes
23
-
24
- ## Architecture
3
+ Read-only MCP server for Satori. It gives coding agents six deterministic tools for repo search, symbol navigation, call graph context, bounded file reads, and index lifecycle management.
25
4
 
5
+ ## Install
6
+
7
+ Use the CLI installer for normal setup:
8
+
9
+ ```bash
10
+ npx -y @zokizuan/satori-cli@0.4.0 install --client all
11
+ npx -y @zokizuan/satori-cli@0.4.0 doctor
26
12
  ```
27
- [MCP Client]
28
- -> [index.ts bootstrap + ListTools/CallTool]
29
- -> [tool registry]
30
- -> [manage_index | search_codebase | call_graph | file_outline | read_file | list_codebases]
31
- -> [ToolContext DI]
32
- -> [CapabilityResolver]
33
- -> [SnapshotManager v3 + access gate]
34
- -> [Context / Vector store / Embedding / Reranker adapters]
13
+
14
+ The CLI installer supports `codex`, `claude`, `opencode`, and `all`. It creates the runtime cache, writes the stable launcher, and writes client config for you. Avoid using `npx` as the resident MCP server command; first-run package resolution can exceed normal MCP startup timeouts.
15
+
16
+ Advanced direct execution is available through the package bin:
17
+
18
+ ```bash
19
+ npx -y @zokizuan/satori-mcp@4.11.0 --help
35
20
  ```
36
21
 
37
- Tool surface is hard-broken to 6 tools. This keeps routing explicit while exposing call-chain traversal and file-level navigation as first-class operations.
22
+ ## Agent Workflow
38
23
 
39
- ## read_file Behavior
24
+ ```text
25
+ list_codebases
26
+ manage_index action="create" path="/absolute/path/to/repo"
27
+ search_codebase path="/absolute/path/to/repo" query="where is auth refresh handled"
28
+ file_outline path="/absolute/path/to/repo" file="src/auth.ts"
29
+ call_graph path="/absolute/path/to/repo" symbolRef={...} direction="both"
30
+ read_file path="/absolute/path/to/repo/src/auth.ts" start_line=1 end_line=160
31
+ ```
32
+
33
+ Important defaults:
34
+
35
+ - `search_codebase` starts with runtime code, grouped by symbol.
36
+ - `search_codebase` runs freshness checks before returning results.
37
+ - `read_file` is bounded and can return continuation hints.
38
+ - `requires_reindex` means reindex first, then retry the original call.
39
+ - `manage_index action="clear"` is destructive and should be explicit.
40
40
 
41
- - Supports optional `start_line` and `end_line` (1-based, inclusive)
42
- - When no range is provided and file length exceeds `READ_FILE_MAX_LINES` (default `1000`), output is truncated and includes a continuation hint with `path` and next `start_line`
43
- - Optional `mode="annotated"` returns content plus `outlineStatus`, `outline`, `hasMore`, and reindex hints when sidecar data is unavailable
41
+ ## Runtime Requirements
44
42
 
45
- ## Proactive Sync
43
+ Configure an embedding provider and Milvus-compatible backend before indexing. Supported embedding providers are OpenAI, VoyageAI, Gemini, and Ollama. Changing provider, model, dimension, vector store, or schema requires a reindex because those values are part of the index fingerprint.
44
+
45
+ Cloud-quality setup:
46
+
47
+ ```bash
48
+ EMBEDDING_PROVIDER=VoyageAI
49
+ EMBEDDING_MODEL=voyage-4-large
50
+ EMBEDDING_OUTPUT_DIMENSION=1024
51
+ VOYAGEAI_API_KEY=your-api-key
52
+ VOYAGEAI_RERANKER_MODEL=rerank-2.5
53
+ MILVUS_ADDRESS=your-milvus-endpoint
54
+ MILVUS_TOKEN=your-milvus-token
55
+ ```
46
56
 
47
- - Enabled by default. Set `MCP_ENABLE_WATCHER=false` to disable
48
- - Debounce window via `MCP_WATCH_DEBOUNCE_MS` (default `5000`)
49
- - Watchers are session-scoped: startup does not watch every indexed codebase, only roots touched by successful index/search/navigation/read flows in the current session
50
- - Watch events reuse the same incremental sync pipeline (`reindexByChange`)
51
- - Ignore control files (`.satoriignore`, root `.gitignore`) trigger no-reindex reconciliation:
52
- - delete indexed paths now ignored by active rules
53
- - incremental sync picks up newly unignored files
54
- - signature checks in `ensureFreshness` keep this working even when watcher events are missed
55
- - Safety gates:
56
- - Watch-triggered sync only runs for `indexed`/`sync_completed` codebases
57
- - Events are dropped for `indexing`, `indexfailed`, and `requires_reindex`
58
- - Ignored/hidden paths are excluded (`node_modules`, `.git`, build artifacts, dotfiles)
59
- - On shutdown (`SIGINT`/`SIGTERM`), watchers are explicitly closed
57
+ The full generated tool reference below is kept in the npm README for MCP clients and package consumers.
60
58
 
61
59
  <!-- TOOLS_START -->
62
60
 
@@ -84,7 +82,7 @@ Unified semantic search with runtime-first defaults (start with scope="runtime")
84
82
  |---|---|---|---|---|
85
83
  | `path` | string | yes | | ABSOLUTE path to an indexed codebase or subdirectory. |
86
84
  | `query` | string | yes | | Natural-language query. |
87
- | `scope` | enum("runtime", "mixed", "docs") | no | `"runtime"` | Search scope policy. runtime excludes docs/tests, docs returns docs/tests only, mixed includes all. Docs scope skips reranker by policy in the current tool surface. |
85
+ | `scope` | enum("runtime", "mixed", "docs") | no | `"runtime"` | Search scope policy. runtime includes source/runtime code and tests while excluding docs/generated/artifacts/landing/fixtures; docs returns docs/tests only; mixed includes all. Docs scope skips reranker by policy in the current tool surface. |
88
86
  | `resultMode` | enum("grouped", "raw") | no | `"grouped"` | Output mode. grouped returns merged search groups, raw returns chunk hits. |
89
87
  | `groupBy` | enum("symbol", "file") | no | `"symbol"` | Grouping strategy in grouped mode. |
90
88
  | `rankingMode` | enum("default", "auto_changed_first") | no | `"auto_changed_first"` | Ranking policy. auto_changed_first boosts files changed in the current git working tree when available. |
@@ -139,171 +137,21 @@ No parameters.
139
137
 
140
138
  <!-- TOOLS_END -->
141
139
 
142
- ### `read_file.open_symbol` Fields
143
-
144
- `open_symbol` resolves symbols inside the same file passed in `read_file.path`.
145
-
146
- - `symbolId` (string, optional): deterministic symbol id to resolve in `path`.
147
- - `symbolLabel` (string, optional): exact symbol label to resolve in `path`.
148
- - `start_line` (integer, optional): direct 1-based start line for span-based jump.
149
- - `end_line` (integer, optional): direct 1-based end line (inclusive).
150
-
151
- ## MCP Config Examples
152
-
153
- ### JSON-style (Claude Desktop, Cursor)
154
-
155
- ```json
156
- {
157
- "mcpServers": {
158
- "satori": {
159
- "command": "npx",
160
- "args": ["-y", "@zokizuan/satori-mcp@4.10.0"],
161
- "timeout": 180000,
162
- "env": {
163
- "EMBEDDING_PROVIDER": "VoyageAI",
164
- "EMBEDDING_MODEL": "voyage-4-large",
165
- "EMBEDDING_OUTPUT_DIMENSION": "1024",
166
- "VOYAGEAI_API_KEY": "your-api-key",
167
- "VOYAGEAI_RERANKER_MODEL": "rerank-2.5",
168
- "MILVUS_ADDRESS": "your-milvus-endpoint",
169
- "MILVUS_TOKEN": "your-milvus-token"
170
- }
171
- }
172
- }
173
- }
174
- ```
175
-
176
- ### TOML-style (Claude Code CLI)
177
-
178
- ```toml
179
- [mcp_servers.satori]
180
- command = "npx"
181
- args = ["-y", "@zokizuan/satori-mcp@4.10.0"]
182
- startup_timeout_ms = 180000
183
- env = { EMBEDDING_PROVIDER = "VoyageAI", EMBEDDING_MODEL = "voyage-4-large", EMBEDDING_OUTPUT_DIMENSION = "1024", VOYAGEAI_API_KEY = "your-api-key", VOYAGEAI_RERANKER_MODEL = "rerank-2.5", MILVUS_ADDRESS = "your-milvus-endpoint", MILVUS_TOKEN = "your-milvus-token" }
184
- ```
185
-
186
- `MILVUS_TOKEN` is optional auth for endpoints that require it; local unauthenticated Milvus only needs `MILVUS_ADDRESS`.
187
-
188
- ### Local development (when working on this repo)
189
-
190
- ```json
191
- {
192
- "mcpServers": {
193
- "satori": {
194
- "command": "node",
195
- "args": ["/absolute/path/to/satori/packages/mcp/dist/index.js"],
196
- "timeout": 180000,
197
- "env": {
198
- "EMBEDDING_PROVIDER": "VoyageAI",
199
- "EMBEDDING_MODEL": "voyage-4-large",
200
- "EMBEDDING_OUTPUT_DIMENSION": "1024",
201
- "VOYAGEAI_API_KEY": "your-api-key",
202
- "VOYAGEAI_RERANKER_MODEL": "rerank-2.5",
203
- "MILVUS_ADDRESS": "your-milvus-endpoint",
204
- "MILVUS_TOKEN": "your-milvus-token"
205
- }
206
- }
207
- }
208
- }
209
- ```
140
+ ## Notes
210
141
 
211
- Never commit real API keys/tokens into repo config files.
142
+ - `open_symbol` resolves exact symbols inside the same file passed to `read_file.path`.
143
+ - `MILVUS_TOKEN` is optional auth; local unauthenticated Milvus only needs `MILVUS_ADDRESS`.
144
+ - MCP startup does not require provider credentials or a live Milvus backend. Provider-backed calls report `MISSING_PROVIDER_CONFIG` when setup is incomplete.
145
+ - `MISSING_PROVIDER_CONFIG` is an active setup failure only when it appears as a tool response `code` or `reason`.
212
146
 
213
- ## Run Locally
147
+ ## Local Development
214
148
 
215
149
  ```bash
216
150
  pnpm --filter @zokizuan/satori-mcp start
217
- ```
218
-
219
- ## Shell CLI (`@zokizuan/satori-cli`)
220
-
221
- The shell-first installer/client now lives in a separate package: `@zokizuan/satori-cli`.
222
-
223
- ### Install / Uninstall
224
-
225
- Supported installer targets in Phase 1:
226
- - `codex`
227
- - `claude`
228
- - `all`
229
-
230
- Examples:
231
-
232
- ```bash
233
- npx -y @zokizuan/satori-cli@0.3.1 install --client codex
234
- npx -y @zokizuan/satori-cli@0.3.1 install --client claude
235
- npx -y @zokizuan/satori-cli@0.3.1 install --client all --dry-run
236
- npx -y @zokizuan/satori-cli@0.3.1 uninstall --client codex
237
- npx -y @zokizuan/satori-cli@0.3.1 doctor
238
- ```
239
-
240
- Install and uninstall run before MCP session startup, only touch Satori-managed config, and copy/remove these packaged skills:
241
- - `satori-search`
242
- - `satori-navigation`
243
- - `satori-indexing`
244
-
245
- ### Commands
246
-
247
- ```bash
248
- satori-cli tools list
249
- satori-cli tool call <toolName> --args-json '{"path":"/abs/repo","query":"auth"}'
250
- satori-cli tool call <toolName> --args-file ./args.json
251
- satori-cli tool call <toolName> --args-json @-
252
- satori-cli <toolName> [schema-subset flags]
253
- ```
254
-
255
- Global flags (`--startup-timeout-ms`, `--call-timeout-ms`, `--format`, `--debug`) must appear before the command token.
256
- Example: `satori-cli --debug tools list`.
257
-
258
- ### Output + Exit Contract
259
-
260
- - `stdout`: JSON only
261
- - `stderr`: diagnostics and text summaries
262
- - exit `0`: success
263
- - exit `1`: tool-level error (`isError=true` or structured envelope `status!="ok"`)
264
- - exit `2`: usage/argument/schema-subset errors
265
- - exit `3`: startup/transport/protocol/timeout failures
266
-
267
- ### Wrapper Flag Support
268
-
269
- Wrapper mode (`satori-cli <toolName> ...`) supports a strict subset from reflected `tools/list` schemas:
270
-
271
- - primitive properties (`string|number|integer|boolean`)
272
- - enums of primitives
273
- - arrays of primitives (repeat flags in insertion order)
274
- - object properties only via `--<prop>-json '{...}'`
275
-
276
- Tool-level flags that overlap global names are preserved in wrapper mode once command parsing starts.
277
- Example: `satori-cli search_codebase --path /repo --query auth --debug` forwards `debug=true` to the tool.
278
- For boolean wrapper flags, `--flag` implies `true` and `--flag false` is supported.
279
-
280
- Unsupported schema shapes (for example `oneOf`, `anyOf`, `$ref`, complex arrays, nested expansion) return `E_SCHEMA_UNSUPPORTED` with fallback guidance to `--args-json` / `--args-file`.
281
-
282
- ### Run Mode Semantics
283
-
284
- When spawned by `satori-cli`, server process mode is `SATORI_RUN_MODE=cli`:
285
-
286
- - startup background loops are disabled (`verifyCloudState`, watcher mode, background sync)
287
- - stdio safety hardening is enabled (`stdout` protocol-only, logs to `stderr`)
288
- - tool behavior stays on-demand and uses the same six MCP tools
289
-
290
- `SATORI_CLI_STDOUT_GUARD=drop|redirect` controls accidental non-protocol stdout handling (`drop` default).
291
-
292
- ### Startup vs Provider Setup
293
-
294
- MCP startup does not require provider credentials, network access, or a live Milvus backend. The server should complete `initialize` and expose the six tools with an empty provider environment. Provider-backed calls (`manage_index create|reindex|sync|clear` and `search_codebase`) validate their required environment at call time and return `MISSING_PROVIDER_CONFIG` when setup is incomplete.
295
-
296
- `MISSING_PROVIDER_CONFIG` is an active setup failure only when it appears as a tool response `code` or `reason`. Seeing the string inside `search_codebase` results can simply mean the query matched Satori code that implements the setup error.
297
-
298
- ## Development
299
-
300
- ```bash
301
151
  pnpm --filter @zokizuan/satori-mcp build
302
152
  pnpm --filter @zokizuan/satori-mcp typecheck
303
153
  pnpm --filter @zokizuan/satori-mcp test
304
154
  pnpm --filter @zokizuan/satori-mcp docs:check
305
- pnpm --filter @zokizuan/satori-cli build
306
- pnpm --filter @zokizuan/satori-cli test
307
155
  ```
308
156
 
309
- `build` automatically runs docs generation from tool schemas.
157
+ `build` regenerates the tool reference from live tool schemas.
@@ -47,7 +47,7 @@ export interface ResolveRawArgsOptions {
47
47
  stdin?: NodeJS.ReadStream;
48
48
  stdinTimeoutMs: number;
49
49
  }
50
- export type InstallClient = "all" | "claude" | "codex";
50
+ export type InstallClient = "all" | "claude" | "codex" | "opencode";
51
51
  export declare function parseCliArgs(argv: string[]): ParsedCliInput;
52
52
  export declare function resolveRawArguments(rawArgsMode: RawArgsMode, options: ResolveRawArgsOptions): Promise<Record<string, unknown>>;
53
53
  export declare function parseWrapperArgumentsFromSchema(toolName: string, inputSchema: unknown, wrapperArgs: string[]): Record<string, unknown>;
package/dist/cli/args.js CHANGED
@@ -20,7 +20,7 @@ function stripFlagPrefix(token) {
20
20
  }
21
21
  function parseGlobalOptions(argv) {
22
22
  const globals = {
23
- startupTimeoutMs: 180000,
23
+ startupTimeoutMs: 30000,
24
24
  callTimeoutMs: 600000,
25
25
  format: "json",
26
26
  debug: false,
@@ -116,8 +116,8 @@ function parseInstallCommand(kind, args) {
116
116
  const token = args[i];
117
117
  if (token === "--client") {
118
118
  const next = args[i + 1];
119
- if (next !== "all" && next !== "claude" && next !== "codex") {
120
- throw new CliError("E_USAGE", "--client must be one of: all, claude, codex.", 2);
119
+ if (next !== "all" && next !== "claude" && next !== "codex" && next !== "opencode") {
120
+ throw new CliError("E_USAGE", "--client must be one of: all, claude, codex, opencode.", 2);
121
121
  }
122
122
  client = next;
123
123
  i += 1;
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { type ManagedRuntimeCommand } from "./install.js";
2
3
  interface RunCliOptions {
3
4
  writeStdout?: (text: string) => void;
4
5
  writeStderr?: (text: string) => void;
@@ -11,6 +12,7 @@ interface RunCliOptions {
11
12
  callTimeoutMs?: number;
12
13
  cwd?: string;
13
14
  installabilityVerifier?: () => string | Promise<string>;
15
+ installRuntimeCommand?: ManagedRuntimeCommand;
14
16
  connectSession?: (options: {
15
17
  command: string;
16
18
  args: string[];
package/dist/cli/index.js CHANGED
@@ -44,8 +44,8 @@ function buildHelpPayload() {
44
44
  return {
45
45
  usage: "satori-cli <command>",
46
46
  commands: [
47
- "install [--client all|codex|claude] [--dry-run]",
48
- "uninstall [--client all|codex|claude] [--dry-run]",
47
+ "install [--client all|codex|claude|opencode] [--dry-run]",
48
+ "uninstall [--client all|codex|claude|opencode] [--dry-run]",
49
49
  "tools list",
50
50
  "tool call <toolName> --args-json '<json>'",
51
51
  "tool call <toolName> --args-file <path>",
@@ -196,11 +196,14 @@ export async function runCli(argv, options = {}) {
196
196
  return 0;
197
197
  }
198
198
  if (parsed.command.kind === "install" || parsed.command.kind === "uninstall") {
199
+ let packageSpecifier;
199
200
  if (parsed.command.kind === "install") {
200
- await (options.installabilityVerifier || verifyManagedPackageInstallability)();
201
+ packageSpecifier = await (options.installabilityVerifier || verifyManagedPackageInstallability)();
201
202
  }
202
203
  const result = executeInstallCommand(parsed.command, {
203
204
  homeDir: effectiveEnv.HOME,
205
+ packageSpecifier,
206
+ runtimeCommand: options.installRuntimeCommand,
204
207
  });
205
208
  emitJson(writers, result);
206
209
  if (parsed.globals.format === "text") {
@@ -1,5 +1,11 @@
1
+ import { execFileSync } from "node:child_process";
1
2
  import type { InstallClient } from "./args.js";
3
+ type ExecFileSyncLike = typeof execFileSync;
2
4
  type ClientName = Exclude<InstallClient, "all">;
5
+ export interface ManagedRuntimeCommand {
6
+ command: string;
7
+ args: string[];
8
+ }
3
9
  export interface InstallCommandInput {
4
10
  kind: "install" | "uninstall";
5
11
  client: InstallClient;
@@ -9,13 +15,17 @@ export interface InstallCommandOptions {
9
15
  homeDir?: string;
10
16
  packageSpecifier?: string;
11
17
  skillAssetRoot?: string;
18
+ runtimeCommand?: ManagedRuntimeCommand;
19
+ execFileSyncImpl?: ExecFileSyncLike;
12
20
  }
13
21
  export interface ClientInstallResult {
14
22
  client: ClientName;
15
23
  configPath: string;
16
- skillsPath: string;
24
+ skillsPath?: string;
25
+ instructionsPath?: string;
17
26
  configChanged: boolean;
18
27
  skillsChanged: boolean;
28
+ instructionsChanged: boolean;
19
29
  status: "updated" | "unchanged";
20
30
  dryRun: boolean;
21
31
  }