portal-labs-infrastructure/number-guessing-game-mcp-server
If you are the rightful owner of number-guessing-game-mcp-server 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.
The Number Guessing Game MCP Server is a demonstration server implemented in TypeScript, showcasing a dynamic, session-based architecture for a simple number guessing game.
Number Guessing Game MCP Server
A demonstration Model Context Protocol (MCP) server implemented in TypeScript. It showcases a dynamic, session-based architecture where each user gets their own set of tools and resources, managed by a central controller. This server hosts a simple number guessing game.
Access it at: https://mcp.number-guessing-game.portal.one/mcp
Find more remote servers at: https://remote-mcp-servers.com/
Read our article talking about the benefits of dynamic MCP servers:
https://portal.one/blog/dynamic-mcp-servers-tame-complexity/
Here's an example of interacting with the server manually. Notice the tools change depending on the current game state.
https://github.com/user-attachments/assets/8bb15870-2adc-4412-a072-4fc4eb14bbef
And a video of an agent interacting with the server. You can't see in the video, but the tools available to the agent are changing as well based on the game state.
https://github.com/user-attachments/assets/d7d338a2-8a93-46c3-b4a9-1a6b4caf9dc0
This project is intended as a learning resource and a practical example for building dynamic, multi-user MCP applications.
Table of Contents
- Key Features
- Architectural Overview
- Prerequisites
- Getting Started
- Running the Server
- Interacting with the Server
- Project Structure
- Key Concepts Demonstrated
- Contributing
- License
Key Features
- True Multi-User Sessions: Each connecting user gets their own isolated game state and set of MCP entities.
- Dynamic MCP Tools: Tools (
start_game
,guess_number
,give_up
) are enabled or disabled on a per-user basis, reflecting their individual game state. - Dynamic MCP Resources: The
game_state
resource is created and destroyed per-user as they start and end games. - Clean, Scalable Architecture:
- A single global
McpServer
handles all connections. - An Express.js controller manages the lifecycle of each user session.
- Session-scoped entities (tools, resources, game logic) are created on-demand.
- State Pattern: Manages the game's flow (Lobby, Playing) for each user.
- A single global
- TypeScript Implementation: Fully typed for better maintainability and developer experience.
- Firestore Integration: Persists game state and high scores, making the server stateless and scalable.
Architectural Overview
The server follows a modern, scalable pattern where a central controller manages ephemeral, session-specific resources.
-
Global Server Config (
src/mcp_setup/index.ts
): A McpServer instance is created when the application starts. It acts as a "blank slate" connection manager and does not contain any tools or resources itself. -
HTTP Controller (
src/controllers/mcp.controller.ts
): This is the brain of the application.- It handles all incoming HTTP requests to the
/mcp
endpoint. - When a new user connects, it creates a
StreamableHTTPServerTransport
. - It uses the transport's lifecycle hooks (
onsessioninitialized
andonclose
) to manage the user's session.
- It handles all incoming HTTP requests to the
-
Session Initialization (
onsessioninitialized
): When a user's transport is ready, the controller:- Creates a new, unique set of MCP entities for that user by calling the setup functions in
src/mcp_setup/tools
andsrc/mcp_setup/resources
. - Creates a new
GameContext
instance, linking it to the user's session ID and their unique MCP entities. - Loads the user's state from Firestore (via
GameSessionService
) and uses the State Pattern (LobbyState
orPlayingState
) to enable/disable the correct tools for their session.
- Creates a new, unique set of MCP entities for that user by calling the setup functions in
-
Session Destruction (
onclose
): When a user disconnects, the controller:- Unregisters and destroys all tools and resources that were created for that specific user, preventing memory leaks.
- Cleans up the transport from its list of active connections.
This architecture ensures that each user's UI state (e.g., which tools are enabled) is completely isolated, stateful, and managed dynamically, while the server itself remains scalable.
Prerequisites
- Node.js (v18.x or later recommended)
- npm or yarn
- Access to a Google Cloud project with Firestore enabled.
Getting Started
Installation
- Clone the repository:
git clone https://github.com/portal-labs-infrastructure/number-guessing-game-mcp-server cd number-guessing-game-mcp-server
- Install dependencies:
npm install # or yarn install
Configuration
- Set up Google Cloud Authentication: Ensure your environment is authenticated to your Google Cloud project. For local development, you can use the gcloud CLI:
gcloud auth application-default login
- Create a
.env
file: Copy the example file.cp .env.example .env
- Edit
.env
: Fill in the required environment variables.PORT
: The port for the server to run on (e.g.,8083
).GCP_PROJECT_ID
: Your Google Cloud Project ID.BASE_URL
: The public-facing URL of your server (e.g.,http://localhost:8083
).OAUTH_ISSUER_URL
: The base URL of your OAuth provider.DOCS_URL
: A link to your service's documentation.
Running the Server
Dev Mode (for development with hot-reloading):
npm run dev
Production Mode:
Compile TypeScript:
npm run build
Start the server:
npm start
You should see output indicating the server is running and connected to Firestore.
Interacting with the Server
Live Server
You'll need an MCP client that supports the following capabilities:
- OAuth2 (with dynamic client registration)
- Tool notifications
- Resource notifications
You can use the MCP Inspector, but it does not have Tool and Resource notifications so you have to manually refresh the tools and resources.
You use the the Portal One web client and find the server in the list of available MCP servers and click 'connect'.
See other clients that support dynamic MCP tools and resources (discovery) in the MCP SDK Example Clients.
Local
Make sure the server can be accessed by the client. If you're running the server locally, and using a web based client, you can use a tool like ngrok to expose the server to the internet:
ngrok http http://localhost:8083
If you're using a client on localhost, you can connect directly to http://localhost:8083/mcp
.
Project Structure
src/
āāā config/
ā āāā index.ts # Loads and exports environment variables
āāā controllers/
ā āāā mcp.controller.ts # Manages session lifecycles and creates entities on-demand
āāā game/
ā āāā commands/ # Command Pattern: Encapsulates user actions
ā ā āāā command.interface.ts
ā ā āāā give-up.command.ts
ā ā āāā guess-number.command.ts
ā ā āāā start-game.command.ts
ā āāā core/
ā ā āāā game-context.ts # Central game logic coordinator for a SINGLE session
ā ā āāā game-session-service.ts # Handles all Firestore interactions (get/set state)
ā ā āāā game-types.ts # Core TypeScript interfaces for the game
ā ā āāā resource-factory.ts # (Not used in current setup, but available)
ā ā āāā tool-factory.ts # (Not used in current setup, but available)
ā āāā states/ # State Pattern: Manages game flow (Lobby, Playing)
ā ā āāā game-state.interface.ts
ā ā āāā lobby.state.ts
ā ā āāā playing.state.ts
ā āāā utils/
ā āāā game-constants.ts # Shared game constants
āāā index.ts # Main application entry point (Express server setup)
āāā mcp_setup/
ā āāā index.ts # Creates the single, global McpServer instance
ā āāā resources/ # Factory functions for creating MCP resources
ā ā āāā index.ts # Barrel file for exporting all resource setups
ā ā āāā ... (setup-banner-image-resource.ts, etc.)
ā āāā tools/ # Factory functions for creating MCP tools
ā āāā index.ts # Barrel file for exporting all tool setups
ā āāā ... (setup-guess-number-tool.ts, etc.)
āāā routes/
ā āāā mcp.routes.ts # Defines the Express routes for /mcp
āāā services/
āāā firestore.service.ts # Initializes the global Firestore client
Key Concepts Demonstrated
- Dynamic, Session-Scoped MCP: The core of this architecture. Tools and resources are not global; they are created and destroyed for each user session.
- Lifecycle Management: Using transport hooks (
onsessioninitialized
,onclose
) to manage the setup and teardown of session resources. - Stateful Services over HTTP: Implementing persistent, isolated user sessions over a stateless protocol.
- State Pattern: Managing complex state transitions for each user's game flow.
- Firestore for State Persistence: Decoupling the server's runtime from the game state, allowing for horizontal scaling and resilience.
- TypeScript Best Practices: Using types for robust code in a real-world, scalable application structure.
Contributing
Contributions are welcome! If you have ideas for improvements, new features, or find any bugs, please feel free to open an issue or a pull request.
License
This project is licensed under the MIT License - see the file for details.