{"record":{"id":"ccd947c3a9918af1","repo":"abhigyanpatwari/GitNexus","slug":"group-resources-are-not-available-in-gitnexus-mcp","errorCode":null,"errorMessage":"Group resources are not available in GitNexus MCP read-only mode.","messagePattern":"Group resources are not available in GitNexus MCP read-only mode\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gitnexus/src/mcp/read-only-policy.ts","lineNumber":73,"sourceCode":"  return !readOnly || !/^gitnexus:\\/\\/group\\//iu.test(uriTemplate);\n}\n\nexport function assertMcpReadOnlyResource(uri: string, readOnly: boolean): void {\n  if (!readOnly) return;\n\n  let isGroupResource = false;\n  try {\n    const parsed = new URL(uri);\n    isGroupResource =\n      parsed.protocol.toLowerCase() === 'gitnexus:' && parsed.hostname.toLowerCase() === 'group';\n  } catch {\n    // Invalid resource URIs are rejected by the normal parser. This fallback\n    // keeps obviously group-shaped malformed inputs fail-closed as well.\n    isGroupResource = /^gitnexus:\\/\\/group(?:\\/|$)/iu.test(uri);\n  }\n\n  if (isGroupResource) {\n    throw new Error('Group resources are not available in GitNexus MCP read-only mode.');\n  }\n}\n\n// Cosmetic only: dispatch enforcement above is the actual boundary. If the\n// generated resource format drifts and a hidden route slips through here, the\n// caller still gets a clean rejection at dispatch.\nexport function filterMcpReadOnlyResourceContent(content: string, readOnly: boolean): string {\n  if (!readOnly) return content;\n  return content\n    .split('\\n')\n    .filter(\n      (line) =>\n        !/^\\s*-\\s+(?:rename|cypher|group_sync|group_list):/u.test(line) &&\n        !/^\\|\\s*`(?:rename|cypher|group_sync|group_list)`\\s*\\|/u.test(line) &&\n        !line.includes('gitnexus://group/'),\n    )\n    .join('\\n');\n}","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/mcp/read-only-policy.ts#L55-L91","documentation":"Thrown by assertMcpReadOnlyResource when reading an MCP resource whose URI targets the group host while read-only mode is active. Any URI that parses to protocol gitnexus: with hostname 'group' (compared case-insensitively, since the non-special gitnexus: scheme keeps opaque hosts) is a group resource; if the URI does not even parse, a fallback regex fails it closed when it still looks group-shaped.","triggerScenarios":"With GITNEXUS_MCP_READ_ONLY=1, reading a resource like gitnexus://group/my-group/contracts, gitnexus://GROUP/my-group/status, or a malformed group-shaped URI such as 'gitnexus://group' via the MCP read_resource / resources/read call.","commonSituations":"A dashboard or agent enumerates resources with a client configured for group mode, then reuses the same URIs against a read-only endpoint. Case-variation ('GITNEXUS://Group/…') is attempted to dodge the filter and still fails, as intended.","solutions":["Read repo-scoped resources instead: gitnexus://repo/{name}/context, .../clusters, .../processes.","Read the flat lists gitnexus://repos and gitnexus://setup, which remain available in read-only mode.","If group resources are required, disable read-only mode on the server."],"exampleFix":"# before (read-only server)\nread_resource 'gitnexus://group/my-group/contracts'\n\n# after\nread_resource 'gitnexus://repo/frontend/contracts'","handlingStrategy":"validation","validationCode":"function isGroupResourceUri(uri: string): boolean {\n  try {\n    const u = new URL(uri);\n    return u.protocol.toLowerCase() === 'gitnexus:' && u.hostname.toLowerCase() === 'group';\n  } catch {\n    return /^gitnexus:\\/\\/group(?:\\/|$)/iu.test(uri);\n  }\n}\nif (readOnly && isGroupResourceUri(uri)) {\n  throw new Error('Group resources disabled in read-only mode; use gitnexus://repo/{name}/...');\n}","typeGuard":"const isReadableInReadOnlyMode = (uri: string): boolean => !isGroupResourceUri(uri);","tryCatchPattern":"try {\n  return await client.readResource({ uri });\n} catch (e) {\n  if (e instanceof Error && e.message.includes('not available in GitNexus MCP read-only mode')) {\n    return null; // skip group resources when iterating a saved bookmark list\n  }\n  throw e;\n}","preventionTips":["Filter saved resource lists through a group-URI check before replaying them against a read-only endpoint.","Prefer enumerating the server's advertised resources; templates are already filtered server-side.","Case tricks do not help (comparisons are case-insensitive) — switch URIs instead."],"tags":["mcp","read-only-mode","resources","group-routing"],"backgroundTag":"readonly-mode-restriction","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","contentChangedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-09-08T20:17:18.057Z"}