Skip to main content

Chapter 19: Model Context Protocol (MCP)


Learning Objectives

By the end of this chapter, you will be able to:

  • Explain what the Model Context Protocol (MCP) is and why it matters for AI-native engineering
  • Distinguish between MCP resources, prompts, and tools
  • Build a minimal MCP server in TypeScript
  • Verify that server locally with MCP Inspector
  • Configure an AI client to launch the server and call its tool
  • See how MCP supports spec-driven workflows by making external context queryable

What is the Model Context Protocol?

The Model Context Protocol (MCP) is an open protocol for connecting AI clients to external context and executable capabilities. Instead of stuffing every requirement, contract, and reference doc directly into a prompt, MCP lets a client ask a server for exactly the resource or tool it needs.

At a high level:

  • MCP client: the AI runtime or editor that can call MCP servers
  • MCP server: a local or remote process that exposes resources, prompts, and tools

In an SDD workflow, that means your agent can fetch only the contract, issue, schema, or checklist it needs instead of working from stale pasted snapshots.


Why MCP is Useful in SDD

In Spec-Driven Development, the specification is the source of truth, but that truth is often spread across multiple systems:

  • feature specs in specs/
  • work items in Jira or Linear
  • API contracts in OpenAPI or AsyncAPI files
  • architecture decisions in ADRs
  • internal docs in a wiki or portal

MCP helps in three practical ways:

1. Live context instead of copied context

Instead of copying a Jira ticket into chat, the agent can query a tool like get_issue("PROJ-123").

2. Smaller, more relevant context windows

Instead of pasting an entire API reference, the agent can ask for just the endpoint or schema it needs.

3. Better automation boundaries

Instead of writing one-off shell scripts for every lookup, you expose stable, named tools and resources that multiple agents can share.


MCP Building Blocks

An MCP server typically exposes three categories of capability:

  1. Resources: read-oriented context such as docs, schemas, contracts, and files
  2. Prompts: reusable prompt templates the client can invoke
  3. Tools: executable functions such as "fetch issue," "query schema," or "trigger validation"

For SDD, tools and resources are usually the most important:

  • Resources hold durable context
  • Tools fetch or transform context on demand

Tutorial: Build and Verify a Minimal MCP Server

This tutorial creates a tiny local MCP server that exposes one tool, get_contract, which returns contract metadata for a named service.

Prerequisites

  • Node.js 20 or newer
  • npm
  • A terminal
  • An MCP-capable client or MCP Inspector for verification

Step 1: Create the Project

mkdir mcp-contract-server
cd mcp-contract-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install -D typescript tsx @types/node
npx tsc --init

This gives you a minimal TypeScript project plus the MCP SDK.

Step 2: Create the Server File

Create src/index.ts:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const contracts = {
billing: { version: "1.2.0", path: "contracts/billing.yaml" },
auth: { version: "2.0.1", path: "contracts/auth.yaml" },
};

const server = new McpServer({
name: "contract-server",
version: "1.0.0",
});

server.tool(
"get_contract",
"Fetch contract metadata for a service name",
{ service: z.string() },
async ({ service }) => {
const result = contracts[service as keyof typeof contracts];

if (!result) {
return {
content: [
{ type: "text", text: `Unknown service: ${service}` },
],
};
}

return {
content: [
{ type: "text", text: JSON.stringify(result, null, 2) },
],
};
}
);

const transport = new StdioServerTransport();
await server.connect(transport);

This example is intentionally small. The point is to verify the protocol flow before you connect real systems.

Step 3: Run the Server Locally

npx tsx src/index.ts

If the process starts and waits silently, that is expected. A stdio MCP server usually stays quiet until a client connects.

Step 4: Verify with MCP Inspector

Use Inspector to confirm the server launches and exposes the expected tool:

npx @modelcontextprotocol/inspector node --loader tsx/esm src/index.ts

In Inspector:

  1. Connect to the server
  2. Confirm get_contract appears in the tool list
  3. Invoke it with billing

Expected result: You receive JSON text containing the billing contract metadata.

Step 5: Configure an MCP Client

Point your MCP-capable client at the server. A minimal config looks like:

