Actspan Docs Quickstart
DocsExamples

Create a customer-scoped support ticket and verify its saved ID and receipt through the qualified LangChain integration.

On this page

Customer service over MCP

Assisted integration · core 0.2.0 / adapter 0.1.1 local-client subset.

A customer reports an integration failure. The agent creates the requested support ticket, reads back its saved record, and reports its actual ID and status. Actspan checks the mediated model and tool calls; the authenticated MCP backend owns customer authorization and persistent ticket records.

Before you begin

Expected result: one saved ticket, a matching committed receipt and reply ID, and a current-request readback. Live runs incur provider charges; use an isolated trial customer and disposable service-desk database.

This is a design-partner Python integration. Request the matching example files, core and adapter packages, dependency handoff, and service-desk setup notes. These MCP examples are not included in the free native examples archive. Keep both supplied folders together: langchain/customer_service_mcp and openai/customer_service_mcp.

Use the prepared Python 3.11 environment and LangChain installation instructions. The qualified path uses core 0.2.0, adapter 0.1.1, LangChain 1.4.6, langchain-core 1.6.10, LangGraph 1.2.15, langchain-openai 1.7.2, MCP 1.26.0, and Uvicorn 0.31.1. It uses gpt-4.1-mini with your OpenAI key. The free native CLI cannot import this Python framework.

Problem and flow

A customer asks an assistant to open a ticket. A generated ticket ID is insufficient: the write must be permitted, belong to that customer and match a record that the backend actually saved.

Mcp ticket flow

Responsibility Owner and evidence
Mediate model and tool calls The LangChain adapter and configured agent permissions.
Authenticate customer and commit writes The MCP backend, bearer token and persistent service-desk database.
Prove the reported ticket A request-bound committed receipt and a fresh record readback.
Request a human decision Only the separate approval workspace; the qualified default writer does not pause.

Handoff checklist

Obtain the locked Python environment and both sibling folders listed above, including service_desk.py, mcp_server.py, check_mcp.py, client modules, workspace/policies and verification code. The following local backend commands are source-checked against that supplied integration; they do not expose a public tunnel or qualify a different dependency tuple.

Create a disposable customer and start the backend

From the supplied openai/customer_service_mcp directory, set the prepared interpreter and create one isolated database/token:

export ACTSPAN_PYTHON="/absolute/path/to/prepared-venv/bin/python"
SERVICE_TRIAL_DIR=$(mktemp -d "${TMPDIR:-/tmp}/actspan-mcp-trial.XXXXXX")
export SERVICE_DESK_DB="$SERVICE_TRIAL_DIR/service-desk.db"
export SERVICE_DESK_TOKEN_FILE="$SERVICE_TRIAL_DIR/customer.env"
"$ACTSPAN_PYTHON" service_desk.py init
"$ACTSPAN_PYTHON" service_desk.py customer \
  --tenant trial-tenant --customer trial-customer \
  --name 'Synthetic trial customer' --token-file "$SERVICE_DESK_TOKEN_FILE"
"$ACTSPAN_PYTHON" mcp_server.py

The last command stays in the foreground on 127.0.0.1:8766. In a second terminal, set the same interpreter, actual database/token-file paths and URL. From that backend directory, check discovery and reads without creating tickets:

export SERVICE_DESK_MCP_URL="http://127.0.0.1:8766/mcp"
"$ACTSPAN_PYTHON" check_mcp.py \
  --url "$SERVICE_DESK_MCP_URL" --token-file "$SERVICE_DESK_TOKEN_FILE"

Keep the server running. Then enter the sibling langchain/customer_service_mcp directory for the run below. No knowledge articles are required for this ticket-only scenario. For your own knowledge questions, explicitly import approved documents before expecting citations.

Connect the service desk

Start the supplied backend using its setup notes. It starts empty; explicitly provide the trial customer and any documents needed for your scenario. The ticket-creation scenario below needs a customer, but no knowledge articles. Do not initialize another database while expecting the running server to use it.

From the supplied langchain/customer_service_mcp directory, set the prepared Python interpreter and existing connection details:

