@thinkdata/mcp-server 0.2.0 → 0.3.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 +18 -0
- package/dist/index.js +755 -881
- package/package.json +48 -50
- package/dist/client.d.ts +0 -104
- package/dist/client.d.ts.map +0 -1
- package/dist/resources.d.ts +0 -12
- package/dist/resources.d.ts.map +0 -1
- package/dist/toolManifest.d.ts +0 -20
- package/dist/toolManifest.d.ts.map +0 -1
- package/dist/tools.d.ts +0 -4
- package/dist/tools.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -7397,10 +7397,6 @@ var init_src = __esm({
|
|
|
7397
7397
|
}
|
|
7398
7398
|
});
|
|
7399
7399
|
|
|
7400
|
-
// src/index.ts
|
|
7401
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
7402
|
-
import { resolve } from "node:path";
|
|
7403
|
-
|
|
7404
7400
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
7405
7401
|
var external_exports = {};
|
|
7406
7402
|
__export(external_exports, {
|
|
@@ -18899,13 +18895,13 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
18899
18895
|
}, true) ?? parseAnyDef(refs)
|
|
18900
18896
|
}), {}) : void 0;
|
|
18901
18897
|
const name = typeof options === "string" ? options : options?.nameStrategy === "title" ? void 0 : options?.name;
|
|
18902
|
-
const
|
|
18898
|
+
const main = parseDef(schema._def, name === void 0 ? refs : {
|
|
18903
18899
|
...refs,
|
|
18904
18900
|
currentPath: [...refs.basePath, refs.definitionPath, name]
|
|
18905
18901
|
}, false) ?? parseAnyDef(refs);
|
|
18906
18902
|
const title = typeof options === "object" && options.name !== void 0 && options.nameStrategy === "title" ? options.name : void 0;
|
|
18907
18903
|
if (title !== void 0) {
|
|
18908
|
-
|
|
18904
|
+
main.title = title;
|
|
18909
18905
|
}
|
|
18910
18906
|
if (refs.flags.hasReferencedOpenAiAnyType) {
|
|
18911
18907
|
if (!definitions) {
|
|
@@ -18926,9 +18922,9 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
18926
18922
|
}
|
|
18927
18923
|
}
|
|
18928
18924
|
const combined = name === void 0 ? definitions ? {
|
|
18929
|
-
...
|
|
18925
|
+
...main,
|
|
18930
18926
|
[refs.definitionPath]: definitions
|
|
18931
|
-
} :
|
|
18927
|
+
} : main : {
|
|
18932
18928
|
$ref: [
|
|
18933
18929
|
...refs.$refStrategy === "relative" ? [] : refs.basePath,
|
|
18934
18930
|
refs.definitionPath,
|
|
@@ -18936,7 +18932,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
18936
18932
|
].join("/"),
|
|
18937
18933
|
[refs.definitionPath]: {
|
|
18938
18934
|
...definitions,
|
|
18939
|
-
[name]:
|
|
18935
|
+
[name]: main
|
|
18940
18936
|
}
|
|
18941
18937
|
};
|
|
18942
18938
|
if (refs.target === "jsonSchema7") {
|
|
@@ -21613,957 +21609,824 @@ var StdioServerTransport = class {
|
|
|
21613
21609
|
}
|
|
21614
21610
|
};
|
|
21615
21611
|
|
|
21616
|
-
//
|
|
21612
|
+
// ../cli/dist/commands/mcp.js
|
|
21613
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
21614
|
+
import { resolve } from "node:path";
|
|
21615
|
+
import { fileURLToPath } from "node:url";
|
|
21616
|
+
import { dirname } from "node:path";
|
|
21617
|
+
|
|
21618
|
+
// ../cli/dist/mcp/client.js
|
|
21619
|
+
var ThinkERDClient = class {
|
|
21620
|
+
baseUrl;
|
|
21621
|
+
headers;
|
|
21622
|
+
constructor(apiUrl, token) {
|
|
21623
|
+
this.baseUrl = apiUrl.replace(/\/+$/, "");
|
|
21624
|
+
this.headers = {
|
|
21625
|
+
"Authorization": `Bearer ${token}`,
|
|
21626
|
+
"Content-Type": "application/json"
|
|
21627
|
+
};
|
|
21628
|
+
}
|
|
21629
|
+
async request(path) {
|
|
21630
|
+
const url = `${this.baseUrl}${path}`;
|
|
21631
|
+
const res = await fetch(url, { headers: this.headers });
|
|
21632
|
+
if (!res.ok) {
|
|
21633
|
+
const body = await res.text().catch(() => "");
|
|
21634
|
+
throw new Error(`ThinkERD API error ${res.status}: ${body || res.statusText}`);
|
|
21635
|
+
}
|
|
21636
|
+
const contentType = res.headers.get("content-type") || "";
|
|
21637
|
+
if (contentType.includes("text/plain")) {
|
|
21638
|
+
return res.text();
|
|
21639
|
+
}
|
|
21640
|
+
return res.json();
|
|
21641
|
+
}
|
|
21642
|
+
// ─── Diagrams ───
|
|
21643
|
+
/** 사용자의 모든 다이어그램 목록 조회 */
|
|
21644
|
+
async listDiagrams() {
|
|
21645
|
+
return this.request("/api/mcp/diagrams");
|
|
21646
|
+
}
|
|
21647
|
+
/** 다이어그램 상세 (엔터티 + 관계 포함) */
|
|
21648
|
+
async getDiagram(diagramId) {
|
|
21649
|
+
return this.request(`/api/mcp/diagrams/${diagramId}`);
|
|
21650
|
+
}
|
|
21651
|
+
// ─── Entities ───
|
|
21652
|
+
/** 단일 엔터티 상세 조회 */
|
|
21653
|
+
async getEntity(diagramId, entityId) {
|
|
21654
|
+
return this.request(`/api/mcp/diagrams/${diagramId}/entities/${entityId}`);
|
|
21655
|
+
}
|
|
21656
|
+
/** 엔터티 이름으로 검색 */
|
|
21657
|
+
async searchEntities(diagramId, query) {
|
|
21658
|
+
return this.request(`/api/mcp/diagrams/${diagramId}/entities?q=${encodeURIComponent(query)}`);
|
|
21659
|
+
}
|
|
21660
|
+
// ─── DDL ───
|
|
21661
|
+
/** 다이어그램의 DDL 생성 */
|
|
21662
|
+
async generateDDL(diagramId, dialect) {
|
|
21663
|
+
const d = dialect ? `?dialect=${encodeURIComponent(dialect)}` : "";
|
|
21664
|
+
return this.request(`/api/mcp/diagrams/${diagramId}/ddl${d}`);
|
|
21665
|
+
}
|
|
21666
|
+
// ─── Dictionary ───
|
|
21667
|
+
/** 표준 사전 단어 목록 */
|
|
21668
|
+
async getDictionary(projectId) {
|
|
21669
|
+
return this.request(`/api/mcp/projects/${projectId}/dictionary`);
|
|
21670
|
+
}
|
|
21671
|
+
// ─── Drafts ───
|
|
21672
|
+
/** 스키마 변경 제안 (Draft 생성) */
|
|
21673
|
+
async proposeSchemaChange(diagramId, data) {
|
|
21674
|
+
return this.postRequest(`/api/mcp/diagrams/${diagramId}/drafts`, data);
|
|
21675
|
+
}
|
|
21676
|
+
// ─── Sync / Push ───
|
|
21677
|
+
async postRequest(path, body) {
|
|
21678
|
+
const url = `${this.baseUrl}${path}`;
|
|
21679
|
+
const res = await fetch(url, {
|
|
21680
|
+
method: "POST",
|
|
21681
|
+
headers: this.headers,
|
|
21682
|
+
body: JSON.stringify(body)
|
|
21683
|
+
});
|
|
21684
|
+
if (!res.ok) {
|
|
21685
|
+
const text = await res.text().catch(() => "");
|
|
21686
|
+
throw new Error(`ThinkERD API error ${res.status}: ${text || res.statusText}`);
|
|
21687
|
+
}
|
|
21688
|
+
return res.json();
|
|
21689
|
+
}
|
|
21690
|
+
// ─── Context Provider (Project-level Ontology) ───
|
|
21691
|
+
/** 자연어 질문 → 관련 엔터티 컨텍스트 (Graph RAG) */
|
|
21692
|
+
async getProjectContext(projectId, question) {
|
|
21693
|
+
return this.postRequest(`/api/mcp/projects/${projectId}/context`, { question });
|
|
21694
|
+
}
|
|
21695
|
+
/** 두 엔터티 간 JOIN 경로 탐색 */
|
|
21696
|
+
async findJoinPath(projectId, from, to) {
|
|
21697
|
+
return this.postRequest(`/api/mcp/projects/${projectId}/join-path`, { from, to });
|
|
21698
|
+
}
|
|
21699
|
+
/** 프로젝트 전체 스키마 요약 */
|
|
21700
|
+
async getProjectSummary(projectId) {
|
|
21701
|
+
return this.request(`/api/mcp/projects/${projectId}/summary`);
|
|
21702
|
+
}
|
|
21703
|
+
/** 메타데이터 풍부도 품질 보고 */
|
|
21704
|
+
async checkMetadataQuality(projectId) {
|
|
21705
|
+
return this.request(`/api/mcp/projects/${projectId}/quality`);
|
|
21706
|
+
}
|
|
21707
|
+
/** SPARQL 직접 실행 */
|
|
21708
|
+
async queryOntology(projectId, query) {
|
|
21709
|
+
return this.postRequest(`/api/ai/ontology/${projectId}/sparql`, { query });
|
|
21710
|
+
}
|
|
21711
|
+
};
|
|
21712
|
+
|
|
21713
|
+
// ../cli/dist/mcp/resources.js
|
|
21617
21714
|
function registerResources(server, client) {
|
|
21618
|
-
server.resource(
|
|
21619
|
-
"
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
|
|
21623
|
-
|
|
21624
|
-
|
|
21625
|
-
|
|
21715
|
+
server.resource("diagrams", "thinkerd://diagrams", {
|
|
21716
|
+
description: "ThinkERD \uD504\uB85C\uC81D\uD2B8\uC758 \uBAA8\uB4E0 \uB2E4\uC774\uC5B4\uADF8\uB7A8 \uBAA9\uB85D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21717
|
+
}, async () => {
|
|
21718
|
+
const diagrams = await client.listDiagrams();
|
|
21719
|
+
return {
|
|
21720
|
+
contents: [{
|
|
21721
|
+
uri: "thinkerd://diagrams",
|
|
21722
|
+
mimeType: "application/json",
|
|
21723
|
+
text: JSON.stringify(diagrams, null, 2)
|
|
21724
|
+
}]
|
|
21725
|
+
};
|
|
21726
|
+
});
|
|
21727
|
+
server.resource("diagram-schema", "thinkerd://diagrams/{diagramId}/schema", {
|
|
21728
|
+
description: "\uD2B9\uC815 \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uC804\uCCB4 \uC2A4\uD0A4\uB9C8(\uC5D4\uD130\uD2F0, \uCEEC\uB7FC, \uAD00\uACC4)\uB97C JSON\uC73C\uB85C \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21729
|
+
}, async (uri) => {
|
|
21730
|
+
const diagramId = extractParam(uri.href, "diagrams");
|
|
21731
|
+
const data = await client.getDiagram(diagramId);
|
|
21732
|
+
return {
|
|
21733
|
+
contents: [{
|
|
21734
|
+
uri: uri.href,
|
|
21735
|
+
mimeType: "application/json",
|
|
21736
|
+
text: JSON.stringify(data, null, 2)
|
|
21737
|
+
}]
|
|
21738
|
+
};
|
|
21739
|
+
});
|
|
21740
|
+
server.resource("entity-detail", "thinkerd://diagrams/{diagramId}/entities/{entityId}", {
|
|
21741
|
+
description: "\uD2B9\uC815 \uC5D4\uD130\uD2F0\uC758 \uB17C\uB9AC\uBA85, \uBB3C\uB9AC\uBA85, \uCEEC\uB7FC \uC0C1\uC138(\uD0C0\uC785, PK/FK, Nullable \uB4F1)\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21742
|
+
}, async (uri) => {
|
|
21743
|
+
const parts = uri.href.split("/");
|
|
21744
|
+
const entitiesIdx = parts.indexOf("entities");
|
|
21745
|
+
const diagramsIdx = parts.indexOf("diagrams");
|
|
21746
|
+
const diagramId = parts[diagramsIdx + 1];
|
|
21747
|
+
const entityId = parts[entitiesIdx + 1];
|
|
21748
|
+
const entity = await client.getEntity(diagramId, entityId);
|
|
21749
|
+
return {
|
|
21750
|
+
contents: [{
|
|
21751
|
+
uri: uri.href,
|
|
21752
|
+
mimeType: "application/json",
|
|
21753
|
+
text: JSON.stringify(entity, null, 2)
|
|
21754
|
+
}]
|
|
21755
|
+
};
|
|
21756
|
+
});
|
|
21757
|
+
server.resource("diagram-ddl", "thinkerd://diagrams/{diagramId}/ddl", {
|
|
21758
|
+
description: "\uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 DDL(CREATE TABLE \uAD6C\uBB38)\uC744 \uC0DD\uC131\uD558\uC5EC \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21759
|
+
}, async (uri) => {
|
|
21760
|
+
const diagramId = extractParam(uri.href, "diagrams");
|
|
21761
|
+
const ddl = await client.generateDDL(diagramId);
|
|
21762
|
+
return {
|
|
21763
|
+
contents: [{
|
|
21764
|
+
uri: uri.href,
|
|
21765
|
+
mimeType: "text/plain",
|
|
21766
|
+
text: typeof ddl === "string" ? ddl : JSON.stringify(ddl)
|
|
21767
|
+
}]
|
|
21768
|
+
};
|
|
21769
|
+
});
|
|
21770
|
+
server.resource("dictionary", "thinkerd://projects/{projectId}/dictionary", {
|
|
21771
|
+
description: "\uD504\uB85C\uC81D\uD2B8\uC758 \uD45C\uC900 \uC0AC\uC804(\uB2E8\uC5B4, \uB3C4\uBA54\uC778, \uAE08\uCE59\uC5B4)\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21772
|
+
}, async (uri) => {
|
|
21773
|
+
const projectId = extractParam(uri.href, "projects");
|
|
21774
|
+
const words = await client.getDictionary(projectId);
|
|
21775
|
+
return {
|
|
21776
|
+
contents: [{
|
|
21777
|
+
uri: uri.href,
|
|
21778
|
+
mimeType: "application/json",
|
|
21779
|
+
text: JSON.stringify(words, null, 2)
|
|
21780
|
+
}]
|
|
21781
|
+
};
|
|
21782
|
+
});
|
|
21783
|
+
server.resource("project-summary", "thinkerd://projects/{projectId}/summary", {
|
|
21784
|
+
description: "\uD504\uB85C\uC81D\uD2B8 \uC804\uCCB4 \uB370\uC774\uD130 \uBAA8\uB378\uC758 \uC694\uC57D(\uC5D4\uD130\uD2F0 \uC218, \uAD00\uACC4 \uC218, \uC8FC\uC81C\uC601\uC5ED \uAD6C\uC131, RDF \uD2B8\uB9AC\uD50C \uC218)\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21785
|
+
}, async (uri) => {
|
|
21786
|
+
const projectId = extractParam(uri.href, "projects");
|
|
21787
|
+
const summary = await client.getProjectSummary(projectId);
|
|
21788
|
+
return {
|
|
21789
|
+
contents: [{
|
|
21790
|
+
uri: uri.href,
|
|
21791
|
+
mimeType: "application/json",
|
|
21792
|
+
text: JSON.stringify(summary, null, 2)
|
|
21793
|
+
}]
|
|
21794
|
+
};
|
|
21795
|
+
});
|
|
21796
|
+
server.resource("metadata-quality", "thinkerd://projects/{projectId}/quality", {
|
|
21797
|
+
description: "\uD504\uB85C\uC81D\uD2B8\uC758 \uBA54\uD0C0\uB370\uC774\uD130 \uD48D\uBD80\uB3C4(\uC124\uBA85, \uB3D9\uC758\uC5B4, \uC18D\uC131 \uC785\uB825\uB960)\uB97C \uBD84\uC11D\uD55C \uD488\uC9C8 \uBCF4\uACE0\uC11C\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21798
|
+
}, async (uri) => {
|
|
21799
|
+
const projectId = extractParam(uri.href, "projects");
|
|
21800
|
+
const report = await client.checkMetadataQuality(projectId);
|
|
21801
|
+
return {
|
|
21802
|
+
contents: [{
|
|
21803
|
+
uri: uri.href,
|
|
21804
|
+
mimeType: "application/json",
|
|
21805
|
+
text: JSON.stringify(report, null, 2)
|
|
21806
|
+
}]
|
|
21807
|
+
};
|
|
21808
|
+
});
|
|
21809
|
+
}
|
|
21810
|
+
function extractParam(href, segment) {
|
|
21811
|
+
const parts = href.split("/");
|
|
21812
|
+
const idx = parts.indexOf(segment);
|
|
21813
|
+
if (idx === -1 || idx + 1 >= parts.length) {
|
|
21814
|
+
throw new Error(`Invalid URI: cannot extract '${segment}' parameter from ${href}`);
|
|
21815
|
+
}
|
|
21816
|
+
return parts[idx + 1];
|
|
21817
|
+
}
|
|
21818
|
+
|
|
21819
|
+
// ../cli/dist/mcp/tools.js
|
|
21820
|
+
function registerTools(server, client) {
|
|
21821
|
+
server.tool("get_entity", "ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC5D0\uC11C \uD2B9\uC815 \uC5D4\uD130\uD2F0\uC758 \uCEEC\uB7FC, \uD0C0\uC785, PK/FK \uC815\uBCF4\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.", {
|
|
21822
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21823
|
+
entityId: external_exports.string().describe("\uC5D4\uD130\uD2F0 ID")
|
|
21824
|
+
}, async ({ diagramId, entityId }) => {
|
|
21825
|
+
try {
|
|
21826
|
+
const entity = await client.getEntity(diagramId, entityId);
|
|
21626
21827
|
return {
|
|
21627
|
-
|
|
21628
|
-
|
|
21629
|
-
|
|
21630
|
-
text: JSON.stringify(diagrams, null, 2)
|
|
21828
|
+
content: [{
|
|
21829
|
+
type: "text",
|
|
21830
|
+
text: JSON.stringify(entity, null, 2)
|
|
21631
21831
|
}]
|
|
21632
21832
|
};
|
|
21633
|
-
}
|
|
21634
|
-
);
|
|
21635
|
-
server.resource(
|
|
21636
|
-
"diagram-schema",
|
|
21637
|
-
"thinkerd://diagrams/{diagramId}/schema",
|
|
21638
|
-
{
|
|
21639
|
-
description: "\uD2B9\uC815 \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uC804\uCCB4 \uC2A4\uD0A4\uB9C8(\uC5D4\uD130\uD2F0, \uCEEC\uB7FC, \uAD00\uACC4)\uB97C JSON\uC73C\uB85C \uBC18\uD658\uD569\uB2C8\uB2E4."
|
|
21640
|
-
},
|
|
21641
|
-
async (uri) => {
|
|
21642
|
-
const diagramId = extractParam(uri.href, "diagrams");
|
|
21643
|
-
const data = await client.getDiagram(diagramId);
|
|
21833
|
+
} catch (err) {
|
|
21644
21834
|
return {
|
|
21645
|
-
|
|
21646
|
-
|
|
21647
|
-
|
|
21648
|
-
|
|
21649
|
-
|
|
21835
|
+
content: [{
|
|
21836
|
+
type: "text",
|
|
21837
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21838
|
+
}],
|
|
21839
|
+
isError: true
|
|
21650
21840
|
};
|
|
21651
21841
|
}
|
|
21652
|
-
);
|
|
21653
|
-
server.
|
|
21654
|
-
"
|
|
21655
|
-
"
|
|
21656
|
-
|
|
21657
|
-
|
|
21658
|
-
|
|
21659
|
-
|
|
21660
|
-
|
|
21661
|
-
|
|
21662
|
-
|
|
21663
|
-
|
|
21664
|
-
|
|
21665
|
-
|
|
21842
|
+
});
|
|
21843
|
+
server.tool("search_entities", "ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC5D0\uC11C \uC774\uB984\uC73C\uB85C \uC5D4\uD130\uD2F0\uB97C \uAC80\uC0C9\uD569\uB2C8\uB2E4. \uB17C\uB9AC\uBA85/\uBB3C\uB9AC\uBA85 \uBAA8\uB450 \uAC80\uC0C9 \uAC00\uB2A5\uD569\uB2C8\uB2E4.", {
|
|
21844
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21845
|
+
query: external_exports.string().describe("\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC (\uC5D4\uD130\uD2F0 \uB17C\uB9AC\uBA85 \uB610\uB294 \uBB3C\uB9AC\uBA85)")
|
|
21846
|
+
}, async ({ diagramId, query }) => {
|
|
21847
|
+
try {
|
|
21848
|
+
const entities = await client.searchEntities(diagramId, query);
|
|
21849
|
+
const summary = entities.map((e) => ({
|
|
21850
|
+
id: e.id,
|
|
21851
|
+
name: e.name,
|
|
21852
|
+
tableName: e.tableName,
|
|
21853
|
+
role: e.entityRole,
|
|
21854
|
+
columnCount: e.columns.length,
|
|
21855
|
+
columns: e.columns.map((c) => `${c.name} (${c.type})${c.isPrimaryKey ? " [PK]" : ""}${c.isForeignKey ? " [FK]" : ""}`)
|
|
21856
|
+
}));
|
|
21666
21857
|
return {
|
|
21667
|
-
|
|
21668
|
-
|
|
21669
|
-
|
|
21670
|
-
text: JSON.stringify(entity, null, 2)
|
|
21858
|
+
content: [{
|
|
21859
|
+
type: "text",
|
|
21860
|
+
text: JSON.stringify(summary, null, 2)
|
|
21671
21861
|
}]
|
|
21672
21862
|
};
|
|
21863
|
+
} catch (err) {
|
|
21864
|
+
return {
|
|
21865
|
+
content: [{
|
|
21866
|
+
type: "text",
|
|
21867
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21868
|
+
}],
|
|
21869
|
+
isError: true
|
|
21870
|
+
};
|
|
21673
21871
|
}
|
|
21674
|
-
);
|
|
21675
|
-
server.
|
|
21676
|
-
"
|
|
21677
|
-
"
|
|
21678
|
-
|
|
21679
|
-
|
|
21680
|
-
|
|
21681
|
-
async (uri) => {
|
|
21682
|
-
const diagramId = extractParam(uri.href, "diagrams");
|
|
21683
|
-
const ddl = await client.generateDDL(diagramId);
|
|
21872
|
+
});
|
|
21873
|
+
server.tool("generate_ddl", "ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 DDL(CREATE TABLE \uAD6C\uBB38)\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4. PostgreSQL, MySQL, Oracle \uB4F1 \uB2E4\uC591\uD55C \uBC29\uC5B8\uC744 \uC9C0\uC6D0\uD569\uB2C8\uB2E4.", {
|
|
21874
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21875
|
+
dialect: external_exports.enum(["postgresql", "mysql", "oracle", "mssql", "sqlite"]).optional().default("postgresql").describe("SQL \uBC29\uC5B8 (\uAE30\uBCF8\uAC12: postgresql)")
|
|
21876
|
+
}, async ({ diagramId, dialect }) => {
|
|
21877
|
+
try {
|
|
21878
|
+
const ddl = await client.generateDDL(diagramId, dialect);
|
|
21684
21879
|
return {
|
|
21685
|
-
|
|
21686
|
-
|
|
21687
|
-
mimeType: "text/plain",
|
|
21880
|
+
content: [{
|
|
21881
|
+
type: "text",
|
|
21688
21882
|
text: typeof ddl === "string" ? ddl : JSON.stringify(ddl)
|
|
21689
21883
|
}]
|
|
21690
21884
|
};
|
|
21885
|
+
} catch (err) {
|
|
21886
|
+
return {
|
|
21887
|
+
content: [{
|
|
21888
|
+
type: "text",
|
|
21889
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21890
|
+
}],
|
|
21891
|
+
isError: true
|
|
21892
|
+
};
|
|
21691
21893
|
}
|
|
21692
|
-
);
|
|
21693
|
-
server.
|
|
21694
|
-
"
|
|
21695
|
-
|
|
21696
|
-
{
|
|
21697
|
-
|
|
21698
|
-
|
|
21699
|
-
|
|
21700
|
-
|
|
21701
|
-
|
|
21894
|
+
});
|
|
21895
|
+
server.tool("validate_schema", "ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uC2A4\uD0A4\uB9C8\uB97C \uAC80\uC99D\uD569\uB2C8\uB2E4. \uB204\uB77D\uB41C PK, \uBBF8\uC5F0\uACB0 FK, \uBE44\uD45C\uC900 \uB124\uC774\uBC0D \uB4F1\uC744 \uC810\uAC80\uD569\uB2C8\uB2E4.", {
|
|
21896
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID")
|
|
21897
|
+
}, async ({ diagramId }) => {
|
|
21898
|
+
try {
|
|
21899
|
+
const data = await client.getDiagram(diagramId);
|
|
21900
|
+
const issues = [];
|
|
21901
|
+
for (const entity of data.entities) {
|
|
21902
|
+
const hasPK = entity.columns.some((c) => c.isPrimaryKey);
|
|
21903
|
+
if (!hasPK) {
|
|
21904
|
+
issues.push(`\u26A0\uFE0F [${entity.name}] PK(Primary Key)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`);
|
|
21905
|
+
}
|
|
21906
|
+
}
|
|
21907
|
+
for (const entity of data.entities) {
|
|
21908
|
+
if (entity.columns.length === 0) {
|
|
21909
|
+
issues.push(`\u26A0\uFE0F [${entity.name}] \uCEEC\uB7FC\uC774 \uD558\uB098\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4.`);
|
|
21910
|
+
}
|
|
21911
|
+
}
|
|
21912
|
+
const connectedIds = /* @__PURE__ */ new Set();
|
|
21913
|
+
for (const rel of data.relationships) {
|
|
21914
|
+
connectedIds.add(rel.sourceEntityId);
|
|
21915
|
+
connectedIds.add(rel.targetEntityId);
|
|
21916
|
+
}
|
|
21917
|
+
for (const entity of data.entities) {
|
|
21918
|
+
if (!connectedIds.has(entity.id) && data.entities.length > 1) {
|
|
21919
|
+
issues.push(`\u2139\uFE0F [${entity.name}] \uB2E4\uB978 \uC5D4\uD130\uD2F0\uC640 \uAD00\uACC4\uAC00 \uC5C6\uB294 \uACE0\uB9BD \uC5D4\uD130\uD2F0\uC785\uB2C8\uB2E4.`);
|
|
21920
|
+
}
|
|
21921
|
+
}
|
|
21922
|
+
const summary = issues.length === 0 ? `\u2705 \uC2A4\uD0A4\uB9C8 \uAC80\uC99D \uC644\uB8CC: ${data.entities.length}\uAC1C \uC5D4\uD130\uD2F0, \uBB38\uC81C \uC5C6\uC74C.` : `\u{1F50D} \uC2A4\uD0A4\uB9C8 \uAC80\uC99D \uC644\uB8CC: ${data.entities.length}\uAC1C \uC5D4\uD130\uD2F0, ${issues.length}\uAC1C \uC774\uC288 \uBC1C\uACAC.
|
|
21923
|
+
|
|
21924
|
+
${issues.join("\n")}`;
|
|
21702
21925
|
return {
|
|
21703
|
-
|
|
21704
|
-
|
|
21705
|
-
|
|
21706
|
-
text: JSON.stringify(words, null, 2)
|
|
21926
|
+
content: [{
|
|
21927
|
+
type: "text",
|
|
21928
|
+
text: summary
|
|
21707
21929
|
}]
|
|
21708
21930
|
};
|
|
21931
|
+
} catch (err) {
|
|
21932
|
+
return {
|
|
21933
|
+
content: [{
|
|
21934
|
+
type: "text",
|
|
21935
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21936
|
+
}],
|
|
21937
|
+
isError: true
|
|
21938
|
+
};
|
|
21709
21939
|
}
|
|
21710
|
-
);
|
|
21711
|
-
server.
|
|
21712
|
-
"
|
|
21713
|
-
"
|
|
21714
|
-
|
|
21715
|
-
|
|
21716
|
-
|
|
21717
|
-
|
|
21718
|
-
|
|
21719
|
-
|
|
21940
|
+
});
|
|
21941
|
+
server.tool("harvest_schema_semantics", "ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uBB3C\uB9AC \uD14C\uC774\uBE14 \uBAA9\uB85D\uC744 \uAE30\uBC18\uC73C\uB85C \uC5ED\uACF5\uD559 \uCD94\uB860\uC744 \uC2E4\uD589\uD558\uC5EC \uB17C\uB9AC\uBA85, \uC124\uBA85, \uAD00\uACC4 \uB4F1\uC758 \uC2DC\uBA58\uD2F1 \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.", {
|
|
21942
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21943
|
+
tableNames: external_exports.array(external_exports.string()).optional().describe("\uCD94\uCD9C\uD560 \uBB3C\uB9AC \uD14C\uC774\uBE14\uBA85 \uBAA9\uB85D. \uC0DD\uB7B5 \uC2DC \uC804\uCCB4 \uB2E4\uC774\uC5B4\uADF8\uB7A8 \uB300\uC0C1")
|
|
21944
|
+
}, async ({ diagramId, tableNames }) => {
|
|
21945
|
+
try {
|
|
21946
|
+
const data = await client.getDiagram(diagramId);
|
|
21947
|
+
let entities = data.entities;
|
|
21948
|
+
if (tableNames && tableNames.length > 0) {
|
|
21949
|
+
const tableSet = new Set(tableNames.map((t) => t.toUpperCase()));
|
|
21950
|
+
entities = entities.filter((e) => e.tableName && tableSet.has(e.tableName.toUpperCase()));
|
|
21951
|
+
}
|
|
21952
|
+
const { extractFrequentTokens: extractFrequentTokens2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
21953
|
+
const harvested = extractFrequentTokens2(entities, [], 1);
|
|
21954
|
+
const summary = {
|
|
21955
|
+
extractedSemantics: harvested,
|
|
21956
|
+
relationships: data.relationships.filter((r) => entities.some((e) => e.id === r.sourceEntityId) || entities.some((e) => e.id === r.targetEntityId))
|
|
21957
|
+
};
|
|
21720
21958
|
return {
|
|
21721
|
-
|
|
21722
|
-
|
|
21723
|
-
mimeType: "application/json",
|
|
21959
|
+
content: [{
|
|
21960
|
+
type: "text",
|
|
21724
21961
|
text: JSON.stringify(summary, null, 2)
|
|
21725
21962
|
}]
|
|
21726
21963
|
};
|
|
21964
|
+
} catch (err) {
|
|
21965
|
+
return {
|
|
21966
|
+
content: [{
|
|
21967
|
+
type: "text",
|
|
21968
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21969
|
+
}],
|
|
21970
|
+
isError: true
|
|
21971
|
+
};
|
|
21727
21972
|
}
|
|
21728
|
-
);
|
|
21729
|
-
server.
|
|
21730
|
-
"
|
|
21731
|
-
"
|
|
21732
|
-
|
|
21733
|
-
|
|
21734
|
-
|
|
21735
|
-
|
|
21736
|
-
|
|
21737
|
-
const
|
|
21973
|
+
});
|
|
21974
|
+
server.tool("propose_schema_change", "\uC678\uBD80 AI\uAC00 ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC5D0 \uC2A4\uD0A4\uB9C8 \uBCC0\uACBD\uC744 \uC81C\uC548\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uC790 \uC2B9\uC778\uC774 \uD544\uC694\uD55C Draft\uB85C \uC804\uC1A1\uB429\uB2C8\uB2E4.", {
|
|
21975
|
+
diagramId: external_exports.string().describe("\uB300\uC0C1 \uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21976
|
+
entityName: external_exports.string().describe("\uBCC0\uACBD \uB300\uC0C1 \uC5D4\uD130\uD2F0\uBA85 (\uB17C\uB9AC\uBA85 \uB610\uB294 \uBB3C\uB9AC\uBA85)"),
|
|
21977
|
+
changeType: external_exports.enum(["add_column", "modify_column", "add_entity"]).describe("\uBCC0\uACBD \uC720\uD615"),
|
|
21978
|
+
changeData: external_exports.record(external_exports.unknown()).describe("\uBCC0\uACBD \uB370\uC774\uD130 (JSON). add_column: {name, type, logicalName}, add_entity: {name, tableName, columns}"),
|
|
21979
|
+
reason: external_exports.string().describe("\uBCC0\uACBD \uC0AC\uC720")
|
|
21980
|
+
}, async ({ diagramId, entityName, changeType, changeData, reason }) => {
|
|
21981
|
+
try {
|
|
21982
|
+
const draft = await client.proposeSchemaChange(diagramId, {
|
|
21983
|
+
entityName,
|
|
21984
|
+
changeType,
|
|
21985
|
+
changeData,
|
|
21986
|
+
reason
|
|
21987
|
+
});
|
|
21738
21988
|
return {
|
|
21739
|
-
|
|
21740
|
-
|
|
21741
|
-
|
|
21742
|
-
|
|
21989
|
+
content: [{
|
|
21990
|
+
type: "text",
|
|
21991
|
+
text: `\u2705 \uC2A4\uD0A4\uB9C8 \uBCC0\uACBD \uC81C\uC548\uC774 ThinkERD\uC5D0 \uC804\uC1A1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
21992
|
+
|
|
21993
|
+
Draft ID: ${draft.draft_id}
|
|
21994
|
+
\uC0C1\uD0DC: ${draft.status}
|
|
21995
|
+
\uB300\uC0C1: ${entityName}
|
|
21996
|
+
\uC720\uD615: ${changeType}
|
|
21997
|
+
\uC0AC\uC720: ${reason}
|
|
21998
|
+
|
|
21999
|
+
\u26A0\uFE0F ThinkERD\uC5D0\uC11C \uC0AC\uC6A9\uC790\uAC00 \uC774 \uC81C\uC548\uC744 \uC2B9\uC778\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.`
|
|
21743
22000
|
}]
|
|
21744
22001
|
};
|
|
22002
|
+
} catch (err) {
|
|
22003
|
+
return {
|
|
22004
|
+
content: [{
|
|
22005
|
+
type: "text",
|
|
22006
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22007
|
+
}],
|
|
22008
|
+
isError: true
|
|
22009
|
+
};
|
|
21745
22010
|
}
|
|
21746
|
-
);
|
|
21747
|
-
|
|
21748
|
-
|
|
21749
|
-
|
|
21750
|
-
|
|
21751
|
-
|
|
21752
|
-
|
|
21753
|
-
|
|
21754
|
-
|
|
21755
|
-
|
|
21756
|
-
|
|
21757
|
-
// src/tools.ts
|
|
21758
|
-
function registerTools(server, client) {
|
|
21759
|
-
server.tool(
|
|
21760
|
-
"get_entity",
|
|
21761
|
-
"ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC5D0\uC11C \uD2B9\uC815 \uC5D4\uD130\uD2F0\uC758 \uCEEC\uB7FC, \uD0C0\uC785, PK/FK \uC815\uBCF4\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4.",
|
|
21762
|
-
{
|
|
21763
|
-
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21764
|
-
entityId: external_exports.string().describe("\uC5D4\uD130\uD2F0 ID")
|
|
21765
|
-
},
|
|
21766
|
-
async ({ diagramId, entityId }) => {
|
|
21767
|
-
try {
|
|
21768
|
-
const entity = await client.getEntity(diagramId, entityId);
|
|
21769
|
-
return {
|
|
21770
|
-
content: [{
|
|
21771
|
-
type: "text",
|
|
21772
|
-
text: JSON.stringify(entity, null, 2)
|
|
21773
|
-
}]
|
|
21774
|
-
};
|
|
21775
|
-
} catch (err) {
|
|
21776
|
-
return {
|
|
21777
|
-
content: [{
|
|
21778
|
-
type: "text",
|
|
21779
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21780
|
-
}],
|
|
21781
|
-
isError: true
|
|
21782
|
-
};
|
|
22011
|
+
});
|
|
22012
|
+
server.tool("get_business_dictionary", "\uC0AC\uB0B4 \uD45C\uC900 \uB2E8\uC5B4/\uC6A9\uC5B4 \uC0AC\uC804\uC5D0\uC11C \uD0A4\uC6CC\uB4DC\uB97C \uAC80\uC0C9\uD558\uC5EC \uB17C\uB9AC\uBA85-\uBB3C\uB9AC\uBA85 \uB9E4\uD551 \uAC00\uC774\uB4DC\uB97C \uC81C\uACF5\uD569\uB2C8\uB2E4. \uAC01 \uB2E8\uC5B4\uC758 \uB3D9\uC758\uC5B4(synonyms)\uB3C4 \uD568\uAED8 \uBC18\uD658\uD558\uBBC0\uB85C, \uC0AC\uC6A9\uC790\uAC00 \uC4F4 \uB9D0\uC774 \uC0AC\uB0B4\uC5D0\uC11C \uC5B4\uB5A4 \uD45C\uC900 \uB2E8\uC5B4\uC778\uC9C0 \uB418\uC9DA\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", {
|
|
22013
|
+
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID"),
|
|
22014
|
+
keyword: external_exports.string().optional().describe("\uAC80\uC0C9\uC5B4 (\uC0DD\uB7B5 \uC2DC \uC804\uCCB4 \uC870\uD68C). \uB3D9\uC758\uC5B4\uB85C\uB3C4 \uAC80\uC0C9\uB429\uB2C8\uB2E4")
|
|
22015
|
+
}, async ({ projectId, keyword }) => {
|
|
22016
|
+
try {
|
|
22017
|
+
let dictionary = await client.getDictionary(projectId);
|
|
22018
|
+
if (keyword) {
|
|
22019
|
+
const lowerKeyword = keyword.toLowerCase();
|
|
22020
|
+
dictionary = dictionary.filter((w) => w.logicalName.toLowerCase().includes(lowerKeyword) || w.physicalName.toLowerCase().includes(lowerKeyword) || (w.synonyms ?? []).some((s) => s.toLowerCase().includes(lowerKeyword)) || w.classifier && w.classifier.toLowerCase().includes(lowerKeyword));
|
|
21783
22021
|
}
|
|
22022
|
+
return {
|
|
22023
|
+
content: [{
|
|
22024
|
+
type: "text",
|
|
22025
|
+
text: JSON.stringify(dictionary, null, 2)
|
|
22026
|
+
}]
|
|
22027
|
+
};
|
|
22028
|
+
} catch (err) {
|
|
22029
|
+
return {
|
|
22030
|
+
content: [{
|
|
22031
|
+
type: "text",
|
|
22032
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22033
|
+
}],
|
|
22034
|
+
isError: true
|
|
22035
|
+
};
|
|
21784
22036
|
}
|
|
21785
|
-
);
|
|
21786
|
-
server.tool(
|
|
21787
|
-
"
|
|
21788
|
-
"
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
|
|
21797
|
-
|
|
21798
|
-
|
|
22037
|
+
});
|
|
22038
|
+
server.tool("analyze_legacy_sql", "\uBCF5\uC7A1\uD55C \uB808\uAC70\uC2DC SQL \uCFFC\uB9AC\uB97C \uBD84\uC11D\uD558\uC5EC ERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC5D0 \uAE30\uBC18\uD55C \uD14C\uC774\uBE14\uB4E4\uC758 \uBE44\uC988\uB2C8\uC2A4 \uC758\uBBF8 \uBC0F \uC5F0\uAD00 \uAD00\uACC4\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.", {
|
|
22039
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
22040
|
+
sqlQuery: external_exports.string().describe("\uBD84\uC11D\uD560 \uB300\uC0C1 SQL \uCFFC\uB9AC")
|
|
22041
|
+
}, async ({ diagramId, sqlQuery }) => {
|
|
22042
|
+
try {
|
|
22043
|
+
const data = await client.getDiagram(diagramId);
|
|
22044
|
+
const queryUpper = sqlQuery.toUpperCase();
|
|
22045
|
+
const matchedEntities = data.entities.filter((e) => e.tableName && queryUpper.includes(e.tableName.toUpperCase()));
|
|
22046
|
+
const matchedEntityIds = new Set(matchedEntities.map((e) => e.id));
|
|
22047
|
+
const matchedRelationships = data.relationships.filter((r) => matchedEntityIds.has(r.sourceEntityId) || matchedEntityIds.has(r.targetEntityId));
|
|
22048
|
+
const { extractFrequentTokens: extractFrequentTokens2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
22049
|
+
const harvested = extractFrequentTokens2(matchedEntities, [], 1);
|
|
22050
|
+
const result = {
|
|
22051
|
+
message: "SQL \uB0B4\uC5D0\uC11C \uC2DD\uBCC4\uB41C \uD14C\uC774\uBE14\uC5D0 \uB300\uD55C \uBE44\uC988\uB2C8\uC2A4 \uBD84\uC11D \uACB0\uACFC\uC785\uB2C8\uB2E4.",
|
|
22052
|
+
matchedTables: matchedEntities.map((e) => ({
|
|
21799
22053
|
tableName: e.tableName,
|
|
21800
|
-
|
|
21801
|
-
|
|
21802
|
-
|
|
21803
|
-
|
|
21804
|
-
|
|
21805
|
-
|
|
21806
|
-
|
|
21807
|
-
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
}
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
);
|
|
21821
|
-
server.tool(
|
|
21822
|
-
"generate_ddl",
|
|
21823
|
-
"ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 DDL(CREATE TABLE \uAD6C\uBB38)\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4. PostgreSQL, MySQL, Oracle \uB4F1 \uB2E4\uC591\uD55C \uBC29\uC5B8\uC744 \uC9C0\uC6D0\uD569\uB2C8\uB2E4.",
|
|
21824
|
-
{
|
|
21825
|
-
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21826
|
-
dialect: external_exports.enum(["postgresql", "mysql", "oracle", "mssql", "sqlite"]).optional().default("postgresql").describe("SQL \uBC29\uC5B8 (\uAE30\uBCF8\uAC12: postgresql)")
|
|
21827
|
-
},
|
|
21828
|
-
async ({ diagramId, dialect }) => {
|
|
21829
|
-
try {
|
|
21830
|
-
const ddl = await client.generateDDL(diagramId, dialect);
|
|
21831
|
-
return {
|
|
21832
|
-
content: [{
|
|
21833
|
-
type: "text",
|
|
21834
|
-
text: typeof ddl === "string" ? ddl : JSON.stringify(ddl)
|
|
21835
|
-
}]
|
|
21836
|
-
};
|
|
21837
|
-
} catch (err) {
|
|
21838
|
-
return {
|
|
21839
|
-
content: [{
|
|
21840
|
-
type: "text",
|
|
21841
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21842
|
-
}],
|
|
21843
|
-
isError: true
|
|
21844
|
-
};
|
|
21845
|
-
}
|
|
21846
|
-
}
|
|
21847
|
-
);
|
|
21848
|
-
server.tool(
|
|
21849
|
-
"validate_schema",
|
|
21850
|
-
"ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uC2A4\uD0A4\uB9C8\uB97C \uAC80\uC99D\uD569\uB2C8\uB2E4. \uB204\uB77D\uB41C PK, \uBBF8\uC5F0\uACB0 FK, \uBE44\uD45C\uC900 \uB124\uC774\uBC0D \uB4F1\uC744 \uC810\uAC80\uD569\uB2C8\uB2E4.",
|
|
21851
|
-
{
|
|
21852
|
-
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID")
|
|
21853
|
-
},
|
|
21854
|
-
async ({ diagramId }) => {
|
|
21855
|
-
try {
|
|
21856
|
-
const data = await client.getDiagram(diagramId);
|
|
21857
|
-
const issues = [];
|
|
21858
|
-
for (const entity of data.entities) {
|
|
21859
|
-
const hasPK = entity.columns.some((c) => c.isPrimaryKey);
|
|
21860
|
-
if (!hasPK) {
|
|
21861
|
-
issues.push(`\u26A0\uFE0F [${entity.name}] PK(Primary Key)\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.`);
|
|
21862
|
-
}
|
|
21863
|
-
}
|
|
21864
|
-
for (const entity of data.entities) {
|
|
21865
|
-
if (entity.columns.length === 0) {
|
|
21866
|
-
issues.push(`\u26A0\uFE0F [${entity.name}] \uCEEC\uB7FC\uC774 \uD558\uB098\uB3C4 \uC5C6\uC2B5\uB2C8\uB2E4.`);
|
|
21867
|
-
}
|
|
21868
|
-
}
|
|
21869
|
-
const connectedIds = /* @__PURE__ */ new Set();
|
|
21870
|
-
for (const rel of data.relationships) {
|
|
21871
|
-
connectedIds.add(rel.sourceEntityId);
|
|
21872
|
-
connectedIds.add(rel.targetEntityId);
|
|
21873
|
-
}
|
|
21874
|
-
for (const entity of data.entities) {
|
|
21875
|
-
if (!connectedIds.has(entity.id) && data.entities.length > 1) {
|
|
21876
|
-
issues.push(`\u2139\uFE0F [${entity.name}] \uB2E4\uB978 \uC5D4\uD130\uD2F0\uC640 \uAD00\uACC4\uAC00 \uC5C6\uB294 \uACE0\uB9BD \uC5D4\uD130\uD2F0\uC785\uB2C8\uB2E4.`);
|
|
21877
|
-
}
|
|
21878
|
-
}
|
|
21879
|
-
const summary = issues.length === 0 ? `\u2705 \uC2A4\uD0A4\uB9C8 \uAC80\uC99D \uC644\uB8CC: ${data.entities.length}\uAC1C \uC5D4\uD130\uD2F0, \uBB38\uC81C \uC5C6\uC74C.` : `\u{1F50D} \uC2A4\uD0A4\uB9C8 \uAC80\uC99D \uC644\uB8CC: ${data.entities.length}\uAC1C \uC5D4\uD130\uD2F0, ${issues.length}\uAC1C \uC774\uC288 \uBC1C\uACAC.
|
|
21880
|
-
|
|
21881
|
-
${issues.join("\n")}`;
|
|
21882
|
-
return {
|
|
21883
|
-
content: [{
|
|
21884
|
-
type: "text",
|
|
21885
|
-
text: summary
|
|
21886
|
-
}]
|
|
21887
|
-
};
|
|
21888
|
-
} catch (err) {
|
|
21889
|
-
return {
|
|
21890
|
-
content: [{
|
|
21891
|
-
type: "text",
|
|
21892
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21893
|
-
}],
|
|
21894
|
-
isError: true
|
|
21895
|
-
};
|
|
21896
|
-
}
|
|
21897
|
-
}
|
|
21898
|
-
);
|
|
21899
|
-
server.tool(
|
|
21900
|
-
"harvest_schema_semantics",
|
|
21901
|
-
"ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uBB3C\uB9AC \uD14C\uC774\uBE14 \uBAA9\uB85D\uC744 \uAE30\uBC18\uC73C\uB85C \uC5ED\uACF5\uD559 \uCD94\uB860\uC744 \uC2E4\uD589\uD558\uC5EC \uB17C\uB9AC\uBA85, \uC124\uBA85, \uAD00\uACC4 \uB4F1\uC758 \uC2DC\uBA58\uD2F1 \uBA54\uD0C0\uB370\uC774\uD130\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4.",
|
|
21902
|
-
{
|
|
21903
|
-
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21904
|
-
tableNames: external_exports.array(external_exports.string()).optional().describe("\uCD94\uCD9C\uD560 \uBB3C\uB9AC \uD14C\uC774\uBE14\uBA85 \uBAA9\uB85D. \uC0DD\uB7B5 \uC2DC \uC804\uCCB4 \uB2E4\uC774\uC5B4\uADF8\uB7A8 \uB300\uC0C1")
|
|
21905
|
-
},
|
|
21906
|
-
async ({ diagramId, tableNames }) => {
|
|
21907
|
-
try {
|
|
21908
|
-
const data = await client.getDiagram(diagramId);
|
|
21909
|
-
let entities = data.entities;
|
|
21910
|
-
if (tableNames && tableNames.length > 0) {
|
|
21911
|
-
const tableSet = new Set(tableNames.map((t) => t.toUpperCase()));
|
|
21912
|
-
entities = entities.filter((e) => e.tableName && tableSet.has(e.tableName.toUpperCase()));
|
|
21913
|
-
}
|
|
21914
|
-
const { extractFrequentTokens: extractFrequentTokens2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
21915
|
-
const harvested = extractFrequentTokens2(entities, [], 1);
|
|
21916
|
-
const summary = {
|
|
21917
|
-
extractedSemantics: harvested,
|
|
21918
|
-
relationships: data.relationships.filter(
|
|
21919
|
-
(r) => entities.some((e) => e.id === r.sourceEntityId) || entities.some((e) => e.id === r.targetEntityId)
|
|
21920
|
-
)
|
|
21921
|
-
};
|
|
21922
|
-
return {
|
|
21923
|
-
content: [{
|
|
21924
|
-
type: "text",
|
|
21925
|
-
text: JSON.stringify(summary, null, 2)
|
|
21926
|
-
}]
|
|
21927
|
-
};
|
|
21928
|
-
} catch (err) {
|
|
21929
|
-
return {
|
|
21930
|
-
content: [{
|
|
21931
|
-
type: "text",
|
|
21932
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21933
|
-
}],
|
|
21934
|
-
isError: true
|
|
21935
|
-
};
|
|
21936
|
-
}
|
|
21937
|
-
}
|
|
21938
|
-
);
|
|
21939
|
-
server.tool(
|
|
21940
|
-
"propose_schema_change",
|
|
21941
|
-
"\uC678\uBD80 AI\uAC00 ThinkERD \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC5D0 \uC2A4\uD0A4\uB9C8 \uBCC0\uACBD\uC744 \uC81C\uC548\uD569\uB2C8\uB2E4. \uC0AC\uC6A9\uC790 \uC2B9\uC778\uC774 \uD544\uC694\uD55C Draft\uB85C \uC804\uC1A1\uB429\uB2C8\uB2E4.",
|
|
21942
|
-
{
|
|
21943
|
-
diagramId: external_exports.string().describe("\uB300\uC0C1 \uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
21944
|
-
entityName: external_exports.string().describe("\uBCC0\uACBD \uB300\uC0C1 \uC5D4\uD130\uD2F0\uBA85 (\uB17C\uB9AC\uBA85 \uB610\uB294 \uBB3C\uB9AC\uBA85)"),
|
|
21945
|
-
changeType: external_exports.enum(["add_column", "modify_column", "add_entity"]).describe("\uBCC0\uACBD \uC720\uD615"),
|
|
21946
|
-
changeData: external_exports.record(external_exports.unknown()).describe("\uBCC0\uACBD \uB370\uC774\uD130 (JSON). add_column: {name, type, logicalName}, add_entity: {name, tableName, columns}"),
|
|
21947
|
-
reason: external_exports.string().describe("\uBCC0\uACBD \uC0AC\uC720")
|
|
21948
|
-
},
|
|
21949
|
-
async ({ diagramId, entityName, changeType, changeData, reason }) => {
|
|
21950
|
-
try {
|
|
21951
|
-
const draft = await client.proposeSchemaChange(diagramId, {
|
|
21952
|
-
entityName,
|
|
21953
|
-
changeType,
|
|
21954
|
-
changeData,
|
|
21955
|
-
reason
|
|
21956
|
-
});
|
|
21957
|
-
return {
|
|
21958
|
-
content: [{
|
|
21959
|
-
type: "text",
|
|
21960
|
-
text: `\u2705 \uC2A4\uD0A4\uB9C8 \uBCC0\uACBD \uC81C\uC548\uC774 ThinkERD\uC5D0 \uC804\uC1A1\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
21961
|
-
|
|
21962
|
-
Draft ID: ${draft.draft_id}
|
|
21963
|
-
\uC0C1\uD0DC: ${draft.status}
|
|
21964
|
-
\uB300\uC0C1: ${entityName}
|
|
21965
|
-
\uC720\uD615: ${changeType}
|
|
21966
|
-
\uC0AC\uC720: ${reason}
|
|
21967
|
-
|
|
21968
|
-
\u26A0\uFE0F ThinkERD\uC5D0\uC11C \uC0AC\uC6A9\uC790\uAC00 \uC774 \uC81C\uC548\uC744 \uC2B9\uC778\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.`
|
|
21969
|
-
}]
|
|
21970
|
-
};
|
|
21971
|
-
} catch (err) {
|
|
21972
|
-
return {
|
|
21973
|
-
content: [{
|
|
21974
|
-
type: "text",
|
|
21975
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
21976
|
-
}],
|
|
21977
|
-
isError: true
|
|
21978
|
-
};
|
|
21979
|
-
}
|
|
21980
|
-
}
|
|
21981
|
-
);
|
|
21982
|
-
server.tool(
|
|
21983
|
-
"get_business_dictionary",
|
|
21984
|
-
"\uC0AC\uB0B4 \uD45C\uC900 \uB2E8\uC5B4/\uC6A9\uC5B4 \uC0AC\uC804\uC5D0\uC11C \uD0A4\uC6CC\uB4DC\uB97C \uAC80\uC0C9\uD558\uC5EC \uB17C\uB9AC\uBA85-\uBB3C\uB9AC\uBA85 \uB9E4\uD551 \uAC00\uC774\uB4DC\uB97C \uC81C\uACF5\uD569\uB2C8\uB2E4. \uAC01 \uB2E8\uC5B4\uC758 \uB3D9\uC758\uC5B4(synonyms)\uB3C4 \uD568\uAED8 \uBC18\uD658\uD558\uBBC0\uB85C, \uC0AC\uC6A9\uC790\uAC00 \uC4F4 \uB9D0\uC774 \uC0AC\uB0B4\uC5D0\uC11C \uC5B4\uB5A4 \uD45C\uC900 \uB2E8\uC5B4\uC778\uC9C0 \uB418\uC9DA\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
|
|
21985
|
-
{
|
|
21986
|
-
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID"),
|
|
21987
|
-
keyword: external_exports.string().optional().describe("\uAC80\uC0C9\uC5B4 (\uC0DD\uB7B5 \uC2DC \uC804\uCCB4 \uC870\uD68C). \uB3D9\uC758\uC5B4\uB85C\uB3C4 \uAC80\uC0C9\uB429\uB2C8\uB2E4")
|
|
21988
|
-
},
|
|
21989
|
-
async ({ projectId, keyword }) => {
|
|
21990
|
-
try {
|
|
21991
|
-
let dictionary = await client.getDictionary(projectId);
|
|
21992
|
-
if (keyword) {
|
|
21993
|
-
const lowerKeyword = keyword.toLowerCase();
|
|
21994
|
-
dictionary = dictionary.filter(
|
|
21995
|
-
(w) => w.logicalName.toLowerCase().includes(lowerKeyword) || w.physicalName.toLowerCase().includes(lowerKeyword) || (w.synonyms ?? []).some((s) => s.toLowerCase().includes(lowerKeyword)) || w.classifier && w.classifier.toLowerCase().includes(lowerKeyword)
|
|
21996
|
-
);
|
|
21997
|
-
}
|
|
21998
|
-
return {
|
|
21999
|
-
content: [{
|
|
22000
|
-
type: "text",
|
|
22001
|
-
text: JSON.stringify(dictionary, null, 2)
|
|
22002
|
-
}]
|
|
22003
|
-
};
|
|
22004
|
-
} catch (err) {
|
|
22005
|
-
return {
|
|
22006
|
-
content: [{
|
|
22007
|
-
type: "text",
|
|
22008
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22009
|
-
}],
|
|
22010
|
-
isError: true
|
|
22011
|
-
};
|
|
22012
|
-
}
|
|
22054
|
+
logicalName: e.logicalName,
|
|
22055
|
+
description: e.columns.map((c) => `${c.name}(${c.type}) ${c.logicalName || ""}`).join(", ")
|
|
22056
|
+
})),
|
|
22057
|
+
semanticHarvest: harvested,
|
|
22058
|
+
relevantRelationships: matchedRelationships
|
|
22059
|
+
};
|
|
22060
|
+
return {
|
|
22061
|
+
content: [{
|
|
22062
|
+
type: "text",
|
|
22063
|
+
text: JSON.stringify(result, null, 2)
|
|
22064
|
+
}]
|
|
22065
|
+
};
|
|
22066
|
+
} catch (err) {
|
|
22067
|
+
return {
|
|
22068
|
+
content: [{
|
|
22069
|
+
type: "text",
|
|
22070
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22071
|
+
}],
|
|
22072
|
+
isError: true
|
|
22073
|
+
};
|
|
22013
22074
|
}
|
|
22014
|
-
);
|
|
22015
|
-
server.tool(
|
|
22016
|
-
"
|
|
22017
|
-
"\
|
|
22018
|
-
|
|
22019
|
-
|
|
22020
|
-
|
|
22021
|
-
|
|
22022
|
-
|
|
22023
|
-
|
|
22024
|
-
|
|
22025
|
-
|
|
22026
|
-
|
|
22027
|
-
|
|
22028
|
-
)
|
|
22029
|
-
|
|
22030
|
-
|
|
22031
|
-
|
|
22032
|
-
);
|
|
22033
|
-
const { extractFrequentTokens: extractFrequentTokens2 } = await Promise.resolve().then(() => (init_src(), src_exports));
|
|
22034
|
-
const harvested = extractFrequentTokens2(matchedEntities, [], 1);
|
|
22035
|
-
const result = {
|
|
22036
|
-
message: "SQL \uB0B4\uC5D0\uC11C \uC2DD\uBCC4\uB41C \uD14C\uC774\uBE14\uC5D0 \uB300\uD55C \uBE44\uC988\uB2C8\uC2A4 \uBD84\uC11D \uACB0\uACFC\uC785\uB2C8\uB2E4.",
|
|
22037
|
-
matchedTables: matchedEntities.map((e) => ({
|
|
22075
|
+
});
|
|
22076
|
+
server.tool("semantic_search", "\uBE44\uC988\uB2C8\uC2A4 \uC6A9\uC5B4(\uC790\uC5F0\uC5B4)\uB85C \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uC5D4\uD130\uD2F0\xB7\uCEEC\uB7FC\uC744 \uAC80\uC0C9\uD569\uB2C8\uB2E4. \uB3D9\uC758\uC5B4, \uC124\uBA85, \uB17C\uB9AC\uBA85\uC744 \uBAA8\uB450 \uD65C\uC6A9\uD558\uC5EC \uB9E4\uCE6D\uD558\uBA70, \uB9E4\uCE6D \uC720\uD615(\uB17C\uB9AC\uBA85/\uB3D9\uC758\uC5B4/\uC124\uBA85/\uBD80\uBD84\uB9E4\uCE6D/\uCEEC\uB7FC)\uC744 \uD568\uAED8 \uBC18\uD658\uD569\uB2C8\uB2E4.", {
|
|
22077
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
22078
|
+
query: external_exports.string().describe("\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC (\uBE44\uC988\uB2C8\uC2A4 \uC6A9\uC5B4, \uB17C\uB9AC\uBA85, \uB3D9\uC758\uC5B4 \uB4F1)"),
|
|
22079
|
+
maxResults: external_exports.number().optional().describe("\uCD5C\uB300 \uACB0\uACFC \uC218 (\uAE30\uBCF8 10)")
|
|
22080
|
+
}, async ({ diagramId, query, maxResults }) => {
|
|
22081
|
+
try {
|
|
22082
|
+
const data = await client.getDiagram(diagramId);
|
|
22083
|
+
const entities = data.entities || [];
|
|
22084
|
+
const limit = maxResults || 10;
|
|
22085
|
+
const q = query.toLowerCase();
|
|
22086
|
+
const results = [];
|
|
22087
|
+
for (const entity of entities) {
|
|
22088
|
+
const e = entity;
|
|
22089
|
+
if (e.name?.toLowerCase().includes(q) || e.logicalName?.toLowerCase().includes(q)) {
|
|
22090
|
+
results.push({
|
|
22091
|
+
entityId: e.id,
|
|
22092
|
+
entityName: e.name,
|
|
22038
22093
|
tableName: e.tableName,
|
|
22039
|
-
|
|
22040
|
-
|
|
22041
|
-
|
|
22042
|
-
|
|
22043
|
-
|
|
22044
|
-
}
|
|
22045
|
-
|
|
22046
|
-
|
|
22047
|
-
|
|
22048
|
-
text: JSON.stringify(result, null, 2)
|
|
22049
|
-
}]
|
|
22050
|
-
};
|
|
22051
|
-
} catch (err) {
|
|
22052
|
-
return {
|
|
22053
|
-
content: [{
|
|
22054
|
-
type: "text",
|
|
22055
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22056
|
-
}],
|
|
22057
|
-
isError: true
|
|
22058
|
-
};
|
|
22059
|
-
}
|
|
22060
|
-
}
|
|
22061
|
-
);
|
|
22062
|
-
server.tool(
|
|
22063
|
-
"semantic_search",
|
|
22064
|
-
"\uBE44\uC988\uB2C8\uC2A4 \uC6A9\uC5B4(\uC790\uC5F0\uC5B4)\uB85C \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uC5D4\uD130\uD2F0\xB7\uCEEC\uB7FC\uC744 \uAC80\uC0C9\uD569\uB2C8\uB2E4. \uB3D9\uC758\uC5B4, \uC124\uBA85, \uB17C\uB9AC\uBA85\uC744 \uBAA8\uB450 \uD65C\uC6A9\uD558\uC5EC \uB9E4\uCE6D\uD558\uBA70, \uB9E4\uCE6D \uC720\uD615(\uB17C\uB9AC\uBA85/\uB3D9\uC758\uC5B4/\uC124\uBA85/\uBD80\uBD84\uB9E4\uCE6D/\uCEEC\uB7FC)\uC744 \uD568\uAED8 \uBC18\uD658\uD569\uB2C8\uB2E4.",
|
|
22065
|
-
{
|
|
22066
|
-
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
22067
|
-
query: external_exports.string().describe("\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC (\uBE44\uC988\uB2C8\uC2A4 \uC6A9\uC5B4, \uB17C\uB9AC\uBA85, \uB3D9\uC758\uC5B4 \uB4F1)"),
|
|
22068
|
-
maxResults: external_exports.number().optional().describe("\uCD5C\uB300 \uACB0\uACFC \uC218 (\uAE30\uBCF8 10)")
|
|
22069
|
-
},
|
|
22070
|
-
async ({ diagramId, query, maxResults }) => {
|
|
22071
|
-
try {
|
|
22072
|
-
const data = await client.getDiagram(diagramId);
|
|
22073
|
-
const entities = data.entities || [];
|
|
22074
|
-
const limit = maxResults || 10;
|
|
22075
|
-
const q = query.toLowerCase();
|
|
22076
|
-
const results = [];
|
|
22077
|
-
for (const entity of entities) {
|
|
22078
|
-
const e = entity;
|
|
22079
|
-
if (e.name?.toLowerCase().includes(q) || e.logicalName?.toLowerCase().includes(q)) {
|
|
22094
|
+
matchType: "logicalName",
|
|
22095
|
+
matchedOn: e.name || e.logicalName,
|
|
22096
|
+
description: e.description || null
|
|
22097
|
+
});
|
|
22098
|
+
continue;
|
|
22099
|
+
}
|
|
22100
|
+
if (Array.isArray(e.synonyms)) {
|
|
22101
|
+
const syn = e.synonyms.find((s) => s.toLowerCase().includes(q));
|
|
22102
|
+
if (syn) {
|
|
22080
22103
|
results.push({
|
|
22081
22104
|
entityId: e.id,
|
|
22082
22105
|
entityName: e.name,
|
|
22083
22106
|
tableName: e.tableName,
|
|
22084
|
-
matchType: "
|
|
22085
|
-
matchedOn:
|
|
22107
|
+
matchType: "synonym",
|
|
22108
|
+
matchedOn: syn,
|
|
22086
22109
|
description: e.description || null
|
|
22087
22110
|
});
|
|
22088
22111
|
continue;
|
|
22089
22112
|
}
|
|
22090
|
-
|
|
22091
|
-
|
|
22092
|
-
|
|
22093
|
-
|
|
22094
|
-
|
|
22095
|
-
|
|
22096
|
-
|
|
22097
|
-
|
|
22098
|
-
|
|
22099
|
-
|
|
22100
|
-
|
|
22101
|
-
|
|
22102
|
-
|
|
22103
|
-
|
|
22104
|
-
if (e.description?.toLowerCase().includes(q)) {
|
|
22113
|
+
}
|
|
22114
|
+
if (e.description?.toLowerCase().includes(q)) {
|
|
22115
|
+
results.push({
|
|
22116
|
+
entityId: e.id,
|
|
22117
|
+
entityName: e.name,
|
|
22118
|
+
tableName: e.tableName,
|
|
22119
|
+
matchType: "description",
|
|
22120
|
+
matchedOn: e.description
|
|
22121
|
+
});
|
|
22122
|
+
continue;
|
|
22123
|
+
}
|
|
22124
|
+
for (const col of entity.columns) {
|
|
22125
|
+
const c = col;
|
|
22126
|
+
if (c.logicalName?.toLowerCase().includes(q) || c.name?.toLowerCase().includes(q) || c.description?.toLowerCase().includes(q)) {
|
|
22105
22127
|
results.push({
|
|
22106
22128
|
entityId: e.id,
|
|
22107
22129
|
entityName: e.name,
|
|
22108
22130
|
tableName: e.tableName,
|
|
22109
|
-
matchType: "
|
|
22110
|
-
|
|
22131
|
+
matchType: "column",
|
|
22132
|
+
matchedColumn: c.name,
|
|
22133
|
+
matchedColumnLogical: c.logicalName
|
|
22111
22134
|
});
|
|
22112
|
-
|
|
22113
|
-
}
|
|
22114
|
-
for (const col of entity.columns) {
|
|
22115
|
-
const c = col;
|
|
22116
|
-
if (c.logicalName?.toLowerCase().includes(q) || c.name?.toLowerCase().includes(q) || c.description?.toLowerCase().includes(q)) {
|
|
22117
|
-
results.push({
|
|
22118
|
-
entityId: e.id,
|
|
22119
|
-
entityName: e.name,
|
|
22120
|
-
tableName: e.tableName,
|
|
22121
|
-
matchType: "column",
|
|
22122
|
-
matchedColumn: c.name,
|
|
22123
|
-
matchedColumnLogical: c.logicalName
|
|
22124
|
-
});
|
|
22125
|
-
break;
|
|
22126
|
-
}
|
|
22135
|
+
break;
|
|
22127
22136
|
}
|
|
22128
22137
|
}
|
|
22129
|
-
return {
|
|
22130
|
-
content: [{
|
|
22131
|
-
type: "text",
|
|
22132
|
-
text: JSON.stringify({
|
|
22133
|
-
query,
|
|
22134
|
-
totalResults: results.length,
|
|
22135
|
-
results: results.slice(0, limit)
|
|
22136
|
-
}, null, 2)
|
|
22137
|
-
}]
|
|
22138
|
-
};
|
|
22139
|
-
} catch (err) {
|
|
22140
|
-
return {
|
|
22141
|
-
content: [{
|
|
22142
|
-
type: "text",
|
|
22143
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22144
|
-
}],
|
|
22145
|
-
isError: true
|
|
22146
|
-
};
|
|
22147
22138
|
}
|
|
22139
|
+
return {
|
|
22140
|
+
content: [{
|
|
22141
|
+
type: "text",
|
|
22142
|
+
text: JSON.stringify({
|
|
22143
|
+
query,
|
|
22144
|
+
totalResults: results.length,
|
|
22145
|
+
results: results.slice(0, limit)
|
|
22146
|
+
}, null, 2)
|
|
22147
|
+
}]
|
|
22148
|
+
};
|
|
22149
|
+
} catch (err) {
|
|
22150
|
+
return {
|
|
22151
|
+
content: [{
|
|
22152
|
+
type: "text",
|
|
22153
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22154
|
+
}],
|
|
22155
|
+
isError: true
|
|
22156
|
+
};
|
|
22148
22157
|
}
|
|
22149
|
-
);
|
|
22150
|
-
server.tool(
|
|
22151
|
-
"
|
|
22152
|
-
"\
|
|
22153
|
-
|
|
22154
|
-
|
|
22155
|
-
|
|
22156
|
-
|
|
22157
|
-
|
|
22158
|
-
|
|
22159
|
-
|
|
22160
|
-
|
|
22161
|
-
|
|
22162
|
-
|
|
22163
|
-
|
|
22164
|
-
|
|
22165
|
-
|
|
22166
|
-
|
|
22167
|
-
|
|
22168
|
-
|
|
22169
|
-
|
|
22170
|
-
|
|
22171
|
-
|
|
22172
|
-
|
|
22173
|
-
|
|
22174
|
-
|
|
22175
|
-
|
|
22158
|
+
});
|
|
22159
|
+
server.tool("get_business_context", "\uD2B9\uC815 \uC5D4\uD130\uD2F0\uC758 \uBE44\uC988\uB2C8\uC2A4 \uC758\uBBF8, \uB3D9\uC758\uC5B4, \uCF54\uB4DC\uAC12, \uAD00\uACC4\uB97C \uD3EC\uD568\uD55C \uC804\uCCB4 \uBE44\uC988\uB2C8\uC2A4 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uC870\uD68C\uD569\uB2C8\uB2E4. Text-to-SQL\uC774\uB098 \uBB38\uC11C \uC0DD\uC131\uC758 \uCC38\uACE0\uC790\uB8CC\uB85C \uD65C\uC6A9\uB429\uB2C8\uB2E4.", {
|
|
22160
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
22161
|
+
entityId: external_exports.string().describe("\uC5D4\uD130\uD2F0 ID")
|
|
22162
|
+
}, async ({ diagramId, entityId }) => {
|
|
22163
|
+
try {
|
|
22164
|
+
const entity = await client.getEntity(diagramId, entityId);
|
|
22165
|
+
const data = await client.getDiagram(diagramId);
|
|
22166
|
+
const e = entity;
|
|
22167
|
+
const relationships = (data.relationships || []).filter((r) => r.sourceEntityId === entityId || r.targetEntityId === entityId);
|
|
22168
|
+
const businessContext = {
|
|
22169
|
+
entity: {
|
|
22170
|
+
id: e.id,
|
|
22171
|
+
name: e.name,
|
|
22172
|
+
tableName: e.tableName,
|
|
22173
|
+
logicalName: e.logicalName || e.name,
|
|
22174
|
+
description: e.description || null,
|
|
22175
|
+
synonyms: e.synonyms || [],
|
|
22176
|
+
entityRole: e.entityRole || null
|
|
22177
|
+
},
|
|
22178
|
+
columns: entity.columns.map((c) => ({
|
|
22179
|
+
name: c.name,
|
|
22180
|
+
logicalName: c.logicalName || null,
|
|
22181
|
+
type: c.type,
|
|
22182
|
+
isPrimaryKey: c.isPrimaryKey || false,
|
|
22183
|
+
isForeignKey: c.isForeignKey || false,
|
|
22184
|
+
description: c.description || null,
|
|
22185
|
+
domainValues: c.domainValues || null
|
|
22186
|
+
})),
|
|
22187
|
+
relationships: relationships.map((r) => ({
|
|
22188
|
+
relatedEntity: r.sourceEntityId === entityId ? r.targetEntityName : r.sourceEntityName,
|
|
22189
|
+
direction: r.sourceEntityId === entityId ? "outgoing" : "incoming",
|
|
22190
|
+
type: r.type,
|
|
22191
|
+
cardinality: `${r.sourceCardinality}:${r.targetCardinality}`
|
|
22192
|
+
}))
|
|
22193
|
+
};
|
|
22194
|
+
return {
|
|
22195
|
+
content: [{
|
|
22196
|
+
type: "text",
|
|
22197
|
+
text: JSON.stringify(businessContext, null, 2)
|
|
22198
|
+
}]
|
|
22199
|
+
};
|
|
22200
|
+
} catch (err) {
|
|
22201
|
+
return {
|
|
22202
|
+
content: [{
|
|
22203
|
+
type: "text",
|
|
22204
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22205
|
+
}],
|
|
22206
|
+
isError: true
|
|
22207
|
+
};
|
|
22208
|
+
}
|
|
22209
|
+
});
|
|
22210
|
+
server.tool("generate_sql", '**\uD55C \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC758 \uBB3C\uB9AC \uC2A4\uD0A4\uB9C8\uB9CC** \uBCF4\uACE0 SQL \uC791\uC131\uC6A9 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uBC18\uD658\uD569\uB2C8\uB2E4. \u26A0\uFE0F \uC774 \uB3C4\uAD6C\uB294 \uD504\uB85C\uC81D\uD2B8 \uC804\uC5ED \uC758\uBBF8 \uACC4\uCE35(\uBE44\uC988\uB2C8\uC2A4 \uBAA8\uB378 \uBC1C\uD589\uBCF8\xB7\uD45C\uC900 \uC0AC\uC804 \uB3D9\uC758\uC5B4\xB7\uC628\uD1A8\uB85C\uC9C0)\uC744 **\uBCF4\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.** \uC5C5\uBB34 \uC6A9\uC5B4("\uACE0\uAC1D", "\uBC30\uC1A1\uC911\uC778 \uC8FC\uBB38")\uAC00 \uC11E\uC778 \uC9C8\uBB38\uC774\uB77C\uBA74 **`get_project_context`\uB97C \uBA3C\uC800 \uD638\uCD9C\uD558\uC2ED\uC2DC\uC624.** \uC774 \uB3C4\uAD6C\uB294 \uB300\uC0C1 \uB2E4\uC774\uC5B4\uADF8\uB7A8\uC774 \uC774\uBBF8 \uD2B9\uC815\uB418\uC5B4 \uC788\uACE0 \uBB3C\uB9AC \uCEEC\uB7FC \uAD6C\uC870\uB9CC \uD544\uC694\uD560 \uB54C \uC4F0\uC2ED\uC2DC\uC624.', {
|
|
22211
|
+
diagramId: external_exports.string().describe("\uB2E4\uC774\uC5B4\uADF8\uB7A8 ID"),
|
|
22212
|
+
question: external_exports.string().describe('\uC790\uC5F0\uC5B4 \uC9C8\uBB38 (\uC608: "\uBD80\uC11C\uBCC4 \uD3C9\uADE0 \uAE09\uC5EC\uAC00 5\uCC9C\uB9CC\uC6D0 \uC774\uC0C1\uC778 \uBD80\uC11C")'),
|
|
22213
|
+
dialect: external_exports.string().optional().describe("SQL \uBC29\uC5B8 (postgresql, mysql, oracle, mssql). \uAE30\uBCF8: postgresql")
|
|
22214
|
+
}, async ({ diagramId, question, dialect }) => {
|
|
22215
|
+
try {
|
|
22216
|
+
const data = await client.getDiagram(diagramId);
|
|
22217
|
+
const entities = data.entities || [];
|
|
22218
|
+
const relationships = data.relationships || [];
|
|
22219
|
+
const schemaContext = entities.map((e) => {
|
|
22220
|
+
const ea = e;
|
|
22221
|
+
return {
|
|
22222
|
+
tableName: e.tableName,
|
|
22223
|
+
logicalName: e.name || ea.logicalName,
|
|
22224
|
+
description: ea.description || null,
|
|
22225
|
+
synonyms: ea.synonyms || [],
|
|
22226
|
+
columns: e.columns.map((c) => ({
|
|
22176
22227
|
name: c.name,
|
|
22177
22228
|
logicalName: c.logicalName || null,
|
|
22178
22229
|
type: c.type,
|
|
22179
22230
|
isPrimaryKey: c.isPrimaryKey || false,
|
|
22180
22231
|
isForeignKey: c.isForeignKey || false,
|
|
22181
|
-
description: c.description || null,
|
|
22182
22232
|
domainValues: c.domainValues || null
|
|
22183
|
-
})),
|
|
22184
|
-
relationships: relationships.map((r) => ({
|
|
22185
|
-
relatedEntity: r.sourceEntityId === entityId ? r.targetEntityName : r.sourceEntityName,
|
|
22186
|
-
direction: r.sourceEntityId === entityId ? "outgoing" : "incoming",
|
|
22187
|
-
type: r.type,
|
|
22188
|
-
cardinality: `${r.sourceCardinality}:${r.targetCardinality}`
|
|
22189
22233
|
}))
|
|
22190
22234
|
};
|
|
22191
|
-
|
|
22192
|
-
|
|
22193
|
-
|
|
22194
|
-
|
|
22195
|
-
|
|
22196
|
-
|
|
22197
|
-
|
|
22198
|
-
|
|
22199
|
-
|
|
22200
|
-
|
|
22201
|
-
|
|
22202
|
-
|
|
22203
|
-
|
|
22204
|
-
|
|
22205
|
-
|
|
22206
|
-
|
|
22207
|
-
|
|
22208
|
-
|
|
22209
|
-
|
|
22210
|
-
|
|
22211
|
-
|
|
22212
|
-
|
|
22213
|
-
|
|
22214
|
-
|
|
22215
|
-
|
|
22216
|
-
|
|
22217
|
-
|
|
22218
|
-
const data = await client.getDiagram(diagramId);
|
|
22219
|
-
const entities = data.entities || [];
|
|
22220
|
-
const relationships = data.relationships || [];
|
|
22221
|
-
const schemaContext = entities.map((e) => {
|
|
22222
|
-
const ea = e;
|
|
22223
|
-
return {
|
|
22224
|
-
tableName: e.tableName,
|
|
22225
|
-
logicalName: e.name || ea.logicalName,
|
|
22226
|
-
description: ea.description || null,
|
|
22227
|
-
synonyms: ea.synonyms || [],
|
|
22228
|
-
columns: e.columns.map((c) => ({
|
|
22229
|
-
name: c.name,
|
|
22230
|
-
logicalName: c.logicalName || null,
|
|
22231
|
-
type: c.type,
|
|
22232
|
-
isPrimaryKey: c.isPrimaryKey || false,
|
|
22233
|
-
isForeignKey: c.isForeignKey || false,
|
|
22234
|
-
domainValues: c.domainValues || null
|
|
22235
|
-
}))
|
|
22236
|
-
};
|
|
22237
|
-
});
|
|
22238
|
-
const relationshipContext = relationships.map((r) => ({
|
|
22239
|
-
from: `${r.sourceEntityName} (${r.sourceEntityId})`,
|
|
22240
|
-
to: `${r.targetEntityName} (${r.targetEntityId})`,
|
|
22241
|
-
type: r.type
|
|
22242
|
-
}));
|
|
22243
|
-
const result = {
|
|
22244
|
-
question,
|
|
22245
|
-
dialect: dialect || "postgresql",
|
|
22246
|
-
schemaContext,
|
|
22247
|
-
relationshipContext,
|
|
22248
|
-
hint: `\uC704 \uC2A4\uD0A4\uB9C8 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uAE30\uBC18\uC73C\uB85C "${question}"\uC5D0 \uB300\uD55C ${dialect || "postgresql"} SQL\uC744 \uC0DD\uC131\uD558\uC138\uC694. tableName\uC744 \uD14C\uC774\uBE14 \uCC38\uC870\uC5D0, columns[].name\uC744 \uCEEC\uB7FC \uCC38\uC870\uC5D0 \uC0AC\uC6A9\uD558\uC138\uC694. \uB3D9\uC758\uC5B4(synonyms)\uC640 \uCF54\uB4DC\uAC12(domainValues)\uC744 \uD65C\uC6A9\uD558\uC5EC \uC815\uD655\uD55C \uB9E4\uD551\uC744 \uC218\uD589\uD558\uC138\uC694.`
|
|
22249
|
-
};
|
|
22250
|
-
return {
|
|
22251
|
-
content: [{
|
|
22252
|
-
type: "text",
|
|
22253
|
-
text: JSON.stringify(result, null, 2)
|
|
22254
|
-
}]
|
|
22255
|
-
};
|
|
22256
|
-
} catch (err) {
|
|
22257
|
-
return {
|
|
22258
|
-
content: [{
|
|
22259
|
-
type: "text",
|
|
22260
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22261
|
-
}],
|
|
22262
|
-
isError: true
|
|
22263
|
-
};
|
|
22264
|
-
}
|
|
22235
|
+
});
|
|
22236
|
+
const relationshipContext = relationships.map((r) => ({
|
|
22237
|
+
from: `${r.sourceEntityName} (${r.sourceEntityId})`,
|
|
22238
|
+
to: `${r.targetEntityName} (${r.targetEntityId})`,
|
|
22239
|
+
type: r.type
|
|
22240
|
+
}));
|
|
22241
|
+
const result = {
|
|
22242
|
+
question,
|
|
22243
|
+
dialect: dialect || "postgresql",
|
|
22244
|
+
schemaContext,
|
|
22245
|
+
relationshipContext,
|
|
22246
|
+
hint: `\uC704 \uC2A4\uD0A4\uB9C8 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uAE30\uBC18\uC73C\uB85C "${question}"\uC5D0 \uB300\uD55C ${dialect || "postgresql"} SQL\uC744 \uC0DD\uC131\uD558\uC138\uC694. tableName\uC744 \uD14C\uC774\uBE14 \uCC38\uC870\uC5D0, columns[].name\uC744 \uCEEC\uB7FC \uCC38\uC870\uC5D0 \uC0AC\uC6A9\uD558\uC138\uC694. \uB3D9\uC758\uC5B4(synonyms)\uC640 \uCF54\uB4DC\uAC12(domainValues)\uC744 \uD65C\uC6A9\uD558\uC5EC \uC815\uD655\uD55C \uB9E4\uD551\uC744 \uC218\uD589\uD558\uC138\uC694.`
|
|
22247
|
+
};
|
|
22248
|
+
return {
|
|
22249
|
+
content: [{
|
|
22250
|
+
type: "text",
|
|
22251
|
+
text: JSON.stringify(result, null, 2)
|
|
22252
|
+
}]
|
|
22253
|
+
};
|
|
22254
|
+
} catch (err) {
|
|
22255
|
+
return {
|
|
22256
|
+
content: [{
|
|
22257
|
+
type: "text",
|
|
22258
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22259
|
+
}],
|
|
22260
|
+
isError: true
|
|
22261
|
+
};
|
|
22265
22262
|
}
|
|
22266
|
-
);
|
|
22267
|
-
server.tool(
|
|
22268
|
-
"
|
|
22269
|
-
'
|
|
22270
|
-
|
|
22271
|
-
|
|
22272
|
-
|
|
22273
|
-
|
|
22274
|
-
|
|
22275
|
-
|
|
22276
|
-
|
|
22277
|
-
|
|
22278
|
-
|
|
22279
|
-
|
|
22280
|
-
|
|
22281
|
-
|
|
22282
|
-
|
|
22283
|
-
|
|
22284
|
-
|
|
22285
|
-
|
|
22286
|
-
|
|
22287
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22288
|
-
}],
|
|
22289
|
-
isError: true
|
|
22290
|
-
};
|
|
22291
|
-
}
|
|
22263
|
+
});
|
|
22264
|
+
server.tool("get_project_context", '**\uC5C5\uBB34 \uC6A9\uC5B4\uAC00 \uC11E\uC778 \uC9C8\uBB38\uC5D0\uB294 \uC774 \uB3C4\uAD6C\uB97C \uBA3C\uC800 \uC4F0\uC2ED\uC2DC\uC624.** \uC790\uC5F0\uC5B4 \uC9C8\uBB38\uC73C\uB85C \uD504\uB85C\uC81D\uD2B8 \uC804\uCCB4\uC5D0\uC11C \uAD00\uB828 \uC5D4\uD130\uD2F0\uB97C \uC2DC\uBA58\uD2F1 \uAC80\uC0C9(Graph RAG)\uD569\uB2C8\uB2E4. \uC774 \uC870\uC9C1\uC774 \uC4F0\uB294 **\uB3D9\uC758\uC5B4\xB7\uCF54\uB4DC\uAC12\uC758 \uB73B\xB7\uBE44\uC988\uB2C8\uC2A4 \uBAA8\uB378 \uBC1C\uD589\uBCF8**\uAE4C\uC9C0 \uBCF4\uBBC0\uB85C, "\uACE0\uAC1D"\uCC98\uB7FC \uBB3C\uB9AC \uC2A4\uD0A4\uB9C8\uC5D0 \uC5C6\uB294 \uB9D0\uB3C4 \uC2E4\uC81C \uD14C\uC774\uBE14\uB85C \uC5F0\uACB0\uD569\uB2C8\uB2E4. \uC751\uB2F5\uC758 `usedFallback: true`\uB294 **\uC9C8\uBB38\uC758 \uAC1C\uB150\uC744 \uCC3E\uC9C0 \uBABB\uD588\uB2E4**\uB294 \uB73B\uC785\uB2C8\uB2E4 \u2014 \uADF8 \uCEE8\uD14D\uC2A4\uD2B8\uB85C SQL\uC744 \uB9CC\uB4E4\uC9C0 \uB9D0\uACE0 \uBAA8\uB978\uB2E4\uACE0 \uB2F5\uD558\uAC70\uB098 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uC6A9\uC5B4\uB97C \uB418\uBB3C\uC73C\uC2ED\uC2DC\uC624.', {
|
|
22265
|
+
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID"),
|
|
22266
|
+
question: external_exports.string().describe('\uC790\uC5F0\uC5B4 \uC9C8\uBB38 (\uC608: "\uBD80\uC11C\uBCC4 \uAE09\uC5EC \uCD1D\uC561", "VIP \uACE0\uAC1D\uC758 \uCD5C\uADFC \uC8FC\uBB38")')
|
|
22267
|
+
}, async ({ projectId, question }) => {
|
|
22268
|
+
try {
|
|
22269
|
+
const result = await client.getProjectContext(projectId, question);
|
|
22270
|
+
return {
|
|
22271
|
+
content: [{
|
|
22272
|
+
type: "text",
|
|
22273
|
+
text: JSON.stringify(result, null, 2)
|
|
22274
|
+
}]
|
|
22275
|
+
};
|
|
22276
|
+
} catch (err) {
|
|
22277
|
+
return {
|
|
22278
|
+
content: [{
|
|
22279
|
+
type: "text",
|
|
22280
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22281
|
+
}],
|
|
22282
|
+
isError: true
|
|
22283
|
+
};
|
|
22292
22284
|
}
|
|
22293
|
-
);
|
|
22294
|
-
server.tool(
|
|
22295
|
-
"
|
|
22296
|
-
|
|
22297
|
-
|
|
22298
|
-
|
|
22299
|
-
|
|
22300
|
-
|
|
22301
|
-
|
|
22302
|
-
|
|
22303
|
-
|
|
22304
|
-
|
|
22305
|
-
|
|
22306
|
-
|
|
22307
|
-
|
|
22308
|
-
|
|
22309
|
-
|
|
22310
|
-
|
|
22311
|
-
|
|
22312
|
-
|
|
22313
|
-
|
|
22314
|
-
|
|
22315
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22316
|
-
}],
|
|
22317
|
-
isError: true
|
|
22318
|
-
};
|
|
22319
|
-
}
|
|
22285
|
+
});
|
|
22286
|
+
server.tool("find_join_path", "\uB450 \uC5D4\uD130\uD2F0(\uD14C\uC774\uBE14) \uAC04 \uCD5C\uC801 JOIN \uACBD\uB85C\uB97C \uD0D0\uC0C9\uD569\uB2C8\uB2E4. BFS \uAE30\uBC18\uC73C\uB85C \uCD5C\uB2E8 \uACBD\uB85C\uB97C \uCC3E\uC73C\uBA70, \uC911\uAC04 \uD14C\uC774\uBE14\uACFC \uAD00\uACC4\uBA85\uC744 \uD3EC\uD568\uD569\uB2C8\uB2E4. \uAC01 \uAD6C\uAC04\uC5D0 \uBB3C\uB9AC \uD14C\uC774\uBE14\uBA85\xB7FK \uCEEC\uB7FC\uC30D(on)\xB7\uC9C4\uD589 \uBC29\uD5A5 \uCE74\uB514\uB110\uB9AC\uD2F0\uAC00 \uC2E4\uB824 \uC788\uC73C\uBBC0\uB85C, **\uC870\uC778 \uC870\uAC74\uC744 \uCD94\uCE21\uD558\uC9C0 \uB9D0\uACE0 on \uAC12\uC744 \uADF8\uB300\uB85C ON \uC808\uC5D0 \uC4F0\uC2ED\uC2DC\uC624.** joinable=false\uBA74 FK \uB9E4\uD551\uC774\uB098 \uBB3C\uB9AC \uD14C\uC774\uBE14\uBA85\uC774 \uC5C6\uC5B4 SQL\uC744 \uC870\uB9BD\uD560 \uC218 \uC5C6\uB2E4\uB294 \uB73B\uC774\uBA70, \uC0AC\uC720\uB294 warnings\uC5D0 \uC788\uC2B5\uB2C8\uB2E4.", {
|
|
22287
|
+
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID"),
|
|
22288
|
+
from: external_exports.string().describe("\uCD9C\uBC1C \uC5D4\uD130\uD2F0 \uC774\uB984 (\uB17C\uB9AC\uBA85 \uB610\uB294 \uBB3C\uB9AC\uBA85)"),
|
|
22289
|
+
to: external_exports.string().describe("\uB3C4\uCC29 \uC5D4\uD130\uD2F0 \uC774\uB984 (\uB17C\uB9AC\uBA85 \uB610\uB294 \uBB3C\uB9AC\uBA85)")
|
|
22290
|
+
}, async ({ projectId, from, to }) => {
|
|
22291
|
+
try {
|
|
22292
|
+
const result = await client.findJoinPath(projectId, from, to);
|
|
22293
|
+
return {
|
|
22294
|
+
content: [{
|
|
22295
|
+
type: "text",
|
|
22296
|
+
text: JSON.stringify(result, null, 2)
|
|
22297
|
+
}]
|
|
22298
|
+
};
|
|
22299
|
+
} catch (err) {
|
|
22300
|
+
return {
|
|
22301
|
+
content: [{
|
|
22302
|
+
type: "text",
|
|
22303
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22304
|
+
}],
|
|
22305
|
+
isError: true
|
|
22306
|
+
};
|
|
22320
22307
|
}
|
|
22321
|
-
);
|
|
22322
|
-
server.tool(
|
|
22323
|
-
"
|
|
22324
|
-
|
|
22325
|
-
{
|
|
22326
|
-
|
|
22327
|
-
|
|
22328
|
-
|
|
22329
|
-
|
|
22330
|
-
|
|
22331
|
-
|
|
22332
|
-
|
|
22333
|
-
|
|
22334
|
-
|
|
22335
|
-
|
|
22336
|
-
|
|
22337
|
-
|
|
22338
|
-
|
|
22339
|
-
|
|
22340
|
-
|
|
22341
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22342
|
-
}],
|
|
22343
|
-
isError: true
|
|
22344
|
-
};
|
|
22345
|
-
}
|
|
22308
|
+
});
|
|
22309
|
+
server.tool("get_project_summary", "\uD504\uB85C\uC81D\uD2B8 \uC804\uCCB4\uC758 \uB370\uC774\uD130 \uBAA8\uB378 \uC694\uC57D\uC744 \uBC18\uD658\uD569\uB2C8\uB2E4. \uC5D4\uD130\uD2F0 \uC218, \uAD00\uACC4 \uC218, \uC8FC\uC81C\uC601\uC5ED(Subject Area) \uAD6C\uC131, RDF \uD2B8\uB9AC\uD50C \uC218 \uB4F1\uC744 \uD3EC\uD568\uD569\uB2C8\uB2E4. \uD504\uB85C\uC81D\uD2B8 \uC628\uBCF4\uB529\uC774\uB098 \uC804\uCCB4 \uAD6C\uC870 \uD30C\uC545\uC5D0 \uC720\uC6A9\uD569\uB2C8\uB2E4.", {
|
|
22310
|
+
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID")
|
|
22311
|
+
}, async ({ projectId }) => {
|
|
22312
|
+
try {
|
|
22313
|
+
const result = await client.getProjectSummary(projectId);
|
|
22314
|
+
return {
|
|
22315
|
+
content: [{
|
|
22316
|
+
type: "text",
|
|
22317
|
+
text: JSON.stringify(result, null, 2)
|
|
22318
|
+
}]
|
|
22319
|
+
};
|
|
22320
|
+
} catch (err) {
|
|
22321
|
+
return {
|
|
22322
|
+
content: [{
|
|
22323
|
+
type: "text",
|
|
22324
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22325
|
+
}],
|
|
22326
|
+
isError: true
|
|
22327
|
+
};
|
|
22346
22328
|
}
|
|
22347
|
-
);
|
|
22348
|
-
server.tool(
|
|
22349
|
-
"
|
|
22350
|
-
"
|
|
22351
|
-
|
|
22352
|
-
|
|
22353
|
-
|
|
22354
|
-
|
|
22355
|
-
|
|
22356
|
-
|
|
22357
|
-
|
|
22358
|
-
|
|
22359
|
-
|
|
22360
|
-
|
|
22361
|
-
|
|
22362
|
-
|
|
22363
|
-
|
|
22364
|
-
|
|
22365
|
-
|
|
22366
|
-
|
|
22367
|
-
|
|
22368
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22369
|
-
}],
|
|
22370
|
-
isError: true
|
|
22371
|
-
};
|
|
22372
|
-
}
|
|
22329
|
+
});
|
|
22330
|
+
server.tool("query_ontology", "\uD504\uB85C\uC81D\uD2B8\uC758 \uC628\uD1A8\uB85C\uC9C0 \uADF8\uB798\uD504\uC5D0 SPARQL \uCFFC\uB9AC\uB97C \uC9C1\uC811 \uC2E4\uD589\uD569\uB2C8\uB2E4. \uACE0\uAE09 \uC0AC\uC6A9\uC790\uAC00 \uC815\uAD50\uD55C \uC2DC\uBA58\uD2F1 \uC9C8\uC758\uB97C \uC218\uD589\uD560 \uB54C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.", {
|
|
22331
|
+
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID"),
|
|
22332
|
+
query: external_exports.string().describe("SPARQL SELECT \uCFFC\uB9AC\uBB38")
|
|
22333
|
+
}, async ({ projectId, query }) => {
|
|
22334
|
+
try {
|
|
22335
|
+
const result = await client.queryOntology(projectId, query);
|
|
22336
|
+
return {
|
|
22337
|
+
content: [{
|
|
22338
|
+
type: "text",
|
|
22339
|
+
text: JSON.stringify(result, null, 2)
|
|
22340
|
+
}]
|
|
22341
|
+
};
|
|
22342
|
+
} catch (err) {
|
|
22343
|
+
return {
|
|
22344
|
+
content: [{
|
|
22345
|
+
type: "text",
|
|
22346
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22347
|
+
}],
|
|
22348
|
+
isError: true
|
|
22349
|
+
};
|
|
22373
22350
|
}
|
|
22374
|
-
);
|
|
22375
|
-
server.tool(
|
|
22376
|
-
"
|
|
22377
|
-
|
|
22378
|
-
{
|
|
22379
|
-
|
|
22380
|
-
|
|
22381
|
-
|
|
22382
|
-
|
|
22383
|
-
|
|
22384
|
-
|
|
22385
|
-
|
|
22386
|
-
|
|
22387
|
-
|
|
22388
|
-
|
|
22389
|
-
|
|
22390
|
-
|
|
22391
|
-
|
|
22392
|
-
|
|
22393
|
-
if (result.suggestions && result.suggestions.length > 0) {
|
|
22394
|
-
summary.push("", "\u{1F4A1} \uAC1C\uC120 \uC81C\uC548 (\uD48D\uBD80\uB3C4 \uB0AE\uC740 \uC21C):");
|
|
22395
|
-
for (const s of result.suggestions.slice(0, 10)) {
|
|
22396
|
-
summary.push(` \u2022 ${s.entity} (${s.richness}%) \u2014 \uB204\uB77D: ${s.missing.join(", ")}`);
|
|
22397
|
-
}
|
|
22351
|
+
});
|
|
22352
|
+
server.tool("check_metadata_quality", "\uD504\uB85C\uC81D\uD2B8\uC758 \uBA54\uD0C0\uB370\uC774\uD130 \uD48D\uBD80\uB3C4\uB97C \uBD84\uC11D\uD569\uB2C8\uB2E4. \uC124\uBA85, \uB3D9\uC758\uC5B4, \uC18D\uC131 \uC785\uB825\uB960\uC744 \uAE30\uBC18\uC73C\uB85C \uC804\uCCB4 \uD488\uC9C8 \uC810\uC218\uB97C \uC0B0\uCD9C\uD558\uACE0, \uAC1C\uC120\uC774 \uD544\uC694\uD55C \uC5D4\uD130\uD2F0 \uBAA9\uB85D\uC744 \uC81C\uC548\uD569\uB2C8\uB2E4.", {
|
|
22353
|
+
projectId: external_exports.string().describe("\uD504\uB85C\uC81D\uD2B8 ID")
|
|
22354
|
+
}, async ({ projectId }) => {
|
|
22355
|
+
try {
|
|
22356
|
+
const result = await client.checkMetadataQuality(projectId);
|
|
22357
|
+
const summary = [
|
|
22358
|
+
`\u{1F4CA} \uBA54\uD0C0\uB370\uC774\uD130 \uD488\uC9C8 \uBCF4\uACE0\uC11C`,
|
|
22359
|
+
`\uD3C9\uADE0 \uD48D\uBD80\uB3C4: ${result.avgRichness}%`,
|
|
22360
|
+
`\uCD1D \uC5D4\uD130\uD2F0: ${result.entityCount}\uAC1C`,
|
|
22361
|
+
``,
|
|
22362
|
+
`\u{1F7E2} \uC644\uC804 (\u226570%): ${result.breakdown?.complete || 0}\uAC1C`,
|
|
22363
|
+
`\u{1F7E1} \uBD80\uBD84 (40-69%): ${result.breakdown?.partial || 0}\uAC1C`,
|
|
22364
|
+
`\u{1F534} \uBBF8\uC785\uB825 (<40%): ${result.breakdown?.missing || 0}\uAC1C`
|
|
22365
|
+
];
|
|
22366
|
+
if (result.suggestions && result.suggestions.length > 0) {
|
|
22367
|
+
summary.push("", "\u{1F4A1} \uAC1C\uC120 \uC81C\uC548 (\uD48D\uBD80\uB3C4 \uB0AE\uC740 \uC21C):");
|
|
22368
|
+
for (const s of result.suggestions.slice(0, 10)) {
|
|
22369
|
+
summary.push(` \u2022 ${s.entity} (${s.richness}%) \u2014 \uB204\uB77D: ${s.missing.join(", ")}`);
|
|
22398
22370
|
}
|
|
22399
|
-
return {
|
|
22400
|
-
content: [{
|
|
22401
|
-
type: "text",
|
|
22402
|
-
text: summary.join("\n")
|
|
22403
|
-
}]
|
|
22404
|
-
};
|
|
22405
|
-
} catch (err) {
|
|
22406
|
-
return {
|
|
22407
|
-
content: [{
|
|
22408
|
-
type: "text",
|
|
22409
|
-
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22410
|
-
}],
|
|
22411
|
-
isError: true
|
|
22412
|
-
};
|
|
22413
22371
|
}
|
|
22372
|
+
return {
|
|
22373
|
+
content: [{
|
|
22374
|
+
type: "text",
|
|
22375
|
+
text: summary.join("\n")
|
|
22376
|
+
}]
|
|
22377
|
+
};
|
|
22378
|
+
} catch (err) {
|
|
22379
|
+
return {
|
|
22380
|
+
content: [{
|
|
22381
|
+
type: "text",
|
|
22382
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`
|
|
22383
|
+
}],
|
|
22384
|
+
isError: true
|
|
22385
|
+
};
|
|
22414
22386
|
}
|
|
22415
|
-
);
|
|
22387
|
+
});
|
|
22416
22388
|
}
|
|
22417
22389
|
|
|
22418
|
-
//
|
|
22419
|
-
var
|
|
22420
|
-
|
|
22421
|
-
|
|
22422
|
-
|
|
22423
|
-
|
|
22424
|
-
|
|
22425
|
-
"
|
|
22426
|
-
|
|
22427
|
-
|
|
22428
|
-
|
|
22429
|
-
|
|
22430
|
-
|
|
22431
|
-
|
|
22432
|
-
|
|
22433
|
-
|
|
22434
|
-
|
|
22435
|
-
}
|
|
22436
|
-
const contentType = res.headers.get("content-type") || "";
|
|
22437
|
-
if (contentType.includes("text/plain")) {
|
|
22438
|
-
return res.text();
|
|
22439
|
-
}
|
|
22440
|
-
return res.json();
|
|
22441
|
-
}
|
|
22442
|
-
// ─── Diagrams ───
|
|
22443
|
-
/** 사용자의 모든 다이어그램 목록 조회 */
|
|
22444
|
-
async listDiagrams() {
|
|
22445
|
-
return this.request("/api/mcp/diagrams");
|
|
22446
|
-
}
|
|
22447
|
-
/** 다이어그램 상세 (엔터티 + 관계 포함) */
|
|
22448
|
-
async getDiagram(diagramId) {
|
|
22449
|
-
return this.request(`/api/mcp/diagrams/${diagramId}`);
|
|
22450
|
-
}
|
|
22451
|
-
// ─── Entities ───
|
|
22452
|
-
/** 단일 엔터티 상세 조회 */
|
|
22453
|
-
async getEntity(diagramId, entityId) {
|
|
22454
|
-
return this.request(`/api/mcp/diagrams/${diagramId}/entities/${entityId}`);
|
|
22455
|
-
}
|
|
22456
|
-
/** 엔터티 이름으로 검색 */
|
|
22457
|
-
async searchEntities(diagramId, query) {
|
|
22458
|
-
return this.request(
|
|
22459
|
-
`/api/mcp/diagrams/${diagramId}/entities?q=${encodeURIComponent(query)}`
|
|
22460
|
-
);
|
|
22461
|
-
}
|
|
22462
|
-
// ─── DDL ───
|
|
22463
|
-
/** 다이어그램의 DDL 생성 */
|
|
22464
|
-
async generateDDL(diagramId, dialect) {
|
|
22465
|
-
const d = dialect ? `?dialect=${encodeURIComponent(dialect)}` : "";
|
|
22466
|
-
return this.request(`/api/mcp/diagrams/${diagramId}/ddl${d}`);
|
|
22467
|
-
}
|
|
22468
|
-
// ─── Dictionary ───
|
|
22469
|
-
/** 표준 사전 단어 목록 */
|
|
22470
|
-
async getDictionary(projectId) {
|
|
22471
|
-
return this.request(`/api/mcp/projects/${projectId}/dictionary`);
|
|
22472
|
-
}
|
|
22473
|
-
// ─── Drafts ───
|
|
22474
|
-
/** 스키마 변경 제안 (Draft 생성) */
|
|
22475
|
-
async proposeSchemaChange(diagramId, data) {
|
|
22476
|
-
return this.postRequest(`/api/mcp/diagrams/${diagramId}/drafts`, data);
|
|
22477
|
-
}
|
|
22478
|
-
// ─── Sync / Push ───
|
|
22479
|
-
async postRequest(path, body) {
|
|
22480
|
-
const url = `${this.baseUrl}${path}`;
|
|
22481
|
-
const res = await fetch(url, {
|
|
22482
|
-
method: "POST",
|
|
22483
|
-
headers: this.headers,
|
|
22484
|
-
body: JSON.stringify(body)
|
|
22485
|
-
});
|
|
22486
|
-
if (!res.ok) {
|
|
22487
|
-
const text = await res.text().catch(() => "");
|
|
22488
|
-
throw new Error(`ThinkERD API error ${res.status}: ${text || res.statusText}`);
|
|
22489
|
-
}
|
|
22490
|
-
return res.json();
|
|
22491
|
-
}
|
|
22492
|
-
// ─── Context Provider (Project-level Ontology) ───
|
|
22493
|
-
/** 자연어 질문 → 관련 엔터티 컨텍스트 (Graph RAG) */
|
|
22494
|
-
async getProjectContext(projectId, question) {
|
|
22495
|
-
return this.postRequest(`/api/mcp/projects/${projectId}/context`, { question });
|
|
22496
|
-
}
|
|
22497
|
-
/** 두 엔터티 간 JOIN 경로 탐색 */
|
|
22498
|
-
async findJoinPath(projectId, from, to) {
|
|
22499
|
-
return this.postRequest(`/api/mcp/projects/${projectId}/join-path`, { from, to });
|
|
22500
|
-
}
|
|
22501
|
-
/** 프로젝트 전체 스키마 요약 */
|
|
22502
|
-
async getProjectSummary(projectId) {
|
|
22503
|
-
return this.request(`/api/mcp/projects/${projectId}/summary`);
|
|
22504
|
-
}
|
|
22505
|
-
/** 메타데이터 풍부도 품질 보고 */
|
|
22506
|
-
async checkMetadataQuality(projectId) {
|
|
22507
|
-
return this.request(`/api/mcp/projects/${projectId}/quality`);
|
|
22508
|
-
}
|
|
22509
|
-
/** SPARQL 직접 실행 */
|
|
22510
|
-
async queryOntology(projectId, query) {
|
|
22511
|
-
return this.postRequest(`/api/ai/ontology/${projectId}/sparql`, { query });
|
|
22512
|
-
}
|
|
22513
|
-
};
|
|
22514
|
-
|
|
22515
|
-
// src/index.ts
|
|
22516
|
-
function parseArgs() {
|
|
22517
|
-
const args = process.argv.slice(2);
|
|
22518
|
-
let apiUrl = process.env.THINKERD_API_URL || "https://api.thinkerd.io";
|
|
22519
|
-
let token = process.env.THINKERD_TOKEN || process.env.THINKERD_API_TOKEN || "";
|
|
22520
|
-
let devMode = false;
|
|
22521
|
-
for (let i = 0; i < args.length; i++) {
|
|
22522
|
-
if (args[i] === "--api-url" && args[i + 1]) {
|
|
22523
|
-
apiUrl = args[++i];
|
|
22524
|
-
} else if (args[i] === "--token" && args[i + 1]) {
|
|
22525
|
-
token = args[++i];
|
|
22526
|
-
} else if (args[i] === "--dev") {
|
|
22527
|
-
devMode = true;
|
|
22528
|
-
}
|
|
22529
|
-
}
|
|
22530
|
-
if (devMode) {
|
|
22531
|
-
apiUrl = process.env.THINKERD_API_URL || "http://localhost:8000";
|
|
22390
|
+
// ../cli/dist/commands/mcp.js
|
|
22391
|
+
var SERVER_DESCRIPTION = 'ThinkERD \u2014 \uC6F9 \uAE30\uBC18 ER \uB2E4\uC774\uC5B4\uADF8\uB7A8 \uBAA8\uB378\uB9C1 \uB3C4\uAD6C\uC758 MCP \uC11C\uBC84. \uB370\uC774\uD130\uBCA0\uC774\uC2A4 \uC2A4\uD0A4\uB9C8 \uC124\uACC4(\uC5D4\uD130\uD2F0/\uCEEC\uB7FC/\uAD00\uACC4)\uB97C \uC870\uD68C\uD558\uACE0, DDL\uC744 \uC0DD\uC131\uD558\uBA70, \uC2A4\uD0A4\uB9C8 \uBCC0\uACBD\uC744 \uC81C\uC548\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uD575\uC2EC \uAC1C\uB150: \uB2E4\uC774\uC5B4\uADF8\uB7A8(ERD \uBB38\uC11C), \uC5D4\uD130\uD2F0(\uD14C\uC774\uBE14, \uB17C\uB9AC\uBA85/\uBB3C\uB9AC\uBA85), \uCEEC\uB7FC(\uD0C0\uC785/PK/FK/Nullable), \uAD00\uACC4(1:1/1:N/M:N), \uC8FC\uC81C\uC601\uC5ED(\uC5C5\uBB34 \uB3C4\uBA54\uC778\uBCC4 \uBD84\uB958), \uD504\uB85C\uC81D\uD2B8(\uCD5C\uC0C1\uC704 \uB2E8\uC704), \uD45C\uC900\uC0AC\uC804(\uB17C\uB9AC\u2194\uBB3C\uB9AC \uB9E4\uD551). \uC0AC\uC6A9\uC790\uAC00 "\uC2A4\uD0A4\uB9C8/\uD14C\uC774\uBE14/ERD/\uC5D4\uD130\uD2F0/DDL"\uC744 \uC5B8\uAE09\uD558\uBA74 \uC774 \uC11C\uBC84\uC758 \uB3C4\uAD6C\uB97C \uC0AC\uC6A9\uD558\uC138\uC694. \uCF54\uB4DC \uC0DD\uC131 \uC694\uCCAD \uC2DC \uBA3C\uC800 \uC2A4\uD0A4\uB9C8\uB97C \uC870\uD68C\uD55C \uD6C4 \uC0DD\uC131\uD558\uC138\uC694.';
|
|
22392
|
+
function findDevToken() {
|
|
22393
|
+
let dir = dirname(fileURLToPath(import.meta.url));
|
|
22394
|
+
for (let depth = 0; depth < 6; depth++) {
|
|
22395
|
+
const candidate = resolve(dir, ".dev-mcp-token");
|
|
22396
|
+
if (existsSync(candidate))
|
|
22397
|
+
return readFileSync(candidate, "utf-8").trim();
|
|
22398
|
+
dir = resolve(dir, "..");
|
|
22399
|
+
}
|
|
22400
|
+
return null;
|
|
22401
|
+
}
|
|
22402
|
+
async function mcpCommand(options) {
|
|
22403
|
+
let apiUrl = options.apiUrl || process.env.THINKERD_API_URL || "https://api.thinkerd.io";
|
|
22404
|
+
let token = options.token || process.env.THINKERD_TOKEN || process.env.THINKERD_API_TOKEN || "";
|
|
22405
|
+
if (options.dev) {
|
|
22406
|
+
apiUrl = options.apiUrl || process.env.THINKERD_API_URL || "http://localhost:8000";
|
|
22532
22407
|
if (!token) {
|
|
22533
|
-
|
|
22534
|
-
|
|
22535
|
-
|
|
22536
|
-
|
|
22537
|
-
|
|
22538
|
-
console.error(`[ThinkERD MCP] Dev mode \u2014 loaded PAT from ${tokenPath}`);
|
|
22539
|
-
break;
|
|
22540
|
-
}
|
|
22541
|
-
dir = resolve(dir, "..");
|
|
22408
|
+
const found = findDevToken();
|
|
22409
|
+
if (!found) {
|
|
22410
|
+
console.error("[ThinkERD MCP] Dev mode \u2014 .dev-mcp-token \uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
|
|
22411
|
+
console.error("[ThinkERD MCP] \uBA3C\uC800 \uC11C\uBC84\uB97C \uB744\uC6B0\uC138\uC694: pnpm dev:server");
|
|
22412
|
+
process.exit(1);
|
|
22542
22413
|
}
|
|
22414
|
+
token = found;
|
|
22543
22415
|
}
|
|
22544
|
-
|
|
22545
|
-
console.error(
|
|
22546
|
-
"[ThinkERD MCP] Dev mode \u2014 .dev-mcp-token not found.\nStart the ThinkERD server first (pnpm dev:server) to auto-generate the token."
|
|
22547
|
-
);
|
|
22548
|
-
process.exit(1);
|
|
22549
|
-
}
|
|
22550
|
-
console.error("[ThinkERD MCP] Dev mode \u2014 connecting to " + apiUrl);
|
|
22416
|
+
console.error(`[ThinkERD MCP] Dev mode \u2014 connecting to ${apiUrl}`);
|
|
22551
22417
|
}
|
|
22552
22418
|
if (!token) {
|
|
22553
|
-
console.error(
|
|
22554
|
-
|
|
22555
|
-
);
|
|
22419
|
+
console.error("Error: ThinkERD API token is required.");
|
|
22420
|
+
console.error("Usage: thinkdata mcp --token <YOUR_PAT>");
|
|
22421
|
+
console.error("Or set THINKERD_TOKEN environment variable.");
|
|
22422
|
+
console.error("For local development: thinkdata mcp --dev");
|
|
22556
22423
|
process.exit(1);
|
|
22557
22424
|
}
|
|
22558
|
-
return { apiUrl, token, devMode };
|
|
22559
|
-
}
|
|
22560
|
-
async function main() {
|
|
22561
|
-
const { apiUrl, token } = parseArgs();
|
|
22562
22425
|
const client = new ThinkERDClient(apiUrl, token);
|
|
22563
22426
|
const server = new McpServer({
|
|
22564
22427
|
name: "thinkerd",
|
|
22565
22428
|
version: "0.1.0",
|
|
22566
|
-
description:
|
|
22429
|
+
description: SERVER_DESCRIPTION
|
|
22567
22430
|
});
|
|
22568
22431
|
registerResources(server, client);
|
|
22569
22432
|
registerTools(server, client);
|
|
@@ -22571,7 +22434,18 @@ async function main() {
|
|
|
22571
22434
|
await server.connect(transport);
|
|
22572
22435
|
console.error("[ThinkERD MCP] Server started. Connected via stdio.");
|
|
22573
22436
|
}
|
|
22574
|
-
|
|
22437
|
+
|
|
22438
|
+
// src/index.ts
|
|
22439
|
+
var argv = process.argv.slice(2);
|
|
22440
|
+
var read = (flag) => {
|
|
22441
|
+
const i = argv.indexOf(flag);
|
|
22442
|
+
return i >= 0 && argv[i + 1] ? argv[i + 1] : void 0;
|
|
22443
|
+
};
|
|
22444
|
+
mcpCommand({
|
|
22445
|
+
apiUrl: read("--api-url"),
|
|
22446
|
+
token: read("--token"),
|
|
22447
|
+
dev: argv.includes("--dev")
|
|
22448
|
+
}).catch((err) => {
|
|
22575
22449
|
console.error("[ThinkERD MCP] Fatal error:", err);
|
|
22576
22450
|
process.exit(1);
|
|
22577
22451
|
});
|