{
"mcpServers": {
"contract-server": {
"command": "node",
"args": ["--loader", "tsx/esm", "/ABSOLUTE/PATH/src/index.ts"]
}
}
}

Use an absolute path. Relative paths are a common source of launch failures.

Step 6: Use the Tool from the Client

Once the client is configured, prompt it with something like:

"Use the get_contract MCP tool to fetch the auth service contract metadata and summarize what file I should read next."

Expected result: The client calls get_contract("auth") and returns the path and version information.


Applying MCP to an SDD Workflow

Once the minimal server works, the next step is replacing the hard-coded contracts object with a real backing system. Typical patterns:

  • get_issue(issueId) -> pull requirements from Jira or Linear
  • get_contract(service) -> return the latest contract location or contents
  • search_docs(query) -> return relevant internal docs
  • list_feature_specs() -> expose available specs/[branch-name]/ folders

That changes the agent workflow from:

  1. Human copies context into chat
  2. Agent works from a static snapshot

to:

  1. Agent discovers the latest source of truth
  2. Agent fetches only the needed context
  3. Agent works from live, queryable inputs

Common Mistakes

Logging to stdout

Stdout is used for protocol traffic. Extra logs there can break the session. Log to stderr instead.

Treating examples as production-ready

The tutorial server is deliberately minimal. Add auth, validation, and real data access before using MCP for sensitive systems.

Returning unstable shapes

If a tool response changes shape frequently, agents become unreliable. Keep tool outputs consistent and documented.

Skipping local verification

Always test with Inspector before debugging client configuration. That isolates protocol problems from client-specific problems.


Troubleshooting

"Server does not appear in Inspector"

  • Confirm npx tsx src/index.ts starts without syntax errors
  • Confirm the file path in the Inspector command is correct
  • Confirm Node.js version is recent enough for your setup

"Tool is missing"

  • Check the server.tool(...) registration name
  • Restart the server after edits
  • Make sure the client is connecting to the file you just changed

"Client cannot launch the server"

  • Use an absolute path in the client config
  • Verify the command and args work directly in the terminal
  • Check whether your client expects a different config location

"The server launches but returns bad data"

  • Start with a hard-coded response like the tutorial example
  • Only add external integrations after the minimal flow is working
  • Validate the returned shape before wiring the next system

Try With AI

Prompt 1: Design a Real MCP Tool

"I have API contracts in specs/[branch-name]/contracts/. Design an MCP tool called get_contract that returns the contract file path and the latest version metadata. Show the response shape and the validation rules."

Prompt 2: Map MCP to SDD

"For a spec-driven workflow that uses Jira, OpenAPI contracts, and ADRs, list the 5 highest-value MCP tools or resources to implement first. Explain what each one replaces in a manual workflow."


Practice Exercises

Exercise 1: Replace the Hard-Coded Data

Change the tutorial server so get_contract reads from a local JSON file instead of a hard-coded object.

Expected outcome: The server still works, but contract metadata now comes from a file you can edit without changing code.

Exercise 2: Add a Second Tool

Add list_contracts so the client can discover available services before calling get_contract.

Expected outcome: The server exposes at least two tools, and Inspector shows both.

Exercise 3: Sketch an MCP Adoption Plan

Choose one real project and list the first external systems you would expose through MCP. For each one, specify whether it should be a resource, a prompt, or a tool.

Expected outcome: A short MCP adoption plan tied to a real SDD workflow.


Key Takeaways

  1. MCP turns external context into queryable context. Agents do not need every document pasted into chat.
  2. Tools and resources are the practical core for SDD. They let agents fetch the exact spec, contract, or issue they need.
  3. Start with a minimal server. Verify the protocol and tool shape locally before integrating real systems.
  4. Inspector-first debugging saves time. Validate the server independently before debugging client config.

Chapter Quiz

  1. What problem does MCP solve in an AI-native workflow?
  2. What is the difference between an MCP client and an MCP server?
  3. Name the three major capability categories an MCP server can expose.
  4. Why should you verify a server with Inspector before debugging the client?
  5. Give one SDD use case where an MCP tool is better than copying context into chat.

Back to: Part VI Overview | Next: Chapter 20 - /speckit.specify - Feature Specification