# Inkgility MCP Server

> Model Context Protocol (MCP) server specification for Inkgility. This
> document describes the **planned production server**. The prototype
> exposes the same data as static JSON at `/api/content/*.json`; the MCP
> layer is the canonical runtime interface for AI agents.

- **Spec version:** 2026-05-26
- **Protocol:** Model Context Protocol 1.0 (JSON-RPC 2.0 over stdio + HTTP+SSE)
- **Server URL (production):** `https://mcp.inkgility.com`
- **Manifest:** `https://inkgility.com/mcp-manifest.json`
- **OpenAPI (fallback REST):** `https://inkgility.com/api/openapi.yaml`
- **Contact:** `developers@inkgility.com`

## Overview

The Inkgility MCP server exposes Inkgility's product catalog, services,
pricing, templates, glossary, audit tools, and (with auth) order data as
**tools** and **resources** an MCP-aware client (Claude, GPT, Cursor, custom
agents, etc.) can invoke.

## Capabilities

```json
{
  "tools":     { "listChanged": true },
  "resources": { "listChanged": true, "subscribe": true },
  "prompts":   { "listChanged": false }
}
```

## Tools

### `inkgility.products.list`
List the print product catalog.

| Field | Type | Notes |
|---|---|---|
| `category` | string? | Filter — `business-cards`, `flyers`, `brochures`, `posters`, `banners-signs`, `stickers-labels`, `postcards` |
| `limit` | integer? | Default 50, max 200 |

Returns: `{ products: Product[], total: number }`.

### `inkgility.products.search`
Free-text search across the catalog.

| Field | Type |
|---|---|
| `query` | string (required) |
| `category` | string? |
| `limit` | integer? |

### `inkgility.templates.search`
Search the 180-template free design library.

| Field | Type |
|---|---|
| `query` | string |
| `category` | string? — same enum as products |
| `industry` | string? |

### `inkgility.services.list`
Returns all 8 core services with tier/pricing structure.

No arguments.
Returns: `{ services: Service[] }` where each service has `slug`, `name`,
`tiers[]`, `priceFrom`, `category`.

### `inkgility.pricing.get`
Quote a specific configuration.

| Field | Type |
|---|---|
| `service` | string (required) — service slug |
| `tier` | string? |
| `quantity` | integer? |
| `options` | object? — service-specific options |

Returns: `{ currency, subtotal, lineItems[], tier }`.

### `inkgility.glossary.lookup`
Define a marketing / design / print term.

| Field | Type |
|---|---|
| `term` | string (required) — either the term slug or the human term |

Returns: `{ slug, term, category, shortDefinition, longDefinition, related[] }`.

### `inkgility.orders.status`  *(auth required)*
Look up an order's status.

| Field | Type |
|---|---|
| `orderId` | string (required) |

Returns: `{ orderId, status, lineItems[], lastUpdate, eta }`.

### `inkgility.audit.run`
Trigger a free Inkgility audit.

| Field | Type |
|---|---|
| `kind` | enum — `search` \| `ads` \| `social` \| `email` \| `website` |
| `target` | string — URL, ad account ID, or handle |
| `email` | string |

Returns: `{ auditId, status, reportUrl }`.

## Resources

Resources are read-only URIs the client can subscribe to.

| URI pattern | Description |
|---|---|
| `inkgility://content/{slug}` | Full structured snapshot of a page (mirrors `/api/content/{slug}.json`) |
| `inkgility://markdown/{slug}` | Markdown rendering (mirrors `/llms/{slug}.md`) |
| `inkgility://services` | Aggregate service catalog |
| `inkgility://templates` | Aggregate template index |
| `inkgility://pricing` | Pricing matrix |
| `inkgility://team` | Team members |
| `inkgility://glossary` | Full glossary |
| `inkgility://blog` | Blog post index |
| `inkgility://feeds/blog` | Atom feed (live) |
| `inkgility://feeds/case-studies` | Atom feed (live) |
| `inkgility://feeds/updates` | Sitewide update feed |

## Prompts

The server ships ready-to-use prompt templates:

- `inkgility.brand-brief` — generate a brand brief from a service config.
- `inkgility.audit-summary` — summarize a finished audit for a customer.
- `inkgility.template-recommendation` — recommend templates given an industry + use case.

## Authentication

```
Authorization: Bearer <token>
```

Tokens are issued from the customer dashboard (`/dashboard-api-keys.html`,
planned). Public tools (`products.list`, `services.list`, `pricing.get`,
`glossary.lookup`, `templates.search`, `products.search`, `audit.run`) work
**unauthenticated**. `orders.status` requires a valid bearer token bound
to the requesting customer.

## Rate limiting

| Plan | Requests / min | Burst |
|---|---|---|
| Anonymous | 30 | 60 |
| Authenticated | 120 | 240 |
| Partner / enterprise | 600 | 1200 |

Standard `429` response with `Retry-After` header.

## Discovery

A client SHOULD discover the server in this order:

1. Fetch `https://inkgility.com/mcp-manifest.json` (machine-readable).
2. Read `capabilities`, `endpoints.mcp`, and `endpoints.openapi`.
3. Connect to the MCP endpoint (`endpoints.mcp`).

## Example client integration (TypeScript / `@modelcontextprotocol/sdk`)

```ts
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

const transport = new StreamableHTTPClientTransport(
  new URL('https://mcp.inkgility.com'),
  { requestInit: { headers: { Authorization: `Bearer ${process.env.INK_TOKEN}` } } }
);
const client = new Client({ name: 'my-agent', version: '0.1.0' }, { capabilities: {} });
await client.connect(transport);

const tools = await client.listTools();
const services = await client.callTool({
  name: 'inkgility.services.list',
  arguments: {}
});
```

## Example client integration (Python / `mcp`)

```python
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
import os, asyncio

async def main():
    async with streamablehttp_client(
        "https://mcp.inkgility.com",
        headers={"Authorization": f"Bearer {os.environ['INK_TOKEN']}"}
    ) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            res = await session.call_tool(
                "inkgility.glossary.lookup",
                {"term": "aeo"}
            )
            print(res.content)

asyncio.run(main())
```

## Prototype shim

Until the production server is online, AI agents can use the static REST
fallback:

| MCP tool | REST equivalent |
|---|---|
| `inkgility.products.list` | `GET /api/content/templates.json` (templates) — products catalog forthcoming |
| `inkgility.services.list` | `GET /api/content/services.json` |
| `inkgility.pricing.get` | `GET /api/content/pricing.json` |
| `inkgility.templates.search` | `GET /api/content/templates.json` |
| `inkgility.glossary.lookup` | `GET /api/content/glossary.json` |

The REST shape mirrors the MCP tool's `result` payload one-to-one.

## Changelog

- **2026-05-26** — Initial Wave 15 spec.