export ACTSPAN_PYTHON="/absolute/path/to/prepared-venv/bin/python"
export OPENAI_API_KEY="<your-openai-api-key>"
export SUPPORT_MODEL=gpt-4.1-mini
export ACTSPAN_PORTAL_DISABLED=1
export SERVICE_DESK_MCP_URL="http://127.0.0.1:8766/mcp"
export SERVICE_DESK_TOKEN_FILE="/absolute/path/to/private/customer.env"
export SERVICE_DESK_DB="/absolute/path/to/the-running-service-desk.db"

The provider key authenticates model calls. The separate customer bearer token authenticates MCP requests and determines the customer in the backend; a customer ID in the user's text cannot replace it. Keep both credentials private. The database path must refer to the server's actual database so record checks can inspect the corresponding receipts.

The LangChain MCP client runs locally, so loopback HTTP needs no public tunnel. Use HTTPS for a remote endpoint. This does not qualify OpenAI's separate provider-hosted MCP path, which needs its own reachable endpoint and test.

Create and verify a ticket

Validate the supplied declaration:

"$ACTSPAN_PYTHON" -m actspan validate workspace.yaml --check-plugins
mkdir -p .actspan/installed-runtime

Compatibility note: installed runtime selection

The current supplied runner has a legacy checkout-discovery default. Until a replacement runner is supplied, the empty source directory below keeps that override from selecting a neighboring product checkout; execution uses your installed Python packages.

"$ACTSPAN_PYTHON" run.py \
  'Create one support ticket with subject MCP connection failure and description My private MCP endpoint times out. Read back the saved ticket and report its actual ID and current status. Do not send notifications or arrange human follow-up.' \
  --source "$PWD/.actspan/installed-runtime" \
  --request-id support-trial-001 \
  > .actspan/create.run.json

Use a new request ID for a new customer request. Retain the ID for a retry of that same request; changing the write arguments under an existing key produces a conflict. After a failure, inspect the saved record before issuing another write. The example does not automatically retry a failed answer check.

Read .actspan/create.run.json. With jq installed:

jq '.result | {execution_status, answer_verification_status, output}' \
  .actspan/create.run.json

Check all of the following:

  • execution_status is succeeded and answer_verification_status is passed.
  • output.disposition is ticket_created; use its actual returned ticket ID.
  • The ID agrees with the committed create_ticket receipt and saved record.
  • A fresh get_ticket readback established the record's current revision before the final reply; inspect the request-scoped evidence in .actspan/verification/ and the backend's database.

The wrapper checks current-request IDs, citations, write receipts and selected unsupported promises. Exit 3 means execution completed but answer checks failed or were incomplete. A saved ticket may already exist; do not interpret that exit as proof that no write occurred. A passing checker does not prove every sentence or replace independent verification of important effects.

Check the permission boundary

The same workspace declares customer_service_readonly, which permits account, knowledge and ticket reads but denies create_ticket and add_ticket_note:

"$ACTSPAN_PYTHON" run.py \
  'Create a ticket: my MCP connection times out.' \
  --source "$PWD/.actspan/installed-runtime" \
  --agent customer_service_readonly

The model chooses its calls. Establish an attempted denial from the recorded policy decision and confirm no write reached MCP; refusal wording alone is insufficient evidence. The fresh release qualification used a deterministic attempted write to check this boundary without another paid model call.

What has been demonstrated

On October 21, 2026, installed core 0.2.0 and adapter 0.1.1 passed one live OpenAI ticket-creation run through the official MCP client over local HTTP. Independent database checks found exactly one ticket and committed receipt, matching reply/receipt IDs, and a fresh readback. Separate checks established zero MCP dispatches for a denied write and an unavailable response when a different authenticated customer requested that ticket.

This is local synthetic-record evidence, not production multitenancy or a commercial support-system integration. See the provider and adapter verification matrix.

Approvals and remaining scope

The default writer permits requested ticket changes directly; it does not pause for review. workspace.approval.yaml separately declares review for ticket creation and notes. It needs authenticated Actspan Cloud decisions; local actor labels cannot approve it. That complete portal approval path was not qualified on the fresh 0.2.0 artifact. Follow the framework approval guide for its setup and separate qualification.

Subscription/account mutations are not implemented or tested here. The service saves tickets and notes; it sends no email or Slack notification, arranges no human follow-up, and performs no refunds or payments. Permitted tools are trusted code; Actspan does not sandbox their internals or govern calls outside the configured integration. An agency deployment or customer isolation guarantee needs its own qualification.