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:Copy
// 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:-
Environment Variables (create a
.envfile):CopyAUTH_DOMAIN=your-auth-domain AGENT_CLIENT_ID=your-client-id AGENT_CLIENT_SECRET=your-client-secret MODE=development # or production -
Server Configuration: Change the
SERVER_SLUGconstant 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
Copy
npm install dotenv
Copy
node examples/basic-mcp-client.js
Show Basic MCP client
Show Basic MCP client
Copy
/**
* 🔗 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();
}
Copy
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
Copy
export OPENAI_API_KEY="your-openai-api-key"
Copy
node examples/openai-integration.js
Show Show Code Example
Show Show Code Example
Copy
/**
* 🤖 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>.mcp.barndoor.ai
*/
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();
}
})();
@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.