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

# General

# Barndoor SDK Examples

This directory contains working examples that demonstrate how to use the Barndoor TypeScript SDK with MCP servers.

## Key Patterns

Both examples follow the same proven pattern:

```typescript theme={null}
// 1. Authenticate
const sdk = await loginInteractive();

// 2. Ensure server is connected
await ensureServerConnected(sdk, SERVER_SLUG);

// 3. Create MCP client
const mcpClient = await makeMcpClient(sdk, SERVER_SLUG);

// 4. Use MCP client
const { tools } = await mcpClient.listTools();
const result = await mcpClient.callTool({ name: 'tool_name', arguments: {} });

// 5. Cleanup
await mcpClient.close();
await sdk.close();
```

## Configuration

Both examples use the same authentication pattern:

1. **Environment Variables** (create a `.env` file):
   ```
   AUTH_DOMAIN=your-auth-domain
   AGENT_CLIENT_ID=your-client-id
   AGENT_CLIENT_SECRET=your-client-secret
   MODE=development  # or production
   ```

2. **Server Configuration**: Change the `SERVER_SLUG` constant in each file to target different MCP servers:
   * `'salesforce'` - Salesforce integration
   * `'notion'` - Notion integration
   * Or any other configured MCP server

## Working Examples

### 1. `basic-mcp-client.js` - Direct MCP Client

Basic example showing direct MCP server interaction without AI frameworks.

**What it does:**

* Authenticates with Barndoor
* Connects to an MCP server
* Lists available tools and resources
* Executes basic operations

**Requirements:**

```bash theme={null}
npm install dotenv
```

**Run:**

```bash theme={null}
node examples/basic-mcp-client.js
```

<Expandable title="Basic MCP client">
  ```typescript theme={null}
  /**
   * 🔗 Universal Barndoor MCP Client
   *
   * Lets the user pick any available MCP server, list its tools,
   * and run a custom prompt / command interactively — no hardcoded Salesforce or Notion.
   */

  import 'dotenv/config';
  import readline from 'readline/promises';
  import {
    loginInteractive,
    ensureServerConnected,
    makeMcpClient,
    BarndoorSDK,
    getDynamicConfig,
    getStaticConfig,
    hasOrganizationInfo,
  } from '../dist/index.esm.js';

  // simple input helper
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  async function ask(q) {
    return (await rl.question(q)).trim();
  }

  async function main() {
    try {
      console.log('\n🚀 Starting Universal MCP Client Example...\n');

      // ---------------------------------------------------------------------
      // 1. Authenticate to Barndoor
      // ---------------------------------------------------------------------
      console.log('🔐 Authenticating with Barndoor...');
      let sdk;
      const envToken = process.env.BARNDOOR_ACCESS_TOKEN;

      if (envToken) {
        console.log('🔑 Using token from BARNDOOR_ACCESS_TOKEN');
        const cfg = hasOrganizationInfo(envToken)
          ? getDynamicConfig(envToken)
          : getStaticConfig();
        sdk = new BarndoorSDK(cfg.apiBaseUrl, { token: envToken });
        await sdk.listServers();
        console.log('✅ Authentication successful (env token)!');
      } else {
        sdk = await loginInteractive();
        await sdk.listServers();
        console.log('✅ Authentication successful!');
      }

      // ---------------------------------------------------------------------
      // 2. List all available servers
      // ---------------------------------------------------------------------
      const servers = await sdk.listServers();
      if (!servers.length) throw new Error('No MCP servers found for this user.');
      console.log('\n📡 Available MCP servers:');
      servers.forEach((s, i) => console.log(`  ${i + 1}. ${s.slug} (${s.connection_status})`));

      // Ask user which one to use
      let idx = await ask('\n👉 Enter the number of the server you want to use: ');
      const choice = servers[parseInt(idx) - 1];
      if (!choice) throw new Error('Invalid selection.');
      const SERVER_SLUG = choice.slug;
      console.log(`\n🔗 Selected: ${SERVER_SLUG}\n`);

      // ---------------------------------------------------------------------
      // 3. Ensure it’s connected
      // ---------------------------------------------------------------------
      await ensureServerConnected(sdk, SERVER_SLUG);
      console.log(`✅ ${SERVER_SLUG} connected.`);

      // ---------------------------------------------------------------------
      // 4. Build MCP client and show available tools
      // ---------------------------------------------------------------------
      const mcpClient = await makeMcpClient(sdk, SERVER_SLUG);
      console.log('\n🔧 Fetching available tools...');
      const { tools = [] } = await mcpClient.listTools();
      if (!tools.length) console.log('⚠️  No tools found for this server.');
      else tools.forEach((t, i) => console.log(`  ${i + 1}. ${t.name} — ${t.description || 'No description'}`));

      // ---------------------------------------------------------------------
      // 5. Ask user for a custom prompt
      // ---------------------------------------------------------------------
      const prompt = await ask('\n💬 What do you want to ask or do? (describe task): ');
      console.log(`\n🧠 Interpreting prompt: "${prompt}"`);

      // Naive tool selection: try to find one that matches keyword
      const matching = tools.find(t =>
        prompt.toLowerCase().includes(t.name.toLowerCase().split('_')[0])
      );
      const tool = matching || tools[0];
      if (!tool) throw new Error('No tools available to handle this prompt.');

      console.log(`\n⚙️  Using tool: ${tool.name}`);

      // Ask user for optional JSON args
      let args = '{}';
      if (tool.input_schema) {
        args = await ask('🧩 Optional JSON arguments (or Enter for none): ');
        if (!args.trim()) args = '{}';
      }

      // ---------------------------------------------------------------------
      // 6. Call the selected tool
      // ---------------------------------------------------------------------
      console.log('\n🚀 Executing MCP tool...\n');
      const parsedArgs = JSON.parse(args);
      const response = await mcpClient.callTool({
        name: tool.name,
        arguments: parsedArgs,
      });

      // ---------------------------------------------------------------------
      // 7. Pretty-print the result
      // ---------------------------------------------------------------------
      console.log('\n✅ MCP Response:');
      if (response?.content?.[0]?.type === 'text') {
        console.log(response.content[0].text);
      } else {
        console.dir(response, { depth: 4, colors: true });
      }

      // ---------------------------------------------------------------------
      // 8. Clean up
      // ---------------------------------------------------------------------
      await mcpClient.close();
      await sdk.close();
      rl.close();

      console.log('\n✨ Done!\n');
    } catch (error) {
      console.error('❌ Error:', error.message);
      if (error.stack) console.error(error.stack);
      rl.close();
      process.exit(1);
    }
  }

  if (import.meta.url === `file://${process.argv[1]}`) {
    main();
  }

  ```
</Expandable>

**Requirements:**

```bash theme={null}
npm install openai dotenv
```

### 2. `openai-integration.js` - OpenAI + MCP Integration

Complete example showing how to integrate OpenAI's function calling with MCP tools.

**What it does:**

* Authenticates with Barndoor
* Connects to an MCP server (Salesforce by default)
* Lets OpenAI decide which MCP tools to call
* Executes the tools and feeds results back to OpenAI

**Environment:**

```bash theme={null}
export OPENAI_API_KEY="your-openai-api-key"
```

**Run:**

```bash theme={null}
node examples/openai-integration.js
```

<Expandable title="Show Code Example">
  ```typescript theme={null}
  /**
   * 🤖 OpenAI Function Calling + Barndoor MCP Integration
   *
   * This script lets the user:
   *  1. Pick an available MCP server (e.g., salesforce, notion, etc)
   *  2. Type a natural-language query (e.g. "list ten notion pages")
   *  3. The model automatically selects the best MCP tool to call
   *  4. The result is returned and summarized in plain English
   *
   * Run with:
   *    node examples/interactive-openai-mcp-client.js
   *
   * Requirements:
   *    npm install openai dotenv readline-sync
   *
   * Make sure `.env` includes:
   *    OPENAI_API_KEY=sk-...
   *    AUTH_DOMAIN=auth.barndoor.ai
   *    AGENT_CLIENT_ID=...
   *    AGENT_CLIENT_SECRET=...
   *    API_AUDIENCE=https://barndoor.ai/
   *    BARNDOOR_URL=https://<your-org>.platform.barndoor.ai/mcp
   */

  import 'dotenv/config';
  import readlineSync from 'readline-sync';
  import { OpenAI } from 'openai';
  import {
    loginInteractive,
    ensureServerConnected,
    makeMcpClient,
  } from '../dist/index.esm.js';

  // --- Step 0: Prepare OpenAI client -------------------------------------------------
  const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

  (async () => {
    let sdk;
    let mcpClient;

    try {
      console.log('🚀 Starting Interactive OpenAI + Barndoor MCP Client...\n');

      // ---------------------------------------------------------------------
      // 1️⃣ Authenticate with Barndoor SDK
      // ---------------------------------------------------------------------
      console.log('🔐 Authenticating with Barndoor...');
      sdk = await loginInteractive();

      const servers = await sdk.listServers();
      if (!servers.length) throw new Error('No MCP servers found! Connect at barndoor.ai.');

      console.log('\n🌐 Available MCP servers:');
      servers.forEach((s, i) => console.log(`  ${i + 1}. ${s.slug} (${s.connection_status})`));

      // Prompt user to choose one
      const idx = readlineSync.questionInt(
        '\n👉 Select a server by number: ',
        { limitMessage: 'Enter a valid number!' }
      ) - 1;
      const chosenServer = servers[idx];
      if (!chosenServer) throw new Error('Invalid selection.');

      const SERVER_SLUG = chosenServer.slug;
      console.log(`\n🔗 Ensuring ${SERVER_SLUG} server is connected...`);
      await ensureServerConnected(sdk, SERVER_SLUG);
      console.log(`✅ ${SERVER_SLUG} server connected!\n`);

      mcpClient = await makeMcpClient(sdk, SERVER_SLUG);

      // ---------------------------------------------------------------------
      // 2️⃣ Let user enter a natural language request
      // ---------------------------------------------------------------------
      const userPrompt = readlineSync.question(
        '💬 What do you want to ask or do? (describe task): '
      );

      // ---------------------------------------------------------------------
      // 3️⃣ List available MCP tools and convert to OpenAI function schemas
      // ---------------------------------------------------------------------
      const { tools = [] } = await mcpClient.listTools();
      if (!tools.length) throw new Error(`No tools available on ${SERVER_SLUG}`);

      const functions = tools.map((t) => ({
        type: 'function',
        function: {
          name: t.name.replace(/[^A-Za-z0-9_]/g, '_').slice(0, 64),
          description: t.description || 'MCP tool',
          parameters: t.parameters ?? {
            type: 'object',
            properties: {},
            additionalProperties: true,
          },
        },
      }));

      // ---------------------------------------------------------------------
      // 4️⃣ Use OpenAI to decide which tool to call
      // ---------------------------------------------------------------------
      console.log(`\n🧠 Interpreting prompt: "${userPrompt}"`);
      const msgs = [{ role: 'user', content: userPrompt }];

      let chat = await openai.chat.completions.create({
        model: 'gpt-4o-mini',
        messages: msgs,
        tools: functions,
        tool_choice: 'auto',
      });

      let msg = chat.choices[0].message;
      const toolCall = msg.tool_calls?.[0];

      if (!toolCall) {
        console.log('\n🤔 Model did not choose a tool. Here’s its reply:');
        console.log(msg.content);
        return;
      }

      const { name: toolName, arguments: raw } = toolCall.function;
      const args = JSON.parse(raw || '{}');
      console.log(`\n⚙️  Using tool: ${toolName}`);
      console.log('🚀 Executing MCP tool...\n');

      const mcpResult = await mcpClient.callTool({
        name: toolName,
        arguments: args,
      });

      console.log('✅ MCP Response:');
      console.log(JSON.stringify(mcpResult, null, 2));

      // ---------------------------------------------------------------------
      // 5️⃣ Feed MCP result back to OpenAI for a natural summary
      // ---------------------------------------------------------------------
      msgs.push(msg);
      msgs.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        name: toolName,
        content: JSON.stringify(mcpResult),
      });

      chat = await openai.chat.completions.create({
        model: 'gpt-4o-mini',
        messages: msgs,
      });

      console.log('\n✨ Final Answer:\n');
      console.log(chat.choices[0].message.content);
    } catch (error) {
      console.error('❌ Error:', error.message);
      if (error.stack) console.error(error.stack);
    } finally {
      if (sdk) await sdk.close();
      if (mcpClient) await mcpClient.close();
    }
  })();

  ```
</Expandable>

This pattern uses the `@modelcontextprotocol/sdk` package internally and handles all the complex MCP protocol details for you.

**Note:** While the SDK is written in TypeScript, the current examples are still in JavaScript (.js files) for broader compatibility. You can easily convert them to TypeScript by changing the file extensions to `.ts` and adding type annotations as needed.
