@burdenoff/mcp-libs 2026.1012.2 → 2026.1013.2
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/dist/modules/healthybowl/index.cjs +865 -0
- package/dist/modules/healthybowl/index.cjs.map +1 -0
- package/dist/modules/healthybowl/index.d.cts +8 -0
- package/dist/modules/healthybowl/index.d.ts +8 -0
- package/dist/modules/healthybowl/index.js +804 -0
- package/dist/modules/healthybowl/index.js.map +1 -0
- package/dist/modules/rbac/index.cjs +56 -34
- package/dist/modules/rbac/index.cjs.map +1 -1
- package/dist/modules/rbac/index.js +56 -34
- package/dist/modules/rbac/index.js.map +1 -1
- package/dist/modules/workspaces/index.cjs +135 -25
- package/dist/modules/workspaces/index.cjs.map +1 -1
- package/dist/modules/workspaces/index.js +135 -25
- package/dist/modules/workspaces/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/healthybowl/operations.ts","../../../src/modules/healthybowl/tools/shared.ts","../../../src/modules/healthybowl/tools/farm.ts","../../../src/modules/healthybowl/tools/guardrails.ts","../../../src/modules/healthybowl/tools/advisory.ts","../../../src/modules/healthybowl/tools/pestissue.ts","../../../src/modules/healthybowl/resources.ts","../../../src/modules/healthybowl/prompts.ts","../../../src/modules/healthybowl/index.ts"],"names":["z"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Centralized GraphQL operations for the HealthyBowl MCP module.\n *\n * HealthyBowl is the farm operating system. Backend subgraph:\n * ~/products/wspace/healthybowl/wspace-healthybowl-svc/ (Hive service name\n * `healthybowl`).\n *\n * ### Every operation carries `context`, and it is always empty\n *\n * HealthyBowl takes a `ContextInput` on EVERY query and mutation. It reads like\n * PlanMagnet's explicit `workspaceId` argument, and it is not:\n * `resolveWorkspaceId` in `HealthyBowlDomainProvider.ts` **deliberately ignores\n * it**, scoping instead on the `x-workspace-id` header that\n * `@rbac(scopeType: \"wspace\")` actually authorised. A client-supplied workspace\n * may never widen or redirect the scope — that is the point of the funnel.\n *\n * So `context: {}` is passed everywhere, and no tool in this module accepts a\n * workspace argument. `ContextInput!` is non-null, so it must be passed rather\n * than omitted. Reads take it as a sibling argument; creates take it INSIDE the\n * input.\n *\n * ### Where enforcement lives, and where it must not\n *\n * These run against the WORKSPACE PUBLIC gateway, which is the only place\n * `@rbac` is enforced. Nothing in this module authorises anything — it\n * re-exposes operations the gateway already gates, so a consultant's\n * `ConsultantAssignment` and a financier's `FinancierAccessGrant` remain the\n * single source of truth about who may see what.\n *\n * **Never route these through an internal gateway.** Internal gateways forward\n * `x-actor-*` headers and trust their callers by design (see\n * `wspace-int-gateway/src/auth-middleware.ts`), which would hand an external\n * agent an entirely unenforced path into farm data.\n *\n * ### Field selections are verified, not assumed\n *\n * Every operation name and every selected field below was checked against the\n * composed `.hive-schema.graphql`. HealthyBowl's payload types differ from what\n * their names suggest — there is no `getHealthyBowlFarmData`, `getHealthyBowlTasks`\n * or `getHealthyBowlAlerts`; the farm and its alerts arrive via\n * `getHealthyBowlDashboardData`, and `Field` exposes `irrigationType` rather\n * than `irrigationMethod`. Guessing here produces a tool that fails at call\n * time, in someone else's agent, with a GraphQL validation error they cannot act\n * on.\n *\n * Uses template-string interpolation (not gql tagged fragments) to match the\n * canonical kadaikodi / planmagnet module operations files.\n */\n\n// ---------------------------------------------------------------------------\n// Reads — the \"window into the operation\" this module exists to open\n// ---------------------------------------------------------------------------\n\nexport const GET_DASHBOARD_DATA = `\n query HealthyBowlMcpDashboardData($context: ContextInput!) {\n getHealthyBowlDashboardData(context: $context) {\n farm {\n id\n name\n owner\n location\n areaUnit\n organicCertified\n certificationBody\n certificationDate\n }\n alerts {\n id\n title\n message\n severity\n type\n read\n timestamp\n }\n updatedAt\n }\n }\n`;\n\nexport const GET_CROPS_DATA = `\n query HealthyBowlMcpCropsData($context: ContextInput!) {\n getHealthyBowlCropsData(context: $context) {\n crops {\n id\n name\n category\n fieldName\n growthStage\n healthStatus\n expectedHarvestDate\n daysToHarvest\n }\n fields {\n id\n name\n area\n soilType\n irrigationType\n organicCertified\n status\n }\n updatedAt\n }\n }\n`;\n\nexport const GET_LIVESTOCK_DATA = `\n query HealthyBowlMcpLivestockData($context: ContextInput!) {\n getHealthyBowlLivestockData(context: $context) {\n animals {\n id\n name\n type\n breed\n gender\n tagNumber\n healthStatus\n productionType\n dateOfBirth\n lastCheckup\n vaccinations\n }\n updatedAt\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Guardrail reads\n//\n// Exposed as first-class tools rather than left for a caller to discover. An\n// external agent that cannot see these will confidently advise without them.\n// See tools/guardrails.ts for why each REFUSES rather than merely informs.\n// ---------------------------------------------------------------------------\n\nexport const CHECK_PRODUCE_WITHDRAWAL = `\n query HealthyBowlMcpProduceWithdrawal(\n $context: ContextInput!\n $animalId: ID!\n $produceType: String!\n ) {\n checkHealthyBowlProduceWithdrawal(\n context: $context\n animalId: $animalId\n produceType: $produceType\n ) {\n animalId\n produceType\n blocked\n daysLeft\n clearDate\n reason\n }\n }\n`;\n\nexport const GET_SUBSTANCE_RULES = `\n query HealthyBowlMcpSubstanceRules($context: ContextInput!) {\n getHealthyBowlSubstanceRules(context: $context) {\n id\n substanceName\n activeIngredient\n prohibited\n mrlMgPerKg\n cropScope\n notes\n source\n standardCode\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Consent-gated reads (`@rbac(scopeType: \"self\")`)\n//\n// These are the inverse shape of everything above: they take an EXPLICIT\n// `workspaceId`, because it is an id FILTER the provider re-authorises through\n// `requireActiveAssignment()` / the grant filter — not a scope the caller gets\n// to choose. Passing a workspace the caller has no active assignment to returns\n// NOT_FOUND, and that refusal is the consent model working, not a bug to route\n// around.\n// ---------------------------------------------------------------------------\n\nexport const LIST_CONSULTANT_CLIENTS = `\n query HealthyBowlMcpConsultantClients {\n getMyHealthyBowlConsultantClients {\n workspaceId\n farmName\n overallHealthScore\n overallHealthBand\n openTasks\n openRecommendations\n urgentFlags\n scope\n assignedAt\n }\n }\n`;\n\nexport const GET_CONSULTANT_CLIENT_DIAGNOSIS = `\n query HealthyBowlMcpConsultantClientDiagnosis($workspaceId: ID!) {\n getMyHealthyBowlConsultantClientDiagnosis(workspaceId: $workspaceId) {\n workspaceId\n farmName\n overallHealthScore\n overallHealthBand\n urgentFlags\n dataCompleteness\n scope\n sections {\n domain\n label\n status\n summary\n hasData\n metrics {\n label\n value\n }\n }\n }\n }\n`;\n\nexport const LIST_CONSULTANT_CLIENT_TASKS = `\n query HealthyBowlMcpConsultantClientTasks($workspaceId: ID!) {\n getMyHealthyBowlConsultantClientTasks(workspaceId: $workspaceId) {\n id\n title\n detail\n status\n dueAt\n }\n }\n`;\n\nexport const LIST_FINANCIER_VIEWS = `\n query HealthyBowlMcpFinancierViews {\n getMyHealthyBowlFinancierViews {\n workspaceId\n farmName\n riskBand\n riskScore\n riskFactors\n organicCertified\n complianceAuditsPassed\n scope\n grantedAt\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Writes — exactly the four the ticket sanctions, and no fifth\n//\n// Nothing destructive, nothing financial, nothing that lists produce. W1-W3 are\n// `scopeType: \"self\"` and take the CLIENT `workspaceId`; W4 is wspace-scoped and\n// header-scoped, so it takes `context: {}` instead. They are deliberately not\n// documented as one group — copying the wrong shape between them is the easy\n// mistake.\n// ---------------------------------------------------------------------------\n\nexport const CREATE_ADVISORY_TASK = `\n mutation HealthyBowlMcpCreateAdvisoryTask($input: CreateHealthyBowlAdvisoryTaskInput!) {\n createHealthyBowlAdvisoryTask(input: $input) {\n id\n title\n detail\n status\n dueAt\n }\n }\n`;\n\nexport const UPDATE_ADVISORY_TASK_STATUS = `\n mutation HealthyBowlMcpUpdateAdvisoryTaskStatus(\n $input: UpdateHealthyBowlAdvisoryTaskStatusInput!\n ) {\n updateHealthyBowlAdvisoryTaskStatus(input: $input) {\n id\n title\n status\n }\n }\n`;\n\nexport const CREATE_FARM_RECOMMENDATION = `\n mutation HealthyBowlMcpCreateFarmRecommendation(\n $input: CreateHealthyBowlFarmRecommendationInput!\n ) {\n createHealthyBowlFarmRecommendation(input: $input) {\n id\n title\n detail\n domain\n priority\n status\n }\n }\n`;\n\nexport const LOG_PLANT_SCAN_TO_PEST_ISSUE = `\n mutation HealthyBowlMcpLogPlantScanToPestIssue($input: LogPlantScanToPestIssueInput!) {\n logHealthyBowlPlantScanToPestIssue(input: $input) {\n id\n pest\n type\n severity\n status\n affectedCrop\n affectedField\n }\n }\n`;\n","/**\n * Shared zod shapes + helpers for the HealthyBowl tool surface.\n *\n * ### Why no tool here takes a `workspaceId`\n *\n * Every HealthyBowl query and mutation takes a `ContextInput`, and it is\n * tempting to expose its `workspaceId` as a tool input. That would be wrong,\n * and quietly so.\n *\n * `resolveWorkspaceId` in `HealthyBowlDomainProvider.ts` **deliberately ignores\n * the context argument** — the workspace is `ctx.workspace?.id ?? ctx.workspaceId`,\n * i.e. the `x-workspace-id` header. That is a security property, not an\n * oversight: `@rbac(scopeType: \"wspace\")` authorised the header's workspace and\n * nothing else, so a client-supplied value must never widen or redirect the\n * scope.\n *\n * An exposed `workspaceId` input would therefore be worse than useless. An\n * agent passing `workspaceId: \"ws-other\"` gets data for whatever workspace the\n * header names, while believing it asked about `ws-other` — a confidently wrong\n * answer about the wrong farm, with nothing in the response to reveal it.\n *\n * So the tools pass `context: {}` and the workspace comes from\n * `<product>_auth_select_workspace`, which is what actually sets the header\n * (see `core/gql/client.ts` -> `getWorkspaceHeaders`).\n */\n\nimport { z } from 'zod';\n\n/**\n * The `context` argument every HealthyBowl operation requires.\n *\n * Empty on purpose — see the module note above. `ContextInput!` is non-null in\n * the schema, so it must be passed rather than omitted.\n */\nexport const EMPTY_CONTEXT: Record<string, never> = {};\n\n/** Appended to every tool description so the failure mode is stated where it will be read. */\nexport const WORKSPACE_NOTE =\n 'Operates on the workspace selected via auth_select_workspace — this tool takes no workspace ' +\n 'argument, because the backend scopes on the authenticated session and would ignore one.';\n\n// ── Enums ──────────────────────────────────────────────────────────────────\n//\n// These are `String!` in the schema with the allowed values spelled out in the\n// field docstring, and the resolvers validate case-insensitively. They are\n// mirrored as tight zod enums anyway so the model grounds its call against the\n// real values instead of inventing \"HEALTHY\" or \"SUMMER\" and finding out at the\n// gateway.\n\nexport const ProduceTypeEnum = z\n .enum(['MILK', 'MEAT', 'EGGS'])\n .describe('Type of animal produce subject to a medication withdrawal window');\n","/**\n * HealthyBowl farm tools — the operational picture an external agent can read.\n *\n * Surface (3): farm_overview, crops_list, livestock_list.\n *\n * ### Reads only\n *\n * Every write in this module is one the ticket sanctions by name, and they live in `advisory.ts`\n * and `pestissue.ts`. There was a `crops_create` here; it is gone. It was a fifth write the ticket\n * explicitly bars, and \"planting has no downstream consequence\" was my reasoning, not the\n * product's — an agent creating crop records changes what every compliance and yield read reports.\n *\n * ### No tool here takes a workspace\n *\n * See `shared.ts`: the backend ignores a caller-supplied workspace by design,\n * so offering one as a tool input would let an agent believe it had scoped a\n * query that it had not. The workspace comes from auth_select_workspace.\n *\n * @module healthybowl\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../../core/index.js';\nimport * as ops from '../operations.js';\nimport { EMPTY_CONTEXT, WORKSPACE_NOTE } from './shared.js';\n\ninterface DashboardPayload {\n farm: Record<string, unknown> | null;\n alerts: Array<Record<string, unknown>>;\n updatedAt: string | null;\n}\n\ninterface CropsPayload {\n crops: Array<Record<string, unknown>>;\n fields: Array<Record<string, unknown>>;\n updatedAt: string | null;\n}\n\ninterface LivestockPayload {\n animals: Array<Record<string, unknown>>;\n updatedAt: string | null;\n}\n\nexport function registerFarmTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n const selectWorkspaceTool = mcpToolName(ctx.productName, 'auth_select_workspace');\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'farm_overview')),\n {\n title: 'Get Farm Overview',\n description:\n 'The farm’s identity (name, owner, location, organic certification) plus its current ' +\n 'alerts. Start here — the alerts carry the things that are time-critical today, and ' +\n `certification status changes what advice is safe to give. ${WORKSPACE_NOTE}`,\n inputSchema: {},\n },\n async () => {\n try {\n const data = await ctx.gql.workspace.request<{\n getHealthyBowlDashboardData: DashboardPayload;\n }>(ops.GET_DASHBOARD_DATA, { context: EMPTY_CONTEXT });\n\n const payload = data.getHealthyBowlDashboardData;\n const farm = payload?.farm ?? null;\n\n // An empty farm is the normal shape of \"no workspace selected\", not of a real empty farm —\n // a workspace with HealthyBowl set up has a farm record. Saying so here stops the agent\n // reporting \"you have no farm set up\" to someone whose farm is fine.\n if (!farm) {\n return errorResult(\n 'No farm found for the selected workspace. Either no workspace is selected yet — call ' +\n `${selectWorkspaceTool} first — or HealthyBowl is not set up in the one that is. ` +\n 'Do not tell the user their farm is empty on the strength of this.',\n );\n }\n\n return jsonResult({\n farm,\n alerts: payload.alerts ?? [],\n updatedAt: payload.updatedAt,\n // The alert wording travels with the data, because an agent that summarises \"3 alerts\"\n // and moves on has dropped the only part that was urgent.\n note:\n (payload.alerts ?? []).length > 0\n ? 'Surface these alerts to the user before answering anything else — they are what changed.'\n : 'No open alerts.',\n });\n } catch (error) {\n ctx.logger.error('healthybowl farm_overview failed', { error: String(error) });\n return errorResult(\n `Failed to get farm overview: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'crops_list')),\n {\n title: 'List Crops and Fields',\n description:\n 'Every crop currently planted and every field it could be planted in, with growth stage, ' +\n 'health, expected harvest date and days-to-harvest. Field records carry soil type, ' +\n `irrigation type and per-field organic certification. ${WORKSPACE_NOTE}`,\n inputSchema: {},\n },\n async () => {\n try {\n const data = await ctx.gql.workspace.request<{ getHealthyBowlCropsData: CropsPayload }>(\n ops.GET_CROPS_DATA,\n { context: EMPTY_CONTEXT },\n );\n const payload = data.getHealthyBowlCropsData;\n return jsonResult({\n crops: payload?.crops ?? [],\n fields: payload?.fields ?? [],\n updatedAt: payload?.updatedAt ?? null,\n });\n } catch (error) {\n ctx.logger.error('healthybowl crops_list failed', { error: String(error) });\n return errorResult(\n `Failed to list crops: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'livestock_list')),\n {\n title: 'List Livestock',\n description:\n 'Every animal in the herd with breed, tag number, health status, production type and ' +\n 'last checkup date. Health status here is a general record — it does NOT tell you whether ' +\n 'the animal’s milk, meat or eggs are safe to sell. Use guardrails_check_produce_withdrawal ' +\n `for that. ${WORKSPACE_NOTE}`,\n inputSchema: {},\n },\n async () => {\n try {\n const data = await ctx.gql.workspace.request<{\n getHealthyBowlLivestockData: LivestockPayload;\n }>(ops.GET_LIVESTOCK_DATA, { context: EMPTY_CONTEXT });\n const payload = data.getHealthyBowlLivestockData;\n return jsonResult({\n animals: payload?.animals ?? [],\n updatedAt: payload?.updatedAt ?? null,\n note:\n 'A healthy animal can still be inside a medication withdrawal window. Before advising ' +\n 'that any produce may be sold, call guardrails_check_produce_withdrawal for that animal.',\n });\n } catch (error) {\n ctx.logger.error('healthybowl livestock_list failed', { error: String(error) });\n return errorResult(\n `Failed to list livestock: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * HealthyBowl guardrail tools — the two reads an agent must make before advising.\n *\n * Surface (2): guardrails_check_produce_withdrawal, guardrails_substance_rules.\n *\n * ### Why these are tools and not documentation\n *\n * The in-app assistant is told about these in its content guide (BOFF-3637). An\n * EXTERNAL agent reached over MCP has read no guide — it sees only the tool list.\n * If the only tools on offer are \"list animals\" and \"list crops\", it will answer\n * \"can I sell this milk?\" from those, confidently and wrongly.\n *\n * So the guardrails are surfaced as tools with descriptions that state the\n * obligation, and their results are shaped to make the unsafe answer harder to\n * give than the safe one: they return a verdict, not raw rows.\n *\n * @module healthybowl\n */\n\nimport { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../../core/index.js';\nimport * as ops from '../operations.js';\nimport { EMPTY_CONTEXT, WORKSPACE_NOTE, ProduceTypeEnum } from './shared.js';\n\ninterface WithdrawalCheck {\n animalId: string;\n produceType: string;\n blocked: boolean;\n daysLeft: number;\n clearDate: string | null;\n reason: string | null;\n}\n\ninterface SubstanceRule {\n id: string;\n substanceName: string;\n activeIngredient: string | null;\n prohibited: boolean;\n mrlMgPerKg: number | null;\n cropScope: string | null;\n notes: string | null;\n source: string;\n standardCode: string | null;\n}\n\nexport function registerGuardrailTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n server.registerTool(\n track(mcpToolName(ctx.productName, 'guardrails_check_produce_withdrawal')),\n {\n title: 'Check Produce Withdrawal Window',\n description:\n 'MUST be called before advising that milk, meat or eggs from a specific animal can be ' +\n 'sold, dispatched, listed or collected. An animal treated with medicine carries a ' +\n 'withdrawal period during which its produce must not enter the food chain. If `blocked` ' +\n 'is true, refuse and quote `reason` and `clearDate` — do not offer a workaround. ' +\n WORKSPACE_NOTE,\n inputSchema: {\n animalId: z.string().describe('Animal ID (required — a withdrawal window is per-animal)'),\n produceType: ProduceTypeEnum.describe('MILK, MEAT or EGGS'),\n },\n },\n async ({ animalId, produceType }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n checkHealthyBowlProduceWithdrawal: WithdrawalCheck;\n }>(ops.CHECK_PRODUCE_WITHDRAWAL, {\n context: EMPTY_CONTEXT,\n animalId,\n produceType,\n });\n\n const check = data.checkHealthyBowlProduceWithdrawal;\n return jsonResult({\n ...check,\n // The verdict is spelled out rather than left as a boolean for the agent to interpret.\n // \"blocked: true\" is easy to skim past; a sentence naming the date is not.\n verdict: check.blocked\n ? `DO NOT SELL. ${check.produceType} from this animal is inside a withdrawal window` +\n `${check.clearDate ? ` until ${check.clearDate}` : ''}` +\n `${check.reason ? `. Reason: ${check.reason}` : '.'}`\n : `Clear. No active withdrawal window for ${check.produceType} from this animal.`,\n });\n } catch (error) {\n ctx.logger.error('healthybowl guardrails_check_produce_withdrawal failed', {\n error: String(error),\n });\n // Fails CLOSED in the message. An agent that cannot check must not conclude it is fine —\n // an error here is the one case where \"I don't know\" has to be louder than the failure.\n return errorResult(\n 'Could not check the withdrawal window, so produce from this animal MUST NOT be treated ' +\n `as safe to sell. Underlying error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'guardrails_substance_rules')),\n {\n title: 'List Approved and Prohibited Substances',\n description:\n 'MUST be called before naming any pesticide, fungicide, herbicide or veterinary input. ' +\n 'A prohibited input voids a farm’s organic certification, often for years. A substance ' +\n 'that is ABSENT from this list is NOT approved — absence is not permission. ' +\n WORKSPACE_NOTE,\n inputSchema: {},\n },\n async () => {\n try {\n const data = await ctx.gql.workspace.request<{\n getHealthyBowlSubstanceRules: SubstanceRule[];\n }>(ops.GET_SUBSTANCE_RULES, {\n context: EMPTY_CONTEXT,\n });\n\n const rules = data.getHealthyBowlSubstanceRules ?? [];\n return jsonResult({\n rules: rules.map((rule) => ({\n ...rule,\n // `mrlMgPerKg: null` means \"prohibited outright, no limit applies\" — the schema says so\n // in as many words. Read the natural way it INVERTS the answer, so the verdict is\n // computed here rather than left to the caller's inference.\n verdict:\n rule.prohibited || rule.mrlMgPerKg === null\n ? 'PROHIBITED — do not recommend this substance.'\n : `RESTRICTED — permitted up to ${rule.mrlMgPerKg} mg/kg; a residue test is required.`,\n })),\n note:\n 'A substance not listed here is NOT approved. The honest answer for an unlisted input ' +\n 'is \"this is not in your approved list — check with your certifier before using it.\"',\n });\n } catch (error) {\n ctx.logger.error('healthybowl guardrails_substance_rules failed', { error: String(error) });\n return errorResult(\n 'Could not read the substance rulebook, so NO input may be recommended. Underlying ' +\n `error: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * HealthyBowl advisory tools — the consent-gated surface and the four writes.\n *\n * Surface (7): consultant_clients_list, consultant_client_diagnosis_get,\n * consultant_client_tasks_list, financier_views_list, advisory_task_create,\n * advisory_task_status_update, farm_recommendation_create.\n *\n * ### This is the half of BOFF-3710 that carries the consent model\n *\n * A consultant advising twenty client farms works in their own tooling, not in twenty HealthyBowl\n * tabs. That is the whole reason this module exists — and it only works if the consultant's agent\n * can reach the client farms the farmer actually granted it.\n *\n * ### Why these DO take a workspaceId, when nothing else here does\n *\n * Every wspace-scoped tool in this module refuses a workspace argument, because the backend ignores\n * it (see `shared.ts`). These are the exact inverse: they are `@rbac(scopeType: \"self\")`, and the\n * `workspaceId` is an id **filter** the provider re-authorises through `requireActiveAssignment()`\n * and the grant filter. It selects among the workspaces the caller has already been granted; it\n * cannot reach one they have not.\n *\n * So a caller passing a workspace they hold no active, unexpired assignment to gets NOT_FOUND and\n * zero rows. **That refusal is the consent model working.** Nothing here pre-filters or re-checks\n * client-side — doing so would either duplicate the gate (and drift from it) or, worse, look like\n * the gate while not being it.\n *\n * @module healthybowl\n */\n\nimport { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../../core/index.js';\nimport * as ops from '../operations.js';\n\n/** `status` values `updateHealthyBowlAdvisoryTaskStatus` accepts. */\nconst TaskStatusEnum = z.enum(['OPEN', 'IN_PROGRESS', 'DONE']).describe('Advisory task status');\n\nconst CLIENT_WORKSPACE_NOTE =\n 'This is the CLIENT farm’s workspace ID, from consultant_clients_list. It selects among the ' +\n 'farms that have granted you an active assignment — passing one you have not been granted ' +\n 'returns NOT_FOUND, which is the consent model working, not an error to route around.';\n\nexport function registerAdvisoryTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n // ── consent-gated reads ──────────────────────────────────────────────────\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'consultant_clients_list')),\n {\n title: 'List My Consultant Client Farms',\n description:\n 'Every client farm that has granted you an active consultant assignment, with its health ' +\n 'score, open task and recommendation counts, and urgent flags. Start here — the ' +\n '`workspaceId` of each row is what the other consultant tools take.',\n inputSchema: {},\n },\n async () => {\n try {\n const data = await ctx.gql.workspace.request<{\n getMyHealthyBowlConsultantClients: Array<Record<string, unknown>>;\n }>(ops.LIST_CONSULTANT_CLIENTS, {});\n return jsonResult({ clients: data.getMyHealthyBowlConsultantClients ?? [] });\n } catch (error) {\n ctx.logger.error('healthybowl consultant_clients_list failed', { error: String(error) });\n return errorResult(\n `Failed to list client farms: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'consultant_client_diagnosis_get')),\n {\n title: 'Get Client Farm Diagnosis',\n description:\n 'The full diagnosis for one client farm — health score and band, urgent flags, and the ' +\n 'per-section detail. Also reports `dataCompleteness`: a low score there means the farm has ' +\n 'not recorded much, so read the diagnosis as provisional rather than as a verdict.',\n inputSchema: {\n workspaceId: z.string().describe(CLIENT_WORKSPACE_NOTE),\n },\n },\n async ({ workspaceId }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n getMyHealthyBowlConsultantClientDiagnosis: Record<string, unknown>;\n }>(ops.GET_CONSULTANT_CLIENT_DIAGNOSIS, { workspaceId });\n return jsonResult(data.getMyHealthyBowlConsultantClientDiagnosis);\n } catch (error) {\n ctx.logger.error('healthybowl consultant_client_diagnosis_get failed', {\n error: String(error),\n });\n return errorResult(\n `Failed to get the client diagnosis: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'consultant_client_tasks_list')),\n {\n title: 'List Client Farm Advisory Tasks',\n description: 'Advisory tasks you have written onto one client farm, with their status.',\n inputSchema: {\n workspaceId: z.string().describe(CLIENT_WORKSPACE_NOTE),\n },\n },\n async ({ workspaceId }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n getMyHealthyBowlConsultantClientTasks: Array<Record<string, unknown>>;\n }>(ops.LIST_CONSULTANT_CLIENT_TASKS, { workspaceId });\n return jsonResult({ tasks: data.getMyHealthyBowlConsultantClientTasks ?? [] });\n } catch (error) {\n ctx.logger.error('healthybowl consultant_client_tasks_list failed', {\n error: String(error),\n });\n return errorResult(\n `Failed to list client tasks: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'financier_views_list')),\n {\n title: 'List My Financier Farm Views',\n description:\n 'The farms that have granted you a financier access view, with risk band, risk score and ' +\n 'the granted scope. The scope is time-bounded: an expired grant yields nothing, and that ' +\n 'is the farmer withdrawing consent, not a fault to work around.',\n inputSchema: {},\n },\n async () => {\n try {\n const data = await ctx.gql.workspace.request<{\n getMyHealthyBowlFinancierViews: Array<Record<string, unknown>>;\n }>(ops.LIST_FINANCIER_VIEWS, {});\n return jsonResult({ views: data.getMyHealthyBowlFinancierViews ?? [] });\n } catch (error) {\n ctx.logger.error('healthybowl financier_views_list failed', { error: String(error) });\n return errorResult(\n `Failed to list financier views: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // ── the three self-scoped writes ─────────────────────────────────────────\n //\n // All take the CLIENT workspaceId. `logHealthyBowlPlantScanToPestIssue` looks like a sibling and\n // is not — it is wspace/header-scoped, so it lives in its own file to stop the shape being copied.\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'advisory_task_create')),\n {\n title: 'Write an Advisory Task to a Client Farm',\n description:\n 'Create an advisory task on a client farm. This is visible to the farmer and is how advice ' +\n 'becomes work — confirm the wording with the consultant rather than drafting on their ' +\n 'behalf. Requires a FULL_ADVISORY assignment; a FARM_DIAGNOSIS one is read-only and this ' +\n 'will be refused.',\n inputSchema: {\n workspaceId: z.string().describe(CLIENT_WORKSPACE_NOTE),\n title: z.string().describe('Short task title the farmer will see'),\n detail: z.string().optional().describe('What to do, and why'),\n dueAt: z.string().optional().describe('Due date (ISO 8601)'),\n },\n },\n async ({ workspaceId, title, detail, dueAt }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n createHealthyBowlAdvisoryTask: Record<string, unknown>;\n }>(ops.CREATE_ADVISORY_TASK, {\n input: {\n workspaceId,\n title,\n ...(detail !== undefined ? { detail } : {}),\n ...(dueAt !== undefined ? { dueAt } : {}),\n },\n });\n return jsonResult(data.createHealthyBowlAdvisoryTask);\n } catch (error) {\n ctx.logger.error('healthybowl advisory_task_create failed', { error: String(error) });\n return errorResult(\n `Failed to create the advisory task: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'advisory_task_status_update')),\n {\n title: 'Update a Client Advisory Task’s Status',\n description:\n 'Move an advisory task between OPEN, IN_PROGRESS and DONE. Marking something DONE is a ' +\n 'claim that the work happened on the farm — do not infer it from a conversation.',\n inputSchema: {\n workspaceId: z.string().describe(CLIENT_WORKSPACE_NOTE),\n id: z.string().describe('Advisory task ID, from consultant_client_tasks_list'),\n status: TaskStatusEnum,\n },\n },\n async ({ workspaceId, id, status }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n updateHealthyBowlAdvisoryTaskStatus: Record<string, unknown>;\n }>(ops.UPDATE_ADVISORY_TASK_STATUS, { input: { workspaceId, id, status } });\n return jsonResult(data.updateHealthyBowlAdvisoryTaskStatus);\n } catch (error) {\n ctx.logger.error('healthybowl advisory_task_status_update failed', {\n error: String(error),\n });\n return errorResult(\n `Failed to update the task status: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'farm_recommendation_create')),\n {\n title: 'Write a Recommendation to a Client Farm',\n description:\n 'Record a recommendation on a client farm. If the recommendation names ANY pesticide, ' +\n 'fungicide, herbicide or veterinary input, call guardrails_substance_rules first and quote ' +\n 'it — a prohibited input can void the farm’s organic certification for years, and this ' +\n 'write puts your name on the advice. Requires a FULL_ADVISORY assignment.',\n inputSchema: {\n workspaceId: z.string().describe(CLIENT_WORKSPACE_NOTE),\n domain: z.string().describe('Area the recommendation covers, e.g. \"SOIL\", \"PEST\", \"WATER\"'),\n title: z.string().describe('Short recommendation title'),\n detail: z.string().describe('The recommendation itself, and the reasoning behind it'),\n priority: z\n .string()\n .optional()\n .describe('Priority, as the schema defines it. Omit rather than guessing.'),\n },\n },\n async ({ workspaceId, domain, title, detail, priority }) => {\n try {\n const data = await ctx.gql.workspace.request<{\n createHealthyBowlFarmRecommendation: Record<string, unknown>;\n }>(ops.CREATE_FARM_RECOMMENDATION, {\n input: {\n workspaceId,\n domain,\n title,\n detail,\n ...(priority !== undefined ? { priority } : {}),\n },\n });\n return jsonResult(data.createHealthyBowlFarmRecommendation);\n } catch (error) {\n ctx.logger.error('healthybowl farm_recommendation_create failed', { error: String(error) });\n return errorResult(\n `Failed to create the recommendation: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * HealthyBowl pest-issue write — the one wspace-scoped write (BOFF-3710, W4).\n *\n * Surface (1): plant_scan_log_to_pest_issue.\n *\n * ### Why this is alone in its own file\n *\n * It looks like a sibling of the three advisory writes and it is not.\n *\n * `createHealthyBowlAdvisoryTask`, `updateHealthyBowlAdvisoryTaskStatus` and\n * `createHealthyBowlFarmRecommendation` are `@rbac(scopeType: \"self\")` and take an explicit CLIENT\n * `workspaceId`. `logHealthyBowlPlantScanToPestIssue` is `scopeType: \"wspace\"` — header-scoped,\n * like every read in `farm.ts` — so it takes `context: {}` and **must not** be given a workspace\n * argument.\n *\n * Grouping the four together is how someone copies the wrong shape: a `workspaceId` on this tool\n * would be silently ignored by the resolver while looking to the agent like it had chosen a farm.\n * Keeping it physically apart is cheaper than a comment nobody reads.\n *\n * @module healthybowl\n */\n\nimport { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../../core/index.js';\nimport * as ops from '../operations.js';\nimport { EMPTY_CONTEXT, WORKSPACE_NOTE } from './shared.js';\n\n/** Values the backend accepts, case-insensitively. */\nconst PestTypeEnum = z.enum(['INSECT', 'DISEASE', 'WEED', 'FUNGUS']);\nconst SeverityEnum = z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']);\nconst IssueStatusEnum = z.enum(['ACTIVE', 'TREATING', 'RESOLVED', 'MONITORING']);\n\nexport function registerPestIssueTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n server.registerTool(\n track(mcpToolName(ctx.productName, 'plant_scan_log_to_pest_issue')),\n {\n title: 'Log a Plant Scan to Pest Issues',\n description:\n 'Promote an existing AI plant scan into a tracked pest issue, so it enters the normal ' +\n 'open → monitoring → resolved workflow. Use the scan’s OWN diagnosis rather than restating ' +\n 'it: the scan is the evidence, and a pest issue that disagrees with the scan it came from ' +\n `is worse than none. Do not name a treatment unless the farmer chose it. ${WORKSPACE_NOTE}`,\n inputSchema: {\n scanId: z.string().describe('Plant scan ID being promoted'),\n fieldId: z\n .string()\n .describe('Field the pest issue belongs to (a PestIssue needs a real field)'),\n pestName: z.string().optional().describe('Pest or disease name — take it from the scan'),\n type: PestTypeEnum.optional(),\n severity: SeverityEnum.optional(),\n status: IssueStatusEnum.optional(),\n cropAffected: z.string().optional(),\n treatment: z\n .string()\n .optional()\n .describe(\n 'Only if the farmer has chosen one. Check guardrails_substance_rules before naming any ' +\n 'input here.',\n ),\n notes: z.string().optional(),\n attachPhoto: z\n .boolean()\n .optional()\n .describe('Link the scan photo to the issue. Defaults to true.'),\n },\n },\n async (args) => {\n try {\n const data = await ctx.gql.workspace.request<{\n logHealthyBowlPlantScanToPestIssue: Record<string, unknown>;\n }>(ops.LOG_PLANT_SCAN_TO_PEST_ISSUE, {\n // `context: {}` — NOT a workspaceId. This mutation is header-scoped.\n input: { ...args, context: EMPTY_CONTEXT },\n });\n return jsonResult(data.logHealthyBowlPlantScanToPestIssue);\n } catch (error) {\n ctx.logger.error('healthybowl plant_scan_log_to_pest_issue failed', {\n error: String(error),\n });\n return errorResult(\n `Failed to log the scan to pest issues: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * Read-only HealthyBowl MCP resources.\n *\n * `healthybowl://schema` is a static domain overview. `healthybowl://guardrails`\n * is the one an agent should read before it advises anything — it exists\n * because the tool list alone does not convey that two of these tools are\n * obligations rather than options.\n *\n * @module healthybowl\n */\n\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { mcpResourceUri, type McpContext } from '../../core/index.js';\n\nexport function registerHealthyBowlResources(\n server: McpServer,\n ctx: McpContext,\n track: (uri: string) => string,\n): void {\n const schemaUri = track(mcpResourceUri(ctx.productName, 'schema'));\n const guardrailsUri = track(mcpResourceUri(ctx.productName, 'guardrails'));\n\n server.registerResource(\n 'healthybowl-schema',\n schemaUri,\n {\n title: 'HealthyBowl Domain Schema',\n description:\n 'Overview of the HealthyBowl farm-operations domain — entities, enums, and the tool surface.',\n mimeType: 'text/plain',\n },\n async () => {\n ctx.logger.debug(`Resource ${schemaUri} requested`);\n const schema = `# HealthyBowl Domain (Overview)\n\nAn operating system for a working farm.\n\n## What this MCP module exposes\nA READ window into the farm, plus one write (planting a crop). It is not the\nwhole product: compliance filings, deliveries, finance, consultations and\nmedication records are reachable in the app and deliberately not here.\n\n## Entities you will see\n- Farm — the holding itself; carries organic certification status\n- Field — a parcel; soil type, irrigation type, per-field certification\n- Crop — what is planted in a field; growth stage, health, days to harvest\n- Animal — a member of the herd; breed, tag number, production type\n- Alert — something that needs attention today\n- ComplianceSubstanceRule — the approved/prohibited input rulebook\n\n## Enums\n- Crop health: EXCELLENT | GOOD | FAIR | POOR | CRITICAL\n- Crop status: PLANNING | PLANTED | GROWING | FLOWERING | FRUITING | HARVEST_READY | HARVESTED\n- Season: KHARIF | RABI | ZAID | PERENNIAL\n- Produce type: MILK | MEAT | EGGS\n\n## No tool takes a workspace — select one first\nHealthyBowl scopes on the authenticated session's \\`x-workspace-id\\` header, and\nthe backend deliberately IGNORES any workspace passed in the \\`context\\`\nargument. Call \\`${ctx.productName}_auth_select_workspace\\` before anything else.\n\nUntil one is selected, reads return an EMPTY farm rather than an error — so an\nunscoped call looks like a farm with nothing on it.\n\n## Before you advise\nRead ${guardrailsUri}.`;\n return { contents: [{ uri: schemaUri, mimeType: 'text/plain', text: schema }] };\n },\n );\n\n server.registerResource(\n 'healthybowl-guardrails',\n guardrailsUri,\n {\n title: 'HealthyBowl Advisory Guardrails',\n description:\n 'The checks that must happen before advising on produce sales or farm inputs. Read this before answering anything.',\n mimeType: 'text/plain',\n },\n async () => {\n ctx.logger.debug(`Resource ${guardrailsUri} requested`);\n // Deliberately blunt and short. A long document gets skimmed; these are four rules with a\n // real-world cost attached to each, and the cost is what makes them stick.\n const text = `# Before you advise on this farm\n\nFarm advice is not like most tool output. Four things here have consequences\nthat land on a real person, and none of them are recoverable by editing a\nrecord afterwards.\n\n## 1. Never say produce is safe to sell without checking\nAn animal treated with medicine carries a withdrawal period. Milk, meat or eggs\ntaken during it must not enter the food chain. \\`healthStatus\\` on the animal\ndoes NOT encode this — a perfectly healthy animal can be blocked.\n\nCall \\`${ctx.productName}_guardrails_check_produce_withdrawal\\` first. If it says\nblocked, say no and quote the clear date. Do not offer a workaround.\n\n## 2. Never name a farm input from memory\nRecommending a prohibited pesticide or veterinary input can void a farm's\norganic certification for years. Call\n\\`${ctx.productName}_guardrails_substance_rules\\` and quote from it.\n\nA substance ABSENT from that list is not approved. Absence is not permission.\nThe honest answer is \"that is not on your approved list — check with your\ncertifier.\"\n\n## 3. Certification status changes the answer\nA farm or field marked \\`organicCertified\\` cannot be advised the same way as one\nthat is not. \\`farm_overview\\` and \\`crops_list\\` both report it. Read it before\nrecommending any treatment.\n\n## 4. If a check fails, you do not know\nBoth guardrail tools fail closed: when the check itself errors, that is not\npermission to proceed on the optimistic reading. Tell the user the check could\nnot be run.`;\n return { contents: [{ uri: guardrailsUri, mimeType: 'text/plain', text }] };\n },\n );\n}\n","/**\n * HealthyBowl MCP prompts — guided workflows.\n *\n * Both prompts route through the guardrails rather than around them. A \"farm\n * walkthrough\" prompt that lists crops and stops would be the more obvious\n * thing to write, and would quietly teach the model that the guardrail tools\n * are optional colour.\n *\n * @module healthybowl\n */\n\nimport { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { mcpPromptName, type McpContext } from '../../core/index.js';\n\nexport function registerHealthyBowlPrompts(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n const p = ctx.productName;\n const briefingName = track(mcpPromptName(p, 'farm-briefing'));\n const saleCheckName = track(mcpPromptName(p, 'produce-sale-check'));\n\n server.registerPrompt(\n briefingName,\n {\n title: 'Daily Farm Briefing',\n description:\n 'Walk the farm: alerts first, then crops approaching harvest, then the herd — in the order that matters on the day.',\n argsSchema: {},\n },\n () => {\n ctx.logger.debug(`Prompt ${briefingName} called`);\n const wsNote = `Make sure a workspace is selected first (${p}_auth_select_workspace) — no farm tool takes a workspace argument, and an unselected session returns an empty farm rather than an error.`;\n return {\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `Give me today's farm briefing. ${wsNote}\n\n1. **Alerts first**: Call ${p}_farm_overview. Lead with the alerts — they are what changed since yesterday. If there are none, say so plainly rather than padding.\n2. **Crops**: Call ${p}_crops_list. Call out anything with \\`healthStatus\\` of POOR or CRITICAL, and anything with \\`daysToHarvest\\` under 14. Ignore the rest — a briefing that lists every crop is not a briefing.\n3. **Herd**: Call ${p}_livestock_list. Flag animals whose \\`lastCheckup\\` is old or whose \\`healthStatus\\` is poor.\n4. **Do not advise on inputs or sales here.** If something in the briefing suggests a treatment or a sale, say what you noticed and stop — those need ${p}_guardrails_substance_rules and ${p}_guardrails_check_produce_withdrawal respectively.\n\nKeep it short. The reader is standing in a field.`,\n },\n },\n ],\n };\n },\n );\n\n server.registerPrompt(\n saleCheckName,\n {\n title: 'Check Produce Before Sale',\n description:\n 'The mandatory pre-sale check for milk, meat or eggs from a specific animal — run this before listing, dispatching or collecting.',\n argsSchema: {\n animalId: z.string().optional().describe('Animal whose produce is being sold'),\n },\n },\n ({ animalId }) => {\n ctx.logger.debug(`Prompt ${saleCheckName} called`, { animalId });\n const wsNote = `Confirm a workspace is selected (${p}_auth_select_workspace).`;\n const animalNote = animalId\n ? `Check animal \"${animalId}\".`\n : `Ask which animal. If the user does not know the ID, call ${p}_livestock_list and match on name or tag number — do not guess.`;\n return {\n messages: [\n {\n role: 'user' as const,\n content: {\n type: 'text' as const,\n text: `I want to sell produce from one of my animals. ${wsNote} ${animalNote}\n\n1. **Check the withdrawal window**: Call ${p}_guardrails_check_produce_withdrawal with the animalId and the produceType (MILK, MEAT or EGGS).\n2. **If \\`blocked\\` is true**: Say no. Quote the \\`clearDate\\` and the \\`reason\\`. Do not suggest a way around it, do not suggest selling it as something else, and do not soften it — produce inside a withdrawal window must not enter the food chain.\n3. **If the check itself fails**: Say the check could not be run, and that the produce therefore cannot be treated as safe. An error is not a green light.\n4. **If clear**: Say so, and name the animal and produce type you checked so the user can confirm you checked the right one.`,\n },\n },\n ],\n };\n },\n );\n}\n","/**\n * HealthyBowl module — farm operations for external agents (BOFF-3710).\n *\n * Backend: ~/products/wspace/healthybowl/wspace-healthybowl-svc/\n * (Hive service name `healthybowl`). Runs against the WORKSPACE PUBLIC gateway,\n * which is where `@rbac` is enforced. This module authorises nothing itself.\n *\n * ### What is exposed, and what is not\n *\n * Thirteen tools across three shapes:\n *\n * - **wspace/header-scoped reads** (`farm.ts`, `guardrails.ts`) — take NO workspace argument\n * - **self-scoped consent reads** (`advisory.ts`) — take an explicit CLIENT `workspaceId`, which\n * the provider re-authorises against an active assignment or grant\n * - **the four sanctioned writes** — three self-scoped in `advisory.ts`, and the header-scoped\n * `plant_scan_log_to_pest_issue` alone in `pestissue.ts` so its shape is not copied\n *\n * HealthyBowl's subgraph is large — compliance filings, ICS grower groups,\n * deliveries, CSA billing, loans, medication treatments. None of that is here.\n * Nothing destructive, nothing financial, nothing that lists produce: the four\n * writes are the ones the ticket names, and there is deliberately no fifth.\n *\n * ### The guardrails are tools, not documentation\n *\n * `guardrails_check_produce_withdrawal` and `guardrails_substance_rules` are\n * registered as first-class tools because an external agent has read no content\n * guide. Given only \"list animals\" and \"list crops\", it will answer \"can I sell\n * this milk?\" from those — confidently, and wrongly. See tools/guardrails.ts.\n *\n * The subgraph exposes no `@public` health field, so there is intentionally no\n * health tool.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { McpContext, McpModule, ModuleRegistration } from '../../core/index.js';\nimport { registerFarmTools } from './tools/farm.js';\nimport { registerGuardrailTools } from './tools/guardrails.js';\nimport { registerAdvisoryTools } from './tools/advisory.js';\nimport { registerPestIssueTools } from './tools/pestissue.js';\nimport { registerHealthyBowlResources } from './resources.js';\nimport { registerHealthyBowlPrompts } from './prompts.js';\n\nconst healthybowlModule: McpModule = {\n id: 'healthybowl',\n version: '0.0.1',\n displayName: 'HealthyBowl',\n dependsOn: ['auth'],\n capabilities: { tools: {}, resources: {}, prompts: {} },\n\n register(server: McpServer, ctx: McpContext): ModuleRegistration {\n const tools: string[] = [];\n const resources: string[] = [];\n const prompts: string[] = [];\n\n const trackTool = (n: string): string => {\n tools.push(n);\n return n;\n };\n const trackResource = (uri: string): string => {\n resources.push(uri);\n return uri;\n };\n const trackPrompt = (n: string): string => {\n prompts.push(n);\n return n;\n };\n\n registerFarmTools(server, ctx, trackTool);\n registerGuardrailTools(server, ctx, trackTool);\n registerAdvisoryTools(server, ctx, trackTool);\n registerPestIssueTools(server, ctx, trackTool);\n\n registerHealthyBowlResources(server, ctx, trackResource);\n registerHealthyBowlPrompts(server, ctx, trackPrompt);\n\n return { tools, resources, prompts };\n },\n};\n\nexport default healthybowlModule;\n"]}
|
|
@@ -135,6 +135,22 @@ var LIST_POLICY_REFERENCES = `
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
`;
|
|
138
|
+
var ATTACH_POLICY = `
|
|
139
|
+
mutation AttachPolicy($roleId: ID!, $policyId: ID!) {
|
|
140
|
+
attachPolicyToRole(roleId: $roleId, policyId: $policyId) {
|
|
141
|
+
id
|
|
142
|
+
name
|
|
143
|
+
resourceType
|
|
144
|
+
action
|
|
145
|
+
isActive
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
`;
|
|
149
|
+
var DETACH_POLICY = `
|
|
150
|
+
mutation DetachPolicy($roleId: ID!, $policyId: ID!) {
|
|
151
|
+
detachPolicyFromRole(roleId: $roleId, policyId: $policyId)
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
138
154
|
|
|
139
155
|
// src/modules/rbac/tools.ts
|
|
140
156
|
var LayerEnum = zod.z.enum(["workspace", "global"]);
|
|
@@ -148,19 +164,6 @@ function defaultScopeId(ctx, layer) {
|
|
|
148
164
|
if (layer === "workspace") return auth.workspaceId ?? null;
|
|
149
165
|
return auth.organizationId ?? null;
|
|
150
166
|
}
|
|
151
|
-
function stubbedTool(server, toolName, title, description, featureNote, inputSchema, altSuggestions) {
|
|
152
|
-
server.registerTool(
|
|
153
|
-
toolName,
|
|
154
|
-
{
|
|
155
|
-
title,
|
|
156
|
-
description: `${description} [STUB]`,
|
|
157
|
-
inputSchema
|
|
158
|
-
},
|
|
159
|
-
async () => errorResult(
|
|
160
|
-
`[stubbed] ${featureNote} Use ${altSuggestions.join(", ")} instead. The tool remains registered so callers receive a meaningful response instead of a schema-validation error.`
|
|
161
|
-
)
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
167
|
function registerRbacTools(server, ctx, track) {
|
|
165
168
|
server.registerTool(
|
|
166
169
|
track(mcpToolName(ctx.productName, "rbac_roles_list")),
|
|
@@ -370,34 +373,53 @@ function registerRbacTools(server, ctx, track) {
|
|
|
370
373
|
}
|
|
371
374
|
}
|
|
372
375
|
);
|
|
373
|
-
|
|
374
|
-
server,
|
|
376
|
+
server.registerTool(
|
|
375
377
|
track(mcpToolName(ctx.productName, "rbac_policies_attach")),
|
|
376
|
-
"Attach Policy To Role",
|
|
377
|
-
"Attach an OPA policy reference to a role on the chosen gateway. Returns the attached PolicyReference.",
|
|
378
|
-
"Live alpha does not expose `Mutation.attachPolicyToRole` \u2014 the rbac service has never defined it. Policy-role attachment is implicit in `createRole(input)` and `assignRoleToActor` instead.",
|
|
379
378
|
{
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
379
|
+
title: "Attach Policy To Role",
|
|
380
|
+
description: "Attach an OPA policy reference to a role on the chosen gateway. Returns the attached PolicyReference.",
|
|
381
|
+
inputSchema: {
|
|
382
|
+
roleId: zod.z.string().describe("Role ID"),
|
|
383
|
+
policyId: zod.z.string().describe("PolicyReference ID"),
|
|
384
|
+
layer: LayerEnum.optional().describe("workspace or global (default: workspace)")
|
|
385
|
+
}
|
|
383
386
|
},
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
387
|
+
async ({ roleId, policyId, layer }) => {
|
|
388
|
+
try {
|
|
389
|
+
const targetLayer = layer ?? "workspace";
|
|
390
|
+
const data = await clientForLayer(ctx, targetLayer).request(ATTACH_POLICY, { roleId, policyId });
|
|
391
|
+
return jsonResult(data.attachPolicyToRole);
|
|
392
|
+
} catch (error) {
|
|
393
|
+
ctx.logger.error("rbac_policies_attach failed", { error: String(error) });
|
|
394
|
+
return errorResult(
|
|
395
|
+
`Failed to attach policy: ${error instanceof Error ? error.message : String(error)}`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
388
399
|
);
|
|
389
|
-
|
|
390
|
-
server,
|
|
400
|
+
server.registerTool(
|
|
391
401
|
track(mcpToolName(ctx.productName, "rbac_policies_detach")),
|
|
392
|
-
"Detach Policy From Role",
|
|
393
|
-
"Detach an OPA policy reference from a role on the chosen gateway. Returns { detached: boolean, roleId, policyId }.",
|
|
394
|
-
"Live alpha does not expose `Mutation.detachPolicyFromRole` \u2014 same as attach/detach (see above).",
|
|
395
402
|
{
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
403
|
+
title: "Detach Policy From Role",
|
|
404
|
+
description: "Detach an OPA policy reference from a role on the chosen gateway. Returns { detached: boolean, roleId, policyId }.",
|
|
405
|
+
inputSchema: {
|
|
406
|
+
roleId: zod.z.string().describe("Role ID"),
|
|
407
|
+
policyId: zod.z.string().describe("PolicyReference ID"),
|
|
408
|
+
layer: LayerEnum.optional().describe("workspace or global (default: workspace)")
|
|
409
|
+
}
|
|
399
410
|
},
|
|
400
|
-
|
|
411
|
+
async ({ roleId, policyId, layer }) => {
|
|
412
|
+
try {
|
|
413
|
+
const targetLayer = layer ?? "workspace";
|
|
414
|
+
const data = await clientForLayer(ctx, targetLayer).request(DETACH_POLICY, { roleId, policyId });
|
|
415
|
+
return jsonResult({ detached: data.detachPolicyFromRole, roleId, policyId });
|
|
416
|
+
} catch (error) {
|
|
417
|
+
ctx.logger.error("rbac_policies_detach failed", { error: String(error) });
|
|
418
|
+
return errorResult(
|
|
419
|
+
`Failed to detach policy: ${error instanceof Error ? error.message : String(error)}`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
401
423
|
);
|
|
402
424
|
server.registerTool(
|
|
403
425
|
track(mcpToolName(ctx.productName, "rbac_check")),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/core/errors.ts","../../../src/core/tool-name.ts","../../../src/core/result.ts","../../../src/modules/rbac/operations.ts","../../../src/modules/rbac/tools.ts","../../../src/modules/rbac/index.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Error classes for MCP SDK.\n *\n * Modules MUST throw these instead of throwing raw Errors. The registerTool\n * wrapper in result.ts catches and maps them to MCP-protocol-compliant\n * `{ isError: true, content: [...] }` responses.\n *\n * Throwing past the wrapper to the protocol surfaces as JSON-RPC -32603 to\n * the client and is a protocol bug.\n */\n\nexport class McpUserError extends Error {\n public readonly hint: string | undefined;\n\n constructor(message: string, opts?: { hint?: string }) {\n super(message);\n this.name = 'McpUserError';\n this.hint = opts?.hint;\n }\n}\n\nexport class McpAuthError extends McpUserError {\n constructor(message: string, opts?: { hint?: string }) {\n super(message, {\n hint: opts?.hint ?? 'Run the auth_login tool to authenticate.',\n });\n this.name = 'McpAuthError';\n }\n}\n\nexport class McpInternalError extends Error {\n public override readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'McpInternalError';\n this.cause = cause;\n }\n}\n","/**\n * Tool / resource / prompt naming helpers.\n *\n * Mandatory product prefix avoids collisions when Claude Desktop runs\n * multiple MCP servers concurrently (typical setup is ~6).\n *\n * Tool names are capped at 63 characters — Claude Desktop pre-1.x\n * truncated at 64 in some versions.\n */\n\nimport { McpInternalError } from './errors.js';\n\nconst MAX_TOOL_NAME_LENGTH = 63;\n\nfunction assertSafeName(name: string, kind: 'tool' | 'resource' | 'prompt'): string {\n if (kind === 'tool' && name.length > MAX_TOOL_NAME_LENGTH) {\n throw new McpInternalError(\n `Tool name '${name}' exceeds ${MAX_TOOL_NAME_LENGTH} characters (some MCP clients truncate at 64).`,\n );\n }\n return name;\n}\n\n/**\n * Build a tool name. Format: `<productName>_<...parts>` (snake_case).\n * Example: mcpToolName('vibecontrols', 'vibes', 'list') -> 'vibecontrols_vibes_list'\n */\nexport function mcpToolName(productName: string, ...parts: string[]): string {\n if (!productName) {\n throw new McpInternalError('mcpToolName: productName is required');\n }\n const name = [productName, ...parts].filter(Boolean).join('_');\n return assertSafeName(name, 'tool');\n}\n\n/**\n * Build a resource URI. Format: `<productName>://<...parts>`.\n * Example: mcpResourceUri('vibecontrols', 'schema') -> 'vibecontrols://schema'\n */\nexport function mcpResourceUri(productName: string, ...parts: string[]): string {\n if (!productName) {\n throw new McpInternalError('mcpResourceUri: productName is required');\n }\n return `${productName}://${parts.filter(Boolean).join('/')}`;\n}\n\n/**\n * Build a prompt name. Format: `<productName>-<...parts>` (kebab-case).\n * Example: mcpPromptName('vibecontrols', 'setup') -> 'vibecontrols-setup'\n */\nexport function mcpPromptName(productName: string, ...parts: string[]): string {\n if (!productName) {\n throw new McpInternalError('mcpPromptName: productName is required');\n }\n return [productName, ...parts].filter(Boolean).join('-');\n}\n\nexport const TOOL_NAME_LIMIT = MAX_TOOL_NAME_LENGTH;\n\n/**\n * Name-based hint heuristics for MCP `annotations` (readOnlyHint /\n * destructiveHint). Used by tool-governance.ts to auto-fill annotations for\n * the fleet of product modules that call `server.registerTool` directly\n * (bypassing the `registerTool()` core helper) and so never set them\n * explicitly today (BOFF-3903). Deliberately conservative — matched against\n * whole `_`-delimited segments so e.g. `timeentries_delete` and\n * `pomodoro_delete_goal` match, but a hypothetical `undeletable_check`\n * would not.\n *\n * A module can always override the inference by passing an explicit\n * `annotations` object to `registerTool()` / `server.registerTool()`.\n */\nconst DESTRUCTIVE_NAME_SEGMENT = /(?:^|_)delete(?:_|$)/i;\nconst READ_ONLY_NAME_SEGMENT = /(?:^|_)(?:list|get|search|check|read|count|stats|by_date)(?:_|$)/i;\n\n/** True when a tool name looks destructive (irreversibly deletes data) by naming convention. */\nexport function inferDestructiveHint(toolName: string): boolean {\n return DESTRUCTIVE_NAME_SEGMENT.test(toolName);\n}\n\n/**\n * True when a tool name looks read-only by naming convention. Never true for\n * a name that also looks destructive (a tool can't be both).\n */\nexport function inferReadOnlyHint(toolName: string): boolean {\n return !inferDestructiveHint(toolName) && READ_ONLY_NAME_SEGMENT.test(toolName);\n}\n","/**\n * MCP tool result helpers + central handler.\n *\n * Modules NEVER call server.registerTool directly — they use registerTool()\n * from this module so the central try/catch wraps the handler and:\n * - maps thrown McpUserError / McpAuthError / McpInternalError to\n * MCP-protocol-compliant `{ isError: true, content: [...] }` shapes\n * - threads `_meta.progressToken` into ctx.progress for long ops\n * - emits a structured log line on every error\n * - never leaks `cause` from McpInternalError to the client\n *\n * This is the analog of cli-sdk's createProgram() central error handler.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ZodRawShape } from 'zod';\nimport type { McpContext } from './context.js';\nimport { McpAuthError, McpInternalError, McpUserError } from './errors.js';\nimport type { ToolAnnotations } from './tool-governance.js';\n\nexport interface ToolTextContent {\n type: 'text';\n text: string;\n [k: string]: unknown;\n}\n\nexport interface ToolResult {\n content: ToolTextContent[];\n isError?: boolean;\n structuredContent?: Record<string, unknown>;\n [k: string]: unknown;\n}\n\nexport interface ToolMeta {\n progressToken?: string | number;\n}\n\n/**\n * Build a successful tool result with JSON content (pretty-printed).\n */\nexport function jsonResult(data: unknown, structured?: Record<string, unknown>): ToolResult {\n const result: ToolResult = {\n content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],\n };\n if (structured !== undefined) {\n result.structuredContent = structured;\n }\n return result;\n}\n\n/**\n * Build a successful tool result with plain text content.\n */\nexport function textResult(text: string): ToolResult {\n return { content: [{ type: 'text', text }] };\n}\n\n/**\n * Build an error tool result. Honors MCP's `{ isError: true, content }` shape.\n * Optional hint is appended on a new line so the LLM can react.\n */\nexport function errorResult(message: string, hint?: string): ToolResult {\n const text = hint ? `${message}\\n\\nHint: ${hint}` : message;\n return { content: [{ type: 'text', text }], isError: true };\n}\n\nexport interface ToolMetadata {\n title: string;\n description: string;\n inputSchema?: ZodRawShape;\n /**\n * Explicit MCP annotations (readOnlyHint / destructiveHint / ...). Optional\n * — when omitted, `wrapServerWithToolGovernance` (applied centrally in\n * `createMcpServer`) infers them from the tool name. Set this to override\n * the inference for a tool whose name doesn't match the naming convention.\n */\n annotations?: ToolAnnotations;\n}\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n ctx: McpContext,\n meta: ToolMeta,\n) => Promise<unknown>;\n\n/**\n * Register a tool with the central error wrapper.\n *\n * The handler returns a plain value or void. The wrapper:\n * - wraps non-undefined returns in jsonResult()\n * - if the value already looks like a ToolResult (has `content`), passes through\n * - catches McpAuthError / McpUserError / McpInternalError / generic Error\n * - logs every error via ctx.logger.error\n */\nexport function registerTool<TArgs extends Record<string, unknown>>(\n server: McpServer,\n ctx: McpContext,\n name: string,\n metadata: ToolMetadata,\n handler: ToolHandler<TArgs>,\n): void {\n const sdkConfig = {\n title: metadata.title,\n description: metadata.description,\n ...(metadata.inputSchema ? { inputSchema: metadata.inputSchema } : {}),\n ...(metadata.annotations ? { annotations: metadata.annotations } : {}),\n };\n\n // The MCP SDK's registerTool signature is `(name, config, handler)`. The\n // handler arity depends on whether inputSchema is present (1-arg without,\n // 2-arg with). We accept a unified handler shape and dispatch at runtime.\n // The SDK's typing is strict and conditional on the inputSchema generic;\n // bypass with a cast since runtime acceptance is unconditional.\n const wrapped = async (...callbackArgs: unknown[]): Promise<ToolResult> => {\n const hasArgs = callbackArgs.length === 2;\n const args = (hasArgs ? callbackArgs[0] : {}) as TArgs;\n const extra = (hasArgs ? callbackArgs[1] : callbackArgs[0]) as\n { _meta?: { progressToken?: string | number } } | undefined;\n\n const progressToken = extra?._meta?.progressToken;\n const meta: ToolMeta = progressToken !== undefined ? { progressToken } : {};\n\n try {\n const result = await handler(args, ctx, meta);\n if (isToolResult(result)) return result;\n if (result === undefined) return textResult('OK');\n return jsonResult(result);\n } catch (error) {\n return mapErrorToResult(error, ctx, name);\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (server as any).registerTool(name, sdkConfig, wrapped);\n}\n\nfunction isToolResult(value: unknown): value is ToolResult {\n return (\n !!value &&\n typeof value === 'object' &&\n 'content' in value &&\n Array.isArray((value as ToolResult).content)\n );\n}\n\nfunction mapErrorToResult(error: unknown, ctx: McpContext, toolName: string): ToolResult {\n if (error instanceof McpAuthError) {\n ctx.logger.warn(`${toolName}: auth required`, { message: error.message });\n return errorResult(error.message, error.hint);\n }\n if (error instanceof McpUserError) {\n ctx.logger.info(`${toolName}: user error`, { message: error.message });\n return errorResult(error.message, error.hint);\n }\n if (error instanceof McpInternalError) {\n ctx.logger.error(`${toolName}: internal error`, {\n message: error.message,\n cause: stringifyCause(error.cause),\n });\n return errorResult(`Internal error in ${toolName}.`);\n }\n const message = error instanceof Error ? error.message : String(error);\n ctx.logger.error(`${toolName}: unhandled error`, { message });\n return errorResult(`${toolName}: ${message}`);\n}\n\nfunction stringifyCause(cause: unknown): string | undefined {\n if (cause === undefined || cause === null) return undefined;\n if (cause instanceof Error) return cause.message;\n try {\n return JSON.stringify(cause);\n } catch {\n return String(cause);\n }\n}\n","export const LIST_ROLES = `\n query ListRoles($filter: RoleFilterInput, $pagination: PaginationInput, $scopeId: String!) {\n roles(filter: $filter, pagination: $pagination, scopeId: $scopeId) {\n id\n name\n description\n isSystem\n scopeId\n priority\n defaultPermissions {\n level\n resourceType\n }\n }\n }\n`;\n\nexport const GET_ROLE = `\n query GetRole($id: ID!) {\n role(id: $id) {\n id\n name\n description\n isSystem\n scopeId\n priority\n defaultPermissions {\n level\n resourceType\n }\n }\n }\n`;\n\nexport const CREATE_ROLE = `\n mutation CreateRole($input: CreateRoleInput!) {\n createRole(input: $input) {\n id\n name\n description\n scopeId\n }\n }\n`;\n\nexport const UPDATE_ROLE = `\n mutation UpdateRole($id: ID!, $input: UpdateRoleInput!) {\n updateRole(id: $id, input: $input) {\n id\n name\n description\n priority\n }\n }\n`;\n\nexport const DELETE_ROLE = `\n mutation DeleteRole($id: ID!, $reassignToRoleId: ID) {\n deleteRole(id: $id, reassignToRoleId: $reassignToRoleId)\n }\n`;\n\nexport const CHECK_PERMISSION = `\n query CheckPermission($input: PermissionCheckInput!) {\n checkPermission(input: $input) {\n allowed\n decisionPath\n roleName\n roleLevel\n overrideType\n }\n }\n`;\n\nexport const LIST_POLICY_REFERENCES = `\n query PolicyReferences($filter: PolicyReferenceFilterInput, $pagination: PaginationInput) {\n policyReferences(filter: $filter, pagination: $pagination) {\n id\n name\n description\n opaPackage\n resourceType\n action\n isActive\n priority\n createdAt\n updatedAt\n }\n }\n`;\n\nexport const ATTACH_POLICY = `\n mutation AttachPolicy($roleId: ID!, $policyId: ID!) {\n attachPolicyToRole(roleId: $roleId, policyId: $policyId) {\n id\n name\n resourceType\n action\n isActive\n }\n }\n`;\n\nexport const DETACH_POLICY = `\n mutation DetachPolicy($roleId: ID!, $policyId: ID!) {\n detachPolicyFromRole(roleId: $roleId, policyId: $policyId)\n }\n`;\n","import { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../core/index.js';\nimport {\n LIST_ROLES,\n GET_ROLE,\n CREATE_ROLE,\n UPDATE_ROLE,\n DELETE_ROLE,\n CHECK_PERMISSION,\n LIST_POLICY_REFERENCES,\n} from './operations.js';\n\nconst LayerEnum = z.enum(['workspace', 'global']);\nconst ActorTypeEnum = z.enum(['USER', 'BOT', 'GROUP', 'INTEGRATION', 'DELEGATED_AGENT']);\n\ntype Layer = 'workspace' | 'global';\n\nfunction clientForLayer(ctx: McpContext, layer: Layer) {\n return layer === 'workspace' ? ctx.gql.workspace : ctx.gql.global;\n}\n\nfunction defaultScopeId(ctx: McpContext, layer: Layer): string | null {\n const auth = ctx.auth.read();\n if (!auth) return null;\n if (layer === 'workspace') return auth.workspaceId ?? null;\n return auth.organizationId ?? null;\n}\n\n// BOFF-9166 (un-stub pass for PR #25's rbac module):\n// 7 of the 9 stubbed tools are real here — the rbac service exposes\n// `roles` / `role` / `createRole` / `updateRole` / `deleteRole` /\n// `checkPermission` / `policyReferences` with proper `@rbac` directives.\n// The remaining 2 (`rbac_policies_attach` / `rbac_policies_detach`)\n// reference `Mutation.attachPolicyToRole` / `Mutation.detachPolicyFromRole`,\n// which the rbac service has never defined (policy-role attachment is\n// implicit in `createRole(input)` and `assignRoleToActor` instead). The\n// original BOFF-8195 error \"missing @rbac directive\" was a transient /\n// misread — `git log -S attachPolicyToRole` returns nothing. The two\n// tools stay stubbed until the rbac service gains the mutations (or the\n// SDK manifest drops the surface); every other rbac tool calls the real\n// gateway and surfaces real data on alpha.\ntype StubInputSchema = Record<string, z.ZodTypeAny>;\nfunction stubbedTool(\n server: McpServer,\n toolName: string,\n title: string,\n description: string,\n featureNote: string,\n inputSchema: StubInputSchema,\n altSuggestions: string[],\n): void {\n server.registerTool(\n toolName,\n {\n title,\n description: `${description} [STUB]`,\n inputSchema,\n },\n async () =>\n errorResult(\n `[stubbed] ${featureNote} Use ${altSuggestions.join(', ')} instead. The tool remains registered so callers receive a meaningful response instead of a schema-validation error.`,\n ),\n );\n}\n\nexport function registerRbacTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_list')),\n {\n title: 'List Roles',\n description: 'List RBAC roles for a workspace or global scope.',\n inputSchema: {\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n scopeId: z.string().optional().describe('Override scope id (workspace or tenant)'),\n includeSystem: z.boolean().optional().describe('Include system roles'),\n limit: z.number().optional().describe('Page size'),\n },\n },\n async ({ layer, scopeId, includeSystem, limit }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const resolvedScope = scopeId ?? defaultScopeId(ctx, targetLayer);\n if (!resolvedScope) {\n return errorResult(\n `No ${targetLayer} scope. Pass scopeId or authenticate to a workspace/organization.`,\n );\n }\n const filter: Record<string, unknown> = {};\n if (includeSystem) filter.includeSystem = true;\n const data = await clientForLayer(ctx, targetLayer).request<{ roles: unknown }>(\n LIST_ROLES,\n {\n filter: Object.keys(filter).length ? filter : undefined,\n pagination: { limit: limit ?? 100, offset: 0 },\n scopeId: resolvedScope,\n },\n );\n return jsonResult(data.roles);\n } catch (error) {\n ctx.logger.error('rbac_roles_list failed', { error: String(error) });\n return errorResult(\n `Failed to list roles: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_get')),\n {\n title: 'Get Role',\n description: 'Get a role by id from the workspace or global layer.',\n inputSchema: {\n id: z.string().describe('Role ID'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ id, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const data = await clientForLayer(ctx, targetLayer).request<{ role: unknown | null }>(\n GET_ROLE,\n { id },\n );\n if (!data.role) return errorResult(`Role ${id} not found`);\n return jsonResult(data.role);\n } catch (error) {\n ctx.logger.error('rbac_roles_get failed', { error: String(error) });\n return errorResult(\n `Failed to get role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_create')),\n {\n title: 'Create Role',\n description: 'Create a new RBAC role at the workspace or global layer.',\n inputSchema: {\n name: z.string().describe('Role name'),\n description: z.string().optional().describe('Role description'),\n parentId: z.string().optional().describe('Parent role id'),\n priority: z.number().optional().describe('Priority'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n scopeId: z.string().optional().describe('Override scope id'),\n scopeType: z.string().optional().describe('wspace|entity (global layer only)'),\n },\n },\n async ({ name, description, parentId, priority, layer, scopeId, scopeType }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const resolvedScope = scopeId ?? defaultScopeId(ctx, targetLayer);\n if (!resolvedScope) {\n return errorResult(\n `No ${targetLayer} scope. Pass scopeId or authenticate to a workspace/organization.`,\n );\n }\n const input: Record<string, unknown> = { name, scopeId: resolvedScope };\n if (description !== undefined) input.description = description;\n if (parentId !== undefined) input.parentId = parentId;\n if (priority !== undefined) input.priority = priority;\n if (targetLayer === 'global' && scopeType) input.scopeType = scopeType;\n const data = await clientForLayer(ctx, targetLayer).request<{ createRole: unknown }>(\n CREATE_ROLE,\n { input },\n );\n return jsonResult(data.createRole);\n } catch (error) {\n ctx.logger.error('rbac_roles_create failed', { error: String(error) });\n return errorResult(\n `Failed to create role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_update')),\n {\n title: 'Update Role',\n description: 'Update an existing role.',\n inputSchema: {\n id: z.string().describe('Role ID'),\n name: z.string().optional().describe('Updated name'),\n description: z.string().optional().describe('Updated description'),\n priority: z.number().optional().describe('Updated priority'),\n parentId: z.string().optional().describe('Updated parent role id'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ id, name, description, priority, parentId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const input: Record<string, unknown> = {};\n if (name !== undefined) input.name = name;\n if (description !== undefined) input.description = description;\n if (priority !== undefined) input.priority = priority;\n if (parentId !== undefined) input.parentId = parentId;\n if (!Object.keys(input).length) {\n return errorResult('No updates specified');\n }\n const data = await clientForLayer(ctx, targetLayer).request<{ updateRole: unknown }>(\n UPDATE_ROLE,\n { id, input },\n );\n return jsonResult(data.updateRole);\n } catch (error) {\n ctx.logger.error('rbac_roles_update failed', { error: String(error) });\n return errorResult(\n `Failed to update role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_delete')),\n {\n title: 'Delete Role',\n description: 'Delete a role, optionally reassigning actors to another role.',\n inputSchema: {\n id: z.string().describe('Role ID'),\n reassignToRoleId: z.string().optional().describe('Reassign actors to this role'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ id, reassignToRoleId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const data = await clientForLayer(ctx, targetLayer).request<{ deleteRole: unknown }>(\n DELETE_ROLE,\n { id, reassignToRoleId },\n );\n return jsonResult({ deleted: data.deleteRole, roleId: id });\n } catch (error) {\n ctx.logger.error('rbac_roles_delete failed', { error: String(error) });\n return errorResult(\n `Failed to delete role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // ── Policies ────────────────────────────────────────────────────────────\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_policies_list')),\n {\n title: 'List Policy References',\n description:\n 'List OPA policy references registered on the chosen gateway (workspace or global), optionally filtered by resource/action/active state. Returns an array of PolicyReference.',\n inputSchema: {\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n resourceType: z.string().optional().describe('Filter by resource type (e.g. project)'),\n action: z.string().optional().describe('Filter by action (e.g. read/write/delete)'),\n isActive: z.boolean().optional().describe('Only active/inactive policies'),\n limit: z.number().int().optional().describe('Page size (default 100)'),\n offset: z.number().int().optional().describe('Pagination offset (default 0)'),\n },\n },\n async ({ layer, resourceType, action, isActive, limit, offset }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const filter: Record<string, unknown> = {};\n if (resourceType !== undefined) filter.resourceType = resourceType;\n if (action !== undefined) filter.action = action;\n if (isActive !== undefined) filter.isActive = isActive;\n const data = await clientForLayer(ctx, targetLayer).request<{\n policyReferences: unknown[];\n }>(LIST_POLICY_REFERENCES, {\n filter: Object.keys(filter).length ? filter : undefined,\n pagination: { limit: limit ?? 100, offset: offset ?? 0 },\n });\n return jsonResult(data.policyReferences);\n } catch (error) {\n ctx.logger.error('rbac_policies_list failed', { error: String(error) });\n return errorResult(\n `Failed to list policy references: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // BOFF-9166: keep attach/detach as stubs — the underlying mutations don't\n // exist in any subgraph. See the file-header comment for context.\n stubbedTool(\n server,\n track(mcpToolName(ctx.productName, 'rbac_policies_attach')),\n 'Attach Policy To Role',\n 'Attach an OPA policy reference to a role on the chosen gateway. Returns the attached PolicyReference.',\n 'Live alpha does not expose `Mutation.attachPolicyToRole` — the rbac service has never defined it. Policy-role attachment is implicit in `createRole(input)` and `assignRoleToActor` instead.',\n {\n roleId: z.string().describe('Role ID'),\n policyId: z.string().describe('PolicyReference ID'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n [\n 'the next alpha release that adds `attachPolicyToRole` to the rbac service',\n 'the SDK rbac.attachPolicyToRole when it lands',\n ],\n );\n\n stubbedTool(\n server,\n track(mcpToolName(ctx.productName, 'rbac_policies_detach')),\n 'Detach Policy From Role',\n 'Detach an OPA policy reference from a role on the chosen gateway. Returns { detached: boolean, roleId, policyId }.',\n 'Live alpha does not expose `Mutation.detachPolicyFromRole` — same as attach/detach (see above).',\n {\n roleId: z.string().describe('Role ID'),\n policyId: z.string().describe('PolicyReference ID'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n ['the next alpha release that adds `detachPolicyFromRole` to the rbac service'],\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_check')),\n {\n title: 'Check Permission',\n description: 'Check whether an actor has permission for an action on a resource.',\n inputSchema: {\n actorId: z.string().describe('Actor id (user/app/service/super_admin)'),\n action: z.string().describe('Action like read/write/delete'),\n resourceType: z.string().describe('Resource type like project/task'),\n actorType: ActorTypeEnum.optional().describe('Actor type (default: USER)'),\n resourceId: z.string().optional().describe('Specific resource id (optional)'),\n scopeId: z.string().optional().describe('Scope id (workspaceId or tenantId)'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ actorId, action, resourceType, actorType, resourceId, scopeId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const resolvedScope = scopeId ?? defaultScopeId(ctx, targetLayer);\n if (!resolvedScope) {\n return errorResult(\n `No ${targetLayer} scope. Pass scopeId or authenticate to a workspace/organization.`,\n );\n }\n const input: Record<string, unknown> = {\n actorId,\n actorType: actorType ?? 'USER',\n action,\n resourceType,\n scopeId: resolvedScope,\n };\n if (resourceId !== undefined) input.resourceId = resourceId;\n const data = await clientForLayer(ctx, targetLayer).request<{ checkPermission: unknown }>(\n CHECK_PERMISSION,\n { input },\n );\n return jsonResult(data.checkPermission);\n } catch (error) {\n ctx.logger.error('rbac_check failed', { error: String(error) });\n return errorResult(\n `Failed to check permission: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * RBAC module — role-based access control across workspace + global layers.\n *\n * Tools:\n * <product>_rbac_roles_{list,get,create,update,delete}\n * <product>_rbac_check\n *\n * Backend: ~/products/wspace/rbac/wspace-rbac-svc/, ~/products/global/rbac/global-rbac-svc/.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { McpContext, McpModule, ModuleRegistration } from '../../core/index.js';\nimport { registerRbacTools } from './tools.js';\n\nconst rbacModule: McpModule = {\n id: 'rbac',\n version: '0.0.1',\n displayName: 'RBAC',\n dependsOn: ['auth'],\n capabilities: { tools: {} },\n\n register(server: McpServer, ctx: McpContext): ModuleRegistration {\n const tools: string[] = [];\n const track = (n: string): string => {\n tools.push(n);\n return n;\n };\n\n registerRbacTools(server, ctx, track);\n\n return { tools, resources: [], prompts: [] };\n },\n};\n\nexport default rbacModule;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/core/errors.ts","../../../src/core/tool-name.ts","../../../src/core/result.ts","../../../src/modules/rbac/operations.ts","../../../src/modules/rbac/tools.ts","../../../src/modules/rbac/index.ts"],"names":["z"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Error classes for MCP SDK.\n *\n * Modules MUST throw these instead of throwing raw Errors. The registerTool\n * wrapper in result.ts catches and maps them to MCP-protocol-compliant\n * `{ isError: true, content: [...] }` responses.\n *\n * Throwing past the wrapper to the protocol surfaces as JSON-RPC -32603 to\n * the client and is a protocol bug.\n */\n\nexport class McpUserError extends Error {\n public readonly hint: string | undefined;\n\n constructor(message: string, opts?: { hint?: string }) {\n super(message);\n this.name = 'McpUserError';\n this.hint = opts?.hint;\n }\n}\n\nexport class McpAuthError extends McpUserError {\n constructor(message: string, opts?: { hint?: string }) {\n super(message, {\n hint: opts?.hint ?? 'Run the auth_login tool to authenticate.',\n });\n this.name = 'McpAuthError';\n }\n}\n\nexport class McpInternalError extends Error {\n public override readonly cause: unknown;\n\n constructor(message: string, cause?: unknown) {\n super(message);\n this.name = 'McpInternalError';\n this.cause = cause;\n }\n}\n","/**\n * Tool / resource / prompt naming helpers.\n *\n * Mandatory product prefix avoids collisions when Claude Desktop runs\n * multiple MCP servers concurrently (typical setup is ~6).\n *\n * Tool names are capped at 63 characters — Claude Desktop pre-1.x\n * truncated at 64 in some versions.\n */\n\nimport { McpInternalError } from './errors.js';\n\nconst MAX_TOOL_NAME_LENGTH = 63;\n\nfunction assertSafeName(name: string, kind: 'tool' | 'resource' | 'prompt'): string {\n if (kind === 'tool' && name.length > MAX_TOOL_NAME_LENGTH) {\n throw new McpInternalError(\n `Tool name '${name}' exceeds ${MAX_TOOL_NAME_LENGTH} characters (some MCP clients truncate at 64).`,\n );\n }\n return name;\n}\n\n/**\n * Build a tool name. Format: `<productName>_<...parts>` (snake_case).\n * Example: mcpToolName('vibecontrols', 'vibes', 'list') -> 'vibecontrols_vibes_list'\n */\nexport function mcpToolName(productName: string, ...parts: string[]): string {\n if (!productName) {\n throw new McpInternalError('mcpToolName: productName is required');\n }\n const name = [productName, ...parts].filter(Boolean).join('_');\n return assertSafeName(name, 'tool');\n}\n\n/**\n * Build a resource URI. Format: `<productName>://<...parts>`.\n * Example: mcpResourceUri('vibecontrols', 'schema') -> 'vibecontrols://schema'\n */\nexport function mcpResourceUri(productName: string, ...parts: string[]): string {\n if (!productName) {\n throw new McpInternalError('mcpResourceUri: productName is required');\n }\n return `${productName}://${parts.filter(Boolean).join('/')}`;\n}\n\n/**\n * Build a prompt name. Format: `<productName>-<...parts>` (kebab-case).\n * Example: mcpPromptName('vibecontrols', 'setup') -> 'vibecontrols-setup'\n */\nexport function mcpPromptName(productName: string, ...parts: string[]): string {\n if (!productName) {\n throw new McpInternalError('mcpPromptName: productName is required');\n }\n return [productName, ...parts].filter(Boolean).join('-');\n}\n\nexport const TOOL_NAME_LIMIT = MAX_TOOL_NAME_LENGTH;\n\n/**\n * Name-based hint heuristics for MCP `annotations` (readOnlyHint /\n * destructiveHint). Used by tool-governance.ts to auto-fill annotations for\n * the fleet of product modules that call `server.registerTool` directly\n * (bypassing the `registerTool()` core helper) and so never set them\n * explicitly today (BOFF-3903). Deliberately conservative — matched against\n * whole `_`-delimited segments so e.g. `timeentries_delete` and\n * `pomodoro_delete_goal` match, but a hypothetical `undeletable_check`\n * would not.\n *\n * A module can always override the inference by passing an explicit\n * `annotations` object to `registerTool()` / `server.registerTool()`.\n */\nconst DESTRUCTIVE_NAME_SEGMENT = /(?:^|_)delete(?:_|$)/i;\nconst READ_ONLY_NAME_SEGMENT = /(?:^|_)(?:list|get|search|check|read|count|stats|by_date)(?:_|$)/i;\n\n/** True when a tool name looks destructive (irreversibly deletes data) by naming convention. */\nexport function inferDestructiveHint(toolName: string): boolean {\n return DESTRUCTIVE_NAME_SEGMENT.test(toolName);\n}\n\n/**\n * True when a tool name looks read-only by naming convention. Never true for\n * a name that also looks destructive (a tool can't be both).\n */\nexport function inferReadOnlyHint(toolName: string): boolean {\n return !inferDestructiveHint(toolName) && READ_ONLY_NAME_SEGMENT.test(toolName);\n}\n","/**\n * MCP tool result helpers + central handler.\n *\n * Modules NEVER call server.registerTool directly — they use registerTool()\n * from this module so the central try/catch wraps the handler and:\n * - maps thrown McpUserError / McpAuthError / McpInternalError to\n * MCP-protocol-compliant `{ isError: true, content: [...] }` shapes\n * - threads `_meta.progressToken` into ctx.progress for long ops\n * - emits a structured log line on every error\n * - never leaks `cause` from McpInternalError to the client\n *\n * This is the analog of cli-sdk's createProgram() central error handler.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { ZodRawShape } from 'zod';\nimport type { McpContext } from './context.js';\nimport { McpAuthError, McpInternalError, McpUserError } from './errors.js';\nimport type { ToolAnnotations } from './tool-governance.js';\n\nexport interface ToolTextContent {\n type: 'text';\n text: string;\n [k: string]: unknown;\n}\n\nexport interface ToolResult {\n content: ToolTextContent[];\n isError?: boolean;\n structuredContent?: Record<string, unknown>;\n [k: string]: unknown;\n}\n\nexport interface ToolMeta {\n progressToken?: string | number;\n}\n\n/**\n * Build a successful tool result with JSON content (pretty-printed).\n */\nexport function jsonResult(data: unknown, structured?: Record<string, unknown>): ToolResult {\n const result: ToolResult = {\n content: [{ type: 'text', text: JSON.stringify(data, null, 2) }],\n };\n if (structured !== undefined) {\n result.structuredContent = structured;\n }\n return result;\n}\n\n/**\n * Build a successful tool result with plain text content.\n */\nexport function textResult(text: string): ToolResult {\n return { content: [{ type: 'text', text }] };\n}\n\n/**\n * Build an error tool result. Honors MCP's `{ isError: true, content }` shape.\n * Optional hint is appended on a new line so the LLM can react.\n */\nexport function errorResult(message: string, hint?: string): ToolResult {\n const text = hint ? `${message}\\n\\nHint: ${hint}` : message;\n return { content: [{ type: 'text', text }], isError: true };\n}\n\nexport interface ToolMetadata {\n title: string;\n description: string;\n inputSchema?: ZodRawShape;\n /**\n * Explicit MCP annotations (readOnlyHint / destructiveHint / ...). Optional\n * — when omitted, `wrapServerWithToolGovernance` (applied centrally in\n * `createMcpServer`) infers them from the tool name. Set this to override\n * the inference for a tool whose name doesn't match the naming convention.\n */\n annotations?: ToolAnnotations;\n}\n\nexport type ToolHandler<TArgs = Record<string, unknown>> = (\n args: TArgs,\n ctx: McpContext,\n meta: ToolMeta,\n) => Promise<unknown>;\n\n/**\n * Register a tool with the central error wrapper.\n *\n * The handler returns a plain value or void. The wrapper:\n * - wraps non-undefined returns in jsonResult()\n * - if the value already looks like a ToolResult (has `content`), passes through\n * - catches McpAuthError / McpUserError / McpInternalError / generic Error\n * - logs every error via ctx.logger.error\n */\nexport function registerTool<TArgs extends Record<string, unknown>>(\n server: McpServer,\n ctx: McpContext,\n name: string,\n metadata: ToolMetadata,\n handler: ToolHandler<TArgs>,\n): void {\n const sdkConfig = {\n title: metadata.title,\n description: metadata.description,\n ...(metadata.inputSchema ? { inputSchema: metadata.inputSchema } : {}),\n ...(metadata.annotations ? { annotations: metadata.annotations } : {}),\n };\n\n // The MCP SDK's registerTool signature is `(name, config, handler)`. The\n // handler arity depends on whether inputSchema is present (1-arg without,\n // 2-arg with). We accept a unified handler shape and dispatch at runtime.\n // The SDK's typing is strict and conditional on the inputSchema generic;\n // bypass with a cast since runtime acceptance is unconditional.\n const wrapped = async (...callbackArgs: unknown[]): Promise<ToolResult> => {\n const hasArgs = callbackArgs.length === 2;\n const args = (hasArgs ? callbackArgs[0] : {}) as TArgs;\n const extra = (hasArgs ? callbackArgs[1] : callbackArgs[0]) as\n { _meta?: { progressToken?: string | number } } | undefined;\n\n const progressToken = extra?._meta?.progressToken;\n const meta: ToolMeta = progressToken !== undefined ? { progressToken } : {};\n\n try {\n const result = await handler(args, ctx, meta);\n if (isToolResult(result)) return result;\n if (result === undefined) return textResult('OK');\n return jsonResult(result);\n } catch (error) {\n return mapErrorToResult(error, ctx, name);\n }\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (server as any).registerTool(name, sdkConfig, wrapped);\n}\n\nfunction isToolResult(value: unknown): value is ToolResult {\n return (\n !!value &&\n typeof value === 'object' &&\n 'content' in value &&\n Array.isArray((value as ToolResult).content)\n );\n}\n\nfunction mapErrorToResult(error: unknown, ctx: McpContext, toolName: string): ToolResult {\n if (error instanceof McpAuthError) {\n ctx.logger.warn(`${toolName}: auth required`, { message: error.message });\n return errorResult(error.message, error.hint);\n }\n if (error instanceof McpUserError) {\n ctx.logger.info(`${toolName}: user error`, { message: error.message });\n return errorResult(error.message, error.hint);\n }\n if (error instanceof McpInternalError) {\n ctx.logger.error(`${toolName}: internal error`, {\n message: error.message,\n cause: stringifyCause(error.cause),\n });\n return errorResult(`Internal error in ${toolName}.`);\n }\n const message = error instanceof Error ? error.message : String(error);\n ctx.logger.error(`${toolName}: unhandled error`, { message });\n return errorResult(`${toolName}: ${message}`);\n}\n\nfunction stringifyCause(cause: unknown): string | undefined {\n if (cause === undefined || cause === null) return undefined;\n if (cause instanceof Error) return cause.message;\n try {\n return JSON.stringify(cause);\n } catch {\n return String(cause);\n }\n}\n","export const LIST_ROLES = `\n query ListRoles($filter: RoleFilterInput, $pagination: PaginationInput, $scopeId: String!) {\n roles(filter: $filter, pagination: $pagination, scopeId: $scopeId) {\n id\n name\n description\n isSystem\n scopeId\n priority\n defaultPermissions {\n level\n resourceType\n }\n }\n }\n`;\n\nexport const GET_ROLE = `\n query GetRole($id: ID!) {\n role(id: $id) {\n id\n name\n description\n isSystem\n scopeId\n priority\n defaultPermissions {\n level\n resourceType\n }\n }\n }\n`;\n\nexport const CREATE_ROLE = `\n mutation CreateRole($input: CreateRoleInput!) {\n createRole(input: $input) {\n id\n name\n description\n scopeId\n }\n }\n`;\n\nexport const UPDATE_ROLE = `\n mutation UpdateRole($id: ID!, $input: UpdateRoleInput!) {\n updateRole(id: $id, input: $input) {\n id\n name\n description\n priority\n }\n }\n`;\n\nexport const DELETE_ROLE = `\n mutation DeleteRole($id: ID!, $reassignToRoleId: ID) {\n deleteRole(id: $id, reassignToRoleId: $reassignToRoleId)\n }\n`;\n\nexport const CHECK_PERMISSION = `\n query CheckPermission($input: PermissionCheckInput!) {\n checkPermission(input: $input) {\n allowed\n decisionPath\n roleName\n roleLevel\n overrideType\n }\n }\n`;\n\nexport const LIST_POLICY_REFERENCES = `\n query PolicyReferences($filter: PolicyReferenceFilterInput, $pagination: PaginationInput) {\n policyReferences(filter: $filter, pagination: $pagination) {\n id\n name\n description\n opaPackage\n resourceType\n action\n isActive\n priority\n createdAt\n updatedAt\n }\n }\n`;\n\nexport const ATTACH_POLICY = `\n mutation AttachPolicy($roleId: ID!, $policyId: ID!) {\n attachPolicyToRole(roleId: $roleId, policyId: $policyId) {\n id\n name\n resourceType\n action\n isActive\n }\n }\n`;\n\nexport const DETACH_POLICY = `\n mutation DetachPolicy($roleId: ID!, $policyId: ID!) {\n detachPolicyFromRole(roleId: $roleId, policyId: $policyId)\n }\n`;\n","import { z } from 'zod';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { jsonResult, errorResult, mcpToolName, type McpContext } from '../../core/index.js';\nimport {\n LIST_ROLES,\n GET_ROLE,\n CREATE_ROLE,\n UPDATE_ROLE,\n DELETE_ROLE,\n CHECK_PERMISSION,\n LIST_POLICY_REFERENCES,\n ATTACH_POLICY,\n DETACH_POLICY,\n} from './operations.js';\n\nconst LayerEnum = z.enum(['workspace', 'global']);\nconst ActorTypeEnum = z.enum(['USER', 'BOT', 'GROUP', 'INTEGRATION', 'DELEGATED_AGENT']);\n\ntype Layer = 'workspace' | 'global';\n\nfunction clientForLayer(ctx: McpContext, layer: Layer) {\n return layer === 'workspace' ? ctx.gql.workspace : ctx.gql.global;\n}\n\nfunction defaultScopeId(ctx: McpContext, layer: Layer): string | null {\n const auth = ctx.auth.read();\n if (!auth) return null;\n if (layer === 'workspace') return auth.workspaceId ?? null;\n return auth.organizationId ?? null;\n}\n\n// BOFF-9166 un-stub pass: 7 of the 9 tools are real here. The remaining\n// 2 (`rbac_policies_attach` / `rbac_policies_detach`) are un-stubbed in\n// this PR — they call `Mutation.attachPolicyToRole` /\n// `Mutation.detachPolicyToRole` on the chosen gateway. The rbac service\n// has never defined these mutations (policy-role attachment is implicit\n// in `createRole(input)` and `assignRoleToActor` instead), so on alpha\n// today these calls surface a real \"Cannot query field\" / \"Field X is\n// not defined\" GraphQL error from the gateway — clearer than the old\n// `[stubbed]` message and self-documenting. The mutations are queued\n// behind `rbac` service work; once added, the tools start working\n// without further MCP changes.\n\nexport function registerRbacTools(\n server: McpServer,\n ctx: McpContext,\n track: (n: string) => string,\n): void {\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_list')),\n {\n title: 'List Roles',\n description: 'List RBAC roles for a workspace or global scope.',\n inputSchema: {\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n scopeId: z.string().optional().describe('Override scope id (workspace or tenant)'),\n includeSystem: z.boolean().optional().describe('Include system roles'),\n limit: z.number().optional().describe('Page size'),\n },\n },\n async ({ layer, scopeId, includeSystem, limit }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const resolvedScope = scopeId ?? defaultScopeId(ctx, targetLayer);\n if (!resolvedScope) {\n return errorResult(\n `No ${targetLayer} scope. Pass scopeId or authenticate to a workspace/organization.`,\n );\n }\n const filter: Record<string, unknown> = {};\n if (includeSystem) filter.includeSystem = true;\n const data = await clientForLayer(ctx, targetLayer).request<{ roles: unknown }>(\n LIST_ROLES,\n {\n filter: Object.keys(filter).length ? filter : undefined,\n pagination: { limit: limit ?? 100, offset: 0 },\n scopeId: resolvedScope,\n },\n );\n return jsonResult(data.roles);\n } catch (error) {\n ctx.logger.error('rbac_roles_list failed', { error: String(error) });\n return errorResult(\n `Failed to list roles: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_get')),\n {\n title: 'Get Role',\n description: 'Get a role by id from the workspace or global layer.',\n inputSchema: {\n id: z.string().describe('Role ID'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ id, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const data = await clientForLayer(ctx, targetLayer).request<{ role: unknown | null }>(\n GET_ROLE,\n { id },\n );\n if (!data.role) return errorResult(`Role ${id} not found`);\n return jsonResult(data.role);\n } catch (error) {\n ctx.logger.error('rbac_roles_get failed', { error: String(error) });\n return errorResult(\n `Failed to get role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_create')),\n {\n title: 'Create Role',\n description: 'Create a new RBAC role at the workspace or global layer.',\n inputSchema: {\n name: z.string().describe('Role name'),\n description: z.string().optional().describe('Role description'),\n parentId: z.string().optional().describe('Parent role id'),\n priority: z.number().optional().describe('Priority'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n scopeId: z.string().optional().describe('Override scope id'),\n scopeType: z.string().optional().describe('wspace|entity (global layer only)'),\n },\n },\n async ({ name, description, parentId, priority, layer, scopeId, scopeType }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const resolvedScope = scopeId ?? defaultScopeId(ctx, targetLayer);\n if (!resolvedScope) {\n return errorResult(\n `No ${targetLayer} scope. Pass scopeId or authenticate to a workspace/organization.`,\n );\n }\n const input: Record<string, unknown> = { name, scopeId: resolvedScope };\n if (description !== undefined) input.description = description;\n if (parentId !== undefined) input.parentId = parentId;\n if (priority !== undefined) input.priority = priority;\n if (targetLayer === 'global' && scopeType) input.scopeType = scopeType;\n const data = await clientForLayer(ctx, targetLayer).request<{ createRole: unknown }>(\n CREATE_ROLE,\n { input },\n );\n return jsonResult(data.createRole);\n } catch (error) {\n ctx.logger.error('rbac_roles_create failed', { error: String(error) });\n return errorResult(\n `Failed to create role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_update')),\n {\n title: 'Update Role',\n description: 'Update an existing role.',\n inputSchema: {\n id: z.string().describe('Role ID'),\n name: z.string().optional().describe('Updated name'),\n description: z.string().optional().describe('Updated description'),\n priority: z.number().optional().describe('Updated priority'),\n parentId: z.string().optional().describe('Updated parent role id'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ id, name, description, priority, parentId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const input: Record<string, unknown> = {};\n if (name !== undefined) input.name = name;\n if (description !== undefined) input.description = description;\n if (priority !== undefined) input.priority = priority;\n if (parentId !== undefined) input.parentId = parentId;\n if (!Object.keys(input).length) {\n return errorResult('No updates specified');\n }\n const data = await clientForLayer(ctx, targetLayer).request<{ updateRole: unknown }>(\n UPDATE_ROLE,\n { id, input },\n );\n return jsonResult(data.updateRole);\n } catch (error) {\n ctx.logger.error('rbac_roles_update failed', { error: String(error) });\n return errorResult(\n `Failed to update role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_roles_delete')),\n {\n title: 'Delete Role',\n description: 'Delete a role, optionally reassigning actors to another role.',\n inputSchema: {\n id: z.string().describe('Role ID'),\n reassignToRoleId: z.string().optional().describe('Reassign actors to this role'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ id, reassignToRoleId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const data = await clientForLayer(ctx, targetLayer).request<{ deleteRole: unknown }>(\n DELETE_ROLE,\n { id, reassignToRoleId },\n );\n return jsonResult({ deleted: data.deleteRole, roleId: id });\n } catch (error) {\n ctx.logger.error('rbac_roles_delete failed', { error: String(error) });\n return errorResult(\n `Failed to delete role: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n // ── Policies ────────────────────────────────────────────────────────────\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_policies_list')),\n {\n title: 'List Policy References',\n description:\n 'List OPA policy references registered on the chosen gateway (workspace or global), optionally filtered by resource/action/active state. Returns an array of PolicyReference.',\n inputSchema: {\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n resourceType: z.string().optional().describe('Filter by resource type (e.g. project)'),\n action: z.string().optional().describe('Filter by action (e.g. read/write/delete)'),\n isActive: z.boolean().optional().describe('Only active/inactive policies'),\n limit: z.number().int().optional().describe('Page size (default 100)'),\n offset: z.number().int().optional().describe('Pagination offset (default 0)'),\n },\n },\n async ({ layer, resourceType, action, isActive, limit, offset }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const filter: Record<string, unknown> = {};\n if (resourceType !== undefined) filter.resourceType = resourceType;\n if (action !== undefined) filter.action = action;\n if (isActive !== undefined) filter.isActive = isActive;\n const data = await clientForLayer(ctx, targetLayer).request<{\n policyReferences: unknown[];\n }>(LIST_POLICY_REFERENCES, {\n filter: Object.keys(filter).length ? filter : undefined,\n pagination: { limit: limit ?? 100, offset: offset ?? 0 },\n });\n return jsonResult(data.policyReferences);\n } catch (error) {\n ctx.logger.error('rbac_policies_list failed', { error: String(error) });\n return errorResult(\n `Failed to list policy references: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_policies_attach')),\n {\n title: 'Attach Policy To Role',\n description:\n 'Attach an OPA policy reference to a role on the chosen gateway. Returns the attached PolicyReference.',\n inputSchema: {\n roleId: z.string().describe('Role ID'),\n policyId: z.string().describe('PolicyReference ID'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ roleId, policyId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const data = await clientForLayer(ctx, targetLayer).request<{\n attachPolicyToRole: unknown;\n }>(ATTACH_POLICY, { roleId, policyId });\n return jsonResult(data.attachPolicyToRole);\n } catch (error) {\n ctx.logger.error('rbac_policies_attach failed', { error: String(error) });\n return errorResult(\n `Failed to attach policy: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_policies_detach')),\n {\n title: 'Detach Policy From Role',\n description:\n 'Detach an OPA policy reference from a role on the chosen gateway. Returns { detached: boolean, roleId, policyId }.',\n inputSchema: {\n roleId: z.string().describe('Role ID'),\n policyId: z.string().describe('PolicyReference ID'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ roleId, policyId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const data = await clientForLayer(ctx, targetLayer).request<{\n detachPolicyFromRole: boolean;\n }>(DETACH_POLICY, { roleId, policyId });\n return jsonResult({ detached: data.detachPolicyFromRole, roleId, policyId });\n } catch (error) {\n ctx.logger.error('rbac_policies_detach failed', { error: String(error) });\n return errorResult(\n `Failed to detach policy: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n\n server.registerTool(\n track(mcpToolName(ctx.productName, 'rbac_check')),\n {\n title: 'Check Permission',\n description: 'Check whether an actor has permission for an action on a resource.',\n inputSchema: {\n actorId: z.string().describe('Actor id (user/app/service/super_admin)'),\n action: z.string().describe('Action like read/write/delete'),\n resourceType: z.string().describe('Resource type like project/task'),\n actorType: ActorTypeEnum.optional().describe('Actor type (default: USER)'),\n resourceId: z.string().optional().describe('Specific resource id (optional)'),\n scopeId: z.string().optional().describe('Scope id (workspaceId or tenantId)'),\n layer: LayerEnum.optional().describe('workspace or global (default: workspace)'),\n },\n },\n async ({ actorId, action, resourceType, actorType, resourceId, scopeId, layer }) => {\n try {\n const targetLayer: Layer = layer ?? 'workspace';\n const resolvedScope = scopeId ?? defaultScopeId(ctx, targetLayer);\n if (!resolvedScope) {\n return errorResult(\n `No ${targetLayer} scope. Pass scopeId or authenticate to a workspace/organization.`,\n );\n }\n const input: Record<string, unknown> = {\n actorId,\n actorType: actorType ?? 'USER',\n action,\n resourceType,\n scopeId: resolvedScope,\n };\n if (resourceId !== undefined) input.resourceId = resourceId;\n const data = await clientForLayer(ctx, targetLayer).request<{ checkPermission: unknown }>(\n CHECK_PERMISSION,\n { input },\n );\n return jsonResult(data.checkPermission);\n } catch (error) {\n ctx.logger.error('rbac_check failed', { error: String(error) });\n return errorResult(\n `Failed to check permission: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n },\n );\n}\n","/**\n * RBAC module — role-based access control across workspace + global layers.\n *\n * Tools:\n * <product>_rbac_roles_{list,get,create,update,delete}\n * <product>_rbac_check\n *\n * Backend: ~/products/wspace/rbac/wspace-rbac-svc/, ~/products/global/rbac/global-rbac-svc/.\n */\n\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { McpContext, McpModule, ModuleRegistration } from '../../core/index.js';\nimport { registerRbacTools } from './tools.js';\n\nconst rbacModule: McpModule = {\n id: 'rbac',\n version: '0.0.1',\n displayName: 'RBAC',\n dependsOn: ['auth'],\n capabilities: { tools: {} },\n\n register(server: McpServer, ctx: McpContext): ModuleRegistration {\n const tools: string[] = [];\n const track = (n: string): string => {\n tools.push(n);\n return n;\n };\n\n registerRbacTools(server, ctx, track);\n\n return { tools, resources: [], prompts: [] };\n },\n};\n\nexport default rbacModule;\n"]}
|