Spec Driven Development
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Beschreibung vom Entwickler (englisches Original)
Serves Oracle Forms module content (.fmb/.mmb/.pll/.olb) from a directory to MCP clients.
Diese drei werden nie zu einer Punktzahl zusammengefasst: Meinungen, Messungen und Beliebtheit sind verschiedene Dinge.
Für diesen Server haben wir noch keine Zusammenfassung in einfacher Sprache geschrieben. Unten stehen die Fakten, die wir aus der Registry gelesen haben.
Wähle die KI-App, die du nutzt, und kopiere die Einstellungen.
OFMCP_CONVERTED_DIR, OFMCP_CONVERT_COMMAND, OFMCP_COMPILE_COMMANDDu brauchst
Welche App nutzt du?
Wähle oben deine App. Wir merken sie uns, damit der Button beim nächsten Mal „In … installieren“ anzeigt.
Die .mcpb-Datei des Entwicklers herunterladen
Der Link führt zur Datei des Entwicklers selbst; wir hosten sie nicht und verpacken sie nicht neu. Öffne die Datei, dann installiert Claude Desktop sie.
Führe das in deinem Terminal aus
claude mcp add oracle-forms --env OFMCP_CONVERTED_DIR=your-value --env OFMCP_CONVERT_COMMAND=your-value --env OFMCP_COMPILE_COMMAND=your-value -- docker run -i --rm -e OFMCP_CONVERTED_DIR -e OFMCP_CONVERT_COMMAND -e OFMCP_COMPILE_COMMAND ghcr.io/aoreshkov/oracle-forms-mcp:0.18.0 --forms-dir /formsTrag die leeren Werte ein, bevor du ihn startest.
In .cursor/mcp.json in deinem Projekt oder in ~/.cursor/mcp.json einfügen
{
"mcpServers": {
"oracle-forms": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"OFMCP_CONVERTED_DIR",
"-e",
"OFMCP_CONVERT_COMMAND",
"-e",
"OFMCP_COMPILE_COMMAND",
"ghcr.io/aoreshkov/oracle-forms-mcp:0.18.0",
"--forms-dir",
"/forms"
],
"env": {
"OFMCP_CONVERTED_DIR": "your-value",
"OFMCP_CONVERT_COMMAND": "your-value",
"OFMCP_COMPILE_COMMAND": "your-value"
}
}
}
}Dein Browser fragt, ob er die App öffnen darf, dann zeigt die App die Einstellungen und bittet dich um Bestätigung. Schlüsselwerte bleiben leer, damit du sie selbst einträgst.
In .vscode/mcp.json in deinem Projekt einfügen
{
"servers": {
"oracle-forms": {
"type": "stdio",
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"-e",
"OFMCP_CONVERTED_DIR",
"-e",
"OFMCP_CONVERT_COMMAND",
"-e",
"OFMCP_COMPILE_COMMAND",
"ghcr.io/aoreshkov/oracle-forms-mcp:0.18.0",
"--forms-dir",
"/forms"
],
"env": {
"OFMCP_CONVERTED_DIR": "your-value",
"OFMCP_CONVERT_COMMAND": "your-value",
"OFMCP_COMPILE_COMMAND": "your-value"
}
}
}
}Dein Browser fragt, ob er die App öffnen darf, dann zeigt die App die Einstellungen und bittet dich um Bestätigung. Schlüsselwerte bleiben leer, damit du sie selbst einträgst.
Dieser Server läuft auf deinem Computer, und ChatGPT kann sich nur mit Servern im Internet verbinden. Wähle eine andere App.
Deine Auswahl bleibt in einem Cookie auf diesem Gerät; kein Konto nötig.
OFMCP_CONVERTED_DIR envOFMCP_CONVERT_COMMAND envOFMCP_COMPILE_COMMAND envDiese Einstellungen werden aus dem Registry-Eintrag des Entwicklers erzeugt. Wenn in der README etwas anderes steht, folge der README.
Läuft auf deinem Computer; die Tool-Liste erscheint nach der Installation in deiner KI-App.
Wir prüfen Informationen, die jeder sehen kann; den Code haben wir nicht gelesen. Checks, die nicht zutreffen, werden nicht mitgezählt. · Geprüft am 6. Nov. 2026
Der Registry-Name wurde mit dem GitHub-Konto aoreshkov bestätigt, dem das Repo gehört
Dieses Repo haben wir noch nicht von GitHub gelesen
Dieses Repo haben wir noch nicht von GitHub gelesen
Dieser Server läuft auf deinem Computer; es gibt keinen Endpunkt im Internet
Läuft auf deinem Computer und nutzt stattdessen lokale Einstellungen
Läuft auf deinem Computer; Tool-Listen können wir nur von Endpunkten im Internet lesen
Verglichen mit allen aktiven Servern dieser Kategorie in der Registry. Sterne zählen nur, wenn dem Herausgeber das Repo gehört.
Er hat 1 von 1 zutreffenden Basischecks bestanden. Den Code haben wir nicht gelesen. Bevor du einen Schlüssel oder Token hinzufügst, sieh nach, welche Zugriffe der Server verlangt, und nutze einen Schlüssel, der nur die Berechtigungen hat, die du brauchst.
Die Registry nennt keinen erforderlichen Schlüssel, manche Server bitten dich aber bei der ersten Nutzung, dich anzumelden.
Er läuft auf deinem Computer. Deine KI-App startet ihn bei Bedarf, und die Daten laufen nicht über die Server des Entwicklers (außer der Server ruft selbst einen Onlinedienst auf).
Das GitHub-Repo wurde zuletzt – geändert, und die neueste Version (0.18.0) kam vorgestern in die Registry.
Apps, die MCP unterstützen, etwa Claude Desktop, Claude Code, Cursor und VS Code. Außerdem brauchst du Docker, MCPB auf deinem Computer.
In derselben Kategorie: Spec Driven Development, Remote Desktop Commander, Reelsaw
Server derselben Kategorie von anderen Entwicklern, sortiert nach Sternen.
So liest du eine Karte:★ GitHub-SterneiDrei Säulen: Bewertungen · Checks · NutzungiAktualisiert = neueste Version in der Registry veröffentlichti
MCP Server that facilitates spec-driven development workflows, not just Vibe Coding.
Remote Desktop Commander: use files, terminal and processes on your own computers from any AI app.
Drive a self-hosted Reelsaw: turn long videos into vertical clips, edit, re-render and export them.
Unverändert aus dem Repo des Entwicklers übernommen. PopNx MCP hat den Inhalt weder geprüft noch empfiehlt es ihn. HTML, Bilder und Skripte wurden entfernt. Links führen von dieser Website weg.
An MCP server that serves the content of Oracle Forms modules (.fmb forms, .mmb menus, .pll PL/SQL libraries, .olb object libraries) found in a directory, so AI assistants can inspect blocks, items, triggers, program units, and raw object XML without opening Forms Builder.
Built as a Kotlin Multiplatform core (pure @Serializable models and ports) with a JVM MCP server on top: declarative tool adapters over a single FormsService, stdio and HTTP transports, and a fingerprint-based on-disk cache. Oracle tool conversion feeds a streaming StAX parser that turns Forms XML into a structured index.
Oracle Forms applications from the 1990s–2000s are still running critical business processes, but their logic is locked inside binary .fmb/.pll modules that only Forms Builder can open. That makes them opaque to modern AI tooling and painful to review, document, or migrate.
Oracle Forms MCP turns those modules into structured, queryable content so an AI assistant can:
It is aimed at developers and teams doing Oracle Forms modernization, reverse engineering, code review, and documentation — anyone who needs to read Forms logic faster than opening it by hand.
A typical session against the bundled sample-forms directory:
You: What does ORDERS.fmb do?
AI → list_modules → ORDERS.fmb (NOT_CACHED), MAINMENU.mmb, UTILS.pll … AI → fetch_module ORDERS.fmb → converted + indexed (3 blocks, 3 triggers, 3 program units) AI → get_module_overview ORDERS → blocks, triggers, LOVs, record groups, windows, canvases … You: Show me the validation logic on the ORDERS block. AI → list_triggers block=ORDERS → WHEN-VALIDATE-ITEM (on ORDER_ID), WHEN-VALIDATE-RECORD AI → get_trigger ORDERS WHEN-VALIDATE-ITEM → the decoded PL/SQL body You: Where else is the CALC_TOTAL procedure called? AI → search_source "calc_total" scope=plsql → hits across triggers and program units You: That validation is the legacy pre-2010 path — note it so we remember. AI → annotate_element ORDERS trigger WHEN-VALIDATE-ITEM kind=note "Legacy pre-2010 validation path" → saved (next session) get_trigger ORDERS WHEN-VALIDATE-ITEM → body + the stored note inline
list_modules scans the configured --forms-dir (non-recursive) and reports each module's cache status: NOT_CACHED, CACHED, STALE (source changed on disk), or SOURCE_MISSING. A production forms directory holds thousands of modules, so the answer is filtered and paged: narrow with pattern/type/status, follow nextCursor for the rest, and read countsByStatus for the shape of the whole match.fetch_module produces the module's text form in the cache and indexes it:%ORACLE_HOME%\bin (then $FORMS_INSTANCE/bin, where Linux Forms 12c+ keeps frmf2xml.sh): frmf2xml for .fmb/.mmb/.olb (XML), frmcmp_batch (Module_Type=LIBRARY Script=YES) for .pll (a .pld text dump).orders_fmb.xml, dupes_fmb.xml, picker_fmb.xml, toolbar_fmb.xml, mainmenu_mmb.xml, objects_olb.xml, utils.pld) and copied into the cache..sql sidecar files; every named XML element gets a line-range reference so get_object_xml can slice it back out of the converted file.STALE and read tools ask for a re-fetch.annotate_element and relate_elements let the assistant write durable meta-information back about individual elements (notes, tags, summaries, classifications, cross-references). This is kept in a separate store — not the derived index — so it survives re-fetching, and the read tools surface it inline. An annotation made before a source change is flagged, never dropped.| Tool | What it returns |
|---|---|
list_modules | Modules in the forms dir with type, size, and cache status; filter by pattern/regex, type, status and page via limit/cursor |
fetch_module | Converts + indexes one module (idempotent; force=true converts a current one again; progress notifications) |
get_module_overview | Names of every section + counts — the first call after a fetch (verbosity=detailed adds window and canvas objects) |
list_blocks | Blocks with base table, item count, trigger count |
get_block | One block: items with type, property class, prompt and trigger names, and its master-detail relations (verbosity=detailed adds data type, column, canvas, size, visible/required/LOV and the DML properties resolved through each item's property class; columns=true adds the base table's columns and the ones no item supplies); flags subclassed blocks/items |
list_triggers | Triggers with level/scope; filter by block, item, or level (verbosity=detailed adds a PL/SQL preview) |
get_trigger | One trigger's decoded PL/SQL body (same-named triggers told apart by ownerPath or level); resolve follows a subclassing pointer into a cached parent module |
list_program_units | Procedures, functions, package specs/bodies with line counts |
get_program_unit | One program unit's PL/SQL (disambiguate spec/body via unitType); resolve as for get_trigger |
search_source | Line search over one fetched module: extracted PL/SQL (plsql), the raw XML (xml), or both; paginated via offset/nextOffset |
search_modules | The same search across every cached module — cross-form calls, shared :GLOBALs, subclassing pointers; reports the modules it could not reach; paged via an opaque cursor |
read_source | A line range of a cached file, by uri (which names its module) or module + file — the converted XML or an extracted PL/SQL sidecar |
get_object_xml | The raw XML fragment of any named object — the escape hatch |
Every tool checks its arguments against its own input schema before running. An argument it does not have is never silently dropped: the call fails with every problem listed at once (unknown arguments with the name most likely meant, missing ones with their permitted values, values outside an enum), plus an example call where the tool has one.
Two Forms properties carry more meaning than anything else in a module, and both used to be reachable only one get_object_xml call at a time.
An item's property class is usually its role: Forms shops name their classes for what the object does, so a push button is an *LOV* button and a text item is a *filter* field only because of the class it inherits. get_block reports propertyClass on every item and block, confirmed against the classes the module actually declares.
A window's modality decides how a form is read — a modal window is a dialog, so the code that fills it and the code that consumes the result sit on opposite sides of one interaction. get_module_overview(verbosity: "detailed") returns the window and canvas objects behind two of its name lists: modality, size, toolbar canvases, and the window each canvas sits on.
A property Forms did not write comes back as null, meaning the object keeps the Forms default — never false. On an item that has a property class it does not even mean the default: the class supplies the value, and in a real form that is where most of an item's behaviour lives. So get_block(verbosity: "detailed") returns both — items[].dml, what the item itself wrote, and effectiveDml, the same properties with the class applied (item, then class, then whatever that class is based on, followed into other modules that are already fetched). An item is listed in effectiveDml only when that chain resolved to the end, so a null there really is the Forms default. Every other item is a row of unresolvedItems, with the reason and — when fetching fixes it — the module to fetch; propertyClasses and the result's hint give the same account per class and name the fetch_module call. items: [...] narrows all of it to the items a question is about.
get_block(columns: true) adds the block's data-source columns, the columns no item supplies, and which of those are mandatory in the database — the ones an insert fails on unless a trigger assigns them.
A block's master-detail relations decide what it can be queried through, so get_block serves them at every verbosity: block.relations, the relations it is the master of (join condition, deferred, autoQuery, deleteRecord, preventMasterlessOperations), and detailOf, the relations that name it as their detail, with the master each is written on. A detail with preventMasterlessOperations cannot be queried except through its master — which the form enforces, not the database, so a port has to enforce it itself.
Everything indexed is a line range into a file the cache owns, and those ranges used to name a path with no way to resolve it. Every result that points at a file now carries a source:
"source": {
"uri": "oracleforms://ORDERS.fmb/plsql/triggers/ORDERS.ORDER_ID.WHEN-VALIDATE-ITEM.sql", "file": "plsql/triggers/ORDERS.ORDER_ID.WHEN-VALIDATE-ITEM.sql", "startLine": 1, "endLine": 3 }
read_source takes either form back, so a search hit can be read in context and a truncated fragment continued. The same files are readable as MCP resources — oracleforms://{module}/converted for the converted text form and oracleforms://{module}/plsql/{category}/{name} for one extracted block of PL/SQL — and every such result also carries a resource_link content block, so a client can follow it without parsing JSON. Reads are capped by lines *and* characters; a cut resource read says so in the text it returns and names the call that continues it.
Paths stay cache-relative and URIs stay layout-independent: an absolute host path would mean nothing to a client talking to the container image or over HTTP.
Forms lets a block, item, trigger or program unit be subclassed from a
Nur der Anfang wird gezeigt; den Rest findest du im Repo