Back to MCP Hub
Code Integration

Integrate Precept MCP into Your Code

Use the standard Model Context Protocol SDK to programmatically access Precept's B2B contact engine, search companies, and enrich target accounts from within your own applications.

NPM Package

Using the NPM Package

The Precept MCP server is published on NPM as @preceptai/mcp-server. You can connect to it programmatically using the official MCP TypeScript SDK.

1

Install Dependencies

Install the official MCP TypeScript SDK, the Precept MCP server, and (optionally) the Anthropic SDK into your project.

npm install @modelcontextprotocol/sdk @preceptai/mcp-server @anthropic-ai/sdk

Installing @preceptai/mcp-server locally is the recommended approach for production. It guarantees fast, deterministic startup with no network dependency. You can also use npx -y @preceptai/mcp-server for quick testing, but npx may check the registry on each run.

2

Call Tools Directly (Without AI)

If you just want to run queries programmatically from your backend, you can execute tools directly. This doesn't involve an LLM—it's just a standard function call over the MCP protocol. Use StdioClientTransport to spawn the server as a persistent child process, make your callTool() requests, and call client.close() when finished.

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

async function run() {
  // Spawn the Precept MCP server as a child process (runs once, stays alive)
  const transport = new StdioClientTransport({
    command: "npx",                             // Quick start
    args: ["-y", "@preceptai/mcp-server"],
    // For production, install locally and use the direct path instead:
    // command: "node",
    // args: ["node_modules/@preceptai/mcp-server/dist/index.js"],
    env: {
      ...process.env,
      PRECEPT_API_KEY: "pt_your_api_key_here",
    },
  });

  const client = new Client(
    { name: "my-app", version: "1.0.0" },
    { capabilities: {} }
  );

  await client.connect(transport);

  try {
    // Discover available tools
    const { tools } = await client.listTools();
    console.log("Available tools:", tools.map(t => t.name));

    // Call as many tools as you need over this single connection
    const result = await client.callTool({
      name: "precept_search_companies",
      arguments: { query: "Find AI companies in the UK that have at least 400 employees." },
    });
    console.log("Result:", result);
  } finally {
    // Always close to clean up the spawned process
    await client.close();
  }
}

run().catch(console.error);
3

Or, Build an AI Agentic Loop

If you want an LLM to automatically decide when to search for companies or leads, you must build an agentic tool-use loop. You provide both your own local tools and the MCP tools to the model, and whenever it asks to use a tool, you route the execution to the correct handler and feed the result back to the model.

Note: The code below is a conceptual example showing how to route between your own local tools and the Precept MCP server using the Anthropic SDK (Claude).

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
import Anthropic from "@anthropic-ai/sdk";

const anthropic = new Anthropic();

// ── Customer's own tools (local tools already present in the app) ──
const customerTools = [
  {
    name: "check_inventory",
    description: "Check product inventory in our warehouse",
    input_schema: {
      type: "object",
      properties: { sku: { type: "string" } },
      required: ["sku"],
    },
  },
];

// Customer's own tool execution logic
async function executeCustomerTool(name: string, args: any): Promise<string> {
  if (name === "check_inventory") {
    return JSON.stringify({ sku: args.sku, quantity: 42 });
  }
  return JSON.stringify({ error: "Unknown tool" });
}

// ── Precept MCP setup (runs ONCE at server startup) ─────────────
async function initPreceptMCP() {
  const transport = new StdioClientTransport({
    // For production with a locally installed package (npm install @preceptai/mcp-server):
    command: "node",
    args: ["node_modules/@preceptai/mcp-server/dist/index.js"],
    //
    // For quick testing without installation, you can use npx instead:
    // command: "npx",
    // args: ["-y", "@preceptai/mcp-server"],
    env: { ...process.env, PRECEPT_API_KEY: process.env.PRECEPT_API_KEY },
  });

  const mcpClient = new Client(
    { name: "my-agent", version: "1.0.0" },
    { capabilities: {} }
  );
  
  await mcpClient.connect(transport);
  return mcpClient;
}

// ── Agentic loop (runs per user message) ────────────────────────
async function runAgent(userPrompt: string) {
  const mcpClient = await initPreceptMCP();

  try {
    // 1. Discover tools from Precept and map to Anthropic's format
    const { tools } = await mcpClient.listTools();
    const preceptTools = tools.map((t) => ({
      name: t.name,
      description: t.description ?? "",
      input_schema: t.inputSchema as any,
    }));

    const preceptToolNames = new Set(tools.map((t) => t.name));
    
    // Combine customer tools and Precept MCP tools
    const allTools = [...customerTools, ...preceptTools];

    // 2. Start the conversation
    let messages: any[] = [{ role: "user", content: userPrompt }];

    let response = await anthropic.messages.create({
      model: "claude-3-5-sonnet-latest",
      max_tokens: 4096,
      tools: allTools,
      messages,
    });

    // 3. Agentic loop — execute tools while the model requests them
    while (response.stop_reason === "tool_use") {
      const toolUseBlocks = response.content.filter(
        (block) => block.type === "tool_use"
      );

      if (toolUseBlocks.length === 0) break;
      
      // Append assistant's message to the conversation (including all tool_use blocks)
      messages.push({ role: "assistant", content: response.content });
      
      const toolResults = [];

      for (const toolUseBlock of toolUseBlocks) {
        let resultContent: string;

        try {
          if (preceptToolNames.has(toolUseBlock.name)) {
            // Route to Precept MCP server
            const mcpResult = await mcpClient.callTool({ 
              name: toolUseBlock.name, 
              arguments: toolUseBlock.input as Record<string, unknown> 
            });
            // Extract text content cleanly from MCP output
            resultContent = mcpResult.content
              .filter((c) => c.type === "text")
              .map((c) => (c as any).text)
              .join("\n") || JSON.stringify(mcpResult.content);
          } else {
            // Route to customer's own logic
            resultContent = await executeCustomerTool(
              toolUseBlock.name, 
              toolUseBlock.input
            );
          }
        } catch (error: any) {
          resultContent = JSON.stringify({ error: error.message || "Execution failed" });
        }

        toolResults.push({
          type: "tool_result",
          tool_use_id: toolUseBlock.id,
          content: resultContent,
        });
      }

      // 4. Feed the tool execution results back to the model
      messages.push({
        role: "user",
        content: toolResults,
      });

      // 5. Get the next model response
      response = await anthropic.messages.create({
        model: "claude-3-5-sonnet-latest",
        max_tokens: 4096,
        tools: allTools,
        messages,
      });
    }

    const textBlock = response.content.find((b) => b.type === "text");
    console.log("Final Answer:", textBlock?.text);
  } finally {
    // Always close the client to clean up the spawned MCP server
    await mcpClient.close();
  }
}

runAgent(
  "Find verified contacts for Product Marketing leads at Stripe."
).catch(console.error);