typespec-mcp-openapi-dual-output-demo

anfibiacreativa/typespec-mcp-openapi-dual-output-demo

3.2

If you are the rightful owner of typespec-mcp-openapi-dual-output-demo and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

This project demonstrates building both a Model Context Protocol (MCP) server and a REST API from a single TypeSpec definition, providing a unified shopping cart service with user and order management capabilities.

Tools
4
Resources
0
Prompts
0

TypeSpec MCP Sample: Shopping Cart Service

TypeSpec.io typeSpec-mcp Node version TypeScript

Dual Output | Requirements | Installation | Build

This project demonstrates building both a Model Context Protocol (MCP) server and a REST API from a single TypeSpec definition. It provides a unified shopping cart service with user and order management capabilities.

✨ Key Feature: Dual Output

Using TypeSpec with HTTP decorators, this project generates:

  • 🤖 MCP Server - For AI agent tool calling
  • 🌐 OpenAPI 3.0 Spec - For REST API documentation and client generation

One definition → Two outputs! See for details.

📦 Requirements

  • Node.js >= 20
  • npm >= 9
  • TypeScript

🏗️ Installation

mkdir api-dual-demo
cd api-dual-demo
git clone https://github.com/anfibiacreativa/typespec-mcp-openapi-dual-output-demo

Install all dependencies:

npm install --legacy-peer-deps

⚠️ Notes on installation issues:

  • Use --legacy-peer-deps to avoid strict npm 7+ peer dependency conflicts
  • On Apple Silicon, some older packages (@alloy-js/core) may require --legacy-peer-deps

Architecture

APISummit/
 ├─ main.tsp                    # Unified TypeSpec definitions (with HTTP decorators)
 ├─ tspconfig.yml               # TypeSpec configuration (dual emitters)
 ├─ src/
 │   ├─ http-server.ts          # Express HTTP bridge
 │   └─ mcp-server.ts           # MCP server implementation
 └─ tsp-output/
     ├─ typespec-mcp-server-js/ # Generated MCP TypeScript server
     │   ├─ index.ts            # MCP server
     │   ├─ tools.ts            # Tool interfaces
     │   └─ schemas/            # Zod and JSON schemas
     └─ openapi/                # Generated OpenAPI spec
         └─ openapi.yaml        # OpenAPI 3.0 specification

🔨 Build

The build process compiles TypeSpec and TypeScript:

npm run build

This runs:

  1. npm run build:tsp - Compiles TypeSpec to generate:
    • MCP server code in tsp-output/typespec-mcp-server-js/
    • OpenAPI spec in tsp-output/openapi/openapi.yaml
  2. npm run build:ts - Compiles TypeScript to JavaScript

Generated Outputs:

  • ✅ MCP Server (TypeScript)
  • ✅ OpenAPI 3.0 Specification (YAML)
  • ✅ Type definitions and validation schemas

🚀 Run HTTP Bridge

The http-server.ts sets up Express to expose MCP operations as HTTP endpoints.

npm start

Server listens on http://localhost:3000

Available Routes:

GET  /users/:id     -> userOperations.getUser
POST /users         -> userOperations.createUser
GET  /orders/:id    -> orderOperations.getOrder
POST /orders        -> orderOperations.createOrder

⚡ Test the API

User Operations

Create a user:

curl -X POST http://localhost:3000/users \
  -H "Content-Type: application/json" \
  -d '{"id":"u-1001","name":"Ada Lovelace","email":"ada@example.com"}'

Get a user:

curl http://localhost:3000/users/u-1001

Expected response:

{
  "id": "u-1001",
  "name": "Alice Example",
  "email": "alice@example.com"
}

Order Operations

Create an order:

curl -X POST http://localhost:3000/orders \
  -H "Content-Type: application/json" \
  -d '{"id":"o-5001","userId":"u-1001","total":149.99}'

Get an order:

curl http://localhost:3000/orders/o-5001

Expected response:

{
  "id": "o-5001",
  "userId": "u-1001",
  "total": 42.99
}

📋 MCP Tools

The TypeSpec definitions generate the following MCP tools:

  • user_operations_get_user - Retrieves a user by ID
  • user_operations_create_user - Creates a new user
  • order_operations_get_order - Retrieves an order by ID
  • order_operations_create_order - Creates a new order

� OpenAPI Specification

The project also generates a complete OpenAPI 3.0 specification at tsp-output/openapi/openapi.yaml.

What You Can Do With It:

  1. View Documentation

    # Serve with Swagger UI (install globally if needed)
    npx swagger-ui-express tsp-output/openapi/openapi.yaml
    
  2. Generate Client SDKs

    # TypeScript client
    npx @openapitools/openapi-generator-cli generate \
      -i tsp-output/openapi/openapi.yaml \
      -g typescript-fetch \
      -o ./generated-client
    
    # Python client
    npx @openapitools/openapi-generator-cli generate \
      -i tsp-output/openapi/openapi.yaml \
      -g python \
      -o ./generated-client-python
    
  3. Import into API Tools

    • Postman: File → Import → tsp-output/openapi/openapi.yaml
    • Insomnia: Create → Import → Select file
    • Bruno: Import Collection → OpenAPI
  4. Mock the API

    # Use Prism to create a mock server
    npx @stoplight/prism-cli mock tsp-output/openapi/openapi.yaml
    

See for more details on using the OpenAPI spec.

�🎯 Expected Behavior

  • MCP server returns JSON objects for User and Order
  • The HTTP bridge provides a REST API wrapper around MCP operations
  • All operations go through the TypeSpec-generated MCP layer
  • Input and output validation is handled via Zod schemas
  • OpenAPI spec provides complete REST API documentation

📝 Data Models

User

{
  id: string;      // Unique user identifier
  name: string;    // User's full name
  email: string;   // User's email address
}

Order

{
  id: string;      // Unique order identifier
  userId: string;  // Reference to user ID
  total: number;   // Order total amount (float32)
}

🛠 Troubleshooting

Build fails with type errors:

  • The build script automatically adds @ts-nocheck to generated files
  • If issues persist, try: npm run build:tsp && npm run build:ts

Port 3000 already in use:

  • Change the PORT constant in src/http-server.ts
  • Or kill the process using port 3000: lsof -ti:3000 | xargs kill

Installation issues on Apple Silicon:

  • Use npm install --legacy-peer-deps
  • Ensure you're using Node.js >= 20