feat(mcp): hosted instance read tools - #7727
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #7727 +/- ##
==========================================
+ Coverage 76.20% 76.27% +0.06%
==========================================
Files 443 444 +1
Lines 23728 23797 +69
Branches 6315 6329 +14
==========================================
+ Hits 18081 18150 +69
Misses 5647 5647
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
04324b4 to
6af352f
Compare
8bfb22e to
9742987
Compare
6af352f to
fdafd47
Compare
fdafd47 to
df8ad04
Compare
103f9ae to
5773bdb
Compare
Add forge/ee/lib/mcp/schemas.js, a shared module of composable zod fragments the platform read tools import instead of redefining entity-id and pagination/search/sort/audit-log query fields in each tool file. - entity-id params: teamId, applicationId, hostedInstanceId (UUID), remoteInstanceId, snapshotId - query fragments composed per route by spreading only the params the backing finder honors: cursorParam/limitParam (basePagination), pageParam, searchQuery, sortParams, auditLogFilters - appendQuery serialises a tool's supported params onto the request URL The module lives one level above tools/ so the tool loader does not register it as a tool module. Closes #7669
eae081f to
e04360f
Compare
283ad01 to
4206424
Compare
4206424 to
526dcd3
Compare
526dcd3 to
da1f501
Compare
…ayload shape
Return each platform_get_instance_config section as { statusCode, data }
so array payloads such as the autoUpdateStack schedule survive instead of
being spread into numeric keys.
Reword platform_get_hosted_instance_resources to describe a time-series of
usage samples rather than a point-in-time snapshot, and drop the claim in
both that tool and platform_get_instance_history that the not-enabled case
is rewritten into a friendly message (the routes return a plain not-found).
Note that flowLastUpdatedAt sort and orderByMostRecentFlows only apply when
includeLiveStatus is set, and drop the inert device:history token scope
(the remote history route checks project:history).
The audit-log export route responds with text/csv, but the MCP response formatter always parses a success body as JSON, so requesting format=csv failed. A downloadable CSV file cannot be delivered over the tool transport anyway, so remove the format argument and always return JSON entries.
| }, | ||
| handler: async (args, { inject }) => { | ||
| const base = args.instanceType === 'remote' ? 'devices' : 'projects' | ||
| const url = appendQuery(`/api/v1/${base}/${args.instanceId}/history`, args, basePaginationKeys) |
There was a problem hiding this comment.
these api endpoints are just syntactic sugar over the audit log for which we already have tools for
There was a problem hiding this comment.
You're right that instance history is built on top of the audit log (AuditLog.forTimelineHistory). The one difference is the shape: the /history route returns the curated TimelineList (a filtered, deploy-oriented timeline) rather than raw audit entries, so it is a little more than a straight alias. I'm happy either way here: keep it for that curated view, or drop it and rely on the audit-log tools. Which would you prefer?
…ce-config-read # Conflicts: # forge/routes/auth/permissions.js
Move the tools shared between hosted and remote instances (list HTTP tokens, get instance history) into a new tools/shared-instances-devices.js so the shared surface is explicit, keeping the instanceType-discriminated shape. Rename the hosted-only tools to the hosted_instance convention: platform_get_hosted_instance_config, platform_get_hosted_instance_custom_hostname and platform_list_hosted_instance_files. platform_get_hosted_instance_config reports the section failure status when every requested section failed, instead of always returning 200. platform_list_hosted_instances now requires exactly one of teamId or applicationId, rejecting both-set and neither-set, and rejects the team-only sort, dir and orderByMostRecentFlows parameters when scoped to an application. Document the file-store result shape and how to build the path, document the audit-log scope and includeChildren parameters, and inline the single-use audit-log schema fragments.
Move the instance audit-log reader into shared-instances-devices.js as platform_get_instance_audit_log, taking an instanceType (hosted or remote) and hitting the projects or devices audit-log route. Both routes accept the same pagination and audit-log query params. scope and includeChildren apply only to hosted instances (a remote instance has no child entities), so they are rejected when instanceType is remote.
Testing results of new/changed tools@cstns for visibility. Re-run after the review changes (shared file, renames, guards, and the shared audit-log tool). Every tool below was invoked against a running local platform. Two teams were used: one with 10 hosted instances and no devices, and one with 9 hosted instances and 10 remote instances (devices), one of them online. Payloads are summarised with ids, names, cursors and timestamps redacted; structural values (counts, statuses, enum echoes, error codes) are verbatim. platform_list_hosted_instancesLists hosted instances for exactly one scope: a whole team (
platform_get_hosted_instance_configReturns the requested config sections, each independently as {statusCode, data}. Reports success when at least one section was returned; reports the failure status when every requested section failed.
platform_get_hosted_instance_custom_hostnameReturns the configured custom hostname; with includeStatus, also the live CNAME verification status.
platform_list_hosted_instance_filesLists files and directories at a path in the instance file store.
platform_get_hosted_instance_resourcesReturns stored CPU/memory usage as a time-series of samples.
platform_list_team_dashboard_instancesReturns the team's hosted instances that have the Node-RED dashboard installed.
platform_list_instance_http_tokens (shared)Lists the HTTP bearer tokens for a hosted or remote instance, selected with instanceType.
platform_get_instance_history (shared)Returns a chronological timeline for a hosted or remote instance, cursor-paginated.
platform_get_instance_audit_log (shared)Reads the audit log for a hosted or remote instance as JSON, selected with instanceType. scope and includeChildren apply to hosted instances only and are rejected for a remote instance.
Findings
ConclusionAll 9 tools added or changed in this PR verified against their descriptions, including every guard. No open defects. |
Summary
Phase 1 read-only MCP tools for the hosted instance resource, added to
forge/ee/lib/mcp/tools/instances.js, plus the two tools that span hosted and remote instances, added to a newforge/ee/lib/mcp/tools/shared-instances-devices.js. This covers per-instance configuration surfaces, instance observability, and the team-scoped instance lists.Hosted instance tools (
instances.js):platform_get_hosted_instance_config- one configuration reader taking asectionsarray (any subset ofha,protection,autoUpdateStack; defaults to all). Backed byGET /projects/:id/ha,GET /projects/:id/protectInstance, andGET /projects/:id/autoUpdateStack, returning each requested section independently as{ statusCode, data }.platform_get_hosted_instance_custom_hostname-GET /projects/:id/customHostname, with anincludeStatusboolean that additionally fetches the live verification status fromGET /projects/:id/customHostname/status.platform_list_hosted_instance_files-GET /projects/:id/files/_/:pathplatform_get_hosted_instance_resources-GET /projects/:id/resourcesplatform_list_team_dashboard_instances-GET /teams/:teamId/dashboard-instancesShared hosted/remote tools (
shared-instances-devices.js):platform_list_instance_http_tokens- takesinstanceType(hostedorremote); lists the HTTP bearer tokens for a hosted or remote instance.platform_get_instance_history- takesinstanceType(hostedorremote); returns the timeline for a hosted or remote instance.platform_get_instance_audit_log- takesinstanceType(hostedorremote); reads the audit log for a hosted or remote instance as JSON.scopeandincludeChildrenapply to hosted instances only and are rejected for a remote instance.Tools that work against both hosted and remote instances live in
shared-instances-devices.jsrather than ininstances.jsordevices.js, so the shared surface is explicit; the owner-specific tools keep the one-file-per-resource convention.All read tools are annotated
readOnlyHint: true, destructiveHint: false. Several backing routes are plan-gated per team (High Availability, custom hostnames, protected instance, static file storage, HTTP bearer tokens, instance history, instance resources); a disabled feature and a genuine not-found both surface as a 404. The/resources/streamWebSocket route is intentionally not exposed; only the point-in-time/resourcessnapshot is implemented.Consolidation notes
platform_get_hosted_instance_ha,platform_get_hosted_instance_protection, andplatform_get_hosted_instance_auto_update_stackare merged intoplatform_get_hosted_instance_config, which takes asectionsarray (subset ofha/protection/autoUpdateStack, defaults to all) and returns each requested section independently. When every requested section fails (for example the instance does not exist) the tool reports that failure status rather than a misleading 200.platform_get_hosted_instance_custom_hostnameand its status variant are merged, with anincludeStatusboolean that also fetches the live verification status.platform_get_instance_audit_logreturns audit entries as JSON.platform_list_instance_http_tokens,platform_get_instance_historyandplatform_get_instance_audit_logtake aninstanceType(hostedorremote) and serve both owner kinds, and are placed inshared-instances-devices.js.platform_get_instance_audit_logsupersedes the remote-onlyplatform_get_remote_instance_audit_logfrom feat(mcp): remote instance (device) read tools #7726.platform_list_hosted_instancesnow takes exactly one ofteamId(team-wide, paginated and sortable) orapplicationId(a single application, unpaginated); passing both, or neither, is rejected. The team-onlysort,dir, andorderByMostRecentFlowsparameters are rejected whenapplicationIdis set.Permissions
No permissions changes. #8185 removed the hardcoded
user:expert-mcpscope allow-list, so expert MCP tokens now inherit the user's permissions gated by team role and no allow-list entries are needed.Closes #7705
Test plan
eslintclean on the changed filesmochaunit tests