Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

feat(mcp-tools): ProcestToolProvider — AI companion MCP tools#418

Merged
rubenvdlinde merged 1 commit into
developmentfrom
feature/procest-mcp-tools
May 12, 2026
Merged

feat(mcp-tools): ProcestToolProvider — AI companion MCP tools#418
rubenvdlinde merged 1 commit into
developmentfrom
feature/procest-mcp-tools

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Summary

Adds the per-app OCA\OpenRegister\Mcp\IMcpToolProvider for Procest (hydra ADR-034 AI Chat Companion + ADR-035 per-app MCP coverage), so the in-app AI companion can surface Procest's process/workflow management to an LLM. This is the MVP skeleton — the remaining tools from #416 (startProcess, advanceStep, listMyTasks, getTaskDetails) are intentionally out of scope here.

Refs #416 (this PR ships 2 of the 6 tools in the issue's full MVP).

Tools added

Tool id Purpose
procest.listProcesses List running process instances (cases). Optional limit (integer 1-50, default 20) + optional status filter.
procest.getProcessDetails Get one process instance (case) by id or uuid (required), including its current step (status) and chronological transition history.

invokeTool() validates arguments first, then runs per-object authorisation before business logic (OWASP A01:2021 / ADR-005): admin via IGroupManager (the procest-admin group OR the NC system admin group), otherwise the caller must be the case assignee or hold a role record linking them to the case. The auth helper actually runs — no unconditional return true, not wrapped in catch(\Throwable). It delegates to the existing SettingsService + OpenRegister ObjectService (same findObject/findObjects pattern as StatusTransitionService/WorkflowDefinitionService), caps any returned list at 20 items, and returns a structured {error: {code, message}} envelope for every failure (unknown tool, bad args, not found, forbidden, storage unavailable, not configured) — it never throws.

Files

  • lib/Mcp/ProcestToolProvider.php — the provider (getAppId()'procest', getTools() → 2 descriptors, invokeTool()).
  • lib/AppInfo/Application.php — registers the provider under the DI alias OCA\OpenRegister\Mcp\IMcpToolProvider::procest (the format OR's McpToolsService enumerates). Also extracted registerBezwaarListeners() + registerWidgetsAndProviders() helpers so register() stays under the PHPMD method-length threshold.
  • tests/Stubs/Mcp/IMcpToolProvider.php — stub interface (copied from decidesk's exemplar, namespace/package adjusted) used until openregister PR #1466 (ai-chat-companion-orchestrator) ships the real interface; no-ops when the real interface is present.
  • tests/bootstrap.php — loads the stub when the real interface is absent.
  • tests/Unit/Mcp/ProcestToolProviderTest.php — asserts getAppId(), the 2 descriptors (ids namespaced, non-empty descriptions, valid inputSchema objects), and that invokeTool() returns structured errors (unknown tool, missing args, no storage) without throwing.
  • composer.jsonautoload-dev PSR-4 OCA\OpenRegister\tests/Stubs/ so PHPStan/PHPUnit discover the stub (mirrors decidesk).
  • psalm.xml / phpstan.neon / phpmd.baseline.xml — analysis config for the dynamically-loaded IMcpToolProvider + a single PHPMD baseline entry for the single-class provider design (mirrors decidesk's exemplar). The psalm change also fixes a pre-existing UndefinedClass gap for the OR Object*ing events already referenced in Application.php.

Done vs deferred

  • IMcpToolProvider implementation (2 read-only tools), DI registration, stub, unit test, ### MCP coverage line below.
  • ⏸️ Widget mount deferred — Procest already consumes @conduction/nextcloud-vue via CnAppRoot (src/App.vue), but CnAiCompanion is not yet in any published @conduction/nextcloud-vue release (it currently lives on feature/ai-chat-companion-widget / fix/ai-companion-* branches; latest published is 1.0.0-beta.30). No package bump made; will follow once a release ships the component.
  • ⏸️ Remaining AI companion: implement the MCP tool MVP for procest #416 tools (procest.startProcess, procest.advanceStep, procest.listMyTasks, procest.getTaskDetails) — follow-up.

Quality

composer lint / phpcs / phpmd (baselined) / psalm / phpstan / phpunit (140 tests, all green) pass for the new/changed code. Two pre-existing failures remain on development, unrelated to this change and not chased here: lib/Validator/ParaferingAuditAppendOnlyValidator.php triggers InvalidTemplateParam (psalm) / 3× registerEventListener type mismatch (phpstan) because it implements IEventListener over the OR Object*ing events.

MCP coverage

Adds tool: procest.listProcesses
Adds tool: procest.getProcessDetails

ADR-034: hydra openspec/architecture/adr-034-ai-chat-companion.md
ADR-035: hydra openspec/architecture/adr-035-mcp-per-app-coverage.md

…eleton)

Adds the per-app IMcpToolProvider (hydra ADR-034 / ADR-035) for the AI
Chat Companion, exposing 2 read-only tools:

- procest.listProcesses — list running process instances (cases),
  optional limit (1-50, default 20) and status filter
- procest.getProcessDetails — one case by id/uuid with its current step
  (status) and chronological transition history

invokeTool() validates arguments, then runs per-object authorisation
(admin via IGroupManager / assignee / role record on the case) BEFORE
business logic, delegates to SettingsService + ObjectService, caps lists
at 20, and returns a structured {error: {code, message}} envelope on any
failure — it never throws.

Registered in Application::register() under the DI alias
'OCA\OpenRegister\Mcp\IMcpToolProvider::procest'. The real interface
ships in openregister PR #1466; until it merges procest implements the
stub at tests/Stubs/Mcp/IMcpToolProvider.php (loaded by tests/bootstrap.php
and via the OCA\OpenRegister -> tests/Stubs autoload-dev mapping).

Also fixes pre-existing quality issues touched along the way:
- psalm: suppress UndefinedClass for the dynamically-loaded OR Object*ing
  events already referenced in Application.php
- phpmd: extract bezwaar listeners + widgets/providers helpers so
  Application::register() is back under the method-length threshold
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/procest @ 417225d

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
composer ✅ 100/100
npm ✅ 419/419
PHPUnit ⏭️
Newman ⏭️
Playwright

Spec coverage: 5% (21 tests / 456 specs)


Quality workflow — 2026-05-12 05:13 UTC

Download the full PDF report from the workflow artifacts.

@rubenvdlinde rubenvdlinde merged commit b5a886c into development May 12, 2026
33 of 41 checks passed
@rubenvdlinde rubenvdlinde deleted the feature/procest-mcp-tools branch May 12, 2026 12:25
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant