@gxp-dev/tools 2.0.81 → 2.0.83

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.
@@ -0,0 +1,181 @@
1
+ /**
2
+ * MCP tools for @gxp-dev/uikit introspection.
3
+ *
4
+ * - list_uikit_components : enumerate components exported by the version
5
+ * of @gxp-dev/uikit installed in the *plugin project's* node_modules
6
+ * (not the toolkit's). Resolves the package relative to process.cwd(),
7
+ * parses named exports out of dist/index.d.ts, and returns sorted
8
+ * PascalCase names plus the package version.
9
+ *
10
+ * We parse the .d.ts with a regex pair (no TS AST) because the file is the
11
+ * built output and is shaped by the package's own build, not by us. Edge
12
+ * cases that the regex misses (e.g. nested namespace exports) are
13
+ * acceptable: the agent gets a strong starting set and can fall back to
14
+ * docs_search for anything unusual.
15
+ */
16
+
17
+ const fs = require("fs")
18
+ const path = require("path")
19
+
20
+ function contentResult(obj) {
21
+ return {
22
+ content: [{ type: "text", text: JSON.stringify(obj, null, 2) }],
23
+ }
24
+ }
25
+
26
+ /**
27
+ * Resolve @gxp-dev/uikit from the given cwd. Returns { root, pkg } where
28
+ * root is the absolute path to the uikit package directory and pkg is the
29
+ * parsed package.json, or null if uikit is not installed at any level.
30
+ *
31
+ * We mimic Node's node_modules walk-up rather than calling
32
+ * require.resolve("@gxp-dev/uikit/...") because the uikit's package.json
33
+ * declares a strict `exports` field with only `import` and `types`
34
+ * conditions. From a CJS context, require.resolve fails against that
35
+ * exports map even though the directory exists on disk. Walking the
36
+ * filesystem directly sidesteps it and works under npm, pnpm (where
37
+ * @gxp-dev/uikit is a symlink into .pnpm), and yarn workspaces.
38
+ */
39
+ function resolveUikit(cwd = process.cwd()) {
40
+ let dir = path.resolve(cwd)
41
+ while (dir) {
42
+ const candidate = path.join(dir, "node_modules", "@gxp-dev", "uikit")
43
+ const pkgPath = path.join(candidate, "package.json")
44
+ if (fs.existsSync(pkgPath)) {
45
+ try {
46
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"))
47
+ if (pkg && pkg.name === "@gxp-dev/uikit") {
48
+ return { root: candidate, pkg }
49
+ }
50
+ } catch {
51
+ // malformed package.json — keep walking
52
+ }
53
+ }
54
+ const parent = path.dirname(dir)
55
+ if (parent === dir) break
56
+ dir = parent
57
+ }
58
+ return null
59
+ }
60
+
61
+ /**
62
+ * Pull named exports out of a .d.ts source string. Picks up:
63
+ * - export declare const/let/var Foo
64
+ * - export declare function Foo
65
+ * - export declare class Foo
66
+ * - export declare interface Foo
67
+ * - export declare type Foo
68
+ * - export declare enum Foo
69
+ * - export { Foo, Bar as Baz }
70
+ */
71
+ function parseNamedExports(source) {
72
+ const names = new Set()
73
+
74
+ const declRe =
75
+ /export\s+(?:declare\s+)?(?:const|let|var|function|class|interface|type|enum)\s+([A-Za-z_$][A-Za-z0-9_$]*)/g
76
+ let m
77
+ while ((m = declRe.exec(source)) !== null) {
78
+ names.add(m[1])
79
+ }
80
+
81
+ const braceRe = /export\s*\{([^}]+)\}/g
82
+ while ((m = braceRe.exec(source)) !== null) {
83
+ const inner = m[1]
84
+ for (const rawPart of inner.split(",")) {
85
+ const part = rawPart.trim()
86
+ if (!part) continue
87
+ const aliasMatch = part.match(
88
+ /^[A-Za-z_$][A-Za-z0-9_$]*\s+as\s+([A-Za-z_$][A-Za-z0-9_$]*)/,
89
+ )
90
+ if (aliasMatch) {
91
+ names.add(aliasMatch[1])
92
+ continue
93
+ }
94
+ const nameMatch = part.match(/^([A-Za-z_$][A-Za-z0-9_$]*)/)
95
+ if (nameMatch) names.add(nameMatch[1])
96
+ }
97
+ }
98
+
99
+ return Array.from(names)
100
+ }
101
+
102
+ function listUikitComponents({ filter, cwd } = {}) {
103
+ const resolved = resolveUikit(cwd || process.cwd())
104
+ if (!resolved) {
105
+ return {
106
+ ok: false,
107
+ error:
108
+ "Could not resolve @gxp-dev/uikit from the current project. Install it with `npm install @gxp-dev/uikit` and re-run mcp-serve from the plugin project root.",
109
+ }
110
+ }
111
+ const { root, pkg } = resolved
112
+ const dtsPath = path.join(root, "dist", "index.d.ts")
113
+ if (!fs.existsSync(dtsPath)) {
114
+ return {
115
+ ok: false,
116
+ error: `@gxp-dev/uikit is installed at ${root} but dist/index.d.ts is missing. The package may not have been built.`,
117
+ resolved: root,
118
+ }
119
+ }
120
+
121
+ const src = fs.readFileSync(dtsPath, "utf-8")
122
+ const all = parseNamedExports(src)
123
+ const pascal = all.filter((n) => /^[A-Z]/.test(n)).sort()
124
+
125
+ let filtered = pascal
126
+ if (filter) {
127
+ const f = String(filter).toLowerCase()
128
+ filtered = pascal.filter((n) => n.toLowerCase().includes(f))
129
+ }
130
+
131
+ return {
132
+ ok: true,
133
+ package: {
134
+ name: pkg.name,
135
+ version: pkg.version || null,
136
+ root,
137
+ },
138
+ count: filtered.length,
139
+ components: filtered,
140
+ }
141
+ }
142
+
143
+ const UIKIT_TOOLS = [
144
+ {
145
+ name: "list_uikit_components",
146
+ description:
147
+ "Enumerate components exported by the @gxp-dev/uikit package installed in the current plugin project. Reads named exports from the built dist/index.d.ts and returns the PascalCase names plus the package version. Resolves uikit relative to the project (process.cwd()), not the toolkit, so the agent sees exactly what the project can import. Pass `filter` for a case-insensitive substring match.",
148
+ inputSchema: {
149
+ type: "object",
150
+ properties: {
151
+ filter: {
152
+ type: "string",
153
+ description:
154
+ "Case-insensitive substring filter applied to component names.",
155
+ },
156
+ },
157
+ },
158
+ },
159
+ ]
160
+
161
+ async function handleUikitToolCall(name, args = {}) {
162
+ switch (name) {
163
+ case "list_uikit_components":
164
+ return contentResult(listUikitComponents(args))
165
+ default:
166
+ throw new Error(`Unknown uikit tool: ${name}`)
167
+ }
168
+ }
169
+
170
+ function isUikitTool(name) {
171
+ return UIKIT_TOOLS.some((t) => t.name === name)
172
+ }
173
+
174
+ module.exports = {
175
+ UIKIT_TOOLS,
176
+ handleUikitToolCall,
177
+ isUikitTool,
178
+ listUikitComponents,
179
+ parseNamedExports,
180
+ resolveUikit,
181
+ }
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * GxP MCP Server (stdio).
5
+ *
6
+ * Primary bin: `mcp-serve`.
7
+ *
8
+ * Speaks Model Context Protocol over stdin/stdout using the official
9
+ * @modelcontextprotocol/sdk's StdioServerTransport. The full tool surface
10
+ * and wiring live in ./lib/server.js so this file stays a thin entry point.
11
+ *
12
+ * Usage:
13
+ * mcp-serve
14
+ * node mcp/mcp-serve.js
15
+ *
16
+ * Configure in your AI tool's MCP settings to enable API-aware,
17
+ * schema-aware, test-aware assistance inside plugin projects.
18
+ */
19
+
20
+ const { startServer } = require("./lib/server")
21
+
22
+ startServer().catch((err) => {
23
+ console.error(err && err.stack ? err.stack : err)
24
+ process.exit(1)
25
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gxp-dev/tools",
3
- "version": "2.0.81",
3
+ "version": "2.0.83",
4
4
  "description": "Dev tools to create platform plugins",
5
5
  "type": "commonjs",
6
6
  "publishConfig": {
@@ -39,6 +39,7 @@
39
39
  },
40
40
  "bin": {
41
41
  "gxdev": "bin/gx-devtools.js",
42
+ "mcp-serve": "mcp/mcp-serve.js",
42
43
  "gxp-api-server": "mcp/gxp-api-server.js"
43
44
  },
44
45
  "keywords": [
@@ -57,6 +58,7 @@
57
58
  "dependencies": {
58
59
  "@faker-js/faker": "^9.9.0",
59
60
  "@fal-works/esbuild-plugin-global-externals": "^2.1.2",
61
+ "@modelcontextprotocol/sdk": "^1.29.0",
60
62
  "@vitejs/plugin-vue": "^6.0.6",
61
63
  "adm-zip": "^0.5.17",
62
64
  "ajv": "^8.18.0",
@@ -481,7 +481,7 @@ export default defineConfig(async (ctx) => {
481
481
  ],
482
482
  name: libName,
483
483
  fileName: (format) => `plugin.${format}.js`,
484
- cssFileName: "style.css",
484
+ cssFileName: "style",
485
485
  formats: ["es"],
486
486
  },
487
487
  rollupOptions: {
@@ -28,7 +28,7 @@ Ask clarifying questions. Don't guess — a single clarification prevents a larg
28
28
 
29
29
  The `gxp-api` MCP server is your source of truth for the platform. Never invent endpoints or event names.
30
30
 
31
- **Before anything else, confirm the MCP is live** — call `api_list_tags`. The server is configured in `.mcp.json` at the project root and provided by the `gxp-api-server` binary that ships with `@gxp-dev/tools` (on PATH; verify with `which gxp-api-server`). If the `api_*` / `config_*` / `docs_*` tools aren't available, tell the user to run `claude mcp add gxp-api gxp-api-server` and restart the session. Do not proceed without it.
31
+ **Before anything else, confirm the MCP is live** — call `api_list_tags`. The server is configured in `.mcp.json` at the project root and provided by the `mcp-serve` binary that ships with `@gxp-dev/tools` (on PATH; verify with `which mcp-serve`). If the `api_*` / `config_*` / `docs_*` tools aren't available, tell the user to run `claude mcp add gxp-api mcp-serve` and restart the session. Do not proceed without it.
32
32
 
33
33
  **API discovery:**
34
34
 
@@ -21,7 +21,7 @@ Ask clarifying questions instead of guessing. A 30-second question beats a 30-mi
21
21
 
22
22
  Use the `gxp-api` MCP server to ground the implementation in the real platform — never invent endpoints or event names.
23
23
 
24
- **Verify the MCP is live before planning anything** by calling `api_list_tags`. The server is defined in `.mcp.json` at the project root and provided by the `gxp-api-server` binary that ships with `@gxp-dev/tools` (on PATH — check with `which gxp-api-server`). If the `api_*` / `config_*` / `docs_*` tools aren't available, tell the user to run `claude mcp add gxp-api gxp-api-server` (or `codex mcp add …` / add it to `~/.gemini/settings.json`) and restart the session. Do not proceed without the MCP.
24
+ **Verify the MCP is live before planning anything** by calling `api_list_tags`. The server is defined in `.mcp.json` at the project root and provided by the `mcp-serve` binary that ships with `@gxp-dev/tools` (on PATH — check with `which mcp-serve`). If the `api_*` / `config_*` / `docs_*` tools aren't available, tell the user to run `claude mcp add gxp-api mcp-serve` (or `codex mcp add …` / add it to `~/.gemini/settings.json`) and restart the session. Do not proceed without the MCP.
25
25
 
26
26
  - **Find endpoints** — `api_list_tags`, `api_list_operation_ids` (optionally scoped by tag), `search_api_endpoints` (keyword).
27
27
  - **Inspect a specific endpoint** — `api_get_operation_parameters`, `get_endpoint_details`.
@@ -18,7 +18,7 @@ Before writing anything, clarify with the client:
18
18
 
19
19
  Ground the implementation in real platform endpoints and events. Do not invent API paths or event names.
20
20
 
21
- **Verify the MCP is live first** — call `api_list_tags`. The server is defined in `.gemini/settings.json` at the project root and provided by the `gxp-api-server` binary that ships with `@gxp-dev/tools` (on PATH). If the tools aren't available, tell the user to add `gxp-api` to `~/.gemini/settings.json` under `mcpServers` with command `gxp-api-server`, then restart the session.
21
+ **Verify the MCP is live first** — call `api_list_tags`. The server is defined in `.gemini/settings.json` at the project root and provided by the `mcp-serve` binary that ships with `@gxp-dev/tools` (on PATH). If the tools aren't available, tell the user to add `gxp-api` to `~/.gemini/settings.json` under `mcpServers` with command `mcp-serve`, then restart the session.
22
22
 
23
23
  - Endpoints — `api_list_tags`, `api_list_operation_ids`, `search_api_endpoints`, `api_get_operation_parameters`, `get_endpoint_details`.
24
24
  - Find by payload shape — `api_find_endpoints_by_schema`.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mcpServers": {
3
3
  "gxp-api": {
4
- "command": "gxp-api-server",
4
+ "command": "mcp-serve",
5
5
  "args": []
6
6
  }
7
7
  }
package/template/mcp.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "mcpServers": {
3
3
  "gxp-api": {
4
- "command": "gxp-api-server",
4
+ "command": "mcp-serve",
5
5
  "args": []
6
6
  }
7
7
  }