Skip to main content
Glama
eneopt

Filly Forms MCP Server

by eneopt
README.md
# Filly Forms MCP Server

NPX-runnable MCP server that exposes the Filly Forms REST API as MCP tools for AI agents.

## Quick Start

### Install from GitHub

```bash
# Install directly from GitHub (recommended)
npx -y git+https://github.com/eneopt/filly-forms-mcp.git

# Or with SSH
npx -y git+ssh://git@github.com/eneopt/filly-forms-mcp.git
```

### Development Setup

```bash
# Clone the source repository
git clone [source-repo-url]

# Install dependencies
npm install

# Build
npm run build

# Run locally
npm start
```

## Usage with Claude Code

Add to your `.mcp.json`:

```json
{
  "mcpServers": {
    "filly-forms": {
      "command": "npx",
      "args": ["-y", "git+https://github.com/eneopt/filly-forms-mcp.git"],
      "env": {
        "FILLY_API_URL": "http://localhost:8000/api/v1"
      }
    }
  }
}
```

Or use local development version (for contributing):

```json
{
  "mcpServers": {
    "filly-forms": {
      "command": "node",
      "args": ["/home/b4zs/workspace/w/jsonforms/packages/mcp-server/dist/index.js"],
      "env": {
        "FILLY_API_URL": "http://localhost:8000/api/v1",
        "FILLY_API_USERNAME": "your-username",
        "FILLY_API_PASSWORD": "your-password"
      }
    }
  }
}
```

## Environment Variables

- `FILLY_API_URL` - Base URL of the Filly Forms REST API (default: `http://localhost:8000/api/v1`)
- `FILLY_API_USERNAME` - HTTP Basic Auth username (optional, only if API requires authentication)
- `FILLY_API_PASSWORD` - HTTP Basic Auth password (optional, only if API requires authentication)

## Available Tools

### `list_form_types`
List all form types in the system with their schemas and metadata.

**Parameters:**
- `name` (optional): Filter by form type name (partial match)

**Returns:**
```json
{
  "types": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Invoice",
      "version": 3,
      "status": "published"
    }
  ]
}
```

### `create_record`
Create a new record of a given form type with validation.

**Parameters:**
- `typeId` (required): UUID of the form type
- `data` (required): Record data (validated against type's JSON schema)
- `name` (optional): Record name

**Returns:**
```json
{
  "id": "uuid",
  "version": 1
}
```

### `get_record`
Get a record by ID, optionally at a specific version.

**Parameters:**
- `id` (required): Record UUID
- `version` (optional): Version number (omit for latest)

**Returns:**
```json
{
  "id": "uuid",
  "name": "Record Name",
  "typeId": "uuid",
  "data": { ... },
  "version": 2,
  "createdAt": "2026-07-21T06:00:00+00:00"
}
```

### `update_record`
Update an existing record with optimistic locking.

**Parameters:**
- `id` (required): Record UUID
- `data` (required): New record data
- `expectedVersion` (required): Expected current version for optimistic locking
- `name` (optional): New name

**Returns:**
```json
{
  "id": "uuid",
  "version": 3
}
```

### `preview_data`
Preview ad-hoc data through a template to see rendered HTML output.

**Parameters:**
- `typeId` (required): Form type UUID for schema validation
- `data` (required): Data to preview
- `templateId` (optional): Template UUID (uses default if omitted)
- `name` (optional): Name for the preview

**Returns:**
```json
{
  "html": "<html>...</html>"
}
```

### `upload_document`
Upload a document for AI extraction (long-running operation with polling).

**Parameters:**
- `name` (required): Document filename
- `fileContent` (required): Base64-encoded document content
- `targetTypeId` (optional): Extract into existing type (data-only mode)
- `pollInterval` (optional): Seconds between polls (default: 2)
- `maxWait` (optional): Maximum seconds to wait (default: 300)

**Returns:**
```json
{
  "uploadId": "uuid",
  "status": "completed",
  "logs": [...],
  "typeId": "uuid",
  "recordId": "uuid",
  "targetTypeId": null
}
```

## Architecture

This MCP server is a **stateless HTTP proxy**:

1. **MCP Protocol** (stdio) ← Claude Code communicates here
2. **HTTP REST API** ← This server forwards requests here
3. **Symfony Backend** ← Handles business logic

**Why this approach?**

- ✅ **Separation of concerns**: MCP server is just a protocol adapter
- ✅ **Standard MCP**: Uses stdio (recommended for CLI clients)
- ✅ **No duplication**: All business logic stays in the Symfony app
- ✅ **Easy debugging**: Test REST API with curl, MCP with Claude
- ✅ **NPX-runnable**: Zero installation for users

## Development

```bash
# Watch mode
npm run dev

# Type checking
npm run typecheck

# Build
npm run build
```

## License

MIT