Skip to main content
Glama
README.md
# fyi-docs-mcp-ts

Remote **MCP server** for **FYI Docs** (document management system), built with **Bun** + TypeScript and deployed on **Railway**.

Exposes read-only FYI tools to MCP clients (Claude, Cursor, etc.) over **Streamable HTTP** for Somerset Accountancy Services.

## Stack

| Component | Choice |
|-----------|--------|
| Runtime | Bun |
| Language | TypeScript (strict) |
| MCP SDK | `@modelcontextprotocol/sdk` |
| Transport | Streamable HTTP (Web Standard, Bun-native) |
| Validation | Zod |
| Hosting | Railway (GitHub-connected) |

## Tools

| Tool | Description |
|------|-------------|
| `search_documents` | Search/list documents |
| `search_clients` | Search/list clients (`/entity`) |
| `list_jobs` | List jobs |
| `list_tasks` | List tasks |
| `list_cabinets` | List filing cabinets |
| `fyi_raw_list` | Low-level list against any FYI resource |
| `check_fyi_connection` | Verify credentials / connectivity |

All tools are **read-only** in v1. Responses are summarised; secrets are redacted.

## Endpoints

| Path | Purpose |
|------|---------|
| `GET /health` | Railway health check (200) |
| `ALL /mcp` | MCP Streamable HTTP endpoint |
| `GET /` | Service metadata |

## Environment variables

**Required**

```
FYI_ACCESS_ID=
FYI_ACCESS_SECRET=
FYI_REGION=uk
MCP_API_KEY=          # shared secret for /mcp (min 16 chars)
```

**Optional**

```
FYI_APPLICATION_ID=
FYI_API_USER=
FYI_BASE_URL=
PORT=3000
NODE_ENV=production
```

| `FYI_REGION` | Base URL |
|--------------|----------|
| `uk` | `https://api-eu-west-2.fyi.app/external` |
| `au` / `anz` | `https://api-ap-southeast-2.fyi.app/external` |

Override with `FYI_BASE_URL` if needed. Copy `.env.example` to `.env` for local development.

## Local setup

```bash
bun install
cp .env.example .env   # fill in FYI credentials
bun run dev            # watch mode
# or
bun start
```

- Health: `http://localhost:3000/health`
- MCP: `http://localhost:3000/mcp`

## Railway

This repo is connected to Railway. Deploys follow GitHub pushes.

Config is in `railway.toml`:

- Install: `bun install --frozen-lockfile`
- Start: `bun run src/index.ts`
- Health check: `/health`

Set secrets in Railway (do not commit them):

```bash
railway variables set FYI_ACCESS_ID=... FYI_ACCESS_SECRET=... FYI_REGION=uk MCP_API_KEY=...
```

Optional Dockerfile (`oven/bun:1`) is included if you prefer image-based builds.

### Authentication (API key only)

No OAuth. `/mcp` requires the shared `MCP_API_KEY` via header:

- `Authorization: Bearer <MCP_API_KEY>`
- or `x-api-key: <MCP_API_KEY>`

`/health` stays public for Railway health checks.

```json
{
  "mcpServers": {
    "fyi-docs": {
      "url": "https://fyi-mcp-production.up.railway.app/mcp",
      "headers": {
        "Authorization": "Bearer <MCP_API_KEY>"
      }
    }
  }
}
```

**Grok Build / CLI:**

```toml
[mcp_servers.fyi-docs]
url = "https://fyi-mcp-production.up.railway.app/mcp"
headers = { "Authorization" = "Bearer <MCP_API_KEY>" }
```

> **Note:** Hosts that only support OAuth custom connectors (e.g. Grok.com web)
> cannot connect to this server. Use clients that accept a static Authorization header.

## Scripts

| Script | Command |
|--------|---------|
| `bun start` | Run server |
| `bun run dev` | Run with `--watch` |
| `bun run typecheck` | `tsc --noEmit` |
| `bun run build` | Bundle to `dist/` |

## Project layout

```
src/
  index.ts           # Bun HTTP entry (/health, /mcp)
  server.ts          # MCP server + tool registration
  fyi/
    client.ts        # FYI External API client
    config.ts        # Env validation (Zod)
    types.ts
  tools/
    documents.ts
    clients.ts
    jobs.ts
    tasks.ts
    cabinets.ts
    connection.ts
  utils/
    response.ts      # Summaries + safe errors
```

## Security

- No secrets in source or logs
- Fail-fast on missing `FYI_ACCESS_ID` / `FYI_ACCESS_SECRET` / `MCP_API_KEY`
- `/mcp` protected by shared API key only (no OAuth)
- Read-only tools for v1
- Sensitive keys redacted from tool output

## Out of scope (v1)

OAuth, write/upsert operations, binary document download, custom domain, persistent storage.

## License

Private / unlicensed unless stated otherwise.