> For the complete documentation index, see [llms.txt](https://k-ai.gitbook.io/knowledge-ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://k-ai.gitbook.io/knowledge-ai/k-ai-mcp/cookbook.md).

# Cookbook

Multi-tool recipes combining the K-AI Retrieval and Audit MCP servers. Each recipe shows the end-to-end MCP tool sequence with sample Python calls using the [`mcp` Python SDK](https://github.com/modelcontextprotocol/python-sdk). Two recipes additionally show TypeScript with `@modelcontextprotocol/sdk`. See the [schema stability policy](/knowledge-ai/k-ai-mcp/schema-stability.md) for our compatibility commitments.

All recipes assume the client has already completed the OAuth flow (see [OAuth flow](/knowledge-ai/k-ai-mcp/oauth-flow.md)) and stored an access token. In the snippets below, `ACCESS_TOKEN` is the bearer token; the SDK transport handles refresh.

K-AI MCP tools wrap every response as `{"response": <payload>}`. With the Python `mcp` SDK, the typed payload is exposed on `result.structuredContent`; the snippets below access it as `result.structuredContent["response"]`. With `@modelcontextprotocol/sdk` for TypeScript the typed payload also lives on `result.structuredContent` (cast `as any` to read it).

## Recipe 1 — Find documents on a topic

**Goal.** A host LLM helps a Consumer find documents in a K-AI instance relevant to a topic.

**Tools used (Retrieval, stable).**

1. `retrieval_semantic_nodes_search` — semantic search over the Neural Semantic Graph.
2. `retrieval_documents_get_document` — fetch the full content of a matching document.

{% tabs %}
{% tab title="Python" %}

```python
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

URL = "https://api-retrieval.kai-studio.ai/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"}

async def find_documents(instance_id: str, query: str):
    async with streamablehttp_client(URL, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            hits = await session.call_tool(
                "retrieval_semantic_nodes_search",
                {"instance_id": instance_id, "query": query},
            )
            nodes = hits.structuredContent["response"]
            # Each node carries a `documents` array; pick the first document of the
            # top-ranked node.
            doc_id = nodes[0]["documents"][0]["id"]
            doc = await session.call_tool(
                "retrieval_documents_get_document",
                {"instance_id": instance_id, "document_id": doc_id},
            )
            return doc.structuredContent["response"]
```

{% endtab %}

{% tab title="TypeScript" %}

```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const URL = new URL("https://api-retrieval.kai-studio.ai/mcp");
const headers = { Authorization: `Bearer ${process.env.ACCESS_TOKEN}` };

export async function findDocuments(instanceId: string, query: string) {
  const transport = new StreamableHTTPClientTransport(URL, { requestInit: { headers } });
  const client = new Client({ name: "kai-cookbook", version: "1.0.0" });
  await client.connect(transport);

  const hits = await client.callTool({
    name: "retrieval_semantic_nodes_search",
    arguments: { instance_id: instanceId, query },
  });
  const nodes = (hits as any).structuredContent.response;
  const docId = nodes[0].documents[0].id;
  const doc = await client.callTool({
    name: "retrieval_documents_get_document",
    arguments: { instance_id: instanceId, document_id: docId },
  });
  await client.close();
  return (doc as any).structuredContent.response;
}
```

{% endtab %}
{% endtabs %}

## Recipe 2 — Resolve an open audit conflict from an LLM

**Goal.** An LLM agent helps a Document Steward resolve a conflict surfaced by K-AI Audit: orient, pick a conflict, record the expert answer, then close it once the Steward confirms the recommended document edits were applied.

**Tools used (Audit).**

1. `audit_dashboard_get` — orient on all instances (open conflicts, pending questions, missing subjects).
2. `audit_full_audit_conflict_list` — list open full-audit conflicts (defaults to `DETECTED`).
3. `audit_full_audit_conflict_get` — inspect a conflict (sources, evidence).
4. `audit_full_audit_conflict_set_answer` — record the expert's resolved answer; the response carries per-document modification **recommendations**.
5. `audit_full_audit_conflict_close` — close the conflict **only after** the Steward confirms the recommended modifications were applied to the source documents.

```python
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

URL = "https://api-audit.kai-studio.ai/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"}

async def resolve_first_open_conflict(instance_id: str, expert_answer: str):
    async with streamablehttp_client(URL, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()

            await session.call_tool("audit_dashboard_get", {})

            conflicts = await session.call_tool(
                "audit_full_audit_conflict_list",
                {"instance_id": instance_id, "limit": 1},
            )
            conflict_id = conflicts.structuredContent["response"][0]["id"]

            await session.call_tool(
                "audit_full_audit_conflict_get",
                {"instance_id": instance_id, "conflict_id": conflict_id},
            )

            recos = await session.call_tool(
                "audit_full_audit_conflict_set_answer",
                {
                    "instance_id": instance_id,
                    "conflict_id": conflict_id,
                    "answer": expert_answer,
                },
            )
            recommendations = recos.structuredContent["response"]["recommendations"]
            # Render `recommendations` as a markdown table with document_url links.
            # Ask the expert to confirm modifications applied, then:
            await session.call_tool(
                "audit_full_audit_conflict_close",
                {"instance_id": instance_id, "conflict_id": conflict_id},
            )
```

## Recipe 3 — Multi-instance search across an org

**Goal.** Search across every K-AI instance the user has access to in one go, then aggregate.

**Tools used (Retrieval, stable).**

1. `retrieval_instances_list_available_instances` — list instances visible to the user.
2. `retrieval_semantic_nodes_search` — call once per instance.

```python
import asyncio, os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

URL = "https://api-retrieval.kai-studio.ai/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"}

async def search_org(query: str):
    async with streamablehttp_client(URL, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            listing = await session.call_tool(
                "retrieval_instances_list_available_instances", {},
            )
            instances = listing.structuredContent["response"]["instances"]

            async def one(inst):
                hits = await session.call_tool(
                    "retrieval_semantic_nodes_search",
                    {"instance_id": inst["id"], "query": query},
                )
                return hits.structuredContent["response"]

            results = await asyncio.gather(*(one(i) for i in instances))
            return [(inst["id"], nodes) for inst, nodes in zip(instances, results)]
```

## Recipe 4 — Fetch documents by ID across instances

**Goal.** A host LLM has accumulated document IDs (from a prior search or a user-provided list) and needs the full content in a single round-trip per instance.

**Tools used (Retrieval, stable).**

1. `retrieval_documents_list_by_ids` — batch fetch.

```python
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

URL = "https://api-retrieval.kai-studio.ai/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"}

async def fetch_batch(instance_id: str, document_ids: list[str]):
    async with streamablehttp_client(URL, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()
            result = await session.call_tool(
                "retrieval_documents_list_by_ids",
                {"instance_id": instance_id, "document_ids": document_ids},
            )
            return result.structuredContent["response"]
```

{% tabs %}
{% tab title="TypeScript" %}

```typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const URL = new URL("https://api-retrieval.kai-studio.ai/mcp");
const headers = { Authorization: `Bearer ${process.env.ACCESS_TOKEN}` };

export async function fetchBatch(instanceId: string, documentIds: string[]) {
  const transport = new StreamableHTTPClientTransport(URL, { requestInit: { headers } });
  const client = new Client({ name: "kai-cookbook", version: "1.0.0" });
  await client.connect(transport);

  const docs = await client.callTool({
    name: "retrieval_documents_list_by_ids",
    arguments: { instance_id: instanceId, document_ids: documentIds },
  });
  await client.close();
  return (docs as any).structuredContent.response;
}
```

{% endtab %}
{% endtabs %}

## Recipe 5 — Surface missing subjects to a Steward

**Goal.** Help a Document Steward review documentary gaps (topics not covered by the Repository) on a K-AI Audit instance and the questions that triggered the gap detection.

**Tools used (Audit).**

1. `audit_missing_subject_list` — list known missing subjects for an instance.
2. `audit_missing_subject_find` — re-run the missing-subject detection.
3. `audit_missing_subject_list_questions` — list the questions that surfaced a given missing subject.

```python
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

URL = "https://api-audit.kai-studio.ai/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"}

async def review_missing_subjects(instance_id: str):
    async with streamablehttp_client(URL, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as session:
            await session.initialize()

            # Refresh detection (optional — may be expensive).
            await session.call_tool(
                "audit_missing_subject_find", {"instance_id": instance_id},
            )

            listing = await session.call_tool(
                "audit_missing_subject_list",
                {"instance_id": instance_id, "offset": 0, "limit": 50},
            )
            for subj in listing.structuredContent["response"]:
                questions = await session.call_tool(
                    "audit_missing_subject_list_questions",
                    {"instance_id": instance_id, "subject_id": subj["id"]},
                )
                yield subj, questions.structuredContent["response"]
```

## Recipe 6 — Cross-check a draft answer against the audited base (Retrieval + Audit)

**Goal.** A host LLM has drafted an answer from Retrieval results. Before returning it, validate that no unresolved K-AI Audit conflict on the same topic would contradict it.

**Tools used.**

1. `retrieval_semantic_nodes_search` — find the supporting passages for the draft.
2. `audit_full_audit_conflict_list` — list open full-audit conflicts in the same instance (defaults to `DETECTED`). Filter by topic client-side on the returned `subject` / `explanation` fields.

```python
import os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

RET = "https://api-retrieval.kai-studio.ai/mcp"
AUD = "https://api-audit.kai-studio.ai/mcp"
HEADERS = {"Authorization": f"Bearer {os.environ['ACCESS_TOKEN']}"}

async def cross_check(instance_id: str, topic: str):
    async with streamablehttp_client(RET, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as ret:
            await ret.initialize()
            passages_result = await ret.call_tool(
                "retrieval_semantic_nodes_search",
                {"instance_id": instance_id, "query": topic},
            )
            passages = passages_result.structuredContent["response"]

    async with streamablehttp_client(AUD, headers=HEADERS) as (r, w, _):
        async with ClientSession(r, w) as aud:
            await aud.initialize()
            conflicts_result = await aud.call_tool(
                "audit_full_audit_conflict_list",
                {"instance_id": instance_id},
            )
            all_open = conflicts_result.structuredContent["response"]
            # Client-side keyword filter on the returned conflicts.
            needle = topic.lower()
            open_conflicts = [
                c for c in all_open
                if needle in (c.get("subject") or "").lower()
                or needle in (c.get("explanation") or "").lower()
            ]

    return {"passages": passages, "open_conflicts": open_conflicts}
```

If `open_conflicts` is non-empty, the host LLM should warn the Consumer that the topic has unresolved contradictions in the audited base before presenting the drafted answer.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://k-ai.gitbook.io/knowledge-ai/k-ai-mcp/cookbook.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
