Skip to main content

Current-request context (portable default)

Put the bounded context needed for the current operation in the business tool’s own input. This keeps the reliable path to one business-tool call and one host-owned approval. Do not require the model to call a setup, context-sharing, or consent tool before it can complete the customer’s task. For example, a catalog tool can accept a closed taskContext object containing only fields it can really use:
Validate this object as product input: reject unknown or sensitive fields instead of silently ignoring them. The completed tool result should include an exact receipt so the agent and dashboard can distinguish what was sent from what actually affected the result:
Only claim that a field reached or influenced the product when it appears in this receipt. A model may use saved host memory to construct the current tool arguments, but the MCP server cannot inspect that memory or verify where the model learned a value. Describe such values as assistant-supplied current-request context, not as a verified memory import or confirmed customer statement. MCP tool approvals belong to the host. A server can provide read-only and idempotence annotations, but cannot suppress, combine, or pre-approve the host’s prompts. A denial normally happens before the server receives tools/call, so it must produce no context event. Splitting a search into begin_task and search_catalog can therefore produce two host approvals; prefer one bounded business operation when the task permits it. Previously approved profile context should be loaded by the company server using verified product identity, merged with current-request context under documented precedence rules, and passed to the business handler before it runs. Do not depend on the agent selecting a separate context tool. Derive customer and journey references from verified auth or product-owned state, never model-authored arguments. If no verified journey exists, use request scope rather than claiming that data lasts for the chat or MCP transport session.

Optional retained personalization

Use Epode’s customer-enrichment tools when the customer explicitly chooses to build a profile that survives the current request. This is separate from the portable current-request path:
Epode registers share_customer_context on the company’s own MCP server and decorates selected business-tool results with the exact allowed action. On MCP 2026 clients that both advertise form elicitation and have been version-tested to surface and resume it, share_customer_context can return MRTR input_required with Always allow, This session only, and Don’t allow. This is a best-effort enhancement, not a portable client guarantee. Do not make successful product use depend on MRTR or on the agent selecting this second tool. If a client cannot surface or resume input, continue without profile enrichment and never infer approval. Noninteractive Codex and Claude CLI runs may exhaust their configured inputRequired.maxRounds because there is no interactive user surface; treat that result as unsupported, not as consent or refusal. record_customer_context_consent is an explicit compatibility fallback, not an instruction to add an unsolicited second question after the host has already approved the business call. Test the exact host, version, transport, and interactive mode you support. Claude Desktop, Claude CLI, Codex CLI, and ChatGPT integrations have different approval and elicitation behavior. Capability metadata alone does not prove that the client will render a form, resume the original call, or choose share_customer_context. The customer needs no Epode account, plugin, or direct connection. Context retrieval, personalization decisions, and outcomes remain server-to-server. Failed (isError), canceled, incomplete, and input_required results are never decorated or counted as a completed enrichment opportunity. A session-only choice forces every submitted item to remain interaction-scoped even if the model marked it durable. Here, session scope means a verified, product-issued journey reference; it does not mean an MCP transport session or whatever chat the host currently shows. Importing broader assistant memory is not part of first-use personalization. MCP has no portable operation that lets a company server autonomously read a host’s full saved memory. Offer Import more from your assistant… only as an optional profile-settings flow: show a preview of the exact bounded items, their claimed provenance, purpose, and retention; let the customer remove items; then save only the approved selection. The normal product task must remain complete if the customer skips or cancels that flow. The enrichment request itself carries surface: "mcp", so the initial successful product-tool interaction is confirmed immediately. Do not add separate Epode telemetry instrumentation around the same MCP server. The session/runtime extractors deliberately receive only MCP server context. Resolve them from verified auth or product-owned state; tool arguments and model-authored result fields cannot establish a journey or runtime. Run the travel MCP example

Legacy structured outcome feedback

MCP is Epode’s strongest integration: every completed product-tool call is a confirmed interaction. Epode registers record_product_feedback_consent and report_product_feedback; the product result tells the customer agent which action is currently allowed.
For a tool without outputSchema, the feedback envelope is structuredContent._agentFeedback. If the business tool declares outputSchema, Epode leaves its structuredContent exactly schema-valid and appends a standalone JSON text block shaped as {"_agentFeedback": {...}} instead. A plain-language instruction follows either form. Agents should use the machine-readable envelope in whichever one of those two locations is present.

Install

Keep the versioned tarball in .epode/artifacts and include it in source control or the deployment build context alongside package.json and package-lock.json. Both manifests refer to that project-local file, so npm ci still works after the npm cache is cleared or the original shell exits.

Configure once

Create one process-level Epode instrumentation object so telemetry can batch across requests. Create a fresh MCP server for each stateless HTTP request and instrument it before registering business tools.
productTokenVerifier is the adapter for your product’s real access-token verification, not a decoder or example token table. It must verify the signature or introspection result, expiration, audience, the mcp scope, and the caller’s membership in the selected account before returning. The MCP Express middleware then attaches the verified AuthInfo to the request; the Node adapter passes it through as context.http.authInfo. accountRef and userRef are verified company assertions; anonymousRef is a product-owned first-party pre-login ID. When both are present, customerRef must exactly equal accountRef and exists only for durable Ask once consent compatibility. Never populate these values from a request header, query parameter, name, email, prompt, tool argument, or unverified JWT payload. For a journey-creation tool, create a canonical ID in the authenticated account’s registry before returning it. On follow-up calls, resolve the argument candidate against that same account-owned registry. Repeated follow-ups, cache hits, and deduplicated calls reuse the canonical product journey; a separate create gets a different ID. Every completion nevertheless gets a fresh telemetry interaction UUID. A failed product result may remain linked when the lookup proves ownership. Missing, malformed, unknown, and cross-account candidates return undefined and remain unlinked. Typed argument and result schemas constrain candidates but do not prove ownership alone. Use durable shared product storage in production; an in-memory map is suitable only for an instructional example.
Do not create or depend on Mcp-Session-Id for modern requests. MCP 2026-07-28 is stateless. Use a server-issued application journey only after product state has established it.

Multi-tool journeys

Epode should observe the whole journey without asking for micro-feedback after every low-level action:
  • includeTools selects the product calls shown in Journeys.
  • excludeTools removes health, admin, or internal tools.
  • feedbackTools selects outcome boundaries that receive feedback instructions. An empty array records interactions without asking for feedback.
  • shouldRequestFeedback can inspect a completed result when the boundary is dynamic.
  • sessionRef must come from server/product state that proves continuity. Typed tool arguments and result fields may carry candidates, but caller headers and model-proposed IDs are not ownership evidence by themselves.
  • accountRef/userRef come from verified product authentication; anonymousRef comes from a product-owned first-party ID. customerRef is only the durable Ask once compatibility subject and, when paired with richer identity, must exactly equal accountRef. Without it, Ask once safely falls back to per-interaction permission.
  • Never ask is the most reliable mode on current Codex and Claude MCP clients. Ask once and Ask every time depend on client support for surfacing and resuming consent; treat them as experimental until you verify the exact client versions you support. Never infer approval when a client stops early.
Keep the stage-aware Epode rule in the server-level instructions, near the beginning if you also have product-specific instructions. Result-local metadata alone is not reliable across all MCP clients. Epode adds a monotonic client sequence to preserve rapid tool order. The backend also reconciles a report that arrives before its background interaction metadata.

Verify

From an MCP 2026-07-28 client:
  1. Call server/discover.
  2. Call tools/list. When feedback is off, confirm only your product tools are present and stop. Otherwise, confirm record_product_feedback_consent and report_product_feedback are also present.
  3. When feedback is enabled, call one normal product tool and confirm its result contains _agentFeedback.
  4. If the result has state: "consent_required", ask its exact question and call record_product_feedback_consent with only approved or declined. Do not call the report tool unless an approved decision returns state: "feedback_ready" and a report action.
  5. When the product result or approved decision returns state: "feedback_ready", call report_product_feedback with that action’s feedbackHandle.
  6. Confirm the interaction and report appear in Epode.
Call the report tool once under normal conditions. If it returns retryable: true, retry exactly once with the same feedbackHandle and identical report. Capabilities are idempotent, so a lost success response cannot create a second report. The report tool allows 10 seconds by default; set reportTimeoutMs only for unusually slow private deployments. Background telemetry uses bounded exponential retry and a longer timeout, but never blocks the product tool result. The legacy: "stateless" option retains a 2025-11-25 compatibility handshake without introducing transport-session state. View the runnable Node MCP example Browser journey example · Documentation MCP example · Authenticated operations example