> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shouldertap.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP integration

> Any MCP-capable agent can tap a human expert with no custom integration, using ShoulderTap's ask_expert and check_answer tools over stdio.

ShoulderTap ships an MCP server, so any MCP-capable agent can tap a human expert with no SDK integration. Run it with `shtap mcp`, which exposes two tools over stdio. Under the hood the MCP server is itself a client of a running `shtap serve`, so start the engine first.

## The tools

<ResponseField name="ask_expert(question, topic, kind='freeform.answer', context?, dedup_key?)">
  Submits a request as the `mcp` consumer and returns immediately.

  Returns `{ request_id, status, answer? }`. The `answer` is present **only** when the call resolved instantly via a [dedup hit](/concepts#deduplication) against an already-accepted proposal; otherwise the answer arrives out-of-band and you poll for it.

  <Note>
    The HTTP API returns this identifier as `id`; the MCP tool renames it to `request_id`. Use `request_id` when calling `check_answer`.
  </Note>
</ResponseField>

<ResponseField name="check_answer(request_id)">
  Polls a request's status. Returns `{ status, answer? }`. The `answer` key appears once a proposal exists; when the expert's reply couldn't be structured, it falls back to `{ "summary": "<raw reply>" }`.
</ResponseField>

## Connect from an agent

Spawn `shtap mcp` over stdio and call the tools with any MCP client:

```python theme={null}
from mcp import ClientSession
from mcp.client.stdio import StdioServerParameters, stdio_client

params = StdioServerParameters(command="shtap", args=["mcp"])
async with stdio_client(params) as (read, write), ClientSession(read, write) as session:
    await session.initialize()
    result = await session.call_tool(
        "ask_expert",
        {
            "question": "What does 'active customer' mean for Q2 reporting?",
            "topic": "revenue metrics",
        },
    )
    print(result.structuredContent)  # {"request_id": "req_01J...", "status": "queued"}
```

## Resuming once the answer lands

Because `ask_expert` returns before a human has replied, a real agent needs a resume strategy:

<CardGroup cols={2}>
  <Card title="Poll" icon="rotate">
    Call `check_answer(request_id)` on a later turn until `status` is `accepted` and an `answer` is present. Simplest to wire into an agent loop.
  </Card>

  <Card title="Webhook" icon="webhook">
    Register a webhook consumer and resume from the `on_proposal_accepted` callback instead of polling. Better for long waits. See [Webhooks](/consumers/webhooks).
  </Card>
</CardGroup>

The `examples/langgraph_agent/` directory in the repository shows this end to end: a small runnable MCP client wrapper (`shouldertap_mcp_client.py`) and a LangGraph node (`tap_expert_if_unsure`) that taps a human on the agent's low-confidence path.

<Tip>
  Try the flow without any agent framework. With `shtap serve --transport console` running in one terminal, run the example client in another:

  ```bash theme={null}
  uv run python examples/langgraph_agent/shouldertap_mcp_client.py \
    "What does 'active customer' mean for Q2 reporting?" "revenue metrics"
  ```
</Tip>
