abhigyanpatwari/GitNexus · error
Tool "${toolName}" is not available in GitNexus MCP read-onl
Error message
Tool "${toolName}" is not available in GitNexus MCP read-only mode. What it means
Thrown by assertMcpReadOnlyToolCall when the MCP server runs in read-only mode (GITNEXUS_MCP_READ_ONLY=1) and a client invokes a tool that is not on the read-only allowlist. In read-only mode only the safe query tools in MCP_READ_ONLY_TOOLS and the legacy aliases 'search', 'explore', 'overview' are dispatchable; every mutating or non-allowlisted tool is rejected before it reaches the backend.
Source
Thrown at gitnexus/src/mcp/read-only-policy.ts:37
]);
const MCP_READ_ONLY_ALIASES = new Set(['search', 'explore', 'overview']);
export function resolveMcpReadOnlyMode(env: NodeJS.ProcessEnv = process.env): boolean {
const value = env.GITNEXUS_MCP_READ_ONLY?.trim();
if (value === undefined || value === '' || value === '0') return false;
if (value === '1') return true;
throw new Error('GITNEXUS_MCP_READ_ONLY must be 0 or 1.');
}
export function assertMcpReadOnlyToolCall(
toolName: string,
args: Record<string, unknown> | undefined,
readOnly: boolean,
): void {
if (!readOnly) return;
if (!MCP_READ_ONLY_TOOLS.has(toolName) && !MCP_READ_ONLY_ALIASES.has(toolName)) {
throw new Error(`Tool "${toolName}" is not available in GitNexus MCP read-only mode.`);
}
if (typeof args?.repo === 'string' && args.repo.trim().startsWith('@')) {
throw new Error('Group routing is not available in GitNexus MCP read-only mode.');
}
// crossDepth/subgroup only do anything on the @group path rejected above,
// but rejecting them here keeps the advertised schema and the dispatch
// contract in agreement.
for (const groupOnlyArg of ['crossDepth', 'subgroup']) {
if (args?.[groupOnlyArg] !== undefined) {
throw new Error(
`Parameter "${groupOnlyArg}" is not available in GitNexus MCP read-only mode.`,
);
}
}
}
export function readOnlyResourceTemplateAllowed(uriTemplate: string, readOnly: boolean): boolean {
return !readOnly || !/^gitnexus:\/\/group\//iu.test(uriTemplate);View on GitHub (pinned to aac7515d2a)
Solutions
- Switch the workflow to read-only-safe tools (query, context, impact, explain, and the other allowlisted read tools).
- If the mutation is genuinely required, restart the server with GITNEXUS_MCP_READ_ONLY unset or set to 0.
- Catch this error client-side and report to the user that the endpoint is read-only instead of retrying — retry cannot succeed.
Example fix
// before
await client.callTool({ name: 'rename', arguments: { target: 'parseArgs', new_name: 'parseCliArgs', repo: '.' } });
// after (read-only mode)
await client.callTool({ name: 'query', arguments: { search_query: 'parseArgs', repo: '.' } }); Defensive patterns
Strategy: validation
Validate before calling
const READ_ONLY_OK = new Set(['query', 'context', 'impact', 'explain', 'search', 'explore', 'overview' /* + the rest of the server's allowlist */]);
function assertToolAllowed(tool: string, readOnly: boolean) {
if (readOnly && !READ_ONLY_OK.has(tool)) {
throw new Error(`Tool ${tool} is not available in read-only mode; pick a read-only tool.`);
}
} Type guard
const isReadOnlyTool = (tool: string): boolean => MCP_READ_ONLY_TOOLS.has(tool) || ['search', 'explore', 'overview'].includes(tool);
Try / catch
try {
return await client.callTool({ name, arguments });
} catch (e) {
if (e instanceof Error && /not available in GitNexus MCP read-only mode/.test(e.message)) {
return { skipped: true, reason: 'endpoint is read-only' }; // degrade gracefully, never retry
}
throw e;
} Prevention
- Fetch the server's advertised tool list at connect time and filter workflows to it, instead of hard-coding tool names.
- Keep agent templates parameterized by deployment mode (read-only vs read-write).
- Treat read-only rejections as permanent for the session: surface them to the operator, do not retry.
When it happens
Trigger: With GITNEXUS_MCP_READ_ONLY=1, calling any tool outside the allowlist — e.g. rename, detect_changes, analyze, or any group_* tool — through the MCP client (callTool / tools/call).
Common situations: An operator hardens a shared MCP endpoint with read-only mode, then an agent re-runs its usual workflow that includes rename or detect_changes. A prompt/agent template written for read-write mode is reused against a read-only deployment.
Related errors
- Group routing is not available in GitNexus MCP read-only mod
- GITNEXUS_MCP_READ_ONLY must be 0 or 1.
- Parameter "${groupOnlyArg}" is not available in GitNexus MCP
- Group resources are not available in GitNexus MCP read-only
- Group routing is unavailable when an MCP repository allowlis
AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20).
Data as JSON: /api/errors/e8a7a360d1fbd59e.
Report an issue: GitHub.