Skip to main content

Command Palette

Search for a command to run...

Build a Server-Side AI-Agentic API for Web Apps

Move beyond prompts. Turn natural language into real database actions with a simple agentic API.

Updated
โ€ข5 min read
Build a Server-Side AI-Agentic API for Web Apps

๐Ÿ› ๏ธ Build a Server-Side Agentic API for Web Apps

Introduction

Imagine being able to send a simple text query like "Add an item to the database" โ€” and having your app understand it, act on it, and respond back intelligently.

In this tutorial, you'll learn how to build a server-side agentic API using:

  • Anthropic SDK to process natural language

  • Tool calling to trigger real MongoDB actions

  • Express server to expose endpoints for your web apps


โœจ What Are We Building?

We'll create a lightweight server that:

  • Accepts a POST /chat request with a user query

  • Passes the query and available tools to Anthropicโ€™s LLM

  • Lets the LLM choose a tool and auto-handle database operations

  • Sends user-friendly final responses back to the client

Example:

User QueryActionFinal Response
Add item "iPhone" with price 1000Inserts into MongoDB"Successfully added item: iPhone"
Tell me the total priceAggregates items in DB"Total price is 1000"

๐Ÿ—๏ธ Project Setup

1. Install Dependencies

npm init -y
npm install express cors dotenv @anthropic-ai/sdk mongodb

2. Create .env file

MONGODB_URI=your_mongodb_connection_string
ANTHROPIC_API_KEY=your_anthropic_api_key

๐Ÿฎฉ Code Walkthrough

๐Ÿ“„ index.ts โ€” Setting up the Express Server

import express from 'express';
import type { RequestHandler } from 'express';
import cors from 'cors';
import MCPClient from './MCPClient';

async function main() {
  const app = express();
  const port = process.env.PORT || 3000;

  app.use(cors());
  app.use(express.json());

  const mcpClient = new MCPClient();

  app.get('/health', (req, res) => {
    res.json({
      status: 'ok',
      tools: mcpClient.tools.map((t) => t.name),
    });
  });

  app.post('/chat', (async (req, res) => {
    try {
      const { query } = req.body;
      if (!query) {
        return res.status(400).json({ error: 'Query is required' });
      }

      const response = await mcpClient.processQuery(query);
      res.json({ response });
    } catch (error) {
      console.error('Error processing query:', error);
      res.status(500).json({ error: 'Failed to process query' });
    }
  }) as RequestHandler);

  app.listen(port, () => {
    console.log(`Server running on port ${port}`);
    console.log(`Health check: http://localhost:${port}/health`);
    console.log(`Chat endpoint: http://localhost:${port}/chat`);
  });
}

main();

Explanation:

  • /health: Checks server status + lists tool names.

  • /chat: Accepts a query, processes it using the AI agent, and returns the AI's final response.


๐Ÿ“„ MCPClient.ts โ€” Anthropic Agent & Tool Orchestration

import { Anthropic } from '@anthropic-ai/sdk';
import { MessageParam, Tool } from '@anthropic-ai/sdk/resources/messages/messages.mjs';
import { tools as importedTools } from './tools';

interface CustomTool extends Tool {
  run: (args: any) => Promise<{ content: string }>;
}

class MCPClient {
  private llm: Anthropic;
  public tools: CustomTool[] = importedTools as CustomTool[];

  constructor() {
    this.llm = new Anthropic({
      apiKey: process.env.ANTHROPIC_API_KEY,
    });
  }

  async processQuery(query: string) {
    const messages: MessageParam[] = [
      { role: 'user', content: query },
    ];

    const response = await this.llm.messages.create({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 1000,
      messages,
      tools: this.tools,
    });

    const finalText = [];

    for (const content of response.content) {
      if (content.type === 'text') {
        finalText.push(content.text);
      } else if (content.type === 'tool_use') {
        const toolName = content.name;
        const toolArgs = content.input;

        const tool = this.tools.find((t) => t.name === toolName && typeof t.run === 'function');

        if (!tool) {
          console.error(`[Tool Error] Tool "${toolName}" not found`);
          continue;
        }

        const result = await tool.run(toolArgs);

        messages.push({
          role: 'user',
          content: result.content,
        });

        const followUp = await this.llm.messages.create({
          model: 'claude-3-5-sonnet-20241022',
          max_tokens: 1000,
          messages,
        });

        if (followUp.content[0]?.type === 'text') {
          finalText.push(followUp.content[0].text);
        }
      }
    }

    return finalText.join('\n');
  }
}

