Skip to main content
Glama
toosoontospoon

io.github.toosoontospoon/crate-quote

README.md
# mcp-services

MCP ([Model Context Protocol](https://modelcontextprotocol.io)) tools for several business services,
one module per service. Each module is a thin client of that business's own HTTP API: no business
logic lives here. The first service is **crate**, Speed Crate quotes for custom wooden shipping crates.

<!-- mcp-name: io.github.toosoontospoon/crate-quote -->

- One server per service, so each can be listed on its own (MCP Registry, Muse Connector
  Platform), or all services in one server.
- Transports: **stdio** (local clients such as Claude Desktop or Cursor) and **streamable HTTP**
  (hosted endpoints).
- Official Python MCP SDK 2.x (`MCPServer`, which replaced FastMCP), `httpx` for the backend APIs.
- MIT licensed.

## Quick start

    pip install toosoon-mcp-services        # not on PyPI yet: pip install -e ".[test]" from a checkout
    export SPEEDCRATE_API_URL=http://127.0.0.1:8080      # the crate API (CustomCrateBuilder speedcrate-api)

    toosoon-mcp-services --list                         # services and their tools
    mcp-crate-quote                                     # crate service only, stdio
    toosoon-mcp-services --service crate                # same
    toosoon-mcp-services                                # every enabled service in one server
    toosoon-mcp-services --service crate --transport streamable-http --host 127.0.0.1 --port 8765
                                                        # -> http://127.0.0.1:8765/mcp  (--stateless for load balancers)

Client config (stdio), e.g. Claude Desktop:

```json
{ "mcpServers": { "crate-quote": {
    "command": "uvx", "args": ["toosoon-mcp-services", "--service", "crate"],
    "env": { "SPEEDCRATE_API_URL": "https://YOUR-CRATE-API" } } } }
```

## Configuration

| Variable | Meaning |
|---|---|
| `MCP_SERVICES` | Comma list of services to run when `--service` isn't given (default: all enabled) |
| `<PREFIX>_API_URL` | Base URL of the service's API (required to call its tools) |
| `<PREFIX>_API_KEY` | Optional API key, sent as `Authorization: Bearer …`. Never logged |
| `<PREFIX>_TIMEOUT` | Request timeout in seconds (default 20) |
| `<PREFIX>_ENABLED` | `0` leaves the service out of "all services" |

Prefixes: crate = `SPEEDCRATE`.

## Services

### crate: Speed Crate quotes (`SPEEDCRATE_*`)

Calls the CustomCrateBuilder HTTP API (`speedcrate-api`). Sizes are inside inches. Quotes need the
customer's email. They return **only a price range** (plus code, sizes, layout and notices) and say the
full quote will be emailed to that address. The API queues the full-quote request; this server sends
no email.

| Tool | API call | Access | Sensitive data | Side effects |
|---|---|---|---|---|
| `quote_crate` | `POST /v1/quote` | **write** | customer email (PII) | queues a full-quote request; the shop emails the customer |
| `quote_crate_by_code` | `POST /v1/quote/by-code` | **write** | customer email (PII) | same |
| `parse_crate_code` | `POST /v1/codes/parse` | read-only | none | none |
| `encode_crate_code` | `POST /v1/codes/encode` | read-only | none | none |
| `crate_size_limits` | `GET /v1/limits` | read-only | none | none |
| `crate_preview_svg` | `GET /v1/designs/{code}/preview.svg` | read-only | none | none |

The tools carry matching MCP annotations: `readOnlyHint` is true for the read tools. The quote tools
are `readOnlyHint: false`, `destructiveHint: false`, `idempotentHint: false`, `openWorldHint: true`.

## MCP Registry entries (one per service)

Each service gets its own registry entry and `server.json` under `servers/<registry-name>/`. All
entries point at the **same PyPI package** (`toosoon-mcp-services`) with a `--service <name>` package
argument, plus that service's environment variables. The registry checks PyPI ownership by looking for
an `mcp-name` line with the registry name in the package README (this file). Every service's name
gets its own line at the top of this file.

| Service | Registry name | server.json |
|---|---|---|
| crate | `io.github.toosoontospoon/crate-quote` | `servers/crate-quote/server.json` |

Publishing (not done yet):
1. Release the package to PyPI.
2. `mcp-publisher login github` as toosoontospoon.
3. `mcp-publisher publish servers/crate-quote/server.json`.

`mcp-publisher validate servers/crate-quote/server.json` passes today.

<!-- TODO(remotes): when the crate MCP server is hosted (streamable HTTP, needed for Muse Connector
Platform), add to servers/crate-quote/server.json:
  "remotes": [{ "type": "streamable-http", "url": "https://<HOST>/mcp" }]
No hosted URL exists yet. -->
**Hosted endpoint (TODO):** no public streamable-HTTP URL exists yet. When there is one, add a
`remotes` entry (`{"type": "streamable-http", "url": "https://<host>/mcp"}`) to the service's
server.json. A public deployment also needs TLS in front of it, an allowed Host/Origin list (the SDK's
DNS-rebinding protection), and probably `--stateless`.

## Development

    uv venv && uv pip install -e ".[test]"
    pytest                                   # unit tests with a mocked API (respx)
    CRATE_API_REPO=/path/to/CustomCrateBuilder CRATE_API_PYTHON=/path/to/its/python pytest
                                             # + integration tests against a local uvicorn of the API
    SPEEDCRATE_TEST_API_URL=http://127.0.0.1:8080 pytest     # or against a running API

See [CONTRIBUTING.md](CONTRIBUTING.md) to add a service.

TDQS

B3.4/5.0

Scored across 6 tools

Disambiguation4/5

quote_crate and quote_crate_by_code have overlapping purpose but are clearly distinguished by input type (dimensions vs configuration code), and the description explicitly cross-references them. parse_crate_code and encode_crate_code are inverse operations with distinct roles, and crate_size_limits and crate_preview_svg are unambiguous. Only the two quote tools risk mild confusion.

Naming Consistency4/5

Most tools use a verb_noun pattern (quote_crate, parse_crate_code, encode_crate_code) with a shared 'crate' token, giving good predictability. crate_size_limits and crate_preview_svg deviate to noun-first phrasing, a minor inconsistency but still readable and clearly scoped.

Tool Count5/5

Six tools is well-scoped for a crate-quoting domain: two quoting paths, code parse/encode, size limits, and a preview generator. Each tool earns its place with no redundant or filler entries.

Completeness4/5

The surface covers the core lifecycle: quote from dimensions or code, encode/decode codes, check size limits, and render a preview. There is no tool to retrieve or manage previously submitted quote requests, but quoting plus code handling covers the main workflows an agent would need.

Maintenance

ActivityMaintained
ResponsivenessNo issues