@zokizuan/satori-mcp 3.5.0 → 4.0.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
@@ -6,6 +6,8 @@ MCP server for Satori — agent-safe semantic code search and indexing.
6
6
 
7
7
  - Capability-driven execution via `CapabilityResolver`
8
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"`)
9
11
  - First-class `call_graph` tool with deterministic node/edge sorting and TS/Python support
10
12
  - Sidecar-backed `file_outline` tool for per-file symbol navigation and direct call_graph jump handles
11
13
  - Snapshot v3 safety with index fingerprints and strict `requires_reindex` access gates
@@ -45,6 +47,10 @@ Tool surface is hard-broken to 6 tools. This keeps routing explicit while exposi
45
47
  - Enabled by default. Set `MCP_ENABLE_WATCHER=false` to disable
46
48
  - Debounce window via `MCP_WATCH_DEBOUNCE_MS` (default `5000`)
47
49
  - Watch events reuse the same incremental sync pipeline (`reindexByChange`)
50
+ - Ignore control files (`.satoriignore`, root `.gitignore`) trigger no-reindex reconciliation:
51
+ - delete indexed paths now ignored by active rules
52
+ - incremental sync picks up newly unignored files
53
+ - signature checks in `ensureFreshness` keep this working even when watcher events are missed
48
54
  - Safety gates:
49
55
  - Watch-triggered sync only runs for `indexed`/`sync_completed` codebases
50
56
  - Events are dropped for `indexing`, `indexfailed`, and `requires_reindex`
@@ -57,29 +63,29 @@ Tool surface is hard-broken to 6 tools. This keeps routing explicit while exposi
57
63
 
58
64
  ### `manage_index`
59
65
 
60
- Manage index lifecycle operations (create/reindex/sync/status/clear) for a codebase path.
66
+ Manage index lifecycle operations (create/reindex/sync/status/clear) for a codebase path. Ignore-rule edits in repo-root .satoriignore/.gitignore reconcile automatically in the normal sync path. Use action="sync" for immediate convergence and action="reindex" for full rebuild recovery.
61
67
 
62
68
  | Parameter | Type | Required | Default | Description |
63
69
  |---|---|---|---|---|
64
70
  | `action` | enum("create", "reindex", "sync", "status", "clear") | yes | | Required operation to run. |
65
71
  | `path` | string | yes | | ABSOLUTE path to the target codebase. |
66
72
  | `force` | boolean | no | | Only for action='create'. Force rebuild from scratch. |
67
- | `splitter` | enum("ast", "langchain") | no | | Only for action='create'. Code splitter strategy. |
68
73
  | `customExtensions` | array<string> | no | | Only for action='create'. Additional file extensions to include. |
69
74
  | `ignorePatterns` | array<string> | no | | Only for action='create'. Additional ignore patterns to apply. |
70
75
  | `zillizDropCollection` | string | no | | Only for action='create'. Zilliz-only: drop this Satori-managed collection before creating the new index. |
71
76
 
72
77
  ### `search_codebase`
73
78
 
74
- Unified semantic search with runtime/docs scope control, grouped/raw output modes, deterministic ranking, and structured freshness decision.
79
+ Unified semantic search with runtime-first defaults (start with scope="runtime"), grouped/raw output modes, and deterministic ranking/freshness behavior. Operators are parsed from a query prefix block: lang:, path:, -path:, must:, exclude: (escape with \\ to keep literals). Use debug:true for explainability payloads, and rely on response hints for remediation (.satoriignore noise handling, navigation fallback, reindex guidance).
75
80
 
76
81
  | Parameter | Type | Required | Default | Description |
77
82
  |---|---|---|---|---|
78
83
  | `path` | string | yes | | ABSOLUTE path to an indexed codebase or subdirectory. |
79
84
  | `query` | string | yes | | Natural-language query. |
80
- | `scope` | enum("runtime", "mixed", "docs") | no | `"runtime"` | Search scope policy. runtime excludes docs/tests, docs returns docs/tests only, mixed includes all. |
85
+ | `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. |
81
86
  | `resultMode` | enum("grouped", "raw") | no | `"grouped"` | Output mode. grouped returns merged search groups, raw returns chunk hits. |
82
87
  | `groupBy` | enum("symbol", "file") | no | `"symbol"` | Grouping strategy in grouped mode. |
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. |
83
89
  | `limit` | integer | no | `50` | Maximum groups (grouped mode) or chunks (raw mode). |
84
90
  | `debug` | boolean | no | `false` | Optional debug payload toggle for score and fusion breakdowns. |
85
91
 
@@ -106,6 +112,9 @@ Return a sidecar-backed symbol outline for one file, including call_graph jump h
106
112
  | `start_line` | integer | no | | Optional start line filter (1-based, inclusive). |
107
113
  | `end_line` | integer | no | | Optional end line filter (1-based, inclusive). |
108
114
  | `limitSymbols` | integer | no | `500` | Maximum number of returned symbols after line filtering. |
115
+ | `resolveMode` | enum("outline", "exact") | no | `"outline"` | Outline mode returns all symbols (windowed/limited). Exact mode resolves deterministic symbol matches in this file. |
116
+ | `symbolIdExact` | string | no | | Used with resolveMode="exact": exact symbolId match in the target file. |
117
+ | `symbolLabelExact` | string | no | | Used with resolveMode="exact": exact symbol label match in the target file. |
109
118
 
110
119
  ### `read_file`
111
120
 
@@ -117,6 +126,7 @@ Read file content from the local filesystem, with optional 1-based inclusive lin
117
126
  | `start_line` | integer | no | | Optional start line (1-based, inclusive). |
118
127
  | `end_line` | integer | no | | Optional end line (1-based, inclusive). |
119
128
  | `mode` | enum("plain", "annotated") | no | `"plain"` | Output mode. plain returns text only; annotated returns content plus sidecar-backed outline metadata. |
129
+ | `open_symbol` | object | no | | Optional deterministic symbol jump request for this file path. Uses exact symbol resolution within `path` when symbolId/symbolLabel is provided. |
120
130
 
121
131
  ### `list_codebases`
122
132
 
@@ -127,6 +137,15 @@ No parameters.
127
137
 
128
138
  <!-- TOOLS_END -->
129
139
 
140
+ ### `read_file.open_symbol` Fields
141
+
142
+ `open_symbol` resolves symbols inside the same file passed in `read_file.path`.
143
+
144
+ - `symbolId` (string, optional): deterministic symbol id to resolve in `path`.
145
+ - `symbolLabel` (string, optional): exact symbol label to resolve in `path`.
146
+ - `start_line` (integer, optional): direct 1-based start line for span-based jump.
147
+ - `end_line` (integer, optional): direct 1-based end line (inclusive).
148
+
130
149
  ## MCP Config Examples
131
150
 
132
151
  ### JSON-style (Claude Desktop, Cursor)
package/dist/config.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export type EmbeddingProvider = 'OpenAI' | 'VoyageAI' | 'Gemini' | 'Ollama';
2
2
  export type VectorStoreProvider = 'Milvus';
3
3
  export type FingerprintSource = 'verified' | 'assumed_v2';
4
+ export declare const DEFAULT_WATCH_DEBOUNCE_MS = 5000;
4
5
  export interface IndexFingerprint {
5
6
  embeddingProvider: EmbeddingProvider;
6
7
  embeddingModel: string;
@@ -37,6 +38,10 @@ export interface CallGraphSidecarInfo {
37
38
  noteCount: number;
38
39
  fingerprint: IndexFingerprint;
39
40
  }
41
+ export interface CodebaseIndexManifest {
42
+ indexedPaths: string[];
43
+ updatedAt: string;
44
+ }
40
45
  export interface CodebaseSnapshotV1 {
41
46
  indexedCodebases: string[];
42
47
  indexingCodebases: string[] | Record<string, number>;
@@ -48,6 +53,9 @@ interface CodebaseInfoBase {
48
53
  fingerprintSource?: FingerprintSource;
49
54
  reindexReason?: 'legacy_unverified_fingerprint' | 'fingerprint_mismatch' | 'missing_fingerprint';
50
55
  callGraphSidecar?: CallGraphSidecarInfo;
56
+ indexManifest?: CodebaseIndexManifest;
57
+ ignoreRulesVersion?: number;
58
+ ignoreControlSignature?: string;
51
59
  }
52
60
  export interface CodebaseInfoIndexing extends CodebaseInfoBase {
53
61
  status: 'indexing';
package/dist/config.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { envManager } from "@zokizuan/satori-core";
2
+ export const DEFAULT_WATCH_DEBOUNCE_MS = 5000;
2
3
  // Helper function to get default model for each provider
3
4
  export function getDefaultModelForProvider(provider) {
4
5
  switch (provider) {
@@ -51,7 +52,6 @@ export function buildRuntimeIndexFingerprint(config, embeddingDimension) {
51
52
  export function createMcpConfig() {
52
53
  const defaultProvider = envManager.get('EMBEDDING_PROVIDER') || 'VoyageAI';
53
54
  const defaultReadFileMaxLines = 1000;
54
- const defaultWatchDebounceMs = 5000;
55
55
  // Parse output dimension from env var
56
56
  const outputDimensionStr = envManager.get('EMBEDDING_OUTPUT_DIMENSION');
57
57
  let encoderOutputDimension;
@@ -92,7 +92,7 @@ export function createMcpConfig() {
92
92
  const watchSyncEnabled = watchSyncEnabledRaw
93
93
  ? watchSyncEnabledRaw.toLowerCase() === 'true'
94
94
  : true;
95
- let watchDebounceMs = defaultWatchDebounceMs;
95
+ let watchDebounceMs = DEFAULT_WATCH_DEBOUNCE_MS;
96
96
  const watchDebounceRaw = envManager.get('MCP_WATCH_DEBOUNCE_MS');
97
97
  if (watchDebounceRaw) {
98
98
  const parsed = Number.parseInt(watchDebounceRaw, 10);
@@ -100,7 +100,7 @@ export function createMcpConfig() {
100
100
  watchDebounceMs = parsed;
101
101
  }
102
102
  else {
103
- console.warn(`[WARN] Invalid MCP_WATCH_DEBOUNCE_MS value: ${watchDebounceRaw}. Using default ${defaultWatchDebounceMs}.`);
103
+ console.warn(`[WARN] Invalid MCP_WATCH_DEBOUNCE_MS value: ${watchDebounceRaw}. Using default ${DEFAULT_WATCH_DEBOUNCE_MS}.`);
104
104
  }
105
105
  }
106
106
  const config = {
@@ -140,7 +140,7 @@ export function logConfigurationSummary(config) {
140
140
  console.log(`[MCP] Embedding Provider: ${config.encoderProvider}`);
141
141
  console.log(`[MCP] Embedding Model: ${config.encoderModel}`);
142
142
  console.log(`[MCP] Milvus Address: ${config.milvusEndpoint || (config.milvusApiToken ? '[Auto-resolve from token]' : '[Not configured]')}`);
143
- console.log(`[MCP] Proactive Watcher: ${config.watchSyncEnabled ? `enabled (${config.watchDebounceMs || 5000}ms debounce)` : 'disabled'}`);
143
+ console.log(`[MCP] Proactive Watcher: ${config.watchSyncEnabled ? `enabled (${config.watchDebounceMs || DEFAULT_WATCH_DEBOUNCE_MS}ms debounce)` : 'disabled'}`);
144
144
  // Log provider-specific configuration without exposing sensitive data
145
145
  switch (config.encoderProvider) {
146
146
  case 'OpenAI':
@@ -23,9 +23,5 @@ export declare class CapabilityResolver {
23
23
  getDefaultSearchLimit(): number;
24
24
  getMaxSearchLimit(): number;
25
25
  getDefaultRerankEnabled(): boolean;
26
- resolveRerankDecision(useReranker: boolean | undefined): {
27
- enabled: boolean;
28
- blockedByMissingCapability: boolean;
29
- };
30
26
  }
31
27
  //# sourceMappingURL=capabilities.d.ts.map
@@ -58,23 +58,5 @@ export class CapabilityResolver {
58
58
  getDefaultRerankEnabled() {
59
59
  return this.matrix.defaultRerankEnabled;
60
60
  }
61
- resolveRerankDecision(useReranker) {
62
- if (useReranker === true) {
63
- return {
64
- enabled: this.hasReranker(),
65
- blockedByMissingCapability: !this.hasReranker()
66
- };
67
- }
68
- if (useReranker === false) {
69
- return {
70
- enabled: false,
71
- blockedByMissingCapability: false
72
- };
73
- }
74
- return {
75
- enabled: this.getDefaultRerankEnabled(),
76
- blockedByMissingCapability: false
77
- };
78
- }
79
61
  }
80
62
  //# sourceMappingURL=capabilities.js.map
@@ -1,4 +1,5 @@
1
- import { Context } from "@zokizuan/satori-core";
1
+ import { Context, VoyageAIReranker } from "@zokizuan/satori-core";
2
+ import { CapabilityResolver } from "./capabilities.js";
2
3
  import { SnapshotManager } from "./snapshot.js";
3
4
  import { SyncManager } from "./sync.js";
4
5
  import { IndexFingerprint } from "../config.js";
@@ -8,12 +9,15 @@ export declare class ToolHandlers {
8
9
  private context;
9
10
  private snapshotManager;
10
11
  private syncManager;
12
+ private readonly capabilities;
11
13
  private runtimeFingerprint;
12
14
  private indexingStats;
13
15
  private currentWorkspace;
14
16
  private readonly now;
15
17
  private readonly callGraphManager;
16
- constructor(context: Context, snapshotManager: SnapshotManager, syncManager: SyncManager, runtimeFingerprint: IndexFingerprint, now?: () => number, callGraphManager?: CallGraphSidecarManager);
18
+ private readonly reranker;
19
+ private readonly changedFilesCache;
20
+ constructor(context: Context, snapshotManager: SnapshotManager, syncManager: SyncManager, runtimeFingerprint: IndexFingerprint, capabilities: CapabilityResolver, now?: () => number, callGraphManager?: CallGraphSidecarManager, reranker?: VoyageAIReranker | null);
17
21
  private buildReindexInstruction;
18
22
  private buildReindexHint;
19
23
  private summarizeFingerprint;
@@ -34,8 +38,23 @@ export declare class ToolHandlers {
34
38
  private isTestPath;
35
39
  private isDocPath;
36
40
  private isGeneratedPath;
41
+ private isFixturePath;
37
42
  private isEntrypointPath;
38
43
  private classifyPathCategory;
44
+ private classifyNoiseCategory;
45
+ private roundRatio;
46
+ private buildNoiseMitigationHint;
47
+ private tokenizeQueryPrefix;
48
+ private unquoteOperatorValue;
49
+ private parseSearchOperators;
50
+ private pathMatchesAnyPattern;
51
+ private tokenMatchesAnyField;
52
+ private resolveRerankDecision;
53
+ private buildRerankDocument;
54
+ private buildOperatorSummary;
55
+ private parseGitStatusChangedPaths;
56
+ private getChangedFilesForCodebase;
57
+ private applyGroupDiversity;
39
58
  private shouldIncludeCategoryInScope;
40
59
  private parseIndexedAtMs;
41
60
  private getStalenessBucket;
@@ -44,6 +63,8 @@ export declare class ToolHandlers {
44
63
  private buildFallbackGroupId;
45
64
  private isCallGraphLanguageSupported;
46
65
  private buildCallGraphHint;
66
+ private sanitizeIndexedRelativeFilePath;
67
+ private buildNavigationFallback;
47
68
  private normalizeRelativeFilePath;
48
69
  private buildRequiresReindexFileOutlinePayload;
49
70
  private getOutlineStatusForLanguage;
@@ -64,6 +85,8 @@ export declare class ToolHandlers {
64
85
  private parseCodebaseFromMetadata;
65
86
  private resolveCollectionCodebasePath;
66
87
  private formatCollectionTimestamp;
88
+ private parseTimestampMs;
89
+ private resolveCollectionSortTimestampMs;
67
90
  private buildZillizCollectionLimitGuidance;
68
91
  private buildCollectionLimitMessage;
69
92
  private clearAllCollectionsForForceReindex;
@@ -131,6 +154,8 @@ export declare class ToolHandlers {
131
154
  searchPassCount: number;
132
155
  searchPassSuccessCount: number;
133
156
  searchPassFailureCount: number;
157
+ rerankerAttempted: boolean;
158
+ rerankerUsed: boolean;
134
159
  };
135
160
  };
136
161
  isError?: undefined;
@@ -153,6 +178,8 @@ export declare class ToolHandlers {
153
178
  searchPassCount: number;
154
179
  searchPassSuccessCount: number;
155
180
  searchPassFailureCount: number;
181
+ rerankerAttempted: boolean;
182
+ rerankerUsed: boolean;
156
183
  };
157
184
  };
158
185
  } | {