mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-23 17:33:51 +02:00
## Thinking Path > - Paperclip agents need governed access to Enterpret's hosted MCP tools for customer feedback. > - The official Enterpret MCP is read-only. Enterpret Agent’s beta write MCP is a separate service and is outside this PR. > - This PR supports both organization auth tokens and personal browser OAuth for the official MCP. > - Enterpret committed to fixing OAuth scope behavior and reducing its token-revocation cache window. The provider fixes will follow after connector deployment and do not gate this release. Paperclip functional validation remains required. New tools stay quarantined on refresh. > - This PR combines the original connector and Vivek's token-path work on current master, with live self-hosted QA recorded in the validation guide. ## Linked Issues or Issue Description No public issue covers this connector. This PR incorporates the work from #14737. The independent OAuth scope-provenance fix is #14059; it is not required for the organization-token path. #13890 is a merged connector precedent. #13692 provides the connector-authoring skill. **Problem or motivation** The generic MCP setup can reach Enterpret, but it has no reviewed Enterpret entry, method-specific setup, artwork, or policy defaults. The original connector branch had also fallen behind master. **Proposed solution** Publish the Enterpret catalog entry with an organization auth token as the selectable method. Support browser OAuth through instance-local DCR on the same read-only endpoint. Default `run_graph_query` to Ask first and quarantine tools newly found on refresh. ## What Changed - Added the Enterpret app definition, generated registry, official icon, Browse card, setup copy, tests, and Storybook states. - Combined #14737 and resolved the current-master conflicts, including the connector permission audit. - Preserved catalog quarantine on token reconnect and updated expiry guidance to follow the token's dashboard expiry. The QA token displayed three months, contradicting the former six-month copy. - Enabled personal OAuth for the official read-only MCP. Removed the write-capability inference and OAuth draft-only setup restriction. The beta Agent endpoint is excluded. - Preserved tool quarantine during token reconnect, with a regression test for existing quarantined and newly discovered tools. - Added OAuth scope and revocation-cache disclosures and an interactive Storybook retry check. - Merged master `d9f600043` into the existing PR branch without rewriting history. Resolved four conflicts, regenerated the combined registry, and retained the model-provider assertions with a catalog count of 66. - Recorded live QA and its limits in [doc/connections/ENTERPRET.md](https://github.com/paperclipai/paperclip/blob/950bacc52/doc/connections/ENTERPRET.md). ## Verification Current head: `6c73d3084202ccbb25080e7a4e9c3467bc1341dd`. All 513 focused connector, discovery, OAuth, policy, shared-definition, and UI-handoff tests passed across 11 suites. Full repository typecheck, build, Storybook build, token gates, module boundaries, Node policy, no-git-push policy, and typecheck-build-gaps passed. Release-registry tests passed 129/129 with modern Bash. The four failures with macOS Bash 3.2 also reproduced on untouched master. The full test suite passed in CI on this exact head, including every general-test and serialized-server shard and all eight E2E shards. The duplicate local `pnpm test:run` was stopped after these remote test lanes passed; it did not complete locally. The combined registry was regenerated. Regeneration also reproduces existing Linear and AgentMail definition drift on untouched master; those unrelated changes were excluded. On an isolated self-hosted Paperclip instance, an organization token connected and discovered eight actions. `get_organization_details` returned the intended organization before and after reconnect. Catalog refresh, invalid-token failure and valid-token recovery, activity logging, local disable, and local removal were exercised. No feedback quotes or graph query were requested. Paperclip revoked both QA connection secrets and archived the QA connections. The token-path agent access preview correctly showed an action Off, but the board Test endpoint still invoked it as the board user. This shared Test-path mismatch is documented; it is not evidence that a real agent can bypass policy. An actual token-path agent-session denial, a real agent process, expiry recovery, server/VPS, and Cloud remain unverified. Enterpret's dashboard confirmed the QA token was revoked, but the same token immediately reconnected and completed a safe read. Vivek explained this as a 24-hour validity cache and committed to reducing the window. The new maximum delay and deployment remain unverified. The earlier OAuth check reported `mcp:write` and `email` for an `mcp:read` request. This is a scope mismatch; it did not prove access to write tools. On 2026-10-01 the account holder relayed Vivek’s clarification that the official MCP is read-only and the beta Agent write MCP is separate. ## Risks The organization token can read the organization's customer feedback, and provider-side revocation did not immediately stop access. Operators should check each token's displayed expiry and remove Paperclip's local connection when retiring access. The account holder confirmed the provider fixes are fast follows after deployment. Release can proceed with the current scope reporting and up-to-24-hour revocation delay documented, once fresh OAuth authorization/refresh, real-agent allow/deny, CI, and review pass. Retest the reduced revocation window after Enterpret deploys it. Scope labels alone must not be used to claim write access. Greptile is 5/5 on head `6c73d3084` with no actionable findings. All current-head CI checks pass, including the canary dry run. Live agent-session denial and fresh OAuth refresh remain explicit deployment QA items. The board Test panel does not prove agent authorization. Provider scope-reporting and revocation-cache fixes are accepted fast follows after deployment. ## Model Used Original connector and validation record: Claude Opus 5 through Claude Code. Integration, current-master reconciliation, and token-path QA: OpenAI Codex, GPT-6 family (exact host variant not exposed), using repository tools and an isolated runtime. Contributor commits retain their authors. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either linked existing issues or described the issue in-PR - [x] I have not referenced internal or instance-local Paperclip issues or links - [x] My branch name describes the change and contains no internal issue ID - [x] I have run relevant local tests and checks - [x] I have updated relevant documentation - [x] I have considered and documented the risks above - [x] All current-head CI gates are green - [x] Greptile is 5/5 with no actionable follow-ups If squash-merging, preserve contributor credit in the squash message: Co-Authored-By: Vivek Kaushal <kaushalvivek@users.noreply.github.com> --------- Co-authored-by: Paperclip <noreply@paperclip.ing> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Vivek Kaushal <vivek@enterpret.com>
635 lines
38 KiB
Markdown
635 lines
38 KiB
Markdown
# Enterpret connection
|
||
|
||
Enterpret's hosted MCP server answers questions about an organization's customer
|
||
feedback — themes, accounts, sentiment, and verbatim quotes with citations back
|
||
to the source records.
|
||
|
||
This document follows the template in
|
||
[Connection Authoring Runbook](./CONNECTOR-PLAYBOOK.md) and records exactly what
|
||
was and was not verified.
|
||
|
||
**The connector has now been exercised against a real Enterpret account** — a
|
||
named account holder signed in through an isolated Paperclip runtime on
|
||
2026-09-25 (PAP-18538), and agent tool calls reached the live server. The
|
||
organization-token method was separately exercised on an isolated self-hosted
|
||
runtime on 2026-09-30.
|
||
|
||
**Release path:** the **organization auth token** (`mcp-api-key`) is the
|
||
primary connection method. Generate a Bearer token under Enterpret
|
||
**Settings → Enterpret MCP** and paste it into Paperclip. Public MCP tools are
|
||
read-only today; the token path does not depend on Enterpret honouring a
|
||
narrowed OAuth grant.
|
||
|
||
**Current product decision — 2026-10-01:** support both organization tokens
|
||
and browser OAuth for the official **read-only Enterpret MCP** at
|
||
`https://wisdom-api.enterpret.com/server/mcp`. The account holder reported a
|
||
live conversation with Vivek confirming that Enterpret Agent's write MCP is a
|
||
separate beta service with known bugs. That service is outside this connector's
|
||
scope and will be reviewed separately when ready.
|
||
|
||
Vivek committed to fixing OAuth scope behavior and reducing the token
|
||
revocation cache window. This is a provider commitment relayed by the account
|
||
holder, **not verified deployment evidence**. The earlier inference that an
|
||
`mcp:write` scope name made this connector write-capable is withdrawn. Both
|
||
methods are selectable on this draft branch; fresh OAuth authorization,
|
||
refresh and real-agent allow/deny checks remain release QA. The account holder
|
||
confirmed the provider fixes are fast follows after deployment, not prerequisites
|
||
for shipping this connector.
|
||
|
||
Several live read and gateway checks passed on the OAuth method. The primary
|
||
token path passed connection, catalog, safe read, refresh, and reconnect checks;
|
||
a real agent process and server/VPS or Cloud deployment remain unverified.
|
||
The dashboard's token revocation did not immediately invalidate the token. See
|
||
[Validation Hook](#validation-hook) for the scenario-by-scenario record.
|
||
|
||
Authored against Paperclip App `fff410dfe777ae0427385e8297df992ba9aed4ce`, with
|
||
`CONNECTOR-PLAYBOOK.md` blob `5efd4cca05a1c94bb47d619833ba347f416bbbed` as the
|
||
authority. Provider metadata read 2026-09-23 and re-read unchanged 2026-09-25.
|
||
Live validation ran on App `ef1606f037a7828a7ba774949e811847c1a1d386`.
|
||
|
||
## Vendor
|
||
|
||
- App key: `enterpret`
|
||
- App name: Enterpret
|
||
- Owner: unassigned. No Paperclip maintainer currently owns an Enterpret account.
|
||
- Reuse classification: **MCP-direct**
|
||
- Reason for classification: Enterpret publishes an official hosted MCP server
|
||
over Streamable HTTP whose authorization server is discoverable from the
|
||
endpoint itself. No REST shim and no vendor-specific wrapper is needed; the
|
||
tools map onto ordinary read grants.
|
||
- Security tier: **S3**
|
||
- Plugin needed? No. The provider is expressible as metadata plus a transport:
|
||
no plugin tables, workers, webhooks, or dedicated UI.
|
||
|
||
### Why a catalog entry at all
|
||
|
||
An operator can already reach this server with no Paperclip code change, through
|
||
**Connect your own MCP server** or **Advanced → Paste a config**
|
||
([Generic remote MCP](./GENERIC-REMOTE-MCP.md)). The catalog entry adds only:
|
||
official artwork, two labelled methods with the correct client-ownership and
|
||
grant-identity shape, a reviewed scope allowlist narrower than the advertised
|
||
set, a recorded risk tier, and the provider docs link. Those are real but
|
||
incremental. Treat the generic path as the baseline, not as a lesser fallback.
|
||
|
||
## Transport And Auth
|
||
|
||
- Transport: `mcp_remote` (Streamable HTTP)
|
||
- Endpoint: `https://wisdom-api.enterpret.com/server/mcp`. The bare and
|
||
trailing-slash forms behave identically — `401`, no redirect.
|
||
- Auth modes: **API key / organization auth token** (`mcp-api-key`, primary)
|
||
and **OAuth** (`mcp-oauth`). Both methods are selectable on one catalog entry.
|
||
- OAuth scopes: requested `mcp:read`. Advertised by the provider: `email`,
|
||
`mcp:read`, `mcp:write`. See [Scope decision](#scope-decision). Fresh OAuth authorization and refresh checks are pending provider deployment.
|
||
- Key scope: the Enterpret auth token is generated per Enterpret organization
|
||
and carries that organization's access. Enterpret does not document a
|
||
restricted or read-only token variant. Public tools remain read-only.
|
||
- Credential owner: the auth token is an organization credential
|
||
(`grantKinds: ["organization"]`); OAuth is user-delegated
|
||
(`grantKinds: ["user"]`).
|
||
- Secret storage: `company_secrets` refs only. The definition records the header
|
||
placement, never a value.
|
||
- Revocation behaviour: **no `revocation_endpoint` is advertised.** See
|
||
[Revocation gap](#revocation-gap).
|
||
|
||
### Connection Flow (mandatory)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant O as Operator
|
||
participant P as Paperclip instance
|
||
participant R as wisdom-api.enterpret.com
|
||
participant A as oauth.enterpret.com
|
||
O->>P: Connect Enterpret, method mcp-oauth
|
||
P->>R: POST /server/mcp initialize, unauthenticated
|
||
R-->>P: 401 WWW-Authenticate with resource_metadata
|
||
P->>R: GET /server/mcp/.well-known/oauth-protected-resource
|
||
R-->>P: authorization_servers https://oauth.enterpret.com
|
||
P->>A: GET /.well-known/oauth-authorization-server
|
||
A-->>P: authorize, token, register, PKCE S256, auth method none
|
||
P->>A: POST /register, RFC 7591 dynamic client registration
|
||
A-->>P: client_id for this Paperclip instance
|
||
P->>O: Redirect to /authorize with PKCE challenge
|
||
O->>A: Sign in and consent
|
||
A-->>P: Redirect to /api/tools/oauth/callback with code
|
||
P->>A: POST /token, code plus verifier
|
||
A-->>P: Access token and refresh token
|
||
P->>R: POST /server/mcp with the access token
|
||
```
|
||
|
||
- Auth endpoints (exact paths), all read from provider metadata on 2026-09-23:
|
||
- Authorize: `https://oauth.enterpret.com/authorize`
|
||
- Token: `https://oauth.enterpret.com/token`
|
||
- Registration (DCR): `https://oauth.enterpret.com/register`
|
||
- Discovery: `https://wisdom-api.enterpret.com/server/mcp/.well-known/oauth-protected-resource`
|
||
(RFC 9728) → `https://oauth.enterpret.com/.well-known/oauth-authorization-server`
|
||
(RFC 8414). `https://oauth.enterpret.com/.well-known/openid-configuration`
|
||
also resolves.
|
||
- Also advertised: `/introspect`, `/userinfo`. `jwks_uri` points at AWS Cognito
|
||
pool `us-east-2_kLiRrPBis`.
|
||
- Paperclip callback: `/api/tools/oauth/callback`
|
||
- Redirect constraints: `https-or-loopback-http` in the definition. An HTTPS
|
||
redirect URI was accepted by DCR and round-tripped through a real consent on
|
||
2026-09-25. Whether Enterpret would also accept a loopback HTTP redirect
|
||
remains **unprobed** — the live run used HTTPS.
|
||
- Paperclip ID / Paperclip Connect involvement: **none.** Enterpret is an
|
||
RFC 7591 DCR provider, so registration is instance-local and Cloud and
|
||
self-hosted use the same path. The only per-instance difference is the
|
||
hostname inside the redirect URI.
|
||
|
||
The definition ships `serverUrl` only. A complete `authorizationEndpoint` +
|
||
`tokenEndpoint` pair would be authoritative and would suppress discovery
|
||
permanently, including endpoints a previous discovery had persisted. Discovery
|
||
resolves cleanly here — the `issuer` in the RFC 8414 document matches the issuer
|
||
used to build the URL — so there is nothing to hard-code and nothing to keep
|
||
current.
|
||
|
||
### Scope decision
|
||
|
||
Paperclip requests `mcp:read` for the official read-only endpoint. The live
|
||
2026-09-25 observation is preserved:
|
||
|
||
```text
|
||
Paperclip authorization request mcp:read
|
||
Enterpret token response no scope field
|
||
Enterpret token introspection openid email profile mcp:read mcp:write
|
||
```
|
||
|
||
This proves a mismatch between requested and reported scopes. It does **not**
|
||
prove the token can invoke write tools or authenticate to the separate beta
|
||
Enterpret Agent MCP. No write tool was observed or invoked on this endpoint.
|
||
The previous description of this as a verified write-capable connector was
|
||
stronger than the evidence and is superseded by the 2026-10-01 product decision.
|
||
|
||
The account holder relayed Vivek's commitment to fix OAuth behavior. Validate a
|
||
fresh authorization and refresh against current provider behavior, record
|
||
requested and reported scopes separately, and confirm the tool inventory still
|
||
belongs to the official read-only service. Do not widen the scope request or
|
||
add the beta write endpoint to this definition.
|
||
|
||
#14059 independently records whether scopes are provider-asserted or inferred
|
||
from the request. That improves Paperclip's reporting; it cannot prove a
|
||
provider's actual endpoint or capability boundary.
|
||
|
||
### Revocation gap
|
||
|
||
The RFC 8414 document advertises no `revocation_endpoint` — re-read 2026-09-25
|
||
and still absent. Removing the connection in Paperclip clears local credential
|
||
material and gateway access, but there is no documented provider-side instrument
|
||
to invalidate an issued OAuth token. The auth-token method is separate: the
|
||
dashboard has a Revoke control, but an immediate post-revocation read still
|
||
succeeded on 2026-09-30. Whether generating another token invalidates an
|
||
earlier one is untested.
|
||
|
||
An `introspection_endpoint` *is* advertised, and Paperclip calls neither. That
|
||
is worth separating: introspection tells you what a token can do, which is how
|
||
the scope mismatch above was found, but it cannot take a token away.
|
||
|
||
Consequence: the OAuth **Revoke and reconnect** scenario cannot reach
|
||
`verified` through a provider-side revocation call — confirmed by the live
|
||
metadata, not merely predicted. The organization-token Revoke control failed
|
||
the immediate denial check. Local removal passed and must be recorded as
|
||
exactly that rather than as full provider-side revocation.
|
||
|
||
**Operator instruction.** Disconnecting Enterpret in Paperclip is only half of
|
||
revoking it — and for OAuth the other half is not a procedure this validation
|
||
can hand you. The two methods differ, and they must not be described as one:
|
||
|
||
- **OAuth.** Paperclip cannot revoke the token: no `revocation_endpoint` is
|
||
advertised and Paperclip ships no RFC 7009 client. Whether the Enterpret
|
||
dashboard offers any way to withdraw an authorized MCP client is
|
||
**unverified** — this validation neither found such a control nor confirmed
|
||
one exists, so no step here should be written as if it does. Until Enterpret
|
||
confirms a procedure, plan on the issued token staying valid **until it
|
||
expires**, treat expiry as the only assured end of access, and ask Enterpret
|
||
support for a revocation path rather than assuming the dashboard has one.
|
||
- **Auth token.** The dashboard can generate and revoke organization tokens.
|
||
On 2026-09-30 it confirmed "Your token has been revoked," but that same
|
||
token immediately connected again and completed `get_organization_details`
|
||
through an isolated Paperclip instance. Provider-side invalidation therefore
|
||
**failed the immediate check**. Vivek later explained a 24-hour validity
|
||
cache and committed to reducing it; the new delay and deployment are unverified. Do not treat the dashboard confirmation, generating another token,
|
||
or local disconnect as proof of revocation. Confirm the old token is denied.
|
||
|
||
Any runbook or teardown that treats "disconnect in Paperclip" as provider-side
|
||
revocation can leave a live credential at Enterpret. The OAuth grant tested
|
||
above also carried `mcp:write`.
|
||
|
||
## Administrator Setup (mandatory)
|
||
|
||
- What the admin must register: **nothing.** Enterpret advertises RFC 7591
|
||
dynamic client registration, so the Paperclip instance registers itself at
|
||
connect time. No client ID, no client secret, no callback URL to pre-register.
|
||
- Where to register it: not applicable. For the auth-token method, an Enterpret
|
||
admin generates a token at **Settings → Enterpret MCP → Generate** under
|
||
**Auth Token**. Check the expiry shown for each token in the dashboard; the
|
||
token generated for the 2026-09-30 QA run showed **three months**.
|
||
- Instance prerequisites: outbound HTTPS to `wisdom-api.enterpret.com` and
|
||
`oauth.enterpret.com`. A public HTTPS base URL is **not** required — that
|
||
applies to the Client ID Metadata Document tier only, and an instance without
|
||
one falls through to DCR.
|
||
- How to verify the connection works: after connecting, the connection health
|
||
and catalog check should list Enterpret's tools. `get_organization_details`
|
||
is the narrowest read and identifies which Enterpret organization the
|
||
credential resolves to — run that first, and confirm it is the organization
|
||
you intended.
|
||
|
||
## Resource Filters
|
||
|
||
- Required filters: none expressible. Enterpret's MCP surface scopes every call
|
||
to the organization behind the credential; the server documents no per-source,
|
||
per-account, or per-workspace request parameter.
|
||
- Optional filters: none.
|
||
- Write-enabling filters: not applicable — no write action is exposed.
|
||
- Filters enforced by: **the credential itself.** The account boundary is the
|
||
only boundary, which is why the organization a credential resolves to has to
|
||
be confirmed at setup rather than assumed.
|
||
|
||
## Manifest
|
||
|
||
- schemaVersion: 1
|
||
- slug: `enterpret`
|
||
- name: Enterpret
|
||
- description: "Ask questions about your customer feedback and pull verbatim
|
||
quotes with citations."
|
||
- categories: `["analytics"]`
|
||
- branding and provenance: `/brands/apps/enterpret.png`. The official Enterpret
|
||
app icon, 256×256, retrieved 2026-09-23 from the `apple-touch-icon` linked by
|
||
`https://www.enterpret.com/`, unmodified.
|
||
SHA-256 `aca19ddae5f52a2caa4f3664286a76cd9439316e0fa3c39890f646536aebc522`.
|
||
The provider's nav logo is a 120×24 light-on-dark wordmark, wrong shape for a
|
||
square tile and unusable on a light frame; the app icon is the correct
|
||
official mark and needs no dark variant.
|
||
- docsUrl: `https://enterpret.support.site/article/enterpret-mcp-server`
|
||
- Methods:
|
||
|
||
| | `mcp-api-key` (primary) | `mcp-oauth` (OAuth) |
|
||
| --- | --- | --- |
|
||
| label | Use an auth token | Sign in with Enterpret |
|
||
| transport | `mcp_remote` | `mcp_remote` |
|
||
| auth | `api_key` | `oauth` |
|
||
| ownershipModes | `["customer"]` | `["dcr"]` |
|
||
| grantKinds | `["organization"]` | `["user"]` |
|
||
| defaults | `serverUrl` | `serverUrl`, `scopesHint: ["mcp:read"]` |
|
||
| credentialFields | `authorization`, password, required, secret | — |
|
||
| keyPlacement | header `Authorization`, prefix `Bearer ` | — |
|
||
| riskTier | S3 | S3 |
|
||
| release role | Primary / store-ready | Personal browser sign-in; fresh release QA pending |
|
||
|
||
`ownershipModes` omits `customer` on the OAuth method on purpose: Enterpret
|
||
documents no way for a customer to register their own OAuth application, and
|
||
`ownershipModes` must reflect what the provider advertises rather than the
|
||
`method()` helper's `["customer", "dcr"]` default.
|
||
|
||
- oauthStrategy and connectorProfile: not used. This is not a Paperclip-managed
|
||
OAuth provider.
|
||
- capabilityProfile and variants: not needed.
|
||
- tenantFields and extensionFields: none. There is no tenant identifier to
|
||
supply — the credential determines the organization.
|
||
- credentialSources: none. Not Vercel Connect eligible.
|
||
- configRequirements: none.
|
||
- guidanceMd, warnings, consoleLinks: see the generated definition at
|
||
`packages/shared/src/app-definitions/enterpret.json`.
|
||
- riskTier: S3. Enterpret exposes broad content access — an organization's
|
||
complete customer feedback corpus including verbatim quotes with speaker
|
||
attribution. It is not S4: no payments, external sends, refunds, production
|
||
deployment, deletion, or tenant-wide administration is documented.
|
||
- requiredResourceFilters: none, for the reason in
|
||
[Resource Filters](#resource-filters).
|
||
- urlPatterns: `["https://wisdom-api.enterpret.com/*"]`
|
||
- setupPrerequisite: not used; the account requirement is carried in method
|
||
warnings.
|
||
- redirectConstraints: `https-or-loopback-http` (unprobed).
|
||
- availability: omitted; organization-token and DCR OAuth methods are selectable
|
||
on this draft branch. Browse visibility is enabled. Release readiness still
|
||
requires the account-bound QA recorded below; selectable setup does not mean
|
||
the provider's pending fixes have been verified.
|
||
|
||
## Actions
|
||
|
||
**Observed.** An authenticated `tools/list` ran against the live server on
|
||
2026-09-25 and returned **8** tools. Two corrections to the previously
|
||
documented table:
|
||
|
||
- `execute_cypher_query` is **absent** from the live server. The legacy alias is
|
||
no longer served, so it cannot be called and does not need a policy.
|
||
- Every one of the 8 tools self-reports `readOnlyHint: true` — **including
|
||
`run_graph_query`**. Paperclip trusts provider annotations to derive
|
||
`riskLevel`, so a Cypher-executing tool self-certifies as `read` and lands on
|
||
Allowed by default. That is the provider's claim, not a verified property, and
|
||
it is exactly the case where a provider annotation should not be believed.
|
||
|
||
**Read the two status columns as the configuration used for the live validation
|
||
run.** Shipping defaults now classify `run_graph_query` as **write** (despite
|
||
the provider `readOnlyHint`) and put write/destructive actions on **Ask first**
|
||
via `recommendedDefaultsForApp` for Enterpret. Other observed tools remain
|
||
Allowed reads. The live-run `deny` below was applied by hand and is stronger
|
||
than Ask first; operators who want Off can still set that after connect. See
|
||
[Governance Defaults](#governance-defaults).
|
||
|
||
| Tool | Risk | Status in validation | Filters | Approval in validation | Audit fields | Negative case |
|
||
| --- | --- | --- | --- | --- | --- | --- |
|
||
| `get_organization_details` | read | active | credential org | allow | actor, run, connection, tool, outcome | ungranted actor is denied before dispatch |
|
||
| `get_graph_schema` | read | active | credential org | allow | same | same |
|
||
| `get_query_examples` | read | active | credential org | allow | same | same |
|
||
| `search_graph_fields` | read | active | credential org | allow | same | same |
|
||
| `search_graph_values` | read | active | credential org | allow | same | same |
|
||
| `run_graph_query` | **write** (Paperclip override) | **deny — set by hand; ships Ask first** | credential org | deny (set by hand) | same, plus redacted query shape | same |
|
||
| `find_user_quote` | read | active | credential org | allow | same, plus quote redaction | same |
|
||
|
||
Legacy aliases `get_schema` and `search_knowledge_graph` remain served for the
|
||
lifetime of an existing session and are dropped when the host refreshes its tool
|
||
list. `execute_cypher_query` is no longer served at all.
|
||
|
||
`run_graph_query` currently retains Paperclip's conservative **write** risk
|
||
classification and Ask first default because it accepts general Cypher. This
|
||
is a Paperclip policy safeguard, not evidence that Enterpret permits mutations.
|
||
Vivek's read-only clarification applies to this official MCP. A scope name or
|
||
tool name does not establish write access. A later risk-policy change can cite
|
||
Enterpret's server-side read-only contract and safe live query proof.
|
||
|
||
Denial was verified on the live connection: a granted agent calling
|
||
`run_graph_query` through the gateway got **HTTP 403 `deny_default`**, and the
|
||
tool was absent from that agent's own `tools/list`.
|
||
|
||
Evidence plan: `find_user_quote` returns verbatim customer text with speaker
|
||
attribution, and `run_graph_query` can return feedback records. Do not put
|
||
those results in screenshots, exported evidence, or PR text. Paperclip currently
|
||
retains provider responses close to verbatim in its invocation log, so a quote
|
||
tool call can persist feedback there. Limit access and retention accordingly;
|
||
the token-path QA uses only `get_organization_details` and records tool name,
|
||
decision, and outcome without copying the payload.
|
||
|
||
## Wizard Path
|
||
|
||
- User path (auth token, primary): gallery card → paste the token from
|
||
**Settings → Enterpret MCP** → access defaults.
|
||
- User path (OAuth): gallery card → **Sign in with Enterpret** → browser
|
||
authorization using instance-local DCR → access defaults.
|
||
- Configuration steps: none beyond credentials. There is no tenant field to
|
||
fill.
|
||
- Error states: expired auth token (check the dashboard expiry); an account with no
|
||
access to the organization's feedback. A scope *rejection* turned out not to
|
||
be one of them — Enterpret accepts the `mcp:read` request and reports broader scopes
|
||
(see [Scope decision](#scope-decision)), so the flow completes and the failure
|
||
is silent rather than visible in the wizard.
|
||
- Also observed on the live run, and not an Enterpret problem: a headless agent
|
||
hits HTTP 409 `user_authorization_required` on this connection's `per_user`
|
||
credential policy until the user grant is delegated to that agent.
|
||
- Redacted metadata shown: endpoint origin and path, method key, resolved
|
||
Enterpret organization from `get_organization_details`, tool names and count.
|
||
Never the token, the authorization code, or feedback content.
|
||
|
||
## Governance Defaults
|
||
|
||
- Default profile: Enterpret-specific `recommendedDefaultsForApp` — read
|
||
actions Allowed; write and destructive actions (including `run_graph_query`)
|
||
start as **Ask first**.
|
||
- Profile bindings: standard.
|
||
- Policies: `classifyRisk(..., "enterpret")` forces `run_graph_query` to
|
||
**write** even when the provider advertises `readOnlyHint: true`. Combined
|
||
with Ask-first defaults, new connections no longer ship that Cypher tool as
|
||
Allowed. Operators who want **Off** can still set that after connect.
|
||
- **Narrowing an install is not a containment control.** The gallery connect
|
||
flow creates both a company install and a company-level binding of the
|
||
`app:<connectionId>` profile. Restricting the install to named agents rewrites
|
||
the install and adds an agent binding but leaves the company binding in place,
|
||
which keeps authorizing every agent in the company. Installs gate runtime
|
||
materialization; the *profile binding* is what authorizes. Containment becomes
|
||
real only when the company binding is also removed. Verified on the live
|
||
connection: both agents still resolved 7 allowed tools after the install was
|
||
narrowed, and the ungranted control agent dropped to 0 of 8 only after the
|
||
company binding was unbound.
|
||
- Quarantine rules: `quarantineNewEntries` is connection-level runtime setup,
|
||
not an `AppDefinition` field. Paperclip enables it for Enterpret connections.
|
||
Enterpret's catalog demonstrably drifts — it renamed three tools and kept the
|
||
old names as session-scoped aliases, and `execute_cypher_query` has since
|
||
disappeared entirely — so newly advertised tools are held for review on a
|
||
subsequent catalog refresh, including after token replacement. The earlier
|
||
live run found the old default was
|
||
`false`; the new default still needs live refresh validation.
|
||
- Rate limits: none set.
|
||
|
||
## Validation Hook
|
||
|
||
### Organization auth-token QA (2026-09-30)
|
||
|
||
This was a separate **self-hosted, same-machine** run on an isolated worktree,
|
||
database, and Paperclip instance at App commit
|
||
`dbe63eaae16fdb2f5386b324067e482f84f7fc7a`. The account holder generated
|
||
one QA-only organization token in Enterpret's MCP settings. Its dashboard
|
||
showed **Expires in 3 months**, so setup copy must not promise six months.
|
||
The token value, feedback content, and full provider responses are excluded
|
||
from this record.
|
||
|
||
| Check | Observed result |
|
||
| --- | --- |
|
||
| Connect and discover | `mcp-api-key` connected as an organization grant; health was `ok`; authenticated catalog refresh found 8 tools. |
|
||
| Safe allowed read | `get_organization_details` returned success for the intended Enterpret organization. The same bounded read succeeded again after reconnect. No quote or graph-query tool was invoked. |
|
||
| Agent policy preview | The selected test agent's access summary changed the read action to `off` and back to `allowed` when its profile was toggled. The Test panel showed “No call will be made” while Off. |
|
||
| Refresh and reconnect | Catalog refresh retained 8 actions. Reconnecting with the same valid token preserved the connection and catalog quarantine setting. An intentionally invalid replacement failed, then reconnecting with the valid token restored `active`/`ok`. This is **not** evidence that an expired token was renewed or that rotating a token revokes its predecessor. |
|
||
| Activity | The safe call produced an explicit-grant decision and completed-call event. Connection activity remained queryable. |
|
||
| Local disable and removal | Disabling the QA connection exposed zero actions in the agent access summary. Archiving it cleared the local secret, grant, install, and catalog entries. |
|
||
| Provider-side revocation | After the Enterpret dashboard said the QA token was revoked, the same token immediately connected again and completed the same bounded organization read. Immediate provider-side invalidation **failed**. Vivek later explained invalidated tokens remain cached for 24 hours and committed to reducing the window. The new delay and deployment are unverified. Both QA connections were removed. |
|
||
| Actual agent execution | Not exercised on this token path. An earlier OAuth QA run proved agent-session denies through the real gateway, but it does not substitute for a token-path agent process. |
|
||
|
||
The board's `POST /tool-connections/:id/test-calls` is **not** an agent-policy
|
||
denial probe. With the agent's action Off, that endpoint still returned
|
||
`allowed` and invoked the safe provider read because it evaluates the board
|
||
user's policy. The agent access summary and Test panel correctly showed Off.
|
||
This mismatch is a shared Test endpoint issue, already noted in the OAuth QA
|
||
below; do not cite the test call as proof of an agent deny. The QA profile was
|
||
restored to Allowed. No customer-feedback content was requested.
|
||
|
||
This run did not exercise a real agent process, a self-hosted VPS, or Cloud.
|
||
Those remain separate verification steps before claiming those deployment
|
||
shapes.
|
||
|
||
### Earlier OAuth QA (2026-09-25)
|
||
|
||
- Environment: an **isolated, issue-owned Paperclip runtime** on the maintainer
|
||
host — its own `PAPERCLIP_HOME`, its own embedded Postgres, its own ports,
|
||
reachable tailnet-only over HTTPS. It shared nothing with any other instance:
|
||
no database, no credentials, no ports, no worktree. Torn down after the run.
|
||
- Deployment shape: **self-hosted, same machine.** Self-hosted VPS and Cloud
|
||
remain untested, and nothing below is inferred for them.
|
||
- Method keys exercised: `mcp-oauth`. `mcp-api-key` remains untested.
|
||
- Date and tested commit: 2026-09-25, App
|
||
`ef1606f037a7828a7ba774949e811847c1a1d386`
|
||
- Account: a named Enterpret account holder signed in personally through the
|
||
isolated UI and consented. Paperclip never saw a password, an OTP or an
|
||
authorization code, and no token value appears in any artifact.
|
||
- Client registration: dynamic. `registrationSource: "dcr"`, a **public** client
|
||
(`token_endpoint_auth_method: none`, so there is no client secret). Nothing
|
||
was pre-registered by hand.
|
||
- Provider metadata: re-read on the day of the test and unchanged from the
|
||
2026-09-23 reading, field for field.
|
||
|
||
Unauthenticated reproduction — these need no account and are safe to re-run:
|
||
|
||
```sh
|
||
curl -s -i -X POST https://wisdom-api.enterpret.com/server/mcp \
|
||
-H 'Content-Type: application/json' \
|
||
-H 'Accept: application/json, text/event-stream' \
|
||
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"probe","version":"0"}}}'
|
||
curl -s https://wisdom-api.enterpret.com/server/mcp/.well-known/oauth-protected-resource
|
||
curl -s https://oauth.enterpret.com/.well-known/oauth-authorization-server
|
||
```
|
||
|
||
Reproducing the scope finding needs a live token. The shape of the check, with
|
||
the token withheld:
|
||
|
||
```sh
|
||
# RFC 7662. `scope` here is the scope OF THIS TOKEN, which is the only place
|
||
# the scope mismatch is visible: the token is opaque and the token response omitted
|
||
# `scope` entirely.
|
||
curl -s https://oauth.enterpret.com/introspect \
|
||
-d "token=$ACCESS_TOKEN" -d "client_id=$DCR_CLIENT_ID"
|
||
# -> {"active": true, "scope": "openid email profile mcp:read mcp:write", ...}
|
||
|
||
# Negative control, same client_id, bogus token. Proves the scope is bound to
|
||
# the token rather than echoed back from the client registration.
|
||
curl -s https://oauth.enterpret.com/introspect \
|
||
-d "token=not-a-real-token" -d "client_id=$DCR_CLIENT_ID"
|
||
# -> {"active": false, "rejection_reason": "invalid_token"} (no `scope` field)
|
||
```
|
||
|
||
**Method note for the next connector.** Do not use
|
||
`POST /tool-connections/:id/test-calls` to show that an ungranted agent is
|
||
denied. It accepts an `agentId` and returns a `decision`, so it reads like an
|
||
agent-authorization probe, but it evaluates policy as the **board user**, which
|
||
is full-control by design. During this run it returned `decision: "allowed"` and
|
||
executed a real provider call for an agent that was denied on all 8 tools. Every
|
||
denial row below was instead produced through the real agent path: mint an agent
|
||
API key, open a gateway session, and call with the session token.
|
||
|
||
### Nine production-validation scenarios
|
||
|
||
Per deployment, self-hosted first. Cloud has no evidence of any kind and is
|
||
never inferred from a self-hosted result.
|
||
|
||
| Scenario | Self-hosted, same machine | Self-hosted, server/VPS | Cloud |
|
||
| --- | --- | --- | --- |
|
||
| Setup and consent | **pass** — account holder signed in; connection reached `active`, health `ok` | not run | not run — no Cloud instance |
|
||
| Authentication | **pass** — DCR public client registered against the live provider; token exchange succeeded | not run | not run |
|
||
| Catalog and configuration | **pass** — authenticated `tools/list` returned 8 tools; `execute_cypher_query` absent | not run | not run |
|
||
| Allowed execution | **pass** — `get_organization_details` resolved to the intended organization; one further bounded metadata read also succeeded | not run | not run |
|
||
| Denied execution | **pass** — ungranted agent got HTTP 403 `deny_default` and saw 0 tools; `run_graph_query` stayed 403 for the *granted* agent | not run | not run |
|
||
| Runtime delivery | **not proven** — gateway and policy were exercised by a real agent-authenticated session, but no agent process ever ran; see below | not run | not run |
|
||
| Refresh and recovery | **not run** — refresh deliberately not exercised once the scope mismatch was found | not run | not run |
|
||
| Revoke and reconnect | **cannot pass** — no `revocation_endpoint` exists to call. Local disable verified: the connection was disabled and the gateway decision flips to deny | cannot pass — structural, not deployment-dependent | cannot pass |
|
||
| Activity and secret handling | **pass** — invocations audited with correct decisions and actor attribution; tokens AES-256-GCM at rest with no plaintext in secret storage; API returns `secretId` references only | not run | not run |
|
||
| **Granted scope (OAuth)** | **scope mismatch observed** — reported scopes differed from the request; write capability was not established; fresh OAuth QA pending | fails identically for OAuth — provider-side | fails identically for OAuth |
|
||
|
||
Self-hosted VPS and Cloud are `not run`, not "probably fine". Nothing in the
|
||
same-machine column is carried across, and nothing here is carried over from the
|
||
PAP-18519 loopback mirror either.
|
||
|
||
**Why runtime delivery is `not proven`, precisely.** Every allowed and denied
|
||
result above was produced through the real gateway path — an agent-minted
|
||
session, `actor_type: agent` on the invocation row, decided by the real policy
|
||
service. What did **not** happen is an agent *process*. Minting that session
|
||
requires a `heartbeat_runs` row, and the two rows used here were inserted by
|
||
hand for that precondition alone. Both show `started_at` NULL, no pid, no
|
||
transcript and no run events other than the reaper's, and the instance later
|
||
marked them `failed` / `process_lost` — which is the reaper correctly noticing
|
||
there was never a process behind them, not a product defect. So this connector
|
||
is proven to work under Paperclip's *authorization and transport* layer, and is
|
||
untested under an actual agent runtime driving it through a heartbeat. Scenario
|
||
6 needs a genuine woken agent run before it can be called a pass.
|
||
|
||
Three further findings from the run, recorded because they change how an
|
||
operator should read this connector rather than what it does:
|
||
|
||
- **`per_user` credential policy blocks unattended agents.** A headless run has
|
||
no acting user, so a `kind: user` grant yields HTTP 409
|
||
`user_authorization_required`. The minimal fix is a delegation of that one
|
||
grant to that one agent — narrower than promoting to an organization grant,
|
||
and it widens nothing at the provider. The delegation path additionally
|
||
requires the run's `invocationSource` to be `automation` or `timer`; an
|
||
`on_demand` run stays 409. Note `credentialPolicy: per_user` is a runtime
|
||
default here, not something this definition pins.
|
||
- **Tool results are persisted close to verbatim.** `result_summary` on an
|
||
invocation stores the provider response body with an empty `redactedFields`.
|
||
It stays in the instance database, but for Enterpret that means a
|
||
`find_user_quote` result would write customer feedback text into the run log.
|
||
`find_user_quote` was deliberately **not** called during validation.
|
||
|
||
### Deployment support matrix
|
||
|
||
Labels as defined in the connector skills' shared matrix.
|
||
|
||
| Capability | Self-hosted, same machine | Self-hosted, server/VPS | Cloud |
|
||
| --- | --- | --- | --- |
|
||
| Definition generates, validates and typechecks | `verified` | `verified` | `verified` — the checks are deployment-independent |
|
||
| Official branding passes the artwork checks | `verified` | `verified` | `verified` |
|
||
| Provider metadata discovery resolves (RFC 9728 → 8414) | `verified` against the provider, from this runtime | `verified` — same request, no deployment dependency | `untested` |
|
||
| Paperclip's discovery ladder resolves this shape | `verified` against the live provider | `untested` | `untested` |
|
||
| DCR client registration | `verified` — public client registered at connect time, nothing pre-registered | `untested` | `untested` |
|
||
| OAuth consent and token exchange | `verified` | `untested` | `untested` |
|
||
| Auth-token (header) connection | `verified` — connected, discovered 8 tools, and completed a safe read on 2026-09-30 | `untested` | `untested` |
|
||
| Authenticated `tools/list` | `verified` — 8 tools on OAuth and the organization-token path | `untested` | `untested` |
|
||
| Agent execution through the gateway | `verified` on OAuth — allowed and denied paths through an agent-authenticated session; token path used the board Test panel only | `untested` | `untested` |
|
||
| Execution driven by an actual agent runtime | `untested` — the sessions above were minted against hand-inserted run rows; no agent process ran | `untested` | `untested` |
|
||
| Granted scope matches the requested scope (OAuth) | `scope mismatch observed` — fresh OAuth QA pending; scope names do not establish write capability | `failed` for OAuth — provider-side | `failed` for OAuth — provider-side |
|
||
| Provider-side revocation | OAuth has no advertised `revocation_endpoint`; the organization token's dashboard Revoke control failed an immediate denial check on 2026-09-30 | `untested` | `untested` |
|
||
| Store visibility (token path) | `ready` — organization auth token is primary; both auth methods target the official read-only MCP | `ready` — same definition | `ready` — same definition |
|
||
|
||
### What must happen before this is store-visible
|
||
|
||
**Organization auth token path (primary) — release criteria**
|
||
|
||
Steps 1–3 below are **done** as of 2026-09-25 and are kept for the record. The
|
||
mechanical store-visibility flip for the token path is also done on this branch
|
||
(clear `availability`, remove `"enterpret"` from `APP_STORE_HIDDEN_SLUGS`, set
|
||
`catalogVisible: true`). Remaining follow-ups improve confidence; they are
|
||
**not** blocked on Enterpret fixing OAuth scopes.
|
||
|
||
1. ~~An authorized Enterpret organization credential, held by a named owner.~~
|
||
**Done** — a named account holder signed in personally (OAuth path).
|
||
2. ~~An authenticated `tools/list`, to replace the documented tool table with an
|
||
observed one and to classify `run_graph_query`.~~ **Done** — 8 tools
|
||
observed. `run_graph_query` is still not classifiable: its only annotation is
|
||
the provider's own `readOnlyHint: true`, which the live evidence gives no
|
||
reason to trust. Enterpret states public tools are read-only today; treat
|
||
that as product guidance, not a substitute for a Paperclip deny policy.
|
||
3. ~~Authorization to attempt DCR against `oauth.enterpret.com`.~~ **Done** —
|
||
DCR succeeded; a public client, no pre-registration needed.
|
||
4. ~~Catalog visibility for the token path.~~ **Done on this branch** —
|
||
`availability` cleared, `"enterpret"` removed from `APP_STORE_HIDDEN_SLUGS`,
|
||
`catalogVisible: true`, tests and Storybook updated so organization auth
|
||
token is primary. OAuth is now selectable for the official read-only MCP.
|
||
5. **Partly done 2026-09-30:** `mcp-api-key` connected on an isolated
|
||
self-hosted instance; authenticated catalog, bounded allowed read, refresh,
|
||
failed replacement and valid reconnect, local disable, removal, and activity
|
||
passed. Token-path agent-session deny remains untested. The board Test
|
||
panel's Off preview is not a substitute for that check.
|
||
6. **Partly done:** reconnect with the same valid token and recovery from an
|
||
invalid replacement passed. Recovery from actual expiry and server/VPS
|
||
deployment remain untested. The dashboard's revocation confirmation failed
|
||
the immediate invalidation check; old-token invalidation after rotation was
|
||
not tested.
|
||
|
||
**Both auth methods — release validation and provider follow-up**
|
||
|
||
OAuth is supported for the official read-only MCP. Before calling the new
|
||
revision release-ready:
|
||
|
||
- Test a fresh OAuth authorization and refresh against the current provider.
|
||
Record requested and reported scopes without
|
||
treating scope names as proof of access to the beta Agent MCP.
|
||
- Exercise a safe allowed read and a denied call through a real agent session;
|
||
the board Test endpoint does not prove agent authorization.
|
||
- Document the current revocation behavior: invalidated tokens can remain
|
||
active in Enterpret’s cache for up to 24 hours. Local disconnect removes
|
||
Paperclip’s stored credential and access, but does not immediately invalidate
|
||
copies elsewhere. The account holder accepted shipping with this known limit.
|
||
- After deployment, follow up on Enterpret’s OAuth fix and reduced revocation
|
||
window. Confirm the new maximum delay and retest after the provider deploys
|
||
those fixes. These provider changes are fast follows, not release gates.
|
||
- Keep Enterpret Agent's beta write MCP outside this PR. Adding it later needs
|
||
separate endpoint, credential-boundary, action-risk, and write QA review.
|
||
|
||
The connector can ship with current provider behavior once Paperclip’s
|
||
functional QA, CI, and review pass. Keep the PR draft until those checks pass;
|
||
do not block release on the provider’s fast-follow fixes.
|