---
title: Dynamic discovery
description: Use `GET /api/v1/developer/tools.json` to wire Pictograph into any agent framework that speaks JSON Schema — no Pictograph-specific adapter required.
section: Agents
order: 4
---
The Pictograph SDK ships first-party adapters for **Claude** and
**OpenAI**. For everything else (Vercel AI SDK, LangChain, raw HTTP
clients, custom dispatchers), the registry is exposed as JSON Schema
at:

```
GET https://api.pictograph.io/api/v1/developer/tools.json
```

Authenticated with the same `X-API-Key` header — any role works (read-only).

## Why this exists

Per-framework adapters are a treadmill. The JSON Schema contract is
the long-term answer:

- **Pictograph** maintains one source of truth (`pictograph.agents.REGISTRY`).
- **Your agent stack** consumes JSON Schema natively — every modern
  framework supports it.
- **No bespoke adapter** to maintain on either side.

The Python SDK still ships Claude + OpenAI adapters because their
ecosystems are big enough to warrant the convenience. Everyone else
gets the open-standard path.

## Vercel AI SDK

```ts
import { generateText, tool } from 'ai';
import { anthropic } from '@ai-sdk/anthropic';
import { z } from 'zod';

const headers = { 'X-API-Key': process.env.PICTOGRAPH_API_KEY! };
const { tools } = await fetch(
  'https://api.pictograph.io/api/v1/developer/tools.json',
  { headers },
).then(r => r.json());

// Build a tools map keyed by name. The execute() function dispatches
// back to the Pictograph REST API directly — no Python required.
const pictographTools = Object.fromEntries(
  tools.map((t: any) => [
    t.name,
    tool({
      description: t.description,
      parameters: t.input_schema,        // Vercel accepts JSON Schema directly
      execute: async (args: any) => {
        // Map tool name → REST endpoint.
        // (See: jsonschema-to-rest mapper, or hardcode the routes you use.)
        const res = await fetch(
          `https://api.pictograph.io/api/v1/developer/_dispatch/${t.name}`,
          { method: 'POST', headers, body: JSON.stringify(args) },
        );
        return res.json();
      },
    }),
  ]),
);

const result = await generateText({
  model: anthropic('claude-opus-4'),
  tools: pictographTools,
  prompt: 'List my Pictograph datasets',
});
```

(Pictograph doesn't ship a `_dispatch` endpoint in v1.0.0 — wire
each tool to its underlying REST endpoint manually. The
`Toolkit.dispatch()` Python method is the reference behavior.)

## LangChain

```python
from langchain_core.tools import tool
import requests, os

headers = {"X-API-Key": os.environ["PICTOGRAPH_API_KEY"]}
schema = requests.get(
    "https://api.pictograph.io/api/v1/developer/tools.json",
    headers=headers,
).json()

# Build LangChain tools from the JSON Schema:
def make_tool(spec):
    @tool(spec["name"], description=spec["description"], args_schema=...)
    def _run(**kwargs):
        # Call the matching REST endpoint with kwargs.
        ...
    return _run

langchain_tools = [make_tool(t) for t in schema["tools"]]
```

For LangChain specifically, you can also use the Pictograph Python SDK
directly inside a `@tool` — that's often simpler than rebuilding the
dispatch loop:

```python
from langchain_core.tools import tool
from pictograph import Client
client = Client()

@tool("list_datasets", description="List Pictograph datasets in your org.")
def list_datasets(limit: int = 100) -> list[dict]:
    return [d.model_dump(mode="json") for d in client.datasets.list(limit=limit)]
```

This trades the dynamic-discovery benefit for typed, tested SDK calls —
worth it for production.

## Custom dispatchers

If you're rolling your own:

1. Fetch `/api/v1/developer/tools.json` once at startup.
2. Hand the `tools` array to your LLM as the function/tool spec.
3. When the LLM emits a tool call, look up the tool by name.
4. Map name → REST endpoint (see the [SDK source](https://github.com/pictograph-labs/pictograph-sdk/tree/main/src/pictograph/resources)
   for canonical mappings).
5. Send the args as the JSON body, return the response to the LLM.

Or use the Python SDK as a server-side dispatcher and only expose tool
names + schemas to your client — usually the cleanest production
architecture.

## Snapshot file

The same registry ships in the Python SDK package — useful for offline
work or if you want to bundle the schema with your agent:

```python
from pictograph.agents import Toolkit
from unittest.mock import MagicMock

toolkit = Toolkit(MagicMock())
schema = toolkit.as_json_schema()    # identical to the HTTP response payload
```

Or via the CLI:

```bash
pictograph agents export-tools -o tools.json
```

## See also

- [Agents — overview](/docs/agents.md) — the three integration paths.
- [Tool registry endpoint](/docs/api-reference/tools.md) — full spec.
- [Cookbook](/docs/agents/cookbook.md) — concrete recipe examples.