@dineug/erd-editor-mcp 0.1.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +166 -77
- package/dist/erd-editor-mcp.js +74 -53
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -1,27 +1,36 @@
|
|
|
1
1
|
# @dineug/erd-editor-mcp
|
|
2
2
|
|
|
3
|
-
> An MCP server that lets a coding agent edit [
|
|
3
|
+
> An MCP server that lets a coding agent edit [ERD Editor](https://github.com/dineug/erd-editor)
|
|
4
4
|
> diagrams, live in VS Code, Obsidian or a JetBrains IDE, or straight on disk
|
|
5
5
|
|
|
6
|
-
Claude Code, Codex and any other client of the
|
|
7
|
-
get one tool per editing operation on an
|
|
8
|
-
|
|
9
|
-
the
|
|
10
|
-
|
|
11
|
-
[ERD Editor plugin](https://
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
Claude Code, Codex and any other client of the
|
|
7
|
+
[Model Context Protocol](https://modelcontextprotocol.io) get one tool per editing operation on an
|
|
8
|
+
ERD document (an `.erd.json` file, or an `.erd` file in an Obsidian vault): add a table, rename a
|
|
9
|
+
column, relate two tables, import a DDL dump, read the schema back as SQL. When VS Code with the
|
|
10
|
+
[ERD Editor extension](https://marketplace.visualstudio.com/items?itemName=dineug.vuerd-vscode),
|
|
11
|
+
Obsidian with the [ERD Editor plugin](https://community.obsidian.md/plugins/erd-editor) or an
|
|
12
|
+
IntelliJ-based IDE with the
|
|
13
|
+
[ERD Editor plugin](https://plugins.jetbrains.com/plugin/23594-erd-editor) has the document open,
|
|
14
|
+
or has open the folder, vault or project that holds it, the agent joins the editor as a
|
|
15
|
+
collaborator: every edit shows up on the canvas as it happens, with the agent's focus on the cell
|
|
16
|
+
it is editing. With no editor around, the same tools edit the file itself.
|
|
15
17
|
|
|
16
18
|

|
|
17
19
|
|
|
18
|
-
The package is one self-contained file with no runtime dependencies.
|
|
19
|
-
later.
|
|
20
|
+
The package is one self-contained file with no runtime dependencies.
|
|
20
21
|
|
|
21
22
|
## Install
|
|
22
23
|
|
|
24
|
+
The server needs Node.js 22.12 or later. `npx` downloads it the first time the agent starts it, so
|
|
25
|
+
there is nothing else to install.
|
|
26
|
+
|
|
27
|
+
Keep ERD Editor and the MCP server up to date together. When one speaks an older hub protocol than
|
|
28
|
+
the other, the server refuses to connect and says which one to update.
|
|
29
|
+
|
|
23
30
|
### Claude Code
|
|
24
31
|
|
|
32
|
+
Run in your project folder:
|
|
33
|
+
|
|
25
34
|
```sh
|
|
26
35
|
claude mcp add --transport stdio erd-editor -- npx -y @dineug/erd-editor-mcp
|
|
27
36
|
```
|
|
@@ -38,71 +47,103 @@ args = ["-y", "@dineug/erd-editor-mcp"]
|
|
|
38
47
|
|
|
39
48
|
### Any other MCP client
|
|
40
49
|
|
|
41
|
-
Run `npx -y @dineug/erd-editor-mcp` as a stdio server.
|
|
42
|
-
against its working directory
|
|
43
|
-
|
|
44
|
-
On Windows it refuses a document name with a colon, such as `orders:v2.erd`, a device name such
|
|
45
|
-
as `NUL.erd` or `CON.erd`, or a name ending in a dot or a space, and leaves such files out when it
|
|
46
|
-
lists documents from disk: Windows would store another file than the one named. Use `-` in place
|
|
47
|
-
of `:`.
|
|
50
|
+
Run `npx -y @dineug/erd-editor-mcp` as a stdio server. Start it in your project folder: it resolves
|
|
51
|
+
relative document paths against its working directory.
|
|
48
52
|
|
|
49
53
|
## Live and headless
|
|
50
54
|
|
|
51
|
-
For every
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
+
For every call the server looks, through the lock files in `~/.erd-editor/ide/`, for an editor that
|
|
56
|
+
holds the document: a VS Code window with the ERD Editor extension, an Obsidian vault window with
|
|
57
|
+
the ERD Editor plugin, or an IntelliJ-based IDE with the ERD Editor plugin, which keeps one lock for
|
|
58
|
+
all its open projects.
|
|
55
59
|
|
|
56
60
|
| What it finds | What an edit does |
|
|
57
61
|
| --- | --- |
|
|
58
|
-
| A window whose workspace or vault contains the document, an IDE with a project that contains it, or an editor that has it open | **Live.** Opens the document in
|
|
59
|
-
| No editor | **Headless.** Loads the file, applies the change and replaces the file atomically. `erd_save` has nothing to do. A read-only file, such as a Perforce or TFVC file not checked out, is refused with `readonly` until you make it writable. On Windows, a file with permissions of its own, unlike its folder's, is written in place so that it keeps them
|
|
60
|
-
| An editor
|
|
62
|
+
| A window whose workspace or vault contains the document, an IDE with a project that contains it, or an editor that has it open | **Live.** Opens the document in ERD Editor if needed, as `erd_open_document` does too, without taking the keyboard focus, joins the editing session and applies the change there. Edits appear at once. VS Code keeps them unsaved until the agent calls `erd_save`, you save, or VS Code's Auto Save does; Obsidian saves them about two seconds later and a JetBrains IDE a fraction of a second after editing stops, as each saves your own edits, and `erd_save` writes them at once. The agent's `erd_undo` reverts only its own edits. |
|
|
63
|
+
| No editor | **Headless.** Loads the file, applies the change and replaces the file atomically. `erd_save` has nothing to do. A read-only file, such as a Perforce or TFVC file not checked out, is refused with `readonly` until you make it writable. On Windows, a file with permissions of its own, unlike its folder's, is written in place, not atomically, so that it keeps them; a program reading it at that moment can find it half written. A file another program holds open is tried again for up to two seconds. |
|
|
64
|
+
| An editor whose hub is off or failed to start | **Refused.** Reads still come from disk, but the server never writes the file behind the editor, where its next save would overwrite the change. |
|
|
65
|
+
| An editor whose hub speaks another protocol than this server | **Refused**, reads included; the message names the side to update, the ERD Editor extension or plugin, or this server. |
|
|
61
66
|
| On Windows, an editor that holds the document under another path to the same file: the agent named it through a network share or a mapped drive of this computer, such as `\\localhost\C$\…`, and the editor opened it by its drive path, or the other way round | **Refused**, reads included; the result names the path the editor holds the document by, to call again with. |
|
|
62
67
|
| An editor Windows keeps the agent out of: one started as administrator while the agent was not, or any editor when the agent runs in a sandbox | **Refused**, reads included, with a result that says why. Run the editor and the agent with the same rights, for example by starting the editor again without administrator rights. With Windows 11's Administrator protection on, an editor started as administrator runs as a separate account whose lock files the agent never sees, so the edit goes headless under that editor: start it without administrator rights there. |
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
69
|
+
Each editor runs its hub, on by default, as follows:
|
|
70
|
+
|
|
71
|
+
- **VS Code** — a hub in each window, in a trusted workspace only; the
|
|
72
|
+
`dineug.erd-editor.agentHub.enabled` setting turns it off for the window. An untrusted window, or
|
|
73
|
+
one with the setting off, still guards its documents from headless writes. The extension starts
|
|
74
|
+
once the folder you open holds an `.erd.json` file, or once you open a diagram. In a folder with
|
|
75
|
+
none yet, open or create a diagram in VS Code first; otherwise the agent writes its new diagram on
|
|
76
|
+
disk, and it does not open in the editor.
|
|
77
|
+
- **Obsidian** — a hub in each vault window while the ERD Editor plugin is enabled;
|
|
78
|
+
**Settings → ERD Editor → Coding agents** turns it off for the vault, and the vault window
|
|
79
|
+
still guards its files from headless writes.
|
|
80
|
+
- **JetBrains IDEs** — one hub for the whole IDE and every project open in it, while the ERD
|
|
81
|
+
Editor plugin is enabled; unticking **Settings | Tools | ERD Editor → Coding agents** turns it
|
|
82
|
+
off for the whole IDE, and the IDE still guards the files of its projects from headless writes. A
|
|
83
|
+
project you have not trusted, opened in safe mode, is kept the same way: agents read its diagrams
|
|
84
|
+
but never change them.
|
|
78
85
|
|
|
79
86
|
The server never falls back to the file on its own while an editor holds a document: if the
|
|
80
|
-
connection drops it reconnects
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
connection drops, it reconnects. Only once that editor has exited, or has closed the document and
|
|
88
|
+
stopped serving it, as VS Code does when you close a document from outside its workspace, Obsidian
|
|
89
|
+
when the plugin is disabled and a JetBrains IDE when a project closes or the plugin is disabled,
|
|
90
|
+
does it edit the file, and it says so in the result.
|
|
91
|
+
|
|
92
|
+
An editor in a Flatpak sandbox is the exception. Obsidian installed from Flathub and a JetBrains IDE
|
|
93
|
+
installed as a Flatpak run in a sandbox the server cannot reach, so they run no hub and write no
|
|
94
|
+
lock. There the agent edits the files on disk, even while a diagram is open, unless an editor
|
|
95
|
+
outside the sandbox, such as a VS Code window, has the document or a folder that holds it open.
|
|
96
|
+
Obsidian picks the change up as it picks up any change made outside it, and an edit of yours it has
|
|
97
|
+
not saved yet gives way to the agent's. A JetBrains IDE does not reload a diagram changed on disk
|
|
98
|
+
while it is open, and your next edit in it would overwrite the agent's, so close the diagram first.
|
|
83
99
|
|
|
84
100
|
## Documents
|
|
85
101
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
With `create`, `erd_open_document` makes the document first when the file is missing, adding
|
|
103
|
+
`.erd.json` to a name with no extension. In an Obsidian vault, name it `.erd`: Obsidian's file
|
|
104
|
+
explorer leaves `.erd.json` files out unless **Settings → Files and links → Detect all file
|
|
105
|
+
extensions** is on. A file that is not an ERD document the editor can read, such as one left with
|
|
106
|
+
merge conflict markers, is refused with `invalidDocument` and left as it is, never loaded as an
|
|
107
|
+
empty diagram and written back.
|
|
108
|
+
|
|
109
|
+
On Windows the server refuses a path with a name Windows would store as another file, a folder's
|
|
110
|
+
included: one holding a colon, such as `orders:v2.erd.json`, or another character Windows refuses
|
|
111
|
+
(`<`, `>`, `"`, `|`, `?`, `*` or a control character), a device name such as `NUL.erd.json` or
|
|
112
|
+
`CON.erd.json`, or a name ending in a dot or a space. It leaves such files and folders out when it
|
|
113
|
+
lists documents from disk too. Use `-` in place of `:`.
|
|
90
114
|
|
|
91
115
|
An agent finds ids with `erd_list`, which lists the settings, the counts and the tables by id, each
|
|
92
|
-
with its position and its size on the canvas (the width approximate, the height exact)
|
|
93
|
-
relationships and indexes, then the
|
|
94
|
-
passes those ids to the edit tools. `erd_read`
|
|
95
|
-
`snapshot` format lists every entity with its id, the `sql`
|
|
96
|
-
eight supported databases and the `json` format is the
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
116
|
+
with its position and its size on the canvas (the width approximate, the height exact) and the table
|
|
117
|
+
group it is in, with their relationships and indexes, then the table groups and the memos. It reads
|
|
118
|
+
columns and other details with `erd_get`, then passes those ids to the edit tools. `erd_read`
|
|
119
|
+
answers the whole document at once: the `snapshot` format lists every entity with its id, the `sql`
|
|
120
|
+
format generates DDL for any of the eight supported databases, and the `json` format is the whole
|
|
121
|
+
document in the form a save writes to the file, with any unsaved live edits and a v2 document in its
|
|
122
|
+
v3 form. Its `scripts` format answers the document's before and after scripts alone, however large
|
|
123
|
+
the schema. Have the agent edit through these tools rather than write the JSON file itself.
|
|
124
|
+
|
|
125
|
+
The `sql` format writes plain `CREATE TABLE` statements and no header by default. Its `statements`
|
|
126
|
+
argument asks for `ifNotExists` (`CREATE TABLE IF NOT EXISTS` on MySQL, MariaDB, PostgreSQL, SQLite
|
|
127
|
+
and Databricks) or `recreate` (the tables dropped first, `CREATE OR REPLACE TABLE` on Snowflake),
|
|
128
|
+
and its `header` for `use`, which selects the database or schema the document's database name
|
|
129
|
+
gives, or `createAndUse`, which creates it first. As the options of the editor's Schema SQL tab do,
|
|
130
|
+
`ifNotExists` writes plain `CREATE TABLE` on the other databases, `createAndUse` writes `use` on
|
|
131
|
+
Oracle, which has `use` alone, `use` writes no header on PostgreSQL, which has `createAndUse` alone,
|
|
132
|
+
and SQLite writes no header; no database writes one while the name is empty or not a plain
|
|
133
|
+
identifier. The DDL of the whole document carries the document's before and after scripts; the DDL
|
|
134
|
+
of some tables carries none.
|
|
135
|
+
|
|
136
|
+
Schemas of hundreds or thousands of tables work too. A read answers at most 40,000 characters, under
|
|
137
|
+
the point where Claude Code sets a tool result aside in a file; only `erd_get` goes past it, when
|
|
138
|
+
the first entity it answers is larger on its own, which it gives whole with a note. `erd_list`
|
|
139
|
+
answers a page of 100 tables and says where the next one starts; its `query` finds tables by a word
|
|
140
|
+
in a table or column name or comment, and `namesOnly` lists the table names alone, 2,000 short names
|
|
141
|
+
in one answer. `erd_get` and `erd_read` take `tableNames` as well as ids, and `erd_read` takes
|
|
142
|
+
`groupNames`, the tables of those table groups, so an agent asked for a SQL query on a large schema
|
|
143
|
+
reads the DDL of just the tables it needs. `erd_read` refuses a read too large for one answer and
|
|
144
|
+
says how to narrow it. `erd_get` answers the entities that fit and lists the ids it had no room for
|
|
145
|
+
under `notReturned`, to ask for again, and refuses only a request for more ids than one answer can
|
|
146
|
+
name.
|
|
106
147
|
|
|
107
148
|
## Tools
|
|
108
149
|
|
|
@@ -111,38 +152,86 @@ refused with how to narrow it.
|
|
|
111
152
|
| Session | `erd_list_documents`, `erd_open_document`, `erd_list`, `erd_get`, `erd_read`, `erd_save`, `erd_undo`, `erd_redo` |
|
|
112
153
|
| Tables | `erd_add_table`, `erd_remove_table`, `erd_change_table_name`, `erd_change_table_comment`, `erd_change_table_color`, `erd_move_table`, `erd_move_tables`, `erd_sort_tables` |
|
|
113
154
|
| Columns | `erd_add_column`, `erd_remove_columns`, `erd_change_column_name`, `erd_change_column_data_type`, `erd_change_column_default`, `erd_change_column_comment`, `erd_set_column_primary_key`, `erd_set_column_unique`, `erd_set_column_not_null`, `erd_set_column_auto_increment`, `erd_move_column` |
|
|
114
|
-
| Relationships | `erd_add_relationship`, `erd_link_columns`, `erd_remove_relationship`, `erd_change_relationship_type` |
|
|
155
|
+
| Relationships | `erd_add_relationship`, `erd_link_columns`, `erd_remove_relationship`, `erd_change_relationship_type`, `erd_change_relationship_on_delete`, `erd_change_relationship_on_update` |
|
|
115
156
|
| Indexes | `erd_add_index`, `erd_remove_index`, `erd_change_index_name`, `erd_set_index_unique`, `erd_add_index_column`, `erd_remove_index_column`, `erd_move_index_column`, `erd_set_index_column_order` |
|
|
116
157
|
| Memos | `erd_add_memo`, `erd_remove_memo`, `erd_change_memo_value`, `erd_change_memo_color`, `erd_move_memo`, `erd_resize_memo` |
|
|
117
|
-
|
|
|
158
|
+
| Table groups | `erd_add_table_group`, `erd_remove_table_group`, `erd_change_table_group_name`, `erd_change_table_group_color`, `erd_move_table_group`, `erd_resize_table_group`, `erd_set_table_group` |
|
|
159
|
+
| Settings | `erd_set_database`, `erd_set_database_name`, `erd_set_ddl_script` |
|
|
118
160
|
| Import | `erd_import_sql`, `erd_import_graphql`, `erd_import_dbml`, `erd_import_aml`, `erd_import_json` |
|
|
119
161
|
| Batch | `erd_batch` |
|
|
120
162
|
|
|
121
|
-
`erd_batch` runs
|
|
122
|
-
a copy of the document first, so a refused
|
|
123
|
-
reverts the whole batch. An operation named with `as` lets a later one pass `$name`
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
163
|
+
`erd_batch` runs up to 100 operations of the edit tools in order as one edit, all or none: it tries
|
|
164
|
+
them on a copy of the document first, so a refused operation is named and nothing is applied, and
|
|
165
|
+
one `erd_undo` reverts the whole batch. An operation named with `as` lets a later one pass `$name`
|
|
166
|
+
where it takes an entity id, `$name.1` for its second created id or `$name.last` for its last, such
|
|
167
|
+
as a relationship's own id after its key columns, so a table and its columns take one call.
|
|
168
|
+
|
|
169
|
+
The five import tools replace the document's tables, relationships, indexes, memos and table groups
|
|
170
|
+
by default: the four schema imports keep its settings but the view, which goes to the start of the
|
|
171
|
+
canvas, and `erd_import_json` takes the settings of the document it loads. With `mode: "append"`
|
|
172
|
+
they add the import instead, as the editor's Import and Add does but without its Flow layout: the
|
|
173
|
+
tables, relationships and indexes arrive as new ones in a grid below everything already there (a
|
|
174
|
+
JSON document's, with its memos and table groups, in the placement it has), the document's settings
|
|
175
|
+
and tables stay as they are, and one `erd_undo` takes them away. A foreign key to a table the import
|
|
176
|
+
does not declare is dropped. Either way, `erd_import_dbml` reads each `TableGroup` as a table group
|
|
177
|
+
of the tables it names, its box round them.
|
|
178
|
+
|
|
179
|
+
`erd_change_relationship_on_delete` and `erd_change_relationship_on_update`, and the `onDelete` /
|
|
180
|
+
`onUpdate` of `erd_add_relationship` and `erd_link_columns`, set a foreign key's ON DELETE and ON
|
|
181
|
+
UPDATE actions; a database that lacks one leaves it out of its DDL. An ERD Editor extension or
|
|
182
|
+
plugin released before referential actions ignores them when it serves the document, so update it.
|
|
183
|
+
|
|
184
|
+
A table group is a box drawn behind its tables, with the name and color it is given, and a table is
|
|
185
|
+
in one group at most. `erd_add_table_group` wraps the tables it is given, or takes a rect and the
|
|
186
|
+
tables in no group whose centre lies inside it, as drawing a group in the editor does.
|
|
187
|
+
`erd_move_table_group` moves a group with its tables, and only `erd_add_table_group`,
|
|
188
|
+
`erd_set_table_group` and `erd_remove_table_group` change which tables a group holds. An ERD Editor
|
|
189
|
+
extension or plugin released before table groups ignores these edits and the groups
|
|
190
|
+
`erd_import_dbml` and `erd_import_json` bring, except that it still moves the tables of a group
|
|
191
|
+
`erd_move_table_group` moves, and drops every group when it saves, so update it.
|
|
192
|
+
|
|
193
|
+
An agent sets the database and its name, the settings of the schema itself, and the Schema SQL
|
|
194
|
+
scripts. What the diagram shows, the column order, the maximum comment width, the relationship data
|
|
195
|
+
type sync, the code generation language, the name cases, the bracket type and the locks that keep
|
|
196
|
+
those last three at their saved values in the file are yours to set in the editor; `erd_list` and
|
|
197
|
+
`erd_read` read them as the file saves them.
|
|
198
|
+
|
|
199
|
+
`erd_set_ddl_script` sets the SQL the document keeps before or after the tables of its Schema SQL,
|
|
200
|
+
such as `CREATE EXTENSION` ahead of them or `GRANT` past them, written into the DDL as is for every
|
|
201
|
+
database (on MSSQL, ended with `GO`), up to 10,000 characters a call. A call replaces the whole
|
|
202
|
+
script, an empty string removes it, and `erd_undo` reverts it. The `erd_read` `scripts` format gives
|
|
203
|
+
both scripts alone, however large the schema, its snapshot gives them too, and its `sql` format of
|
|
204
|
+
the whole document writes them in place. An ERD Editor extension or plugin released before scripts
|
|
205
|
+
neither shows nor keeps them when it serves the document, so update it.
|
|
206
|
+
|
|
207
|
+
Every edit tool takes the document `path`. `erd_set_database`, `erd_set_database_name` and
|
|
208
|
+
`erd_resize_memo` make no undo entry in the editor, nor does an `erd_move_table_group` of under 20
|
|
209
|
+
pixels in all, so `erd_undo` passes over them, inside an `erd_batch` too, and the result says so. An
|
|
210
|
+
`erd_set_column_*`, `erd_set_index_*` or `erd_set_table_group` call that finds the value already set
|
|
211
|
+
sends nothing and makes no entry either, and its result says so.
|
|
212
|
+
|
|
213
|
+
The edit tools and the read tools (`erd_list`, `erd_get`, `erd_read`) refuse an argument they do not
|
|
214
|
+
declare, or one of the wrong type, with a JSON-RPC invalid params error (-32602) before touching the
|
|
215
|
+
document. `erd_batch` does the same for its own arguments and for an operation's `tool`, `as` and
|
|
216
|
+
`args` keys; it checks each operation's own arguments as the batch runs and refuses a bad one with
|
|
217
|
+
`invalidArgs`, naming the operation, before anything is applied. Either way a misspelled argument is
|
|
218
|
+
never silently dropped. The other session tools ignore arguments they do not know.
|
|
134
219
|
|
|
135
220
|
## Documentation
|
|
136
221
|
|
|
137
222
|
- [Introduction](https://docs.erd-editor.io/docs/mcp/introduction) — what an agent can and cannot
|
|
138
223
|
do, how it works, requirements
|
|
139
224
|
- [Install](https://docs.erd-editor.io/docs/mcp/installation) — Claude Code, Codex and any other
|
|
140
|
-
client, setting up VS Code, updating
|
|
225
|
+
client, setting up VS Code, Obsidian or a JetBrains IDE, updating
|
|
141
226
|
- [Live and Headless](https://docs.erd-editor.io/docs/mcp/live-and-headless) — where an edit
|
|
142
227
|
lands, saving, undo, a window that goes away, conflicts on disk
|
|
143
228
|
- [Tools](https://docs.erd-editor.io/docs/mcp/tools) — every tool with its arguments, paging a
|
|
144
229
|
large schema, `erd_batch`, results and refusals
|
|
145
230
|
|
|
231
|
+
## Issues
|
|
232
|
+
|
|
233
|
+
Found a bug or want a feature? [Open an issue](https://github.com/dineug/erd-editor/issues).
|
|
234
|
+
|
|
146
235
|
## License
|
|
147
236
|
|
|
148
237
|
[MIT](https://github.com/dineug/erd-editor/blob/main/LICENSE)
|