Skip to main content
A consumer is anything that submits requests to ShoulderTap and receives answers back — most often an AI agent’s low-confidence path, but also your own service, the CLI, or the MCP server. Integrating a consumer means answering three questions: how you submit a request, which kinds of questions you handle, and how you want the answer delivered.

Ways to integrate

MCP

Any MCP-capable agent can tap a human expert with no SDK, via the ask_expert and check_answer tools over stdio.

Python SDK

ShoulderTapClient for HTTP consumers, or in-process callbacks for a consumer embedded alongside the engine.

HTTP + webhooks

Submit over the REST API and register a webhook to receive answers as they’re accepted.

Submitting a request

Every consumer submits a ContextRequest. Four fields are required — kind, topic, question, and consumer — and the rest are optional:
topic drives routing. context is free-form and shown to the expert (asked_because becomes the “why I’m asking” line). dedup_key prevents asking an expert the same thing twice. See the ContextRequest contract for every field. Submitting is asynchronous: you get back { id, status } immediately, and the answer arrives later — once a human replies and a reviewer accepts it.

Kinds

A request’s kind determines the schema its answer is captured into. Two ship built in: Register your own kind with a custom JSON Schema at registration time if the built-ins don’t fit. See Kinds.

Delivery

Because answers arrive out-of-band, a consumer chooses how it wants to be notified:
ShoulderTap POSTs each event to a URL you register. This is the standard choice for a consumer running as its own service. Register with delivery: { "type": "webhook", "url": "..." }. See Webhooks.
For a consumer embedded in the same process as the engine, register callbacks directly with the SDK’s register_in_process. No HTTP round-trip. See the SDK.
Simplest of all: submit, then poll GET /requests/{id} (or the MCP check_answer tool) until the status is accepted. Good for scripts and the CLI’s shtap ask.

Callback events

A registered consumer receives up to four events, whether delivered as an in-process callable or a webhook POST ({ "event": "<name>", ... }):
on_proposal
Informational — fires when a proposal is created, before approval.
on_proposal_accepted
The actual delivery event. Write to your system of record here. This is the one that matters.
on_proposal_rejected
Fires with the rejection reason when a reviewer rejects the proposal.
on_request_failed
Fires with a reason code (for example timeout or no_expert_found) when a request can’t be answered.

Auto-accept

By default every answer is held for human review. A consumer can register with auto_accept: true to have proposals delivered without review.
auto_accept is off by default because writing an unreviewed expert answer straight into a system of record is a real poisoning risk. Turn it on only for kinds and consumers where an occasional wrong answer is acceptable.

Deduplication

Set a dedup_key on requests that represent the same underlying question. Within a consumer’s dedup window (default 24 hours), a matching key means ShoulderTap won’t ask an expert again: if the earlier request already resolved, you get its accepted proposal immediately; if it’s still open, you’re attached as a subscriber and get the answer when it lands. See Concepts.