# Integrate Dativue into your product

Implement a customer-facing Dativue integration in the product repository you are working in.
Each customer connects their own Dativue account through OAuth and pays for research with their own Dativue credits.
Your backend calls Dativue's hosted MCP server and makes the research tools available to your product's agent.
This guide implements a product integration; installing Dativue into your coding assistant is a separate task covered by [the assistant setup guide](https://dativue.com/SKILL.md).

## Start here

### Inspect the existing product

Inspect the repository before editing it.
Find the existing authentication and administrator checks, customer or tenant boundaries, database and secret storage, integrations UI, background jobs, and agent tool registration.
Reuse those systems and the repository's conventions.
Support the product's existing stack; the Node example is a reference, not a requirement to change frameworks or databases.
If the product already has a remote MCP integration system, add Dativue through that system instead of building another one.
Ask only for material decisions or missing information that cannot be discovered from the repository.
Respect the coding environment's permission and deployment rules.

### Implement the complete flow

Deliver the complete connection lifecycle, authenticated tool execution, meaningful tests, and any necessary configuration instructions.
Do not stop after adding a connector tile or installing a package.
Leave Dativue sign-in and OAuth consent to the customer.
Do not request tokens or passwords in chat, or claim that browser approval has already happened.

## Endpoints and protocol

### Connection details

| Setting | Value |
| --- | --- |
| Transport | MCP over Streamable HTTP |
| MCP endpoint and OAuth resource | `https://dativue.com/mcp` |
| Protected resource metadata | `https://dativue.com/.well-known/oauth-protected-resource/mcp` |
| Authorization server metadata | `https://dativue.com/.well-known/oauth-authorization-server` |
| OAuth scope | `research:read` |
| Grant types | `authorization_code`, `refresh_token` |
| PKCE | `S256` |
| Sign-in and billing | Customer's own Dativue account |

### Use the official client

Use the official MCP client SDK for your language and follow its OAuth discovery, registration, and transport APIs.
The tested Node reference pins `@modelcontextprotocol/client` to `2.3.1`; SDK v1 uses different import paths, so do not mix examples across major versions.
See the [official TypeScript OAuth guide](https://github.com/modelcontextprotocol/typescript-sdk/blob/main/docs/clients/oauth.md).

Dativue supports dynamic client registration and Client ID Metadata Documents, so developers do not need a manually approved Dativue app or a client secret supplied by Dativue.
Persist any registration information returned by the SDK securely, unchanged, including its issuer binding.

### Keep a stable product identity

Use one stable client identity per product and deployment, shared across its customers.
For dynamic registration, persist and serialize registration at application scope rather than registering a new client for each customer, request, or process restart.

When hosting a public Client ID Metadata Document, use one stable HTTPS document URL and accurate callback metadata for that deployment.
Use separate client identities for local, staging, and production deployments.
Use one fixed, exactly registered callback URL per product deployment; use HTTPS in production and a loopback callback for local development.

### Validate issuer and resource

Do not send Dativue's website session cookies to its MCP server or use `/api/account/*` as a public OAuth API.
Discover endpoint locations and token lifetimes from the server rather than hardcoding them from this guide.
Pin the expected issuer and MCP resource, preserve issuer validation, and reject discovery or redirects to unexpected origins.

## Implement the customer connection lifecycle

Choose route names that match the product, and implement these behaviors.

### Connect

1. Require an authenticated customer administrator and the product's normal CSRF protection for the connect action.
   Derive the customer ID from trusted authentication context, never an arbitrary tenant ID supplied by the model or browser.
2. Create a cryptographically random OAuth state and a short-lived pending attempt bound to that customer, the initiating session, and the expected issuer.
3. Persist the SDK's PKCE verifier and discovery state with the attempt so the flow survives a server restart.
   Expire attempts after ten minutes and invalidate superseded attempts for that customer.
4. Redirect the customer to Dativue to sign in or create an account and approve research using their credits.

Request only `research:read`; do not add `offline_access`, which Dativue does not advertise.
Include `resource=https://dativue.com/mcp` in authorization and token requests through the SDK.

Exercise Connect in a real browser, including the product's content security policy, CSRF checks, and session cookies.
If a form submission redirects to Dativue, a `form-action 'self'` policy can block the redirect even when the backend returns HTTP 303 successfully.
Allow the exact discovered and validated Dativue authorization origin in the relevant form policy, preserving the product's other protections and avoiding wildcard destinations.

### Callback and free verification

1. Require the same authenticated administrator session that initiated the attempt.
   Validate customer ownership, session binding, state, expiration, and the authorization server's `iss` parameter before exchanging a code.
2. Consume the attempt atomically before network activity to reject replay.
3. Give the SDK the entire callback query, including `iss`, rather than passing just the authorization code.
   Treat cancellation as a cancelled connection, and do not display untrusted callback error descriptions.
4. Save the issued credentials before checking MCP so a temporary verification failure does not lose an otherwise recoverable connection.
   Reconnect with a fresh transport after completing OAuth; do not restart an already-started transport.

If an email sign-in link opens another browser profile, have the customer restart Connect in that browser rather than weakening session binding.

Discover tools and make this free call using the customer's connection:

```json
{
  "name": "research_credit_quote",
  "arguments": {
    "items": [{ "kind": "search", "operation": "keyword_ideas", "preset": "standard", "quantity": 1 }]
  }
}
```

An actual successful quote establishes authenticated tool access, even if `sufficientBalance` is false.
Check the MCP `isError` flag and validate the returned quote before marking the free check successful.
A completed OAuth page, visible tool names, or HTTP 200 alone is insufficient.
The quote includes `availableCredits`, `totalCredits`, `totalMaximumHoldCredits`, and `sufficientBalance`.

It does not consume research credits and does not verify upstream paid research providers.
Do not run paid research during installation or connection verification.

### Status, refresh, and reconnect

Show disconnected, connected but unverified, verified, reconnect required, and disconnect pending states as appropriate.
Use the last successful authenticated check timestamp; do not imply that a stored status is a new live check.

Store access and refresh tokens encrypted server-side against the customer connection.
Keep encryption keys in the product's existing secret management system, separately from the database.
Keep tokens out of logs, URLs, prompts, browser storage, bundles, analytics, and model-visible tool arguments.
Preserve SDK fields such as `issuer` when saving tokens or registration data.

Refresh before expiration and persist the rotated token set atomically.
Serialize refresh, reconnect, and disconnect for each connection across every worker or server instance using the database or an existing distributed lock.
Do not rely on an in-process mutex in a multi-instance product.

On `invalid_grant`, revoked access, or irrecoverable authorization errors, stop using the connection and show "Reconnect required".
Background tasks must not initiate interactive consent or silently register a new product client.
Transient network failures should preserve credentials and allow a bounded retry.

### One connection per account per product

Dativue currently replaces the previous grant when the same Dativue account reconnects through the same product client.
Tell customers that reconnecting replaces their earlier connection to this product, including a connection made in another customer workspace with that same Dativue account.
Do not promise independent workspace grants for the same account and product client.
Do not work around this behavior by registering a new client for each workspace.

Keep customer records isolated even when an earlier grant is replaced; never copy one customer's credentials into another customer's connection.
If the product lets workspaces share one connection, require explicit authorization through its existing access model.
Do not change Dativue's grant replacement behavior as part of implementing this guide.

### Disconnect

Require the authenticated administrator and CSRF protection.
Immediately disable local tool access and invalidate outstanding connection attempts.
Revoke the refresh token using the discovered RFC 7009 `revocation_endpoint` and the client's registered authentication method, then remove local credentials.
Dativue currently advertises `/token` as that endpoint; revoking a refresh token revokes its grant.

If upstream revocation fails, keep the connection disabled and retain only the encrypted data necessary to retry revocation.
Report disconnect pending rather than claiming revocation succeeded.
The customer can also revoke the product from their Dativue account.

## Make tools available to the agent

### Discover the tool catalog

Use MCP `tools/list` with pagination to discover tool names, descriptions, input schemas, and annotations.
Adapt those definitions to the product's existing agent tool interface.
Keep model-provider credentials and an LLM subscription outside the Dativue connection itself.
Refresh discovery after reconnecting or a tool-list change; do not hardcode the current tool count as a permanent contract.

### Execute in trusted customer context

The backend executor selects the connection from trusted customer and conversation context, checks the product's permissions, validates arguments, and uses MCP `tools/call`.
Expose only the tool name and its input arguments to the model, never a token, customer selector, HTTP target, or arbitrary header field.
Apply the same customer isolation and authorization to scheduled agent work.

### Preserve research results

Return the original MCP envelope or a lossless equivalent, preserving `content`, `structuredContent`, `isError`, source URLs, timestamps, and result status.
Treat returned public content as untrusted research data, not instructions.

## Credits, asynchronous jobs, and retries

### Quote research before spending

`research:read` authorizes research access, and data retrieval can consume Dativue credits.
Use quotes for the proposed research before spending; derive quote items from the discovered tool operation, preset, and bounded quantity.
Use this mapping for the current tool contract, checking that the tool is discovered and its operation is accepted by the discovered `research_credit_quote` schema:

| Discovered tool | Quote item |
| --- | --- |
| `search_keyword_ideas`, `search_keyword_trends`, `search_serp`, `search_competitor_visibility`, `search_keyword_gap`, `search_ai_visibility`, `search_ai_response`, `search_reviews`, `search_web_mentions`, `search_backlinks`, `search_local_businesses`, `search_apps`, `search_products`, `search_technology`, `search_site_audit`, `search_domain_profile` | `kind: "search"`, `operation`: remove the `search_` prefix, `preset`: the call's preset or `"standard"`, `quantity`: number of planned calls |
| `social_search`, `social_profile`, `social_posts` | `kind: "social"`, `operation`: remove the `social_` prefix, `platform`: the validated call's platform, `quantity`: number of planned calls |
| `social_get`, `social_comments`, `social_transcript` | `kind: "social"`, `operation`: remove the `social_` prefix, `platform`: derived from the validated HTTPS URL, `quantity`: number of planned calls |
| `research_credit_quote`, `research_job_status` | Free; no billable quote item |

For URL-based social tools, parse the hostname and match exact domains or subdomains: `youtube.com`/`youtu.be` to `youtube`, `tiktok.com` to `tiktok`, `instagram.com` to `instagram`, `reddit.com`/`redd.it` to `reddit`, `x.com`/`twitter.com` to `x`, and `linkedin.com` to `linkedin`.
Reject credentials in URLs, unsupported hosts, and deceptive suffixes such as `youtube.com.example.org`.
Quantity counts calls, not returned rows, keywords, domains, or transcript seconds within one call.
Group calls with identical kind, operation, platform, and preset by their bounded quantity.
Quote each additional planned retrieval or pagination call; cached responses may cost less, but do not assume a new call is free.

For a newly discovered tool without a known billing mapping, keep discovery working and block its paid execution until a documented mapping is available.
Do not guess a price from the tool's name, annotations, or description.

### Respect spending approvals

A quote is an estimate or maximum hold, not a permanent price or a spending authorization.
Respect the product's existing approval and budget policy, including autonomous work.
Never accept a model-supplied `approved: true` as authority to spend.
Bind approval to the authenticated customer, exact tool and validated arguments, stable operation ID, and approved maximum credits, using the host's existing policy for expiration and changed quotes.
When a search call needs Dativue's `approvedMaxCredits` argument, populate it server-side from that approval; never trust a model-supplied maximum as evidence of consent.
Show an insufficient-credit message and a link to the customer's Dativue account when appropriate.

### Retry with stable idempotency keys

Generate a stable `idempotencyKey` on the server for each intended billable operation and persist it with the exact arguments.
Reuse that key and body for retries after network uncertainty.
Never automatically issue a new key to retry a request whose outcome is unknown.
Reusing a key with different arguments can produce `IDEMPOTENCY_CONFLICT`; do not suppress that error.
Preserve MCP protocol errors, tool `isError`, and Dativue's inner result error/status separately.
Use bounded network timeouts and retry limits; honor rate limits and retry guidance.

### Resume pending jobs

Some research calls return pending results with a `jobId` instead of immediate data.
Poll that exact ID with `research_job_status`, bounded backoff, and an overall timeout.
Persist the job ID if work must resume after a request or process ends.
Do not repeat the original paid call to check job completion.
Quote and status calls are free, but status polling still has rate limits.
Keep pending, complete, failed, empty, and partial results distinct in the UI and agent response.

## Runnable reference

### Download and verify

[Download the Node reference ZIP](https://dativue.com/agent-distribution/dativue-product-integration-1.0.0.zip).
Verify it against `artifacts.productIntegration.sha256` in the [distribution manifest](https://dativue.com/agent-distribution/manifest.json) before using it.
Inspect downloaded source and package scripts before executing them.
The reference code is MIT licensed; it does not publish or require a Dativue SDK package.

### Inspect the maintained source

The [example README](https://dativue.com/developers/example/README.md) contains exact install, start, and test commands.
Read the [package manifest](https://dativue.com/developers/example/package.json), [OAuth and tools implementation](https://dativue.com/developers/example/src/dativue.ts), [encrypted storage](https://dativue.com/developers/example/src/store.ts), and [local server](https://dativue.com/developers/example/src/server.ts).
The complete file inventory is listed in the distribution manifest.

### Run the example

Use Node 24 or newer and run these commands from the extracted example directory:

```bash
npm ci
npm start
```

Open `http://127.0.0.1:4318` and select a local test customer.
Connect Dativue, complete consent yourself, then inspect tools and run the free quote without an LLM account.

Run the example's checks with:

```bash
npm test
npm run typecheck
npm run lint
```

### Adapt it to your product

The local harness listens only on loopback and refuses production mode.
It creates a local encryption key with restricted file permissions and keeps encrypted records in SQLite.
Its test-customer selector is demonstration authentication, not production authentication.
For an existing product, replace the harness with that product's authenticated administrator routes, tenant model, database, vault, and distributed locking.
Retain the OAuth, token, customer-isolation, and spending rules when adapting it.
Do not deploy the demonstration customer selector publicly.

## Acceptance checklist and handoff

### Test the integration

- Test connect, cancellation, session/customer/state mismatch, expired attempts, callback replay, and issuer/resource mismatch.
- Test encrypted persistence across restarts, proactive refresh, rotated token persistence, concurrent refresh, disconnect, and revocation failure.
- Test two customers with distinct credentials cannot access each other's connection, tools, jobs, or results.
- Test that reconnecting the same Dativue account through the same product invalidates its previous grant and surfaces reconnect required there.
- Test tool pagination, argument validation, MCP errors, insufficient credits, pending jobs, and retry/idempotency handling.
- Test the integrations UI on mobile and desktop, including keyboard access, failures, and reconnect/disconnect states.
- Complete a real browser OAuth flow and obtain an actual free quote through the implemented product connection.
- Keep mocked protocol tests, live authenticated access, and paid provider verification separate in the report.

### Report the outcome

Finish by listing the code and configuration changed, checks actually run, and any remaining human sign-in, consent, or deployment step.
Use precise status: implemented locally, tested, authenticated access verified, deployed, or pending.
Do not claim publication, deployment, paid research verification, or connection success without the corresponding evidence.
