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 aContextRequest. 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’skind 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:Webhook
Webhook
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.In-process
In-process
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.Polling
Polling
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 withauto_accept: true to have proposals delivered without review.
Deduplication
Set adedup_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.