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

# Ask Wolfia Programmatically: Instant Answers over MCP

> Send a question to Wolfia from your own code and get an expert answer with citations back, authenticated with an API key. Build internal Slack bots, ticket deflection, and support automations on the same answering pipeline as the Wolfia app.

Your team already answers security and product questions in Wolfia. The `send_message` tool on the Wolfia MCP server lets your own tools ask those questions too: an internal Slack bot that answers teammates instantly, a helpdesk workflow that drafts a grounded reply before an agent picks up the ticket, or a script that sanity-checks a claim against your knowledge base.

Every answer comes from the full Wolfia answering pipeline, grounded in your knowledge base with citations, and scoped to what the calling credential is allowed to see.

<Frame caption="The same answer your team sees in the Wolfia app, available to your own code over MCP.">
  <img src="https://mintcdn.com/wolfia/7-HCUKhtsCkCzMs6/images/wolfia-mcpQa-answer-light.png?fit=max&auto=format&n=7-HCUKhtsCkCzMs6&q=85&s=a03bd186fb39a0dd9d1d546c3c5f8efa" alt="A Wolfia chat answer to a security question, marked ready to send with a cited source" width="3488" height="900" data-path="images/wolfia-mcpQa-answer-light.png" />
</Frame>

<Note>
  Looking for analytics on questions your team already asked? That is the [Conversation insights API](/how-to/api-conversation-insights). It reads past conversations and never generates new answers, so it is the wrong endpoint for a bot that needs a live answer. Use `send_message` for that.
</Note>

## What you need

* A Wolfia account with **Admin** access (to create the service account and API key)
* The MCP endpoint: `https://api.wolfia.com/mcp/`
* Any language that can speak [MCP](https://modelcontextprotocol.io) over streamable HTTP. The examples below use the official Python SDK.

## Set up credentials

<Steps>
  <Step title="Create a service account">
    Go to [Settings → Service accounts](https://wolfia.com/settings/service-accounts) and click **Create service account**. Name it after the integration, for example `internal-slack-bot`.

    A service account keeps the integration's access separate from any person's login, so the bot keeps working when teammates change.

    <Frame>
      <img src="https://mintcdn.com/wolfia/7-HCUKhtsCkCzMs6/images/wolfia-mcpQa-serviceAccount-light.png?fit=max&auto=format&n=7-HCUKhtsCkCzMs6&q=85&s=8b9acf6b12054ba9d4e7f52b5e2e8734" alt="The service accounts page showing a service account for an internal Slack bot" width="3488" height="660" data-path="images/wolfia-mcpQa-serviceAccount-light.png" />
    </Frame>
  </Step>

  <Step title="Create an API key for it">
    Go to [Settings → API](https://wolfia.com/settings/api), click **Create API key**, and attach the key to the service account you just created.

    Choose **Restricted** access and select only **Knowledge: read**. That is the only scope `send_message` needs, so a leaked key cannot touch questionnaires, integrations, or your trust center.

    <Frame>
      <img src="https://mintcdn.com/wolfia/7-HCUKhtsCkCzMs6/images/wolfia-mcpQa-apiKeyScopes-light.png?fit=max&auto=format&n=7-HCUKhtsCkCzMs6&q=85&s=3b26f7b89d7654c37605757ba0b12394" alt="The API key creation dialog with restricted access and the knowledge read scope selected" width="1100" height="1780" data-path="images/wolfia-mcpQa-apiKeyScopes-light.png" />
    </Frame>
  </Step>

  <Step title="Store the key securely">
    The key is shown once and looks like `wolfia-api-...`. Put it in your secrets manager, never in source code.
  </Step>
</Steps>

## Call `send_message`

Connect to `https://api.wolfia.com/mcp/` with the API key in the `Authorization` header, then call the `send_message` tool:

```python theme={null}
import asyncio
import json
import os

from mcp import ClientSession
from mcp.client.streamable_http import create_mcp_http_client, streamable_http_client

WOLFIA_MCP_URL = "https://api.wolfia.com/mcp/"
WOLFIA_API_KEY = os.environ["WOLFIA_API_KEY"]


async def ask_wolfia(question: str, conversation_id: str | None = None) -> dict:
    headers = {"Authorization": f"Bearer {WOLFIA_API_KEY}"}
    async with create_mcp_http_client(headers=headers) as http_client:
        async with streamable_http_client(WOLFIA_MCP_URL, http_client=http_client) as streams:
            read_stream, write_stream = streams[0], streams[1]
            async with ClientSession(read_stream, write_stream) as session:
                await session.initialize()
                arguments = {"message": question}
                if conversation_id:
                    arguments["conversation_id"] = conversation_id
                result = await session.call_tool("send_message", arguments)
                return json.loads(result.content[0].text)


answer = asyncio.run(ask_wolfia("Do you use customer data to train AI models?"))
print(answer["response"])
```

The example uses the official [`mcp` Python SDK](https://pypi.org/project/mcp/) (version 2.x shown here).

The response contains:

| Field             | What it is                                                                                                   |
| ----------------- | ------------------------------------------------------------------------------------------------------------ |
| `response`        | The full answer, grounded in your knowledge base                                                             |
| `conversation_id` | The conversation this answer belongs to. Pass it back on the next call to ask a follow-up in the same thread |
| `citations`       | The sources the answer is grounded in, so you can show receipts                                              |

Answers stream back as they generate, and a thorough answer to a hard question can take a couple of minutes. Call `send_message` from a background job and post the answer when it arrives. Never block a user-facing request on it.

<Note>
  `X-API-Key: wolfia-api-...` works as an alternative to the `Authorization: Bearer` header. Both authenticate the same way.
</Note>

## DIY: build an internal Slack bot

A common pattern: teammates ask security questions in an internal channel, the bot answers instantly from Wolfia, and the thread stays connected so follow-ups keep their context. Here is the full shape using [Slack Bolt for Python](https://tools.slack.dev/bolt-python/):

<Steps>
  <Step title="Create the Slack app">
    Create a Slack app with a bot token, subscribe it to the `app_mention` event, and install it to the channel where questions get asked.
  </Step>

  <Step title="Wire mentions to Wolfia">
    On each mention, acknowledge Slack immediately, then fetch the answer in the background and post it in the thread:

    ```python theme={null}
    import asyncio
    import re

    from slack_bolt.async_app import AsyncApp

    app = AsyncApp(token=SLACK_BOT_TOKEN, signing_secret=SLACK_SIGNING_SECRET)

    thread_conversations: dict[str, str] = {}


    @app.event("app_mention")
    async def answer_security_question(event, say):
        question = re.sub(r"<@[^>]+>", "", event["text"]).strip()
        thread_ts = event.get("thread_ts", event["ts"])

        await say(text="Looking that up...", thread_ts=thread_ts)

        answer = await ask_wolfia(question, thread_conversations.get(thread_ts))
        thread_conversations[thread_ts] = answer["conversation_id"]

        await say(text=answer["response"], thread_ts=thread_ts)
    ```
  </Step>

  <Step title="Keep follow-ups in context">
    The `thread_conversations` map above ties each Slack thread to one Wolfia conversation. When a teammate asks a follow-up in the thread, the bot passes the saved `conversation_id` and Wolfia answers with the whole exchange in mind. Use a real store (Redis, a database) instead of an in-memory dict in production.
  </Step>

  <Step title="Ship it">
    Run the bot anywhere that can reach Slack and `api.wolfia.com`: a small container, a serverless function with a queue, or an existing internal service.
  </Step>
</Steps>

<Tip>
  Slack gives you 3 seconds to acknowledge an event. The pattern above acknowledges first and answers when ready, so slow answers never cause Slack retries or duplicate replies.
</Tip>

## Rate limits

`send_message` allows short bursts of up to 5 calls per second and a sustained 20 calls per minute per API key, with a shared ceiling across your organization. Rejected calls return a `Retry-After` header telling you when to retry. That is comfortable for a team-sized bot; if your integration needs more, contact [support@wolfia.com](mailto:support@wolfia.com).

## Beyond Q\&A

The same connection gives your integration every tool its scopes allow. Two that pair well with a bot:

* `search_knowledge` returns raw knowledge base search results in seconds. Use it when you want sources to link rather than a written answer.
* `submit_questionnaire` accepts a whole questionnaire for automated answering. If the bot receives a spreadsheet instead of a question, hand it off here.

<Card title="Browse every MCP tool" icon="screwdriver-wrench" href="/how-to/mcp-tools">
  The full tool reference, grouped by category, with what each tool does and which role it needs.
</Card>

## FAQ

<AccordionGroup>
  <Accordion title="Why does my Accept header matter?">
    Include `text/event-stream` in the `Accept` header (MCP SDKs do this by default). Long answers stream progress while they generate, and `send_message` requires a streaming-capable connection so slow answers arrive reliably.
  </Accordion>

  <Accordion title="Can I use OAuth instead of an API key?">
    Yes. Interactive clients such as Claude Code and Cursor sign in with OAuth as a real user. API keys exist for headless server-to-server use where nobody can click through a browser login. See [MCP OAuth, direct connections and gateways](/how-to/mcp-server-oauth).
  </Accordion>

  <Accordion title="Whose permissions do the answers respect?">
    The service account's. It carries the role you assign it, and the API key's scopes narrow that further. The bot only ever sees content that credential is allowed to see.
  </Accordion>

  <Accordion title="Is there a plain REST endpoint for this?">
    Live Q\&A is available over MCP. The [REST API](/how-to/api-overview) covers user management, knowledge upload, questionnaires, and analytics. MCP client libraries exist for every major language, and the connection is a normal HTTPS request under the hood.
  </Accordion>
</AccordionGroup>

## Related pages

<CardGroup cols={2}>
  <Card title="MCP server overview" icon="plug" href="/how-to/mcp-server">
    Connect Claude Code, Cursor, Windsurf, and other interactive clients.
  </Card>

  <Card title="Service accounts" icon="robot" href="/how-to/service-accounts">
    Non-human identities for automations, and why keys should attach to them.
  </Card>

  <Card title="API overview" icon="code" href="/how-to/api-overview">
    API key creation, scopes, and the REST endpoint catalog.
  </Card>

  <Card title="Conversation insights API" icon="chart-line" href="/how-to/api-conversation-insights">
    Analytics over the questions your team already asked.
  </Card>
</CardGroup>
