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

# MCP Integration of Polyvia

> Use Polyvia with Model Context Protocol

Polyvia implements the [Model Context Protocol (MCP)](https://modelcontextprotocol.io), enabling seamless integration with AI assistants like Claude Desktop, IDEs, and other MCP-compatible tools.

<Tip>
  **Using Claude Code or Cursor?** The [Polyvia plugin](/products/skills) installs the MCP server and agent skills in one command — no config editing required.

  ```
  /plugin add polyvia-ai/skills
  ```
</Tip>

## What is MCP?

Model Context Protocol is an open standard that allows AI applications to securely access external data sources and tools. Polyvia's MCP server exposes your document workspace as a set of tools that AI assistants can use to ingest, browse, and query your documents — all without leaving the conversation.

Polyvia's MCP server is hosted at `https://app.polyvia.ai/mcp` and uses the streamable HTTP transport. No installation required — just point your client at the URL and pass your API key as a bearer token.

## Connecting from Claude Code

Add the server with a single command:

```bash theme={null}
claude mcp add --transport http polyvia https://app.polyvia.ai/mcp \
  --header "Authorization: Bearer poly_<your-key>"
```

This registers `polyvia` for the current project. Add `--scope user` to make it available in every project, or `--scope project` to share it with your team via a checked-in `.mcp.json`. Run `claude mcp list` to confirm it's connected, then ask Claude about your documents.

<Tip>
  Generate a dedicated API key for each MCP client so you can revoke it independently.
</Tip>

## Connecting from Claude Desktop & other clients

Claude Desktop and most other MCP clients read a JSON config file rather than a CLI. Open (or create) `~/.claude/claude_desktop_config.json` and add the `polyvia` entry:

```json theme={null}
{
  "mcpServers": {
    "polyvia": {
      "type": "http",
      "url": "https://app.polyvia.ai/mcp",
      "headers": {
        "Authorization": "Bearer poly_<your-key>"
      }
    }
  }
}
```

Restart Claude Desktop. You should see **Polyvia** appear in the MCP server list.

## Connecting via SDK

Both the Python and TypeScript SDKs expose a `client.mcp` helper that generates the correct config for each major AI client.

| Python method                | TypeScript method         | Use with                            |
| ---------------------------- | ------------------------- | ----------------------------------- |
| `claude_code_command()`      | `claudeCodeCommand()`     | The `claude mcp add …` command line |
| `to_anthropic_mcp_server()`  | `toAnthropicMcpServer()`  | Anthropic beta messages API         |
| `to_openai_responses_tool()` | `toOpenAIResponsesTool()` | OpenAI Responses API                |
| `to_openai_mcp_server()`     | `toOpenAIMcpServer()`     | OpenAI Agents SDK                   |
| `to_claude_desktop_config()` | `toClaudeDesktopConfig()` | Claude Desktop config file          |

### Anthropic SDK

<CodeGroup>
  ```python Python theme={null}
  from anthropic import Anthropic
  from polyvia import Polyvia

  polyvia = Polyvia(api_key="poly_<key>")
  ant     = Anthropic()

  response = ant.beta.messages.create(
      model="claude-opus-4-5",
      max_tokens=1000,
      messages=[{"role": "user", "content": "What are my Q4 findings?"}],
      mcp_servers=[polyvia.mcp.to_anthropic_mcp_server()],
      betas=["mcp-client-2025-04-04"],
  )
  print(response.content[0].text)
  ```

  ```ts TypeScript theme={null}
  import Anthropic from "@anthropic-ai/sdk";
  import { Polyvia } from "polyvia";

  const polyvia = new Polyvia({ apiKey: "poly_<key>" });
  const ant = new Anthropic();

  const response = await ant.beta.messages.create({
    model: "claude-opus-4-5",
    max_tokens: 1000,
    messages: [{ role: "user", content: "What are my Q4 findings?" }],
    mcp_servers: [polyvia.mcp.toAnthropicMcpServer()],
    betas: ["mcp-client-2025-04-04"],
  });
  ```
</CodeGroup>

### OpenAI Responses API

<CodeGroup>
  ```python Python theme={null}
  from openai import OpenAI
  from polyvia import Polyvia

  polyvia = Polyvia(api_key="poly_<key>")
  oai     = OpenAI()

  response = oai.responses.create(
      model="gpt-4o",
      tools=[polyvia.mcp.to_openai_responses_tool()],
      input="What are my Q4 findings?",
  )
  print(response.output_text)
  ```

  ```ts TypeScript theme={null}
  import OpenAI from "openai";
  import { Polyvia } from "polyvia";

  const polyvia = new Polyvia({ apiKey: "poly_<key>" });
  const oai = new OpenAI();

  const response = await oai.responses.create({
    model: "gpt-4o",
    tools: [polyvia.mcp.toOpenAIResponsesTool()],
    input: "What are my Q4 findings?",
  });
  console.log(response.output_text);
  ```
</CodeGroup>

### OpenAI Agents SDK

<CodeGroup>
  ```python Python theme={null}
  from agents import Agent, Runner
  from agents.mcp import MCPServerStreamableHTTP
  from polyvia import Polyvia

  polyvia = Polyvia(api_key="poly_<key>")
  cfg = polyvia.mcp.to_openai_mcp_server()

  server = MCPServerStreamableHTTP(url=cfg["url"], headers=cfg["headers"])
  agent  = Agent(name="Research", mcp_servers=[server])
  result = Runner.run_sync(agent, "What do my Q4 reports say about revenue?")
  print(result.final_output)
  ```

  ```ts TypeScript theme={null}
  import { Agent, Runner } from "@openai/agents";
  import { MCPServerStreamableHTTP } from "@openai/agents/mcp";
  import { Polyvia } from "polyvia";

  const cfg = new Polyvia({ apiKey: "poly_<key>" }).mcp.toOpenAIMcpServer();
  const server = new MCPServerStreamableHTTP({ url: cfg.url, headers: cfg.headers });
  const agent = new Agent({ name: "Research", mcpServers: [server] });
  const result = await Runner.runSync(agent, "What do my Q4 reports say about revenue?");
  console.log(result.finalOutput);
  ```
</CodeGroup>

### Claude Desktop

<CodeGroup>
  ```python Python theme={null}
  # Print a snippet to copy-paste into ~/.claude/claude_desktop_config.json
  client.mcp.print_claude_desktop_snippet()

  # Or wire it up programmatically
  import json, pathlib

  cfg_path = pathlib.Path.home() / ".claude" / "claude_desktop_config.json"
  config = json.loads(cfg_path.read_text()) if cfg_path.exists() else {}
  config.setdefault("mcpServers", {})["polyvia"] = client.mcp.to_claude_desktop_config()
  cfg_path.write_text(json.dumps(config, indent=2))
  ```

  ```ts TypeScript theme={null}
  import { Polyvia } from "polyvia";

  // Print a snippet to copy-paste into ~/.claude/claude_desktop_config.json
  new Polyvia({ apiKey: "poly_<key>" }).mcp.printClaudeDesktopSnippet();
  ```
</CodeGroup>

***

## Agent Tools (programmatic)

For frameworks that don't support remote MCP, use `client.tools` to get JSON-schema tool definitions and an executor that calls the REST API directly. All 10 Polyvia tools are available: ingest, status, list/get/update/delete documents, list/create/delete groups, and query.

### Anthropic Messages API

<CodeGroup>
  ```python Python theme={null}
  import anthropic
  from polyvia import Polyvia

  client = Polyvia(api_key="poly_<key>")
  ant    = anthropic.Anthropic()
  tools, call = client.tools.anthropic()

  response = ant.messages.create(
      model="claude-opus-4-5",
      max_tokens=2048,
      messages=[{"role": "user", "content": "Summarise my Finance documents."}],
      tools=tools,
  )
  for block in response.content:
      if block.type == "tool_use":
          print(call(block.name, block.input))
  ```

  ```ts TypeScript theme={null}
  import Anthropic from "@anthropic-ai/sdk";
  import { Polyvia } from "polyvia";

  const client = new Polyvia({ apiKey: "poly_<key>" });
  const ant = new Anthropic();
  const [tools, callTool] = client.tools.anthropic();

  const response = await ant.messages.create({
    model: "claude-opus-4-5",
    max_tokens: 2048,
    messages: [{ role: "user", content: "Summarise my Finance documents." }],
    tools,
  });
  for (const block of response.content) {
    if (block.type === "tool_use") {
      console.log(await callTool(block.name, block.input as Record<string, unknown>));
    }
  }
  ```
</CodeGroup>

### OpenAI ChatCompletion

<CodeGroup>
  ```python Python theme={null}
  import json
  from openai import OpenAI
  from polyvia import Polyvia

  client = Polyvia(api_key="poly_<key>")
  oai    = OpenAI()
  tools, call = client.tools.openai()

  response = oai.chat.completions.create(
      model="gpt-4o",
      messages=[{"role": "user", "content": "What are my Q4 findings?"}],
      tools=tools,
  )
  for tc in response.choices[0].message.tool_calls or []:
      print(call(tc.function.name, json.loads(tc.function.arguments)))
  ```

  ```ts TypeScript theme={null}
  import OpenAI from "openai";
  import { Polyvia } from "polyvia";

  const client = new Polyvia({ apiKey: "poly_<key>" });
  const oai = new OpenAI();
  const [tools, callTool] = client.tools.openai();

  const response = await oai.chat.completions.create({
    model: "gpt-4o",
    messages: [{ role: "user", content: "What are my Q4 findings?" }],
    tools,
  });
  for (const tc of response.choices[0]?.message.tool_calls ?? []) {
    console.log(await callTool(tc.function.name, JSON.parse(tc.function.arguments)));
  }
  ```
</CodeGroup>

### LangChain (Python)

Requires `pip install "polyvia[langchain]"`.

```python theme={null}
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate
from polyvia import Polyvia

client = Polyvia(api_key="poly_<key>")
tools  = client.tools.langchain()

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant with access to a document workspace."),
    ("user", "{input}"),
    ("placeholder", "{agent_scratchpad}"),
])
agent    = create_tool_calling_agent(ChatOpenAI(model="gpt-4o"), tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
executor.invoke({"input": "What risks are mentioned in my reports?"})
```

***

## Available Tools

### `polyvia_ingest_document`

Upload a document from a public URL or raw base64 content.

**Parameters:**

* `source_url` (string, either/or): Publicly accessible URL of the document
* `file_content_base64` (string, either/or): Base64-encoded file bytes
* `file_name` (string, required with base64): Filename with extension (e.g. `report.pdf`)
* `file_mime_type` (string, optional): MIME type; inferred from `file_name` if omitted
* `name` (string, optional): Display name in Polyvia

Returns `{ "document_id", "task_id", "status": "pending" }`.

### `polyvia_check_ingestion_status`

Poll a parse task started by `polyvia_ingest_document`.

**Parameters:**

* `task_id` (string, required): From `polyvia_ingest_document`

Returns `{ "task_id", "document_id", "status", "error" }`.

### `polyvia_list_documents`

List documents in your workspace.

**Parameters:**

* `status` (string, optional): Filter by `uploading`, `parsing`, `completed`, or `failed`
* `response_format` (string, optional): `markdown` (default) or `json`

### `polyvia_get_document`

Get metadata and summary for one document.

**Parameters:**

* `document_id` (string, required): From `polyvia_list_documents`
* `response_format` (string, optional): `markdown` (default) or `json`

### `polyvia_query`

Ask a natural-language question about your documents.

**Parameters:**

* `query` (string, required): Your question (max 2000 chars)
* `document_id` (string, optional): Scope to one document
* `group_id` (string, optional): Scope to documents in a specific group
* `group_ids` (string\[], optional): Scope to documents across multiple groups
* Omit all three to search your entire workspace

Documents must have `status=completed` before they can be queried.

***

### `polyvia_list_groups`

List all groups in your workspace.

No parameters required. Returns an array of group objects with `id`, `name`, `color`, and `created_at`.

***

### `polyvia_create_group`

Create a new group.

**Parameters:**

* `name` (string, required): Display name for the group

Returns `{ "group_id": "g_<id>" }`.

***

### `polyvia_update_document`

Move a document to a different group, or remove it from its current group.

**Parameters:**

* `document_id` (string, required): The document to update
* `group_id` (string | null, required): Target group ID, or `null` to remove from any group

***

### `polyvia_delete_document`

Permanently delete a document and all its indexed content.

**Parameters:**

* `document_id` (string, required): The document to delete

***

### `polyvia_delete_group`

Delete a group. The group must be empty, or you must pass `delete_documents: true` to wipe its documents first.

**Parameters:**

* `group_id` (string, required): The group to delete
* `delete_documents` (boolean, optional): If `true`, delete all documents in the group before deleting the group itself. Defaults to `false`.

## Example Workflows

### Ingest a public PDF and ask a question

```
User: Ingest this paper and tell me the main contributions:
      https://arxiv.org/pdf/2501.12345

Claude:
  1. polyvia_ingest_document(source_url="https://arxiv.org/pdf/2501.12345")
     → { document_id: "k57abc...", task_id: "3f2e..." }

  2. polyvia_check_ingestion_status(task_id="3f2e...")
     → status: "parsing" … (waits) … status: "completed"

  3. polyvia_query(query="What are the main contributions?",
                   document_id="k57abc...")
     → "The paper introduces three key contributions: ..."
```

### Find information across your whole workspace

```
User: What do all my uploaded reports say about supply chain risks?

Claude:
  1. polyvia_list_documents(status="completed")
     → lists completed documents

  2. polyvia_query(query="What supply chain risks are mentioned across all reports?")
     → "Across your documents, three recurring supply chain risks appear: ..."
```

### Check what documents you have before querying

```
User: Do I have anything about GDPR compliance?

Claude:
  1. polyvia_list_documents(status="completed", response_format="json")
     → scans titles and summaries

  2. polyvia_get_document(document_id="<matched-id>")
     → confirms the document is about GDPR

  3. polyvia_query(query="What does this document say about data retention?",
                   document_id="<matched-id>")
     → focused answer from that document
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="MCP server not appearing in Claude">
    * Verify the configuration file path is correct (`~/.claude/claude_desktop_config.json`)
    * Check that the API key is valid and starts with `poly_`
    * Restart Claude Desktop completely
    * Check Claude's logs for error messages
  </Accordion>

  <Accordion title="Authentication errors">
    * Ensure your API key is correctly set in the `Authorization` header
    * Verify the API key has not been revoked or expired
    * Check that you have an active Polyvia account
  </Accordion>

  <Accordion title="Slow response times">
    * Large workspaces may take longer to search
    * Use `document_id` in `polyvia_query` to narrow to a specific document
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="Python SDK" icon="python" href="/products/python-sdk">
    Full Python SDK reference
  </Card>

  <Card title="TypeScript SDK" icon="js" href="/products/js-sdk">
    Full TypeScript / JavaScript SDK reference
  </Card>

  <Card title="Polyvia API" icon="code" href="/products/api">
    Build custom integrations with the REST API
  </Card>

  <Card title="Polyvia Platform" icon="browser" href="/products/platform">
    Upload documents and manage your workspace
  </Card>
</CardGroup>
