CodeGym /Courses /ChatGPT Apps /What MCP is and why your ChatGPT App needs it

What MCP is and why your ChatGPT App needs it

ChatGPT Apps
Level 6 , Lesson 0
Available

1. Why a separate protocol is needed at all

In this module, we’ll finally sort out what MCP (Model Context Protocol) is and how it fits into the ChatGPT App stack. Let’s start by fixing the place of MCP in the architecture, compare it to “typical REST,” and go through the core protocol entities: tools, resources, and prompts.

Imagine you’re building a regular web service. By old, good tradition, you spin up a REST API: you have /api/gifts, /api/users, /api/orders, each with its own input/output format, error codes, and authorization. This is familiar, but there’s a catch: you have to explain to every client what and how you implemented. Documentation, OpenAPI, examples, SDKs—all of this is needed because you designed the API format yourself.

With a ChatGPT App, the situation gets more complicated. Your client is not only the frontend but also the model itself. It needs to:

  • discover what operations are available at all;
  • understand what arguments each operation requires;
  • call these operations during the dialogue, sometimes multiple times, sometimes with different parameters;
  • interpret the structured response and decide what to show the user and what to use only as context for the next turn.

If every developer invents their own API format, the model will end up in integration hell: each App would need a custom client, tons of “glue,” and fragile logic. A protocol solves this problem.

MCP (Model Context Protocol) is an open specification for a standard way an LLM client (ChatGPT, an IDE plugin, an agent, etc.) communicates with your tools-and-data server. It defines a common language in which the server declares its tools, resources, and prompts, and the client calls them and receives results.

Intuitively, MCP is the USB‑C port for the AI world: if you make a “flash drive” (a service, database, CRM, search engine), you implement one standard connector. Then any “laptop” (ChatGPT, another agent, an IDE) can plug in without a custom cable.

2. A high-level view: where MCP lives in the ChatGPT App architecture

To lock in the picture, let’s recall the now-familiar architecture, but this time with an explicit MCP layer.

You’ve already seen the current mental model: the user talks to ChatGPT, a widget (Apps SDK) is rendered within the dialogue, and somewhere outside lives your backend. Now let’s add MCP and lay everything out by layers.

Here’s a simplified diagram:

User
   ↓ (natural language)
ChatGPT (model + UI)
   ↓ (tool calls via MCP)
MCP client inside ChatGPT
   ↓ (JSON-RPC, MCP)
Your MCP server (backend)
   ↓
Your DB / external APIs / queues

By “the MCP client inside ChatGPT” we mean the internal platform component that talks to your MCP server via the protocol: performs discovery, calls tools, and reads resources.

From the Apps SDK point of view, a minimal ChatGPT App consists of three components. First—the MCP server, which declares tools and returns structured data. Second—the UI bundle (widget), which is rendered inside ChatGPT and reads that data through window.openai. Third—the model itself, which decides when to call which tool and how to respond to the user.

It’s important to see the following. In previous modules, you worked a lot at the Apps SDK and widget level—that is, at the top of the diagram. Now we’re moving down to the MCP server level—this is your official “language” for communicating with ChatGPT and any other clients that choose to use your App.

3. MCP versus “typical REST”: what’s different

In the diagram above, we fixed where MCP sits in the ChatGPT App architecture. Now it’s time to carefully compare the “your own REST” approach and MCP so it’s clear why, in the context of ChatGPT Apps, the second option wins almost every time.

In the REST approach, you design endpoints and request/response formats however is convenient for you. For a client to work with you, it must know the URLs, methods, schemas, and error codes. Sometimes OpenAPI helps; sometimes you just paste a sample request into a README. The model itself understands none of this: it needs a layer of code that turns “find a gift for mom’s 50th birthday” into a specific HTTP request and then turns the JSON response back into data suitable for dialogue.

In MCP, it’s different. The protocol itself defines:

  • how a client can discover your tools list;
  • how to describe arguments and results via JSON Schema;
  • how to describe resources and prompts;
  • what a tool call and its response look like.

Thanks to this, ChatGPT and other MCP clients can automatically:

  • perform discovery—learn what tools/resources/prompts you have;
  • build an internal parameter schema for each tool;
  • call them without custom hardcoded client logic;
  • cache metadata and use it for app search and ranking.

We can summarize the difference in a small table.

Question Your own REST / gRPC MCP
How does a client learn what you can do? From documentation, README, OpenAPI Through standard discovery methods (list of tools/resources)
Who describes the parameters? You, arbitrarily (JSON, FormData, whatever) JSON Schema within the tool fields
How does the model call functions? Through your custom client code Directly via MCP primitives
How much client-side glue code? A lot, and different for every service One common protocol for all MCP servers
Support across multiple clients You need to write an SDK for each client MCP server is self-describing; the client can reuse logic

Put emotionally: REST is “everyone for themselves,” MCP is “an agreement across the ecosystem on how to talk to the model and the data.”

4. Core MCP entities: tools, resources, prompts

Now let’s name the three main characters of MCP: tools, resources, and prompts.

Tools: actions you’re already used to

You’ve already encountered tools in Module 4: we described a tool, gave it a name, description, and a JSON Schema for arguments, and then the model called it via callTool. At the MCP level, a tool is a server-side operation with a clear contract:

  • a name and description (for the model and for UX/discovery);
  • a JSON Schema for arguments;
  • a JSON Schema or description for the result structure;
  • additional meta information (for example, binding to a specific UI component in the Apps SDK).

An MCP server must at least be able to respond to a “list tools” request and handle a “call tool,” returning a structured result.

In our training Gift assistant app, there’s already, say, a tool suggest_gifts that takes age, gender, budget, and a couple of preferences and returns a list of recommended gifts.

A notional TypeScript sketch of such a tool in the MCP server code might look like this (pseudo-code/stub):

// Pseudo-code, not final SDK API
const suggestGiftsTool = defineTool({
  name: "suggest_gifts",
  description: "Picks gift ideas based on the recipient's parameters",
  inputSchema: z.object({
    age: z.number(),
    relation: z.enum(["friend", "partner", "parent"]),
    budgetUsd: z.number(),
  }),
  handler: async (input) => {
    // TODO: your business logic
    return { items: [] };
  },
});

We’ll go through the real signatures in subsequent lectures; the key idea here is: a tool isn’t just a REST endpoint—it’s a protocol element with a declared schema.

Resources: data addressable by ID/URI

Resources in MCP are a way to describe available data: files, directories, database records, wiki pages, even search index results. A client can:

  • get a list of resources;
  • read a specific resource by ID/URI;
  • sometimes perform a search over them.

Unlike tools, which “do something,” resources usually “store something.” For example, in a Gift App you might represent a product catalog as the resource gift_catalog, which the model queries to find available categories, filters, price ranges, and so on.

In code, this might conceptually look like:

const giftCatalogResource = defineResource({
  uri: "catalog://gifts",
  description: "Catalog of gifts available for recommendation",
  read: async () => {
    // Return the catalog structure
    return { categories: [], priceRanges: [] };
  },
});

We’re not diving into the MCP message format yet, but keep in mind: resources are addressable entities that an MCP server can reference and a client can read and use as part of context.

Prompts: predefined prompts

Prompts in the context of MCP are templates of queries or instructions that the server can provide to the client. For example, you can declare a prompt gift_followup that describes how the model should ask the user for details about the gift recipient before calling a tool.

A typical protocol-style example: the server provides a prompt name, its purpose, and sometimes parameters. The client can request the list of prompts, choose the one it needs, and inject it into the model request.

Why does a ChatGPT App need this? First, it’s a unified way to reuse complex prompts across clients. Second, MCP makes such prompts explicit and “under contract” instead of hiding them in random places in code.

Capabilities: declaring what you support

Finally, there’s a fourth element—capabilities. It’s just a declaration: the server states which entities it supports (tools, resources, prompts, notifications, etc.) and which methods it implements. For the client, it’s a way not to guess what is possible and to adapt its behavior cleanly to the server’s capabilities.

In practice, when ChatGPT connects to your MCP server, it first performs a “handshake,” obtains the list of capabilities, and only then asks: “Okay, show me your tools and resources.”

5. How MCP fits into your current App

All of this sounds a bit abstract, but in reality you’ve already encountered MCP through the Apps SDK. I think it’s worth starting by understanding how this all fits together with what you’ve already written using the Apps SDK. Let’s connect the entities we just introduced with how your App template is structured today.