export default MCPClient;

Explanation:

  • Sends the query and available tools to Anthropic.

  • Executes the tool if the LLM decides to use one.

  • Sends the tool output back to LLM for final human-readable text.

  • Returns the final output to the web app.


๐Ÿ“„ tools.ts โ€” MongoDB Tool Definitions

import { MongoClient } from 'mongodb';

const uri = process.env.MONGODB_URI;
if (!uri) throw new Error('MONGODB_URI environment variable is not set');

const dbName = 'mcptool';
const collectionName = 'items';

const validateMongoDBUri = (uri: string) => {
  if (!uri.startsWith('mongodb://') && !uri.startsWith('mongodb+srv://')) {
    throw new Error('Invalid MongoDB URI format.');
  }
  return uri;
};

export const tools = [
  {
    name: 'get_items',
    description: 'Fetch all items from the MongoDB collection',
    input_schema: {
      type: 'object',
      properties: {},
    },
    run: async () => {
      const client = new MongoClient(validateMongoDBUri(uri));
      try {
        await client.connect();
        const collection = client.db(dbName).collection(collectionName);
        const items = await collection.find().toArray();
        return { content: JSON.stringify(items, null, 2) };
      } catch (error) {
        console.error('[MongoDB Error - get_items]:', error);
        return { content: 'Failed to fetch items.' };
      } finally {
        await client.close();
      }
    },
  },
  {
    name: 'add_item',
    description: 'Add a new item to the MongoDB collection',
    input_schema: {
      type: 'object',
      properties: {
        id: { type: 'string' },
        name: { type: 'string' },
        price: { type: 'number' },
      },
      required: ['id', 'name', 'price'],
    },
    run: async ({ id, name, price }: { id: string; name: string; price: number }) => {
      const client = new MongoClient(validateMongoDBUri(uri));
      try {
        await client.connect();
        const collection = client.db(dbName).collection(collectionName);

        const existingItem = await collection.findOne({ id });
        if (existingItem) {
          return { content: `Item with ID ${id} already exists.` };
        }

        const newItem = { id, name, price, createdAt: new Date() };
        await collection.insertOne(newItem);
        return { content: `Successfully added item: ${name}` };
      } catch (error) {
        console.error('[MongoDB Error - add_item]:', error);
        return { content: 'Failed to add item.' };
      } finally {
        await client.close();
      }
    },
  },
];

Explanation:

  • Defines MongoDB tools get_items and add_item.

  • Handles database connection validation and execution per call.


๐Ÿ“Š Final Demo Example

Request

POST /chat
{
  "query": "Add an item called MacBook Pro with a price of 2500"
}

Response

{
  "response": "Successfully added item: MacBook Pro"
}

๐Ÿš€ Final Thoughts

With just a few simple tools and a smart LLM, we created an agentic server API that can:

  • Understand user intent

  • Execute real-world database operations

  • Reply intelligently with user-friendly messages

This is just the beginning โ€” you can easily extend this by:

  • Adding more tools (update, delete, search)

  • Handling chained tasks (multi-turn actions)

  • Integrating authentication

  • Deploying it online (Render, Railway, AWS)

The future of intelligent backend development is here โ€” and itโ€™s agentic.


๐Ÿ“ฆ Full Folder Structure

/your-app
  โ”œโ”€โ”€ MCPClient.ts
  โ”œโ”€โ”€ tools.ts
  โ”œโ”€โ”€ index.ts
  โ”œโ”€โ”€ .env
  โ””โ”€โ”€ package.json