Core Concepts

MCP Basics

The three building blocks every MCP server exposes, and how a request reaches your code.

The Model Context Protocol (MCP) is an open standard for connecting AI assistants to external software. An MCP client (Claude Desktop, Cursor, ChatGPT, VS Code) connects to an MCP server, asks what it can do, and then uses those capabilities during a conversation. NitroStack is how you build the server.

The three primitives

Everything a server offers falls into one of three types. The difference between them is who decides when they are used.

PrimitiveWho triggers itUse it for
ToolThe model, when it decides an action is neededRunning code with an effect: queries, API calls, calculations, writes
ResourceThe application, to give the model contextRead-only data: files, records, schemas, logs
PromptThe user, usually by picking it from a menuReusable instructions: a code review checklist, a debugging workflow

If you aren't sure which one you need, start with a tool. Most servers are mostly tools.

Tools

A tool is a method the model can call with structured input. The schema tells the model what arguments to send, and NitroStack rejects invalid input before your method runs.

import { ToolDecorator as Tool, ExecutionContext, z } from '@nitrostack/core';

export class WeatherTools {
  @Tool({
    name: 'get_weather',
    description: 'Get the current weather for a city',
    inputSchema: z.object({ city: z.string() }),
  })
  async getWeather(input: { city: string }, ctx: ExecutionContext) {
    return { city: input.city, conditions: 'sunny', temperatureC: 24 };
  }
}

Resources

A resource is data addressed by a URI. Clients read it to give the model context, and reading it never changes anything.

import { ResourceDecorator as Resource, ExecutionContext } from '@nitrostack/core';

export class DocsResources {
  @Resource({ uri: 'docs://style-guide', name: 'Style guide', mimeType: 'text/markdown' })
  async styleGuide(uri: string, ctx: ExecutionContext) {
    return { contents: [{ uri, mimeType: 'text/markdown', text: '# Write short sentences.' }] };
  }
}

Prompts

A prompt is a message template the user can invoke, optionally with arguments.

import { PromptDecorator as Prompt, ExecutionContext } from '@nitrostack/core';

export class ReviewPrompts {
  @Prompt({ name: 'review_code', description: 'Ask for a focused code review' })
  async reviewCode(args: { language: string }, ctx: ExecutionContext) {
    return [
      { role: 'user' as const, content: { type: 'text' as const, text: `Review this ${args.language} code for bugs.` } },
    ];
  }
}

How a request reaches your code

Clients and servers exchange JSON-RPC 2.0 messages. When the model calls get_weather, the client sends:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": { "name": "get_weather", "arguments": { "city": "Pune" } }
}

NitroStack finds the method registered as get_weather, validates arguments against its schema, runs it, and sends the return value back as the result. You never handle JSON-RPC directly.

Messages travel over a transport. STDIO is used when the client starts your server as a local process, and HTTP when the server runs on its own, locally or remotely. The same code works over both; Transports explains when to use each.

Why a framework on top of MCP

The official MCP SDK gives you protocol handlers. NitroStack adds the application structure you would otherwise build yourself.

You needWith the raw MCP SDKWith NitroStack
Organize a growing serverYour own conventionsModules
Share services between toolsWire them up manuallyDependency injection
Validate inputWrite checks by handZod schemas, checked automatically
Auth, logging, cachingCustom code per toolGuards, middleware, interceptors
Rich UI in the clientNot includedWidgets built with React

Next steps

On this page