MCP Task Board Playground
README.md
# MCP Task Board Playground
A TypeScript playground for the [Model Context Protocol (MCP)](https://modelcontextprotocol.io): a small **task-board MCP server** (stdio) plus a **terminal host** that talks to that server and to a local **Ollama** model.
Use it to learn how MCP **tools**, **resources**, and **prompts** work end-to-end — from decorator registration on the server, through a stdio client, into an LLM tool loop in the CLI.
## What you get
| Piece | Role |
| --- | --- |
| MCP server (`npm run mcp:stdio`) | Exposes task-board tools, one resource, one prompt over stdio |
| CLI host (`npm start`) | Spawns the server, connects to Ollama, chat + `/` prompts + `@` resources |
| Domain (`TasksService`) | In-memory board; knows nothing about MCP or LLMs |
```
you (terminal)
│
▼
CLI host ──HTTP──► Ollama (/api/chat + tools)
│
│ stdio (StdioClientTransport)
▼
MCP server ──► TaskTools ──► TasksService
```
## Requirements
- **Node.js** ≥ 22
- **Ollama** running locally, with a **tool-capable** model (e.g. `llama3.1`)
```bash
ollama serve
ollama pull llama3.1
```
Phi-3 and similar models that do not support tools will return HTTP 400 when the CLI sends tool definitions.
## Quick start
```bash
npm install
npm start
```
On startup the CLI:
1. Spawns `src/stdio/main.stdio.ts` as an MCP child process
2. Lists tools / resources / prompts from the server
3. Pings Ollama (`OLLAMA_HOST`, default `http://127.0.0.1:11434`)
4. Opens a raw-mode REPL (`you>`)
### Environment
| Variable | Default | Meaning |
| --- | --- | --- |
| `OLLAMA_HOST` | `http://127.0.0.1:11434` | Ollama base URL |
| `OLLAMA_MODEL` | `llama3.1` | Chat model (must support tools for free-text chat) |
```powershell
$env:OLLAMA_MODEL="llama3.1"
npm start
```
## CLI usage
### Live `/` and `@` menus
At an empty `you>` prompt:
- Press **`/`** → inline menu of MCP **prompts** (filter as you type; arrows + Enter)
- Press **`@`** → inline menu of MCP **resources**
Mid-line incomplete `@…` still works after Enter (picker / expand). Escape dismisses the current menu token.
### Chat (Ollama + tools)
Type a normal sentence and press Enter. The host sends MCP tool schemas to Ollama, executes `tool_calls` via the MCP client (up to 8 rounds), and prints the final answer.
Examples:
```
list my todos
create a task titled Fix the retry loop for islam
```
### `@` resource mentions
`@name` or `@uri` in a message is resolved: the host `readResource`s and appends the body into the text sent to Ollama.
```
rewrite this using @board-conventions
```
Unknown `@foo` → error, that turn does not call Ollama.
### Slash commands
| Input | Behavior |
| --- | --- |
| `/` (keypress) | Prompt picker |
| `/standup-review assignee=islam` | Run that MCP prompt, then complete with Ollama |
| `/prompt <name> …` | Alias for the above |
| `@` (keypress) | Resource picker, then optional message |
| `/tools` | List tools |
| `/resource <uri>` | Print resource contents |
| `/help` | Help |
| `/quit` | Exit |
## MCP server surface
Registered from [`src/mcp/tools/task.tools.ts`](src/mcp/tools/task.tools.ts) via homemade decorators (`@McpTool` / `@McpResource` / `@McpPrompt`) and [`createMcpServer()`](src/mcp/mcp-server.factory.ts).
### Tools
| Name | Purpose |
| --- | --- |
| `list-tasks` | List tasks; optional `status` filter |
| `create-task` | Create a todo (`title`, optional `assignee`) |
| `set-task-status` | Move a task by UUID |
| `task-stats` | Counts per column (structured + text) |
### Resource
| Name | URI | Content |
| --- | --- | --- |
| `board-conventions` | `board://conventions` | Markdown house rules for the board |
### Prompt
| Name | Args | Behavior |
| --- | --- | --- |
| `standup-review` | `assignee` | Builds a user message from that person’s tasks for stand-up drafting |
Seed data (in-memory, per MCP process): two sample tasks on startup.
## Project layout
```
src/
cli/ # Terminal MCP host + Ollama
main.ts # REPL entry
mcp-session.ts # Stdio MCP client (spawns server)
ollama.client.ts # /api/chat + tool mapping
chat-loop.ts # Tool-calling loop
slash.ts # Slash parse + line classification
mentions.ts # @resource expand
pickers.ts # Inquirer search helpers (fallback flows)
repl-input.ts # Raw-mode editor + live / and @ menus
mcp/ # MCP server registration
decorators/ # WeakMap @McpTool / @McpResource / @McpPrompt
tools/task.tools.ts
mcp-server.factory.ts
stdio/main.stdio.ts # serveStdio(() => createMcpServer())
tasks/tasks.service.ts
test/ # Vitest (slash, mentions, chat-loop, tools, repl-input)
```
The server wires `TasksService` → `TaskTools` by hand and discovers decorated methods with `collectDecorated()`.
## Scripts
| Script | Description |
| --- | --- |
| `npm start` | CLI host (spawns MCP over stdio) |
| `npm run mcp:stdio` | MCP server only (for Cursor / Claude Desktop / Inspector) |
| `npm test` | Vitest |
### Point another host at this server
```json
{
"command": "node",
"args": [
"--import",
"@swc-node/register/esm-register",
"src/stdio/main.stdio.ts"
]
}
```
(Working directory = this repo.) Do not write logs to stdout in the stdio process — stdout is the MCP wire.
## How registration works
1. Methods on `TaskTools` are marked with `@McpTool` / `@McpResource` / `@McpPrompt`.
2. Decorators store metadata in a `WeakMap` keyed by the class constructor.
3. `createMcpServer(tasks?)` constructs `TaskTools`, calls `collectDecorated()`, and `registerTool` / `registerResource` / `registerPrompt` on a fresh `McpServer`.
4. Stdio uses a process-level `TasksService` singleton so board state survives across connection factory calls. Tests pass `new TasksService()` for isolation.
## Ollama tool loop (host)
1. `listTools` → map to Ollama `{ type: 'function', function: { name, description, parameters } }`
2. User message → `POST /api/chat` with `tools`
3. If `tool_calls` → `callTool` on MCP → append `role: 'tool'` results → chat again (max 8 rounds)
4. Domain tool errors (`isError`) are returned as text so the model can retry
## Tests
```bash
npm test
```
Coverage includes:
- Slash / line classification
- `@` mention expand (name + URI, unknown tokens)
- Chat-loop with mocked Ollama + MCP
- In-memory MCP protocol (tools + resource) via `InMemoryTransport`
- Live-menu helpers (`shouldOpenPromptMenu` / resource)
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues