LESSON 81 / 215·2 min readIntermediate

Conceptual MCP server: four business tools

Must knowConcept lesson
01 Understand02 Recall03 Prepare

Words made simple

A few useful meanings before you read the explanation.

MCP
A shared protocol for connecting AI applications to tools and resources. It does not replace permission checks or application security.
API
A way for one piece of software to ask another for data or an action. A claims API might return the current status of a claim.
JSON
A common text format for exchanging data using named fields, lists, numbers and values. Example: {"status": "pending"}.
More words from this lesson
Schema
A description of the fields and value types that data should contain. It helps check that an answer has the expected shape.
Agent
An application that uses a model to choose its next action within defined limits. It can use tools and continue through several steps.
Persistence
Saving information so it remains available after a request ends or a process restarts.
Durable
Able to retain progress and recover across interruptions. Durable workflows require appropriate storage and retry behavior.
Idempotency
Making a repeated request have the same intended business effect as one request. It helps avoid duplicate submissions or payments.
  • This example defines server-side contracts and dispatch logic, not a particular MCP SDK's registration syntax.
  • Attach this registry to the selected SDK's authenticated request handlers, implement capability discovery, and encode its documented result envelopes.
  • This separates the durable engineering idea from rapidly changing transport APIs.
TypeScript
import { z } from "zod";

type Principal = { userId: string; tenantId: string; scopes: readonly string[] };
type Services = {
  customerForCaller(p: Principal, customerId: string): Promise<unknown>;
  orderForCaller(p: Principal, orderId: string): Promise<unknown>;
  createTicket(p: Principal, subject: string, body: string, key: string): Promise<unknown>;
  searchKnowledge(p: Principal, query: string): Promise<unknown>;
};
const Id = z.string().regex(/^[A-Za-z0-9_-]{1,80}$/);
const registry = {
  customer_lookup: { schema: z.object({ customerId: Id }).strict(), scope: "customer:read" },
  order_lookup: { schema: z.object({ orderId: Id }).strict(), scope: "order:read" },
  ticket_create: {
    schema: z.object({
      subject: z.string().min(1).max(200),
      body: z.string().min(1).max(5000),
    }).strict(),
    scope: "ticket:create",
  },
  knowledge_search: {
    schema: z.object({ query: z.string().min(1).max(1000) }).strict(),
    scope: "knowledge:read",
  },
} as const;

async function executeTool(
  name: string, raw: unknown, principal: Principal, services: Services,
  operationKey?: string,
): Promise<unknown> {
  // principal comes from verified middleware, never model-supplied JSON.
  if (!Object.prototype.hasOwnProperty.call(registry, name)) {
    throw new Error("Unknown tool");
  }
  const toolName = name as keyof typeof registry;
  if (!principal.scopes.includes(registry[toolName].scope)) {
    throw new Error("Tool scope denied");
  }
  switch (toolName) {
    case "customer_lookup": {
      const a = registry.customer_lookup.schema.parse(raw);
      return services.customerForCaller(principal, a.customerId);
    }
    case "order_lookup": {
      const a = registry.order_lookup.schema.parse(raw);
      return services.orderForCaller(principal, a.orderId);
    }
    case "ticket_create": {
      const a = registry.ticket_create.schema.parse(raw);
      // Reuse the host's persisted key for this logical write across retries.
      // The model cannot mint a new key to turn a retry into another ticket.
      const key = Id.parse(operationKey);
      return services.createTicket(principal, a.subject, a.body, key);
    }
    case "knowledge_search": {
      const a = registry.knowledge_search.schema.parse(raw);
      return services.searchKnowledge(principal, a.query);
    }
  }
}
  • The Services dependency deliberately owns object authorization and business rules.
  • Scope checks alone are insufficient.
  • The trusted host persists operationKey for one logical write and reuses it across retries; it is not a model-generated argument.
  • createTicket must enforce idempotency atomically and reject a changed payload under the same key, and the host/server must impose any required approval policy.
  • Read results should omit unnecessary PII.
  • Add deadlines, rate limits, output schemas, bounded sizes, audit events, and safe error envelopes in the transport layer.

How the agent consumes this server: the host establishes trusted identity, discovers allowed contracts, translates them to the model's tool format, receives a proposed call, applies its approval policy, sends the MCP request, validates the returned result, and supplies the observation to the model. In the insurance domain, order_lookup might become policy-order lookup, ticket_create creates a support case, and knowledge_search retrieves policy instructions. Claim submission would be a separate, more restrictive capability.


PAUSE & RECALL

Can you explain it without the notes?

Conceptual MCP server: four business tools

Use your own words. Explain an example and one limitation before checking the explanation.

Check your explanation

This example defines server-side contracts and dispatch logic, not a particular MCP SDK's registration syntax. Attach this registry to the selected SDK's authenticated request handlers, implement capability discovery, and encode its documented result…

CONNECT IT TO YOUR INTERVIEW

Turn this concept into a clear answer.

Practice this concept
YOUR NEXT STEP

Keep connecting the ideas.

Next lesson: Context, short-term memory, and conversation memory

Adapted from 13_AI.MD · “Conceptual MCP server: four business tools”. Examples are study fragments; framework behavior can depend on your version.