Skip to main content
Glama
breakit

abl-mcp-server

by breakit
README.md
# abl-mcp-server

MCP (Model Context Protocol) server for OpenEdge ABL — pluggable tool architecture with per-project YAML configuration. Provides AI assistants with 24 tools to parse, analyze, lint, document, and scaffold ABL projects.

Built on:
- [`@breakit/abl-mcp-core`](https://github.com/breakit/abl-mcp-core) — ABL parsing, analysis, linting
- [`@breakit/abl-mcp-generators`](https://github.com/breakit/abl-mcp-generators) — Code scaffolding with REST annotations, ProDataSets, OpenEdge class hierarchy
- [`@breakit/abl-mcp-contracts`](https://github.com/breakit/abl-mcp-contracts) — Data contract generators (.i, JSON Schema, TypeScript)
- [`@breakit/abl-mcp-doc`](https://github.com/breakit/abl-mcp-doc) — ABLDoc parsing, doc comment generation, HTML documentation

## Quick Start

```sh
npx github:breakit/abl-mcp-server
```

Or add to opencode config:

```json
"abl": {
  "type": "local",
  "command": ["npx", "-y", "github:breakit/abl-mcp-server"],
  "enabled": true
}
```

## Pluggable Architecture

Each tool is a separate module in `src/tools/`. Tools are auto-discovered at startup and can be enabled/disabled via a per-project YAML config file.

### Per-Project Config (`./abl-mcp-server.yaml`)

Place this in your ABL project root:

```yaml
tools:
  enabled:
    - read-abl-file
    - query-abl-symbols
    - analyze-dependencies
    - gen-doc-comment
    - gen-abldoc
    - gen-ablunit-test
    - abl-lint
    # ... add any tools you need
  disabled:
    - check-project-config
```

All tools are enabled by default. Add names to `disabled` to turn them off, or set `enabled` to a specific subset.

### Adding Custom Tools

Drop a `.ts` file into `~/.config/abl-mcp-server/tools/`:

```typescript
import type { ToolModule } from '@breakit/abl-mcp-server/types'

export default {
  name: 'my-custom-tool',
  description: 'Does something custom',
  inputSchema: { type: 'object', properties: { input: { type: 'string' } }, required: ['input'] },
  handler: async ({ input }) => {
    return { content: [{ type: 'text', text: `Got: ${input}` }] }
  },
} satisfies ToolModule
```

Add `my-custom-tool` to your `abl-mcp-server.yaml` enabled list.

## Tools (24 total, 13 enabled by default)

All 24 tools are available but only a curated subset is enabled by default. Enable additional tools via `abl-mcp-server.yaml` (see Pluggable Architecture above).

### Default-enabled

#### Analytical

| Tool | Description |
|---|---|
| `read-abl-file` | Parse an ABL file — list class info, methods, constructors, functions, includes, using statements, preprocessor defines |
| `query-abl-symbols` | List all symbols (class, methods, constructors, functions) in a file |
| `read-df-file` | Parse a `.df` schema — tables, fields, indexes, sequences |
| `resolve-includes` | Resolve `{include}` paths against the project PROPATH |
| `list-project-files` | List all `.p`/`.w`/`.cls`/`.i` files in a project |
| `analyze-dependencies` | Build a full dependency graph — includes, calls, cycles, orphans |
| `df-diff` | Compare two `.df` schema files — structured diff |
| `find-dead-code` | Find unused functions, includes, and preprocessor defines |
| `find-annotations` | Find TODO, FIXME, HACK, XXX, NOTE and similar marker comments |
| `abl-lint` | Lint ABL files for coding conventions (37 rules defined in config.yaml) |

#### Generative

| Tool | Description |
|---|---|
| `gen-doc-comment` | Generate a formatted ABLDoc (`/** */`) comment block for classes, methods, functions, or procedures (powered by `@breakit/abl-mcp-doc`) |
| `gen-abldoc` | Generate HTML documentation from existing ABLDoc comments in a project (powered by `@breakit/abl-mcp-doc`) |
| `gen-ablunit-test` | Generate ABLUnit test class extending `TestCase` with ProDataSet CRUD tests |

### Available (disabled by default)

| Tool | Category | Description |
|---|---|---|
| `check-project-config` | Analytical | Read `abl.toml` config |
| `gen-business-entity` | Generative | Generate BE `.cls`, Service, and Controller with ProDataSets and REST annotations |
| `gen-workflow` | Generative | Generate a workflow `.cls` with Execute + step methods, ProDataSet context |
| `gen-business-task` | Generative | Generate a standalone Business Task `.cls` with ProDataSet input/output |
| `gen-ccs-layer` | Generative | Generate the full CCS stack (BE + Service + Controller) |
| `gen-openapi` | Generative | Generate OpenAPI 3.0 spec from `@openapi.openedge.export` annotations |
| `init-project` | Generative | Scaffold a new ABL project with directory structure and `abl.toml` |
| `gen-contract-tt` | Data Contract | Generate temp-table include (`.i`) from schema fields |
| `gen-contract-ds` | Data Contract | Generate ProDataSet include (`.i`) wrapping the temp-table |
| `gen-contract-json-schema` | Data Contract | Generate JSON Schema from table/field definition |
| `gen-contract-typescript` | Data Contract | Generate TypeScript interface from table/field definition |

## Lint Rules

All 37 rules are defined in `config.yaml` (shipped with the server). They are inspired by [Prolint](https://github.com/jcaillon/prolint). To see all active rules: call `abl-lint` with `listRules: true`.

Customize rules via your project's `abl-mcp-server.yaml`:

```yaml
lint:
  rules:
    # Override severity of an existing rule
    no-undo:
      pattern: '^DEFINE (?:VARIABLE|VAR) +\w+ (?:AS \w+ )?(?!.*NO-UNDO)'
      message: 'DEFINE VARIABLE should include NO-UNDO'
      severity: warning

    # Add a custom rule
    my-naming-convention:
      pattern: '^\s*PROCEDURE\s+[a-z\d]'
      message: 'Procedure names should start with uppercase'
      severity: warning

    # Disable a rule by not including it in enabled (see tools.disabled pattern)
```

| Group | Rules |
|---|---|
| **No-undo / Lock** | `no-undo`, `no-undo-param` |
| **Deprecations** | `pause`, `global-define`, `recid`, `shared` |
| **Shell / Security** | `shell-call`, `hardcoded-email` |
| **Find / Performance** | `no-lock-type`, `find-no-error`, `for-each-no-where`, `exclusive-no-wait`, `no-index` |
| **Style / Convention** | `end-type`, `block-label`, `lex-colon`, `method-name-case`, `class-name-case`, `function-name-case`, `nolonglines` |
| **Strings / i18n** | `backslash-in-string`, `colon-t`, `string-concat` |
| **Potential bugs** | `dot-comment`, `return-error`, `weak-char`, `release-statement`, `public-var` (`.cls` only) |
| **Cross-platform** | `run-backslash`, `include-case`, `include-backslash` |
| **Misc** | `table-name`, `when-misuse` |
| **Naming** | `naming-tt`, `naming-ds`, `naming-var`, `naming-param` |

## Test Generator Skill

The `gen-ablunit-test` tool generates skeleton ABLUnit test files. For fully filled test files with realistic assertions and data, an opencode skill is available:

- **Skill**: [`llm-fill-ablunit-test`](https://gist.github.com/breakit/10871753d7bc168919c59cde19c572eb)
- **Workflow**: parse source class → generate skeleton → LLM-fills test data + assertions → write completed file
- **Requires**: opencode with the `llm-fill-ablunit-test` skill enabled

To install, add to your `.opencode/skills/` directory and reference it in your opencode config.

## Architecture

```
abl-mcp-server
├── config.yaml                # Default tool enable/disable + 37 lint rules
├── src/
│   ├── index.ts               # Bootstrap: auto-discovers tools, registers MCP handlers
│   ├── config-loader.ts       # Load + parse per-project YAML config (+ project overlay)
│   ├── types.ts               # ToolModule interface + config types
│   └── tools/                 # 24 pluggable tool modules (auto-discovered)
│       ├── read-abl-file.ts
│       ├── analyze-dependencies.ts
│       ├── abl-lint.ts
│       ├── find-annotations.ts
│       ├── gen-business-entity.ts
│       ├── gen-workflow.ts
│       ├── gen-business-task.ts
│       ├── gen-doc-comment.ts
│       ├── gen-abldoc.ts
│       ├── gen-contract-*.ts
│       └── ...
├── @breakit/abl-mcp-core      # Pure analysis layer — parsers, analysis, linting
├── @breakit/abl-mcp-generators # Scaffolding templates — BE, Service, Controller, Workflow
├── @breakit/abl-mcp-contracts  # Data contract generators — .i, JSON Schema, TypeScript
└── @breakit/abl-mcp-doc        # Documentation utilities — ABLDoc parser + comment generator
```

## Installation

The server is distributed as a GitHub package (not published to npm). Install directly from the repo:

```sh
# npm
npm install github:breakit/abl-mcp-server

# pnpm
pnpm add github:breakit/abl-mcp-server

# yarn
yarn add github:breakit/abl-mcp-server
```

### One-shot usage (no install)

```sh
npx github:breakit/abl-mcp-server
```

### As an MCP server dependency

Add to your project's `package.json`:

```json
"dependencies": {
  "@breakit/abl-mcp-server": "github:breakit/abl-mcp-server"
}
```

Then import in your MCP host:

```typescript
import { createServer } from '@breakit/abl-mcp-server'
```

## Development

```sh
git clone https://github.com/breakit/abl-mcp-server.git
cd abl-mcp-server
yarn install
yarn build
yarn start
```

### Local Multi-Repo Development

If you are working on the sibling repos in `../abl-mcp-core`, `../abl-mcp-contracts`, `../abl-mcp-doc`, and `../abl-mcp-generators`, bootstrap them with Yarn and symlink them into this repo:

```sh
yarn setup:local
```

That command:

- runs `yarn install` in each sibling repo
- builds each sibling repo so their `dist/` entrypoints exist
- symlinks them into this repo's `node_modules/@breakit/`
- includes `@breakit/abl-mcp-doc` in the local sibling package graph
- links `../abl-mcp-core` into `../abl-mcp-generators/node_modules/@breakit/` for local runtime resolution

When you change sibling repo code, rerun:

```sh
yarn build:local-deps
yarn link:local-deps
```

## Acknowledgments

- Lint rules inspired by [Prolint](https://github.com/jcaillon/prolint) by Jurjen Dijkstra and contributors
- ABL parsing via [tree-sitter-abl](https://github.com/usagi-coffee/tree-sitter-abl)
- Language server concepts from [abl-language-server](https://github.com/usagi-coffee/abl-language-server)
- Naming conventions derived from Progress ABL community standards

## License

MIT