Skip to content

Extend mcp tool feature set - #8283

Open
cstns wants to merge 33 commits into
mainfrom
feat/extend-mcp-tool-feature-set
Open

Extend mcp tool feature set#8283
cstns wants to merge 33 commits into
mainfrom
feat/extend-mcp-tool-feature-set

Conversation

@cstns

@cstns cstns commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Description

Feature branch for extending mcp tools

Related Issue(s)

#7727
#7726
#7724
#7723
#7722
#7721
#7720
#7719
#7718
#7717
#7716
#7715

Checklist

  • I have read the contribution guidelines
  • Suitable unit/system level tests have been added and they pass
  • Documentation has been updated
    • Upgrade instructions
    • Configuration details
    • Concepts
  • Changes flowforge.yml?
    • Issue/PR raised on FlowFuse/helm to update ConfigMap Template
    • Issue/PR raised on FlowFuse/CloudProject to update values for Staging/Production
  • Link to Changelog Entry PR, or note why one is not needed.

Labels

  • Includes a DB migration? -> add the area:migration label

andypalmi and others added 30 commits August 25, 2026 10:52
Add RFC 8414 authorization-server metadata and RFC 9728 protected-resource
metadata under /.well-known so MCP clients can auto-discover the OAuth
endpoints and the MCP resource URL. Public, license-tier independent.

Ref #7431
…agents

Extend the OAuth2 flow so external MCP agents (Claude, Cursor, etc.) can
authenticate. Rather than a single hardcoded client id, agents register
dynamically per RFC 7591: POST /account/client persists a public AuthClient
(type 'mcp', no secret) with its approved redirect URIs and returns a generated
client id. The authorize, complete, and token endpoints recognise these clients
by looking them up, skip the project/device ownership checks (MCP is
user-scoped), and drive an MCP consent step that records the read-only and team
selection before issuing a scoped personal access token. Redirect URIs must be
loopback http (RFC 8252, port-flexible) or https for hosted clients; token
issuance and refresh require no client secret.

Also forward the caller scope through the platform automation handler and add a
platform_get_active_user tool that reports the calling token's scope.

Adds AuthClient.type/name/redirectURIs (migration + model), an
AuthClient.createMCPClient controller, and AccessToken.createMCPOAuthToken.

Ref #7432
Add the AccessRequestMCP.vue consent page and its /account/request/:id/mcp
modal route. The page lets the user pick read-only or full access and scope
the grant to specific teams before approving the MCP agent request.

Ref #7433
Move the RFC 9728 protected-resource document out of the root
.well-known handler into the license-gated EE mcp plugin, so it is only
advertised where the /mcp resource exists. Serve it at the path-inserted
/.well-known/oauth-protected-resource/mcp (RFC 9728 3.1) with the bare
path kept as an alias, and challenge unauthenticated /mcp requests with a
WWW-Authenticate header pointing at that metadata.
An AccessToken row holds both the access token and its refresh token,
and getOrExpire destroyed the row when the access token expired, taking
the refresh token with it so a client could never refresh (RFC 6749
1.5). Add a separate refreshTokenExpiresAt lifetime: reject an expired
access token but keep the row while its refresh token is still valid.

The MCP refresh token is stable rather than rotating, and concurrent
refreshes coalesce through a shared cache so they reuse the most
recently minted access token instead of overwriting the row.
Capture the pre-refresh expiry after lowering it, so the assertion
compares against the shortened lifetime rather than the original one and
no longer ties when the refresh lands in the same millisecond.
Link the MCP OAuth token to the AuthClient it was issued to and name it
after the registered client instead of the fixed 'MCP Agent', so the
user's token list and later audit attribution can tell agents apart.
Platform tool calls were always stamped source 'mcp:expert', so a
third-party agent's actions rendered as the first-party Expert. The MCP
door now records the caller's registered client name against its
mcpSessionId, and the comms handler reads it to stamp source 'mcp' with
that client name. The Expert path never opens that door, so it keeps the
'mcp:expert' default. The audit entry surfaces the client name.

Closes #8271.
getOrExpire eager-loaded AuthClient on every token lookup so the client
name could be attached to the session, adding a join to every Bearer
request when only MCP tokens set AuthClientId. Drop the join and resolve
the name with a targeted lookup that runs only when AuthClientId is set.
The refresh_token grant returned access_token, expires_in and
refresh_token but omitted token_type, which RFC 6749 section 5.1
requires. A spec-compliant client rejects the response and falls back to
re-authorization even though the server rotated the token successfully.
Return token_type: bearer to match the authorization_code response.
Run third-party MCP platform actions under the caller's own PAT rather
than a freshly minted platform token, and derive the audit source from
whether the session has one. The door stashes the PAT against the
mcpSessionId; the comms layer injects it and marks the entry 'mcp', or
mints a token and marks 'mcp:expert' for the first-party Expert path.

Removes the per-client identity plumbing (AuthClientId column, client
name lookup and rendering), which is not needed to distinguish
expert, third-party and api sources.
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: cstns <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
Co-authored-by: andypalmi <andrea@flowfuse.com>
Co-authored-by: Costin Serban <cstn.serban@gmail.com>
…feature-set

# Conflicts:
#	forge/db/controllers/AccessToken.js
#	forge/db/controllers/AuthClient.js
#	forge/db/migrations/20260824-01-add-mcp-authclient-fields.js
#	forge/db/models/AuthClient.js
#	forge/ee/lib/mcp/tools/applications.js
#	forge/ee/lib/mcp/tools/instances.js
#	forge/ee/lib/mcp/tools/platform.js
#	forge/ee/lib/mcp/tools/snapshots.js
#	forge/ee/lib/mcp/tools/teams.js
#	forge/routes/auth/oauth.js
#	test/unit/forge/routes/auth/oauth_spec.js
@cstns
cstns deployed to staging August 26, 2026 10:16 — with GitHub Actions Active
@cstns
cstns deployed to staging August 26, 2026 11:15 — with GitHub Actions Active
@codecov

codecov Bot commented Aug 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.78%. Comparing base (41a10fd) to head (d9e8d19).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #8283      +/-   ##
==========================================
+ Coverage   76.17%   76.78%   +0.60%     
==========================================
  Files         451      458       +7     
  Lines       24175    24395     +220     
  Branches     6461     6478      +17     
==========================================
+ Hits        18416    18732     +316     
+ Misses       5759     5663      -96     
Flag Coverage Δ
backend 76.78% <100.00%> (+0.60%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants