-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathmain.ts
More file actions
150 lines (137 loc) · 3.75 KB
/
Copy pathmain.ts
File metadata and controls
150 lines (137 loc) · 3.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
import { z } from 'zod'
import * as FRAGS from '@thatopen/fragments'
import fs from 'fs'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { convertIfcToFragment, fetchCategoriesWithGeometry, fetchElementsOfCategory, loadFragments } from './fragments'
let fragments: FRAGS.SingleThreadedFragmentsModel
const server = new McpServer({
name: 'BIM',
version: '1.0.0',
})
server.tool(
'convert-ifc-to-frag',
'Convert an IFC file to a .frag file. Needs file-system server',
{
inputPath: z.string().describe('Full path of the IFC file to convert'),
outputPath: z
.string()
.describe('Full path where the output .frags file will be saved'),
},
async ({ inputPath, outputPath }) => {
if (!fs.existsSync(inputPath)) {
return {
content: [
{
type: 'text',
text: 'IFC file not found. Please provide a valid .ifc file path.',
},
],
}
}
if (fs.existsSync(outputPath)) {
return {
content: [
{
type: 'text',
text: 'Output .frag file already exists. Please call load-frag directly',
},
],
}
}
const model = await convertIfcToFragment(inputPath, outputPath)
return {
content: [
{
type: 'text',
text: `Converted IFC file to .frag format. Output saved to ${outputPath}. Model contains ${
model.getItemsWithGeometry().length
} items with geometry: ${JSON.stringify(
fetchCategoriesWithGeometry(fragments)
)}`,
},
],
}
}
)
server.tool(
'load-frag',
'Load a .frag file. Needs file-system server',
{
filePath: z
.string()
.describe('Full path of the file to load with fragments'),
},
async ({ filePath }) => {
if (!fs.existsSync(filePath) || filePath.endsWith('.ifc')) {
return {
content: [
{
type: 'text',
text: `No .frag file found. Please call convert-ifc-to-frag first: Input file path: ${filePath.replace(
'.frag',
'.ifc'
)}; Output file path: ${filePath.replace('.ifc', '.frag')}`,
},
],
}
}
fragments = await loadFragments(filePath)
return {
content: [
{
type: 'text',
text: `Loaded fragments from ${filePath}. Loaded ${fragments.getItemsWithGeometry().length} items with geometry: ${JSON.stringify(
fetchCategoriesWithGeometry(fragments)
)}`,
},
],
}
}
)
server.tool(
'fetch-elements-of-category',
'Fetch elements of a specified category',
{
category: z.string().describe('Category name. e.g. IFCWALL'),
config: z
.object({
attributesDefault: z.boolean(),
attributes: z.array(z.string()),
relations: z.object({
HasAssociations: z.object({
attributes: z.boolean(),
relations: z.boolean(),
}),
IsDefinedBy: z.object({
attributes: z.boolean(),
relations: z.boolean(),
}),
}),
})
.describe('Configuration for fetching elements'),
},
({ category, config }) => {
if (!fragments) {
return {
content: [
{
type: 'text',
text: 'No fragments loaded. Please call load-frag first.',
},
],
}
}
const itemsData = fetchElementsOfCategory(fragments, category, config)
return {
content: [
{
type: 'text',
text: JSON.stringify(itemsData),
},
],
}
}
)
const transport = new StdioServerTransport()
await server.connect(transport)