Skip to main content
Glama
README.md
# MCP Ticket Server

An MCP (Model Context Protocol) server that exposes ticket classification as a tool any MCP-compatible client can use — verified working with Claude Desktop. Packaged as a Desktop Extension (`.mcpb`) for one-click installation, with the Anthropic API key collected securely through Claude Desktop's own settings UI rather than stored in any file.

Built as a Phase 3 project in a self-directed learning path on AI-assisted software development, following Phase 1 (a full-stack ticket triager) and Phase 2 (a codebase Q&A agent). This project's focus: understanding MCP as a standard protocol, distinct from the Anthropic API tool-use pattern the underlying tool actually uses.

## What it does

Exposes one MCP tool, `classify_ticket`, which takes raw support ticket text and returns a structured classification (severity, category, sentiment, summary) — the same classification logic first built in the Phase 1 project, now reachable from any MCP client, not just a custom-built backend.

## Why this project matters conceptually

Phase 1 and 2 both used the Anthropic API's tool-use feature directly, inside code written specifically for those projects. This project is about a different, higher-level problem: **making a tool usable by _any_ AI application, not just one you wrote yourself.**

Without MCP, connecting N tools to M different AI applications requires custom integration work for every tool-app pair. MCP standardizes the interface, so a tool built once as an MCP **server** can be used by any MCP **client** — Claude Desktop, Claude Code, or a custom-built client — without bespoke integration code per pairing.

**Important distinction worth being explicit about:** this project genuinely has two separate "tool" concepts stacked on top of each other:

- The **MCP tool** (`classify_ticket`) — what Claude Desktop sees and calls, defined via `server.registerTool(...)` and the MCP SDK
- Inside that tool's implementation, a **separate, ordinary Anthropic API call** using API-level tool use (`tool_choice` forcing a specific tool) — the exact same pattern from Phase 1 — to actually perform the classification

These are two different systems that happen to share vocabulary. The MCP tool is about how an _application_ discovers and invokes a capability. The API tool-use call inside it is about how a _single model response_ gets structured, reliable output. Confusing the two was the single most disorienting part of this phase early on.

## Tech stack

- **MCP SDK:** `@modelcontextprotocol/sdk`, using `McpServer` and `StdioServerTransport`
- **Schema validation:** `zod` (the MCP SDK's convention for describing tool input, distinct from the raw JSON Schema objects used for Anthropic API tool-use)
- **LLM:** Claude, via the Anthropic TypeScript SDK, called from inside the MCP tool's implementation
- **Packaging:** `@anthropic-ai/mcpb`, Anthropic's CLI for building `.mcpb` Desktop Extension bundles

## Architecture

```
Claude Desktop (MCP client)
      │  launches as subprocess, communicates over stdio
      ▼
server.js (MCP server)
      │  registers "classify_ticket" as an MCP tool
      │  on invocation, calls:
      ▼
Anthropic API (tool-use, tool_choice forced)
      │  returns structured { severity, category, sentiment, summary }
      ▼
Result returned back through MCP to Claude Desktop, shown to the user
```

No HTTP port, no `app.listen()` — MCP servers running locally communicate over stdio, with the client (Claude Desktop) responsible for launching the server process and piping messages to it.

## Packaging as a Desktop Extension

Rather than manually editing `claude_desktop_config.json` (the older, lower-level way to register a local MCP server), this project is packaged as an `.mcpb` bundle — Anthropic's current recommended distribution format for local MCP servers in Claude Desktop. The manifest (`manifest.json`) declares:

- The server entry point and launch command
- A `user_config` field for the Anthropic API key, marked `sensitive: true`, so Claude Desktop collects it through its own UI and stores it in the OS credential vault — the key is never written into any file in this repo or the packaged bundle

## Running it locally

**Prerequisites:** Node.js, an Anthropic API key, Claude Desktop installed

```bash
npm install
npm install -g @anthropic-ai/mcpb
mcpb pack
```

This produces a `.mcpb` file. In Claude Desktop: **Settings → Extensions → Advanced settings → Install Extension…**, select the generated file, and enter your API key when prompted.

## What I'd build next

- Expose the Phase 2 codebase Q&A agent's tools (`list_files`, `read_file`, `search_code`) as additional MCP tools on this same server, so Claude Desktop could explore a real codebase directly
- Add a second, write-capable tool (mirroring Phase 2's `propose_edit`), and confirm Claude Desktop's own consent-prompt mechanism handles the human-in-the-loop approval, rather than building that logic manually again
- Investigate remote (non-stdio) MCP transports, for a server that isn't tied to a single local machine

## What I learned building this

The core lesson of this phase was almost entirely about a **moving target**: the documented way to add a custom local MCP server to Claude Desktop changed between when I started looking into it and when I finished — from a manually-edited JSON config file toward a packaged `.mcpb` extension format with its own CLI tooling. Working through that shift firsthand was a good, realistic preview of what building on fast-evolving developer tooling actually feels like: verifying current documentation rather than trusting an older guide, and treating a UI element (like a missing "Developer" tab) as a signal to check for a changed process, not a sign of doing something wrong.