DD

dexter-dao/dexter-mcp

Developer tools
11 stars 6 forks Quality 63 Trend 38

Source for the hosted Dexter and OpenDexter MCP runtimes, including OAuth-bound Wallet, x402, and governed asset tools.

Overview

Dexter API · Dexter FE · Dexter MCP · Dexter Vault · Dexter Facilitator This repository contains one codebase for two independently deployed OAuth MCP services and the shared @dexterai/x402-core package: The npm packages (@dexterai/opendexter, @dexterai/x402-discovery) live in Dexter-DAO/opendexter-ide. This OpenDexter source candidate requires the coordinated internal package train recorded in release/opendexter-dependency-train.json. Its release runtime is Node ^20.19.0 || >=22.12.0, matching the pinned Vite toolchain; npm run verify:release:runtime checks that boundary before install or build. The exact internal versions are published and this candidate carries a registry-resolved lock. Release construction fails closed if either the lock or installed graph drifts from the recorded train.

README

Dexter API · Dexter FE · Dexter MCP · Dexter Vault · Dexter Facilitator

This repository contains one codebase for two independently deployed OAuth MCP services and the shared @dexterai/x402-core package:

Product Endpoint Auth Payment
Dexter MCP (full platform) mcp.dexter.cash/mcp Dexter OAuth Managed wallet, automatic
OpenDexter MCP open.dexter.cash/mcp OAuth scope=vault before discovery or use Session-bound passkey wallet; explicit user or policy authority

The npm packages (@dexterai/opendexter, @dexterai/x402-discovery) live in Dexter-DAO/opendexter-ide.

This OpenDexter source candidate requires the coordinated internal package train recorded in release/opendexter-dependency-train.json. Its release runtime is Node ^20.19.0 || >=22.12.0, matching the pinned Vite toolchain; npm run verify:release:runtime checks that boundary before install or build. The exact internal versions are published and this candidate carries a registry-resolved lock. Release construction fails closed if either the lock or installed graph drifts from the recorded train. An isolated local source train and its installed dependency graph can be checked without deploying:

OPENDXTER_IDE_SOURCE=/absolute/path/to/opendexter-ide-candidate \
DEXTER_VAULT_SDK_SOURCE=/absolute/path/to/dexter-vault-sdk-candidate \
OPENDEXTER_API_SOURCE_ROOT=/absolute/path/to/dexter-api-candidate \
OPENDEXTER_FACILITATOR_SOURCE_ROOT=/absolute/path/to/dexter-facilitator-candidate \
OPENDXTER_RUNTIME_ROOT=/absolute/path/to/disposable-installed-graph \
  npm run verify:release:source

The source gate verifies the current Node runtime, package Git provenance, exact installed versions, source-link destinations, built entrypoints, and npm peer closure. Before npm can run, it rejects dirty or unpinned external source repositories and any pack lifecycle hook outside the exact reviewed contract. Vault’s declared prepack command is matched byte-for-byte but never executed: the gate exports the reviewed SDK commit into a disposable directory, performs an exact-lock scripts-disabled install and the explicit reviewed build with npm 10.9.3, then requires the packed bytes to match the registry artifact exactly. It never uses or changes the source checkout’s ignored dist/ or node_modules/. Release construction separately verifies the Node runtime and registry lock, performs the exact-lock install and reviewed builds, and rejects any installed graph that differs from the recorded train. Descriptor generation exports the exact Git commit into a disposable directory, installs that archive from its lock, runs only the reviewed workspace build, and executes the archived materializer. Mutable checkout files and ignored node_modules are never descriptor evidence.

Use npm run build:apps-sdk:local for a non-deploying widget build. build:apps-sdk retains its release behavior and copies served assets. After the API and facilitator releases have been accepted in production, freeze their advertised immutable identities and regenerate the hosted derivatives in one step:

npm run prepare:open-accepted-production

Preparation reads https://api.dexter.cash/health and https://x402.dexter.cash/version exactly once each. It writes the generated release/opendexter-accepted-production.json receipt, derives the existing public sourceContracts/v3 projection from that receipt, and regenerates the hosted descriptor. Release verification, construction, and activation read only those frozen files; they never resolve mutable production endpoints. Construct a sealed candidate from the current clean, canonical Git commit into an explicit trusted release root without activating it:

npm run build:mcp-release -- --output-root /absolute/protected/release-root

The builder refuses a dirty checkout, hidden index flags, replacement refs, a noncanonical or unreachable origin, a commit the canonical origin does not advertise, an existing destination, or an unreviewed Node/npm/lock identity. deploy:mcp accepts only a sealed immutable OpenDexter release containing deterministic provenance, the exact descriptor, and a complete file manifest that also authenticates the provenance bytes. It replaces only dexter-open-mcp, while proving the separate full dexter-mcp PID, path, configuration, and restart counters remain unchanged. It verifies the new public process’s PM2 and kernel paths, protected environment, health-reported release identity and 17-tool server roster, and public asset bytes and MIME types before pm2 save. Any mismatch independently restores and re-verifies the prior public OpenDexter process without restarting the private service. It never reloads or updates an existing process in place. The OAuth challenge, authenticated tools/list, 16-model-visible plus one app-only visibility split for the Primary (15 plus one for other clients), and real-user experience remain separate post-deploy proof gates. This is still activation, not authorization to deploy.


OpenDexter: the hosted x402 buyer

OpenDexter is the hosted MCP server behind the OpenDexter connector. The canonical https://open.dexter.cash/mcp resource requires OAuth scope=vault before MCP initialization, tool discovery, or invocation. One successful authorization covers discovery and search, exact request checks, wallet and portfolio reads, identity-gated access, payment, and governed actions on the same connection. Consequential calls still require the exact user instruction or bounded policy authority described below.

The authorized server roster is 17 registered tools:

  1. indexter_discover
  2. indexter_search
  3. x402_mcp_tools
  4. x402_check
  5. x402_fetch
  6. x402_status
  7. x402_access
  8. dexter_wallet
  9. dexter_wallet_portfolio
  10. dexter_prepare_asset_action
  11. dexter_execute_asset_action
  12. dexter_asset_action_status
  13. dexter_reconcile_asset_action
  14. dexter_wallet_history
  15. dexter_report_work
  16. dexter_find_assets
  17. dexter_trade (Primary-only)

dexter_trade buys or sells the confirmed investment and amount in one call. Only the admitted Primary runtime can discover or call it; the public manifest and other connected clients retain sixteen tools. Its answer and refusal bodies pass through unchanged. A failed call can have an uncertain outcome.

dexter_find_assets searches stock products and token candidates beyond the connected wallet holdings. It accepts a company name, ticker or exact mint. Stock results preserve issuer identity and expose catalog pagination. Token results cover the provider search batch. Prepare checks whether the connected wallet can trade the selected asset.

dexter_report_work records the connected agent’s current work statement with server observation and expiry times. Reporting uses the existing connection identity without requiring funds or spending permission. Keep the acknowledged revision for the next update, and reuse the exact operation and content after an uncertain response. A revision conflict returns the current report so the agent can decide whether a new update is still appropriate. Reported completion is separate from transaction finality; expired reports show the age of the statement. The owner roster displays these reports through its existing API.

Every tool in this roster carries the OAuth security scheme and requires the current vault Bearer on each invocation. Compatibility aliases, composed-skill, passkey-probe, and card tools stay outside this hosted roster.

The hosted server revalidates the session’s current authorization with the API before handling each request. OPEN_MCP_OAUTH_SEED_TIMEOUT_MS sets the request budget at startup, including response-body reading: the default is 5000 ms, and overrides must be integers from 1 through 10000 ms. Invalid values prevent startup. The budget bounds MCP’s wait; the API may complete after it expires. A timeout returns the existing temporary authorization error before tool dispatch. Each attempt logs its elapsed time, stage and outcome with a generated request ID and a hashed session reference. X-Dexter-Seed-Request-Id carries that generated ID to the API for log correlation. These diagnostics exclude credentials and response bodies. Recovery keeps the original session and operation identifiers.

The MCP Apps visibility metadata exposes 16 of these tools to the model in the Primary runtime and 15 in other clients that honor it. The remaining registered tool, indexter_discover, is reserved for app browsing. Text-only clients use indexter_search and its structured result; MCP Apps clients render the widget, with additional ChatGPT display controls where supported.

indexter_search is the only model-visible Indexter entry. It accepts the user’s natural-language request and selects a curated overview, one provider, or task search on the server. Broad and ambiguous requests use the overview; named-provider questions use the provider view; concrete requests use task search. Ambiguous provider names are resolved against the current catalog, including lowercase names. An explicit catalog miss falls back to task search; an unavailable catalog returns an error. Task search returns at most twelve results. indexter_discover remains registered for widget browsing and is hidden from the model. Endpoint and Actor cursors are separate opaque values and must be copied unchanged. Neither tool requires a wallet read.

x402_mcp_tools lists tools at a public HTTPS MCP server. Copy the selected tool’s schema string into the mcp target for x402_check, along with its arguments. A tool check can change provider state. See the native MCP purchase guide.

x402_check accepts one target: mcp, a public endpoint URL, or a stable resourceId from the current Indexter result. Dexter resolves managed resources server-side without exposing their private routes. The tool also accepts a method and optional exact raw request-body string. A check asks Dexter to custody the request and seller terms. A purchasable result carries quoteOnly=false and one opaque intentId; quoteOnly=true carries no executable intent. x402_fetch accepts that intentId plus an explicit user- or policy-approved maxAmountAtomic ceiling. It never accepts URL, body, route, tab, seller, or caller-carried prepared-purchase JSON. x402_status accepts only the same intentId and reads state without redispatching.

For supported USDC payments, Fetch and Status already return readable amounts in outcome.amount.displayAmount, with symbol, decimals, and the original amountAtomic. Read outcome.amount.basis to distinguish a requested payment from a confirmed payment. The existing continuation supplies the next action, message, and any returned same-intent status arguments. These fields describe payment and delivery separately.

If execution authority is missing, the hosted consent handoff must preserve the same intent. Only a returned dispatch.boundary: "crossed" permits the agent to say the merchant request was dispatched. A missing result or host-disabled invocation never does. After a returned pending, ambiguous, or post-dispatch result, OpenDexter does not retry the purchase; it checks status on that same intent. Internal settlement-rail choice remains API-owned and is not a public tool or mode menu.

Governed Buy and Sell, plus the preserved fail-closed Send contract, use one API-owned intent through five hosted tools. dexter_prepare_asset_action accepts one stable operationId plus the exact action fields and persists/evaluates the request without signing or submitting it. Send and non-stock Buy/Sell use the canonical assetId returned by dexter_wallet_portfolio from an approved holding or an approvedActionTarget whose matching action is available, never a symbol or mint. Natural-language stock Buy/Sell instead use the exact human companyQuery; the API normalizes that query and selects and pins the current catalog product. A caller must never replace a stock query with a remembered static assetId, symbol, or mint. Stock Buy supports either an amountAtomic USDC budget (6 decimals) or a human decimal shareQuantity minimum-receive target, optionally bounded by maximumSpendAtomic. Stock Sell supports companyQuery plus direct token amountAtomic; it does not accept shareQuantity. For non-stock Sell and Send, amountAtomic is the selected asset amount using the server-certified decimals. Send does not expose a memo.

A prepared stock result exposes the immutable release in top-level stockRuntime and its frozen catalog pin in preview.stockSelection. Execute exposes top-level tradeSummary; Status exposes top-level stockSelection, tradeSummary, and stockV2Identity; History carries the same Status shape in items; Reconcile carries it in statusAfter. Stock success requires a canonical 64-byte Solana signature, confirmed or finalized commitment, executionSucceeded: true, and exact public-identity binding.

Governed tool responses declare the existing human presentation in structuredContent.presentation. Action results expose summary, status, and nextActions; History pages expose those fields per entry in presentation.items, alongside presentation.nextCursor. The existing JSON text presentation remains available to historical consumers. Clients that validate against a cached tools/list schema must refresh that schema when adopting this output contract.

presentation.preview.basis: "estimated_quote" identifies preparation terms. presentation.actual contains recorded receipt amounts or an explicit reason they are unavailable. A saved quote remains an estimate after execution. Successful responses and landed program errors retain detailed backend fields at their original structuredContent paths. Ordinary normalized governed errors carry { presentation } there and preserve the validated error body in _meta["dexter/governedWidgetResult"] for widgets. Existing IDs, evidence, recovery restrictions, and history records remain intact. Use each nextActions entry’s returned arguments and conditions. Authentication and SDK input-validation errors keep their existing protocol responses.

dexter_execute_asset_action accepts only operationId and the prepared intentId; the API request body is exactly {} and the operation ID becomes its Idempotency-Key. It accepts no action, attempt, plan, plan hash, approval, wallet, agent, or grant selector. dexter_asset_action_status reads durable receipt and finality evidence, dexter_reconcile_asset_action asks for the same-intent reconciliation result without automatic retry, and dexter_wallet_history reads cursor-paginated canonical status records. Tool/schema presence is not runtime capability: the exact Prepare response is authoritative. A covered Buy or Sell may execute autonomously under the reusable bounded mandate. In the current integrated release, Send is preserved in the public contract but Prepare refuses it with protected_agent_send_sdk_required before capacity reservation or intent creation. Do not call Execute or Reconcile for that refusal. No mandate, insufficient scope, or an unavailable signer otherwise fails closed for enrollment, extension, or owner escalation. Those ceremonies remain separately authenticated and are not model-callable OpenDexter tools.

The MCP-to-API governed-action bridge uses GOVERNED_AGENT_ACTIONS_HMAC_SECRET (32 bytes or longer), configured to the same value in Dexter API and this MCP service, and signs the timestamp, authenticated MCP session, method, exact mounted URL including query, Idempotency-Key (or empty), and canonical request-body hash. It does not use the Dextercard/session or x402 service secrets and has no legacy fallback.

The hosted check/fetch/status adapter also requires NATIVE_EXACT_MCP_SERVICE_HMAC_SECRET (32 bytes or longer), configured to the same value in Dexter API and this MCP service. Every internal request signs its timestamp, method, exact route, and exact serialized body. Missing or weak configuration fails closed before the request leaves MCP; the secret is never part of a tool argument or result.

This release’s production activation runs only dexter-open-mcp from ecosystem.production.cjs and leaves the distinct full dexter-mcp process untouched. Set DEXTER_MCP_ENV_FILE to one absolute, service-owned mode-0600 regular file before asking PM2 to load that config. The launcher rejects symlinks, hard links, foreign ownership, permissive modes, and inherited Node loader controls; the immutable release itself contains no credential file.

How wallet identity works. OAuth authorizes the canonical https://open.dexter.cash/mcp resource before tool discovery. The same authorized MCP session resolves the durable wallet binding and stored passkey-vault identity for every product tool. Wallet and portfolio calls use that binding. They do not accept a caller-supplied wallet address or user handle. dexter_wallet reads the bound passkey wallet; dexter_wallet_portfolio starts with a compact Solana portfolio summary. Use view: "detail" with a mint or name/symbol query for one holding’s available market and quantity details, view: "holdings" for additional rows, and view: "targets" for approved assets the wallet does not hold. Targets never create a holding, quantity, balance, or portfolio value. Their matching action must be available and the exact Prepare response remains authoritative.

Pass the returned snapshotId to read another view of the same observation; pass nextCursor to continue a page. sourceSummary describes the whole observed portfolio, while selection reports the response’s scope. An expired snapshot requires a fresh summary. The portfolio card uses the same read-only tool and shows selected details from widget metadata. Historical v1 results, including approvedActionTargets, remain supported. See portfolio read contract.

How the npm package connects. @dexterai/opendexter is independently versioned. Published version 1.25.2 runs a local stdio proxy for Codex, Claude Code, and other clients, forwarding account-bound tools to the hosted OpenDexter runtime with an OAuth bearer obtained through opendexter connect. Payments use the connected Dexter Wallet’s server-verified grant. Connecting the CLI alone does not establish spending authority. Package installation, connection guidance, and the seller-side opendexter audition command live in Dexter-DAO/opendexter-ide.

OpenDexter MCP @dexterai/opendexter
Transport Hosted HTTP MCP Local stdio proxy to hosted HTTP MCP
Authorization OAuth required before discovery and use OAuth bearer for account-bound tools; hosted grant for payments
Wallet identity Durable passkey wallet bound to the authenticated MCP session Connected Dexter Wallet bound to the authenticated session
Executable roster Sixteen tools on one authorized connection Independently versioned; verify the installed package
Seller onboarding Not exposed as a hosted tool opendexter audition
Best for ChatGPT, Claude, hosted agents Codex, Claude Code, CLI agents

Source: open-mcp-server.mjs (hosted server). npm package source is in opendexter-ide/packages/mcp.

The opaque-intent boundary and its unverified backend dependencies are documented in docs/contracts/OPENDXTER-OPAQUE-INTENT-V1.md. It is a source candidate, not proof of deployment or end-to-end settlement.


Dexter MCP: the authenticated server

The authenticated server at mcp.dexter.cash/mcp exposes the broader Dexter platform surface over OAuth-authenticated HTTPS, reusing the managed Dexter wallet infrastructure for automatic payment. It’s what the Dexter brand connector on Claude and ChatGPT talks to.

Source: http-server-oauth.mjs.


Access Tiers

Label Who can call Examples
guest Shared demo bearer, no login required general/search, wallet/resolve_wallet
member Authenticated Supabase session / dexter_mcp_jwt wallet/list_my_wallets, wallet/set_session_wallet_override
pro Role-gated (Pro or Super Admin) hyperliquid_markets, hyperliquid_perp_trade
dev Super Admins only codex_start, codex_exec
internal Diagnostic tooling, not exposed to end users wallet/auth_info

Every new Dexter account ships with a managed wallet, so resolver-backed tools immediately report source:"resolver".


Quick Start

git clone https://github.com/Dexter-DAO/dexter-mcp.git
cd dexter-mcp
npm install
cp .env.example .env

# populate .env with required Supabase/OAuth settings

# HTTPS transport (port 3930)
npm start

# or stdio transport for local tools
node server.mjs --tools=wallet

Verify the HTTP transport:

curl -sS http://localhost:3930/mcp/health | jq

With the public proxy in place:

curl -H "Authorization: Bearer " \
     https://mcp.dexter.cash/mcp/health

Authentication

Mode When to use How
OAuth2 / OIDC Claude, ChatGPT, hosted connectors Set TOKEN_AI_MCP_OAUTH=true and supply TOKEN_AI_OIDC_* (or Supabase) endpoints. Users sign in via the Dexter IdP; credentials are checked on every HTTP request, including existing sessions.
Bearer token Service-to-service calls, Codex, Cursor Define TOKEN_AI_MCP_TOKEN and send the matching Authorization: Bearer header on every request. Tool permissions still apply.

Session IDs identify transport state. Each request must carry valid credentials for the session owner. Refreshed tokens for that owner can continue the session. The private server refuses MCP requests when no authentication method is configured.

Provider validation may be cached for up to five minutes, shortened by token expiry when present. Revocation is subject to that cache and the provider’s validation behavior.

Metadata endpoints (for connector discovery):

  • /.well-known/oauth-authorization-server
  • /.well-known/oauth-protected-resource
  • /.well-known/openid-configuration

These routes are proxied on both dexter.cash and mcp.dexter.cash, so connectors can follow the same issuer regardless of which hostname they use.


Toolsets

Tool bundles live under toolsets//index.mjs and register themselves through the manifest in toolsets/index.mjs. Bundles currently shipped:

Bundle What it does
x402 Auto-registered paid resources from dexter-api (slippage sentinel, Jupiter quote, Twitter topic analysis, Solscan trending, Sora/meme jobs, GMGN snapshot, etc). Updates itself whenever /api/x402/resources changes.
wallet Session-aware helpers (resolve_wallet, list_my_wallets, set_session_wallet_override, auth_info) backed by the Supabase resolver.
solana Managed Solana trading utilities (solana_resolve_token, balance listings, swap preview/execute) proxied through dexter-api with entitlement checks.
markets markets_fetch_ohlcv over Birdeye v3 pair data, auto-selecting the top-liquidity pair when only a mint is supplied.
onchain onchain_activity_overview and onchain_entity_insight for wallet/token analytics.
general Tavily-backed web search with depth + answer summaries plus a fetch helper for realtime research.
hyperliquid hyperliquid_markets, hyperliquid_opt_in, hyperliquid_perp_trade for Hyperliquid copy-trading.
codex Bridges MCP clients to the Codex CLI via codex_start, codex_reply, codex_exec.
pumpstream pumpstream_live_summary view of https://pump.dexter.cash/api/live with filters, sort, viewer/USD floors.
stream DexterVision shout utilities (stream_public_shout, stream_shout_feed).

Each tool exposes an _meta block so downstream clients can group or gate consistently:

{
  "name": "solana_swap_execute",
  "title": "Execute Solana Swap",
  "_meta": {
    "category": "solana.trading",
    "access": "member",
    "tags": ["swap", "execution"]
  }
}
  • category: high-level grouping for UX (e.g. wallets, analytics, solana.trading)
  • access: entitlement level (guest, member, pro, dev, internal)
  • tags: free-form labels for filtering/badging

Selection options:

Where How
Environment default Leave TOKEN_AI_MCP_TOOLSETS unset to load every bundle. Set it (comma-separated) to restrict, e.g. TOKEN_AI_MCP_TOOLSETS=wallet.
Launch profile shortcut TOKEN_AI_MCP_PROFILE=opendexter loads only the x402 surface on the authenticated server.
CLI / stdio node server.mjs --tools=wallet or --profile=opendexter.
HTTP query POST /mcp?tools=wallet or POST /mcp?profile=opendexter.

Legacy Token-AI bundles in legacy-tools/ remain for reference; they are not registered by default.


Architecture Notes

  • common.mjs: builds the MCP server, normalizes Zod schemas, wraps tool registration with logging.
  • toolsets/: declarative manifest of tool bundles plus the wallet toolset implementation. Authoring guide at toolsets/ADDING_TOOLSETS.md.
  • server.mjs: stdio entrypoint (used by local agents and Codex); respects --tools= flags.
  • dexter-mcp-stdio-bridge.mjs: bridges stdio clients to the hosted OAuth HTTP transport (for Codex/Cursor when they only support stdio).
  • http-server-oauth.mjs: HTTPS transport with OAuth/OIDC, session caching, metadata routes.
  • legacy-tools/: archived Token-AI tools kept for reference during migration.

Supabase interactions flow through Dexter API helpers for consistent auth enforcement.


Development

For local dev, PM2, harness operations, and Supabase session maintenance, see docs/dev/HARNESS.md.

Dexter Studio uses Claude Agent SDK and Zod 4 in an isolated, non-workspace tooling profile so it cannot change the hosted MCP’s Zod 3 runtime. Run npm run studio:setup once before npm run studio.


Dexter Stack

Repo Role
dexter-api OAuth issuer, wallet resolver, OTS buyer-side implementation, x402 billing
dexter-fe Web frontend (Claude/ChatGPT connector auth, /wallet dashboard, admin)
dexter-vault Open Tabs Standard reference implementation (Anchor program on Solana)
dexter-facilitator x402 v2 payment facilitator (Solana + EVM)

License

All rights reserved. This source is public for transparency and reference, not for reuse. You may not copy, modify, redistribute, or use this code in your own projects without written permission from Dexter. The Dexter and OpenDexter names and marks are not licensed for any use.

For licensing inquiries: [email protected].

View the full README on GitHub

Install

This server does not publish a one-line install command.

Open the repository installation guide New to MCP? Start with the mcpskill.org guide →