Developer Getting Started

This guide walks through building an application that connects to a user's local Bodhi instance. By the end, you will have an app that authenticates via OAuth, calls OpenAI-compatible LLM APIs, and discovers and executes MCP tools.

Prerequisites

  • A React project (React 18.3+ or 19+) with Node.js 18+
  • Bodhi App running locally (default: http://localhost:1135)
  • An OAuth client ID from the developer portal

1. Register Your OAuth App

Register your application at https://developer.getbodhi.app to obtain an authClientId. This is the OAuth client identifier your app uses to authenticate with Bodhi users.

2. Install the SDK

npm install @bodhiapp/bodhi-js-react

This single package includes React bindings, the web SDK, and core types.

3. Setup BodhiProvider

Wrap your application with BodhiProvider:

// App.tsx
import { BodhiProvider } from '@bodhiapp/bodhi-js-react';

function App() {
  return (
    <BodhiProvider authClientId="your-client-id">
      <YourApp />
    </BodhiProvider>
  );
}

The provider manages connection state, OAuth flows, and exposes the API client. See the Bodhi JS SDK reference for the full list of BodhiProvider props.

Connection Modes

The SDK connects to the Bodhi server via direct HTTP (primary) or through the Bodhi Browser extension (alternative). On first load, the SDK auto-detects: it tries direct HTTP first (lower latency), then falls back to the extension if unavailable. The selected mode is persisted for subsequent page loads.

const { isDirect, isExtension, clientState } = useBodhi();
// clientState.mode is 'direct' | 'extension' | null

4. Check Connection and Login

Use the useBodhi() hook to access connection state and trigger login:

import { useBodhi } from '@bodhiapp/bodhi-js-react';

function Dashboard() {
  const { isOverallReady, isAuthenticated, canLogin, login, showSetup } = useBodhi();

  if (!isOverallReady) {
    return <button onClick={showSetup}>Connect to Bodhi</button>;
  }

  if (!isAuthenticated) {
    return <button onClick={login} disabled={!canLogin}>Login</button>;
  }

  return <ChatInterface />;
}

Login with Resource Access Requests

When your app needs access to specific MCP servers, request access during login. The user reviews and approves the request before your app gains access:

const handleLogin = async () => {
  await login({
    requested: {
      mcp_servers: [
        { url: 'http://localhost:3000/mcp' },
      ],
    },
    onProgress: (stage) => {
      // stage: 'requesting' -> 'reviewing' -> 'authenticating'
      console.log('Login stage:', stage);
    },
  });
};

This triggers the app access request flow. The user sees a review page where they select which MCP instances to grant your app, and which role level to approve.

5. Call OpenAI-Compatible APIs

Once authenticated, use client from the hook to make API calls. Bodhi exposes OpenAI-compatible endpoints at /v1/chat/completions, /v1/models, and /v1/embeddings.

List Models

const { client } = useBodhi();

async function fetchModels() {
  const models: string[] = [];
  for await (const model of client.models.list()) {
    models.push(model.id);
  }
  return models;
}

Chat Completions (Streaming)

const { client } = useBodhi();

async function chatWithStreaming(model: string, userMessage: string) {
  const stream = client.chat.completions.create({
    model,
    messages: [{ role: 'user', content: userMessage }],
    stream: true,
  });

  let fullResponse = '';
  for await (const chunk of stream) {
    const content = chunk.choices?.[0]?.delta?.content || '';
    fullResponse += content;
  }
  return fullResponse;
}

Chat Completions (Non-Streaming)

const response = await client.chat.completions.create({
  model: 'your-model',
  messages: [{ role: 'user', content: 'Hello!' }],
});
const content = response.choices[0].message.content;

Embeddings

const response = await client.embeddings.create({
  model: 'your-embedding-model',
  input: 'Text to embed',
});
const embedding = response.data[0].embedding; // number[]

For the full list of endpoints, see the OpenAPI Reference.

6. MCP Tool Discovery and Execution

After the user approves your app's access request with MCP servers, you can list, discover, and execute tools:

const { client } = useBodhi();

// List MCP instances accessible to your app
const { mcps } = await client.mcps.list();

// List tools for a specific MCP instance
const { tools } = await client.mcps.listTools(mcp.id);

// Execute a tool
const result = await client.mcps.executeTool(
  mcp.id,
  'tool_name',
  { param: 'value' }
);

Each MCP instance has a slug identifier and a tools_cache array. Tools have name, description, and input_schema fields.

Agentic Tool Calling

For building agentic chat loops where the LLM discovers and calls MCP tools autonomously, convert MCP tools to the ChatCompletionTools format:

import type { ChatCompletionTools } from '@bodhiapp/bodhi-js-react/api';

const { mcps } = await client.mcps.list();

const tools: ChatCompletionTools[] = [];
for (const mcp of mcps) {
  for (const tool of mcp.tools_cache ?? []) {
    tools.push({
      type: 'function',
      function: {
        name: `mcp__${mcp.slug}__${tool.name}`,
        description: tool.description ?? '',
        parameters: tool.input_schema as Record<string, unknown>,
      },
    });
  }
}

// Pass tools to chat completions
const stream = client.chat.completions.create({
  model: 'your-model',
  messages,
  stream: true,
  tools,
});

The tool naming convention is mcp__<slug>__<tool-name>. When the LLM returns a tool call, parse the name to find the MCP instance and execute it. See the SDK Advanced Patterns guide for the complete agentic loop implementation.

REST API Endpoints

All Bodhi-specific endpoints use the /bodhi/v1/ prefix. External app endpoints use /bodhi/v1/apps/:

Endpoint Method Description
/v1/chat/completions POST OpenAI-compatible chat completions
/v1/models GET List available models
/v1/embeddings POST Generate embeddings
/bodhi/v1/apps/request-access POST Create access request
/bodhi/v1/apps/access-requests/{id} GET Poll access request status
/bodhi/v1/apps/mcps GET List accessible MCP instances
/bodhi/v1/apps/mcps/{id} GET Get MCP instance details
/bodhi/v1/apps/mcps/{id}/tools/refresh POST Refresh MCP tool list
/bodhi/v1/apps/mcps/{id}/tools/{tool_name}/execute POST Execute an MCP tool

For the complete API specification, visit /swagger-ui on your Bodhi instance or see the OpenAPI Reference.

Next Steps