Recall the chain you’ve already implemented in the template:

  1. The widget, via window.openai or ready-made hooks, calls callTool with the tool name and arguments.
  2. The Apps SDK inside ChatGPT turns this into a call to the App’s server-side.
  3. The server executes the tool and returns a ToolOutput containing structuredContent, content, and _meta.
  4. The widget receives the ToolOutput and renders the UI.

The trick is that steps 2–3 are implemented as an interaction over MCP. Your Next.js template includes an endpoint (usually app/mcp/route.ts or similar) that is the MCP server. It:

  • registers your tools;
  • describes them via JSON Schema;
  • implements handlers;
  • responds to ChatGPT’s MCP requests list tools and call tool.

So, in fact, even now—using the template—you’re already working with MCP, just “automatically”: most of the protocol magic is hidden in the SDK.

Module 6 is here so you stop treating MCP as a “magical black box” and start designing it consciously:

  • adding and versioning tools;
  • using resources and prompts, not just tools;
  • reading and understanding MCP logs;
  • spinning up separate MCP servers outside the Next.js template when needed (for example, a Python service for working with an ML model or a separate service for access to a corporate database).

6. MCP from different roles’ perspectives: product vs. developer

It’s useful to articulate separately what MCP gives to a product manager and what it gives to an engineer.

MCP for product managers

From a product perspective, MCP is a way to make your service a “plugin module” for a whole zoo of clients: ChatGPT, other LLM clients, IDE plugins, your own agents. Once you describe the server’s capabilities as a set of tools/resources/prompts, you allow any client to:

  • discover your service automatically;
  • understand what problems it solves;
  • call the necessary operations safely.

In the case of a ChatGPT App, this also increases the likelihood that your app is selected: the model uses metadata about your tools to decide when to suggest your App to a user and how to present it correctly.

In short: MCP makes your service a standard “building block” of the ecosystem, not a one-off custom integration for one or two clients.

MCP for developers

From an engineer’s perspective, MCP is a contract and a protocol. It answers the questions:

  • In what format should I declare a tool?
  • How do I describe arguments and return a result?
  • How will a client know that I support resources and prompts?
  • What JSON will actually flow over the network?

When you have such a protocol, it becomes easier to:

  • write servers in different languages (there are official SDKs for TypeScript and Python);
  • debug the application via the MCP Inspector or similar tools;
  • split responsibilities across teams: one team builds the MCP server with data and tools, another builds the widget with the Apps SDK, a third can build its own agents on top of this same MCP server.

7. A small practical perspective: our first MCP server

In this lecture, we’re intentionally not going into the details of message formats and server implementation—that’s material for the next topics. But so you know where we’re headed, it’s helpful to see the overall structure of a minimal MCP server in TypeScript.

In reality, the official MCP TypeScript library gives you primitives for creating a server, registering tools/resources/prompts, and starting a transport (usually HTTP or SSE).

A conceptual pseudo-example might look like this:

// This is a conceptual example; we'll discuss the SDK API later
import { createServer } from "@modelcontextprotocol/sdk";

const server = createServer({
  name: "gift-genius",
  version: "1.0.0",
});

// Register the tool
server.tool("suggest_gifts", {
  description: "Selects gifts based on the recipient's preferences",
  inputSchema: {/* ... */},
  handler: async (input) => {
    // your logic
    return { items: [] };
  },
});

// Start the transport (for example, HTTP)
server.listen(3001);

An important point: there’s no mention here of ChatGPT, the Apps SDK, or your specific frontend. The MCP server is self-sufficient. It simply knows how to respond to MCP requests. A ChatGPT App is just one type of client that can use such a server.

Within the course, we’ll stick to the Next.js template where the MCP server lives as part of the project, but that’s not the only possible setup.

8. MCP in the ecosystem: Apps SDK, Agents SDK, and ACP

To avoid thinking of MCP as “a feature only for the Apps SDK,” it’s helpful to see it in a broader picture.

First, the Apps SDK directly relies on MCP as the standard bridge between ChatGPT and external services. The official documentation emphasizes that the Apps SDK works with any MCP servers. The protocol itself allows you to describe tools, return structured data, and specify a component for UI rendering.

Second, the Agents SDK—which you’ll explore in a separate module—can also connect to MCP servers. This means the same MCP server with business logic can be used:

  • inside ChatGPT as part of your App;
  • inside an autonomous agent running, for example, in the background of your product or in batch mode.

Third, ACP (Agentic Commerce Protocol), which you’ll need for purchases and Instant Checkout, is logically built on top of the MCP approach: the model and agents call commerce tools that are also described through standardized contracts.

Thus, MCP becomes the foundation on which UI (Apps SDK), agentic scenarios (Agents SDK), and commerce (ACP) are built. Once you’re confident with MCP, everything else becomes clearer and more predictable.

Note: Formally, ACP does not depend on MCP as a specification, but in practical implementations, ACP tools will most likely be called by the model via MCP interfaces. One approach fits the other very neatly—so we shouldn’t have to wait long.

9. Small mental exercises before hands-on practice

Before we dive into the MCP message format in the next lecture, it’s helpful to run through a couple of thought exercises. This will help switch your mindset from “typical REST” to “protocol + contract.”

Imagine not only ChatGPT but also a VS Code IDE plugin and an internal corporate assistant in Slack want to connect to your Gift App. Describe in one sentence what all of them need to know about your service. The answer will likely be something like: “We have a suggest_gifts tool with such-and-such parameters, and a gift catalog available via such-and-such resource.” That’s exactly what MCP formalizes.

Also try to formulate in two sentences:

  • what MCP is for your App’s product manager (hint: a standard way to “package” functionality for different clients);
  • what MCP is for a developer (hint: a JSON-RPC protocol with clear tools/resources/prompts primitives).

If you can do this without hesitation—you’re already halfway to working confidently with MCP.

If we boil everything above down to one thesis: MCP is not just another wrapper API but a foundational contract between your logic and LLM clients. In the next lectures, we’ll look inside the protocol itself: we’ll parse the MCP message format, handshake/capabilities, and learn to inspect traffic with inspectors so that these principles become a practical tool, not an abstraction.

10. Common mistakes and misconceptions around MCP

Mistake #1: assuming MCP is “just another API layer on top of my REST.”
Sometimes there’s a temptation: “I already have REST, I’ll just bolt on a thin adapter that turns MCP calls into REST and back—and forget about it.” Formally you can do that, but then you often start dragging the quirks of the old API into MCP: odd types, unstructured responses, lack of explicit schemas. Over time the adapter grows, and the benefit of MCP shrinks. It’s better to treat MCP as the primary contract and the old REST as an internal implementation detail—if you still need it.

Mistake #2: thinking MCP is “only for ChatGPT Apps.”
MCP is a general open protocol for any LLM clients: ChatGPT, IDE plugins, autonomous agents. If you design an MCP server targeting only one App, you’re limiting yourself. It’s much better to think early on: “other clients will be able to use this server too,” and design tools and resources a bit more universally.

Mistake #3: ignoring JSON Schema and describing arguments “in words.”
Even if an SDK lets you pass “any JSON” somewhere, don’t be lazy—describe argument and result schemas. This directly affects the model’s ability to call your tool correctly, the quality of autocomplete and discovery, and how easy it is to debug via inspectors. Undescribed or poorly described arguments are a direct path to mysterious tool-call errors.

Mistake #4: treating MCP as “magical transport” and not looking at logs.
While everything works, it can feel like MCP is some invisible thing you don’t need to think about. The problem is that when something breaks, without understanding the MCP structure you’ll be guessing for a long time: “Is it the Apps SDK? the model? my backend?” The habit of looking at MCP messages and logs early on will save you hours of fruitless guesswork.

Mistake #5: trying to design a complex workflow only via REST, ignoring MCP primitives.
When you have multi-step scenarios (find a gift → clarify preferences → choose → place an order), it’s tempting to “just make one big REST endpoint.” In the context of ChatGPT Apps, this often hurts manageability: the model understands intermediate steps worse, and the MCP client loses the ability to reuse resources and prompts. It’s much better to split functionality into several well-described tools/resources and connect the logic with system prompts and correct descriptions.

1
Task
ChatGPT Apps, level 6, lesson 0
Locked
MCP vs REST — one operation, two integration methods
MCP vs REST — one operation, two integration methods
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION