# Dativue product integration reference

A runnable customer OAuth integration using Hono, Node, and the official MCP client.
No LLM account or model API key is needed.
Research uses each connected customer's own Dativue credits.
The reference source is MIT licensed.

## Run locally

Install Node 24 or newer.
Extract the downloaded archive and run these commands inside its directory:

```sh
npm ci
npm start
```

Open http://127.0.0.1:4318 and select customer-a.
Choose Connect Dativue, sign in, and approve research using your credits.
Open email sign-in links in the same browser profile that started Connect Dativue.
If your email app opens another browser, restart the local customer selection and connection in that browser after sign-in.
The callback automatically runs a free research_credit_quote and shows its real response.
Discover tools, inspect their schemas, and run further free quotes in the form.
Paid research requires the explicit approval checkbox and an idempotencyKey in its JSON arguments.
Quote the intended operation first and reuse the same key and arguments when retrying it.
Poll pending job IDs with research_job_status; do not repeat the original paid request.
No paid research runs automatically.

Customer-b is isolated from customer-a.
If you link the same Dativue account to customer-b, its new grant replaces the older grant for customer-a because both use the same product client.
Customer-a will show reconnect required on its next authenticated call.
Use distinct Dativue accounts to test two concurrently usable customers.

Run the controlled protocol and storage tests:

```sh
npm test
npm run typecheck
npm run lint
```

Tests use an isolated local OAuth/MCP fixture and do not spend real Dativue credits.
A successful free quote against Dativue verifies authentication, not upstream paid providers.

## Local persistence and security

The server binds to 127.0.0.1, rejects unexpected hosts and cross-origin mutations, and refuses production mode.
The two-customer selector is demonstration authentication and must never be exposed publicly.
The local server creates .local/key with restricted permissions and stores AES-256-GCM encrypted records in .local/connections.sqlite.
The key is separate from the database; keep both private and never commit them.
Sessions, OAuth state, PKCE verifiers, credentials, and discovery data survive process restarts.
The database lease serializes each customer's refresh, reconnect, and disconnect across local processes.
The default port is 4318; optionally copy .env.example to .env and choose another local port.
Keep the same port across a connection's lifetime, because callback URLs are registered exactly.
Use separate data directories for separate product deployments.
Do not delete .local to reset the app until you disconnect its accounts, or revoke this example from those Dativue accounts first.

## Embed in an existing product

Read the complete integration guide at https://dativue.com/developers/integrate.md.
Reuse the product's authentication, administrator checks, customer model, integrations UI, and agent runtime.
Replace the demonstration routes in src/server.ts rather than adding a new login system to your product.
Derive the customer ID from trusted authentication context before calling the integration.
Use the same identity for interactive and scheduled research, with explicit workspace access checks.
Replace src/store.ts with your production database, encryption or vault, and distributed locking while retaining its lifecycle guarantees.
Use one stable OAuth client identity per product deployment and retain issuer-bound registration information unchanged.
Use HTTPS callbacks in production, and preserve the expected issuer and resource checks.

The backend lifecycle methods in src/dativue.ts are:

| Method | Behavior |
| --- | --- |
| start(customerId, sessionId) | Persist a ten-minute session-bound attempt and return the consent URL |
| callback(customerId, sessionId, params) | Consume state once, finish OAuth, persist credentials, and verify with a free quote |
| status(customerId) | Return stored connection status and the last successful free-check timestamp |
| verify(customerId) | Make a real free quote using the customer's credentials |
| tools(customerId) | Discover all tool definitions, including paginated schemas |
| call(customerId, name, arguments, approved) | Execute a discovered tool and preserve the MCP result envelope |
| disconnect(customerId) | Disable local access, revoke the refresh token grant, and delete credentials |

In production, approved must come from your existing server-side authorization and spending policy, never the language model.
Generate and persist billable operation IDs in your backend; the local form requires you to supply a stable idempotencyKey explicitly so retries are visible.
No automatic retry of a paid operation is performed.
When a result is pending, persist its jobId and resume bounded status polling through the same customer connection.
Keep the tool schema, MCP errors, source URLs, timestamps, and inner result statuses intact when adapting the tools to your agent framework.

Disconnect blocks local tool access before attempting upstream revocation.
If revocation fails, encrypted credentials remain only so disconnect can be retried; the connection stays disabled.
Do not report upstream revocation complete until it succeeds.

## Public source inventory

The ZIP contains this README, LICENSE, package.json, package-lock.json, tsconfig.json, eslint.config.mjs, .gitignore, .env.example, and every src/*.ts file.
The distribution manifest supplies its version, checksum, and public source URLs.
No .env, local databases, tokens, encryption keys, or node_modules are included.
