@jspm/local-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 JSPM
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/Readme.md ADDED
@@ -0,0 +1,140 @@
1
+ # `@jspm/local-mcp`
2
+
3
+ `@jspm/local-mcp` is a local-first [Model Context Protocol](https://modelcontextprotocol.io/) server for managing JSPM import maps inside a real project directory.
4
+
5
+ It is built for coding agents that already have filesystem access to your repo, such as Codex, Claude Code / Claude Desktop, Cursor, and VS Code MCP clients.
6
+
7
+ Instead of asking an LLM to hand-edit only the `imports` section and accidentally break `scopes`, this server uses `@jspm/generator` to keep the full import map correct.
8
+
9
+ ## Why local-first
10
+
11
+ - It works directly against your project files.
12
+ - It can write either `importmap.json` or inject an inline import map into an HTML file.
13
+ - It can trace local source files and install the dependencies they actually use.
14
+ - It preserves and reloads an existing import map when you revisit a project.
15
+
16
+ ## Tools
17
+
18
+ The server exposes these MCP tools:
19
+
20
+ - `set_project`: set the working project directory.
21
+ - `set_target`: choose `importmap` or `html` output mode.
22
+ - `install_package`: install one or more packages with JSPM.
23
+ - `uninstall_package`: remove one or more packages from the import map.
24
+ - `trace_file`: trace imports from local source files and add the required mappings.
25
+
26
+ ## Install
27
+
28
+ After publish, the simplest way to run it will be with `npx`:
29
+
30
+ ```sh
31
+ npx -y @jspm/local-mcp
32
+ ```
33
+
34
+ You can also install it globally:
35
+
36
+ ```sh
37
+ npm install -g @jspm/local-mcp
38
+ jspm-local-mcp
39
+ ```
40
+
41
+ ## MCP Client Setup
42
+
43
+ ### Codex
44
+
45
+ Add an MCP server that runs `npx`:
46
+
47
+ ```json
48
+ {
49
+ "mcpServers": {
50
+ "jspm": {
51
+ "command": "npx",
52
+ "args": ["-y", "@jspm/local-mcp"]
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### Claude Desktop
59
+
60
+ ```json
61
+ {
62
+ "mcpServers": {
63
+ "jspm": {
64
+ "command": "npx",
65
+ "args": ["-y", "@jspm/local-mcp"]
66
+ }
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### VS Code MCP / GitHub Copilot
72
+
73
+ ```json
74
+ {
75
+ "servers": {
76
+ "jspm": {
77
+ "command": "npx",
78
+ "args": ["-y", "@jspm/local-mcp"]
79
+ }
80
+ }
81
+ }
82
+ ```
83
+
84
+ If your environment does not expose `npx`, point the client at the installed executable instead.
85
+
86
+ ## Typical Flow
87
+
88
+ Example conversation:
89
+
90
+ ```text
91
+ Set the project to the current workspace.
92
+ Use index.html as the import map target.
93
+ Install react and react-dom.
94
+ Trace src/main.js and update the import map.
95
+ ```
96
+
97
+ Equivalent tool calls:
98
+
99
+ 1. `set_project({ path: "/absolute/path/to/project" })`
100
+ 2. `set_target({ target: "html", fileName: "index.html" })`
101
+ 3. `install_package({ packages: [{ packageName: "react" }, { packageName: "react-dom" }] })`
102
+ 4. `trace_file({ fileNames: ["src/main.js"] })`
103
+
104
+ ## Behavior Notes
105
+
106
+ - `set_project` defaults to `importmap.json`.
107
+ - Switching targets reloads the generator from the current file state.
108
+ - `set_target("html")` reads the existing HTML file and preserves any inline import map already there.
109
+ - `trace_file` works on files inside the configured project directory.
110
+ - Target files are restricted to the configured project directory.
111
+
112
+ ## Local Development
113
+
114
+ ```sh
115
+ npm install
116
+ npm run build
117
+ npm start
118
+ ```
119
+
120
+ For local unpublished testing, point your MCP client to:
121
+
122
+ ```json
123
+ {
124
+ "command": "node",
125
+ "args": ["/absolute/path/to/jspm-mcp/dist/index.js"]
126
+ }
127
+ ```
128
+
129
+ ## Publish Checklist
130
+
131
+ ```sh
132
+ npm run build
133
+ npm publish --access public
134
+ ```
135
+
136
+ `prepublishOnly` rebuilds `dist` before publish.
137
+
138
+ ## License
139
+
140
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env node
2
+ import { Generator } from "@jspm/generator";
3
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { existsSync, readFileSync, statSync, writeFileSync } from "node:fs";
6
+ import { dirname, resolve } from "node:path";
7
+ import process from "node:process";
8
+ import { fileURLToPath, pathToFileURL } from "node:url";
9
+ import { z } from "zod";
10
+ import { ensureProjectDirectory, ensureWritable, getImportMapLocation, getProjectFileLocation, normalizeMapTarget, } from "./utils.js";
11
+ const server = new McpServer({
12
+ name: "@jspm/local-mcp",
13
+ version: "0.1.0",
14
+ });
15
+ const mapTargetSchema = z.enum(["importmap", "html"]);
16
+ const state = {
17
+ mapTarget: "importmap",
18
+ };
19
+ function failure(text) {
20
+ return {
21
+ content: [{ type: "text", text }],
22
+ isError: true,
23
+ };
24
+ }
25
+ function trailingSlash(path) {
26
+ return path.endsWith("/") ? path : `${path}/`;
27
+ }
28
+ function ensureStateProjectPath() {
29
+ return ensureProjectDirectory(state.projectPath);
30
+ }
31
+ function assertInsideProject(projectPath, candidatePath) {
32
+ const normalizedProjectPath = trailingSlash(resolve(projectPath));
33
+ const normalizedCandidatePath = resolve(candidatePath);
34
+ if (normalizedCandidatePath !== resolve(projectPath) &&
35
+ !normalizedCandidatePath.startsWith(normalizedProjectPath)) {
36
+ throw new Error("Target file must stay inside the configured project");
37
+ }
38
+ return normalizedCandidatePath;
39
+ }
40
+ function resolveProjectFilePath(fileName) {
41
+ const projectPath = ensureStateProjectPath();
42
+ const filePath = getProjectFileLocation(projectPath, fileName);
43
+ return assertInsideProject(projectPath, filePath);
44
+ }
45
+ function getGenerator() {
46
+ if (!state.generator) {
47
+ throw new Error("Generator is not ready. Call set_project first and optionally set_target.");
48
+ }
49
+ return state.generator;
50
+ }
51
+ async function refreshGenerator() {
52
+ const projectPath = ensureStateProjectPath();
53
+ const projectUrl = pathToFileURL(trailingSlash(projectPath));
54
+ const mapPath = state.mapTarget === "html"
55
+ ? resolveProjectFilePath(state.htmlFileName)
56
+ : getImportMapLocation(projectPath);
57
+ const mapUrl = pathToFileURL(mapPath);
58
+ const generator = new Generator({
59
+ mapUrl,
60
+ rootUrl: projectUrl,
61
+ defaultProvider: "jspm",
62
+ });
63
+ if (state.mapTarget === "importmap") {
64
+ if (existsSync(mapPath)) {
65
+ await generator.addMappings(readFileSync(mapPath, "utf-8"), mapUrl, projectUrl);
66
+ }
67
+ }
68
+ else {
69
+ const htmlSource = readFileSync(mapPath, "utf-8");
70
+ await generator.addMappings(htmlSource, mapUrl, projectUrl);
71
+ }
72
+ state.generator = generator;
73
+ }
74
+ async function saveImportMap() {
75
+ const projectPath = ensureStateProjectPath();
76
+ const generator = getGenerator();
77
+ const projectUrl = pathToFileURL(trailingSlash(projectPath));
78
+ try {
79
+ if (state.mapTarget === "importmap") {
80
+ const importMapPath = getImportMapLocation(projectPath);
81
+ const parentDirectory = dirname(importMapPath);
82
+ await ensureWritable(parentDirectory);
83
+ writeFileSync(importMapPath, `${JSON.stringify(generator.getMap(), null, 2)}\n`, "utf-8");
84
+ return;
85
+ }
86
+ const htmlPath = resolveProjectFilePath(state.htmlFileName);
87
+ const htmlSource = readFileSync(htmlPath, "utf-8");
88
+ await ensureWritable(htmlPath);
89
+ const injectedHtml = await generator.htmlInject(htmlSource, {
90
+ trace: true,
91
+ htmlUrl: pathToFileURL(htmlPath),
92
+ rootUrl: projectUrl,
93
+ esModuleShims: true,
94
+ });
95
+ writeFileSync(htmlPath, injectedHtml, "utf-8");
96
+ }
97
+ catch (error) {
98
+ if (error.code === "EACCES") {
99
+ throw new Error("Permission denied while updating the import map target");
100
+ }
101
+ throw error;
102
+ }
103
+ }
104
+ server.registerTool("set_project", {
105
+ title: "Set current project",
106
+ description: "Sets the active project directory",
107
+ inputSchema: z.object({
108
+ path: z.string(),
109
+ }),
110
+ }, async ({ path }) => {
111
+ try {
112
+ const projectPath = ensureProjectDirectory(resolve(path));
113
+ state.projectPath = projectPath;
114
+ state.mapTarget = "importmap";
115
+ state.htmlFileName = undefined;
116
+ await refreshGenerator();
117
+ const importMapPath = getImportMapLocation(projectPath);
118
+ const existingMapMessage = existsSync(importMapPath)
119
+ ? "Loaded the existing importmap.json from this project."
120
+ : "No importmap.json found yet. I will create one when you install packages.";
121
+ return {
122
+ content: [
123
+ {
124
+ type: "text",
125
+ text: [
126
+ `Project set to ${projectPath}.`,
127
+ existingMapMessage,
128
+ 'The default target is "importmap". Call set_target with "html" and a fileName to manage an HTML file instead.',
129
+ ].join("\n"),
130
+ },
131
+ ],
132
+ };
133
+ }
134
+ catch (error) {
135
+ return failure(error.message);
136
+ }
137
+ });
138
+ server.registerTool("set_target", {
139
+ title: "Set how importmap is managed",
140
+ description: "Choose whether to store the importmap in a file or inject it into an HTML file.",
141
+ inputSchema: z.object({
142
+ target: z
143
+ .string()
144
+ .describe('Target type. Accepts flexible values like "importmap", "file", "json", "html", "inline".'),
145
+ fileName: z
146
+ .string()
147
+ .optional()
148
+ .describe("Required when using HTML target (e.g. index.html)"),
149
+ }),
150
+ }, async ({ target, fileName }) => {
151
+ try {
152
+ ensureStateProjectPath();
153
+ const normalizedTarget = normalizeMapTarget(target);
154
+ if (normalizedTarget === "html") {
155
+ if (!fileName) {
156
+ return failure('HTML target requires "fileName" (for example "index.html")');
157
+ }
158
+ const htmlPath = resolveProjectFilePath(fileName);
159
+ if (!existsSync(htmlPath)) {
160
+ return failure(`HTML file not found: ${fileName}`);
161
+ }
162
+ if (!statSync(htmlPath).isFile()) {
163
+ return failure(`Target is not a file: ${fileName}`);
164
+ }
165
+ state.mapTarget = "html";
166
+ state.htmlFileName = fileName;
167
+ await refreshGenerator();
168
+ return {
169
+ content: [
170
+ {
171
+ type: "text",
172
+ text: `Importmap target set to HTML: ${fileName}`,
173
+ },
174
+ ],
175
+ };
176
+ }
177
+ state.mapTarget = "importmap";
178
+ state.htmlFileName = undefined;
179
+ await refreshGenerator();
180
+ return {
181
+ content: [
182
+ {
183
+ type: "text",
184
+ text: "Importmap target set to importmap.json",
185
+ },
186
+ ],
187
+ };
188
+ }
189
+ catch (error) {
190
+ return failure(error.message);
191
+ }
192
+ });
193
+ server.registerTool("install_package", {
194
+ title: "Install a package / dependency",
195
+ description: "Installs one or more packages with @jspm/generator and updates the configured importmap target.",
196
+ inputSchema: z.object({
197
+ packages: z.array(z.object({
198
+ packageName: z.string(),
199
+ version: z.string().optional(),
200
+ })),
201
+ }),
202
+ }, async ({ packages }) => {
203
+ try {
204
+ const generator = getGenerator();
205
+ const content = [];
206
+ for (const input of packages) {
207
+ const specifier = input.version
208
+ ? `${input.packageName}@${input.version}`
209
+ : input.packageName;
210
+ await generator.install(specifier);
211
+ content.push({ type: "text", text: `Installed ${specifier}` });
212
+ }
213
+ await saveImportMap();
214
+ return { content };
215
+ }
216
+ catch (error) {
217
+ return failure(error.message);
218
+ }
219
+ });
220
+ server.registerTool("uninstall_package", {
221
+ title: "Uninstall a package / dependency",
222
+ description: "Removes one or more packages from the importmap and saves the result.",
223
+ inputSchema: z.object({
224
+ packageName: z.union([z.string(), z.array(z.string())]),
225
+ }),
226
+ }, async ({ packageName }) => {
227
+ try {
228
+ const generator = getGenerator();
229
+ const packages = Array.isArray(packageName) ? packageName : [packageName];
230
+ await generator.uninstall(packages);
231
+ await saveImportMap();
232
+ return {
233
+ content: [
234
+ {
235
+ type: "text",
236
+ text: `Uninstalled ${packages.join(", ")}`,
237
+ },
238
+ ],
239
+ };
240
+ }
241
+ catch (error) {
242
+ return failure(error.message);
243
+ }
244
+ });
245
+ server.registerTool("trace_file", {
246
+ title: "Trace file imports",
247
+ description: "Traces imports from one or more local source files and adds the required mappings to the importmap.",
248
+ inputSchema: z.object({
249
+ fileNames: z.array(z.string()),
250
+ }),
251
+ }, async ({ fileNames }) => {
252
+ try {
253
+ const generator = getGenerator();
254
+ const content = [];
255
+ for (const fileName of fileNames) {
256
+ const filePath = resolveProjectFilePath(fileName);
257
+ if (!existsSync(filePath)) {
258
+ return failure(`File not found: ${fileName}`);
259
+ }
260
+ await generator.link(pathToFileURL(filePath).href);
261
+ content.push({
262
+ type: "text",
263
+ text: `Scanned imports from ${fileName}`,
264
+ });
265
+ }
266
+ await saveImportMap();
267
+ return {
268
+ content: [
269
+ ...content,
270
+ {
271
+ type: "text",
272
+ text: "Updated the importmap target with traced dependencies.",
273
+ },
274
+ ],
275
+ };
276
+ }
277
+ catch (error) {
278
+ return failure(error.message);
279
+ }
280
+ });
281
+ async function main() {
282
+ const transport = new StdioServerTransport();
283
+ await server.connect(transport);
284
+ await server.sendLoggingMessage({
285
+ level: "info",
286
+ data: "JSPM MCP server started",
287
+ });
288
+ console.error(`JSPM MCP server running from ${fileURLToPath(import.meta.url)}`);
289
+ }
290
+ main().catch((error) => {
291
+ console.error("Fatal error:", error);
292
+ process.exit(1);
293
+ });
294
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function ensureWritable(path: string): Promise<void>;
2
+ export declare function ensureProjectDirectory(projectPath?: string): string;
3
+ export declare function normalizeMapTarget(input: string): "importmap" | "html";
4
+ export declare function getImportMapLocation(projectPath?: string): string;
5
+ export declare function getProjectFileLocation(projectPath: string | undefined, fileName: string): string;
6
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,iBAMhD;AAED,wBAAgB,sBAAsB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAgBnE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CActE;AAED,wBAAgB,oBAAoB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAEjE;AAED,wBAAgB,sBAAsB,CACpC,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,QAAQ,EAAE,MAAM,GACf,MAAM,CAMR"}
package/dist/utils.js ADDED
@@ -0,0 +1,44 @@
1
+ import { access } from "node:fs/promises";
2
+ import { constants, existsSync, statSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ export async function ensureWritable(path) {
5
+ try {
6
+ await access(path, constants.W_OK);
7
+ }
8
+ catch {
9
+ throw new Error(`No write permission for: ${path}`);
10
+ }
11
+ }
12
+ export function ensureProjectDirectory(projectPath) {
13
+ if (!projectPath) {
14
+ throw new Error("Project path is not configured");
15
+ }
16
+ const resolvedPath = resolve(projectPath);
17
+ if (!existsSync(resolvedPath)) {
18
+ throw new Error(`Project path does not exist: ${resolvedPath}`);
19
+ }
20
+ if (!statSync(resolvedPath).isDirectory()) {
21
+ throw new Error(`Project path is not a directory: ${resolvedPath}`);
22
+ }
23
+ return resolvedPath;
24
+ }
25
+ export function normalizeMapTarget(input) {
26
+ const value = input.toLowerCase().trim();
27
+ if (["html", "inline", "dom", "page"].includes(value)) {
28
+ return "html";
29
+ }
30
+ if (["importmap", "file", "json", "map"].includes(value)) {
31
+ return "importmap";
32
+ }
33
+ throw new Error(`Invalid target "${input}". Use something like "importmap" or "html".`);
34
+ }
35
+ export function getImportMapLocation(projectPath) {
36
+ return resolve(ensureProjectDirectory(projectPath), "importmap.json");
37
+ }
38
+ export function getProjectFileLocation(projectPath, fileName) {
39
+ if (!fileName) {
40
+ throw new Error("HTML file name is not configured");
41
+ }
42
+ return resolve(ensureProjectDirectory(projectPath), fileName);
43
+ }
44
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,WAAoB;IACzD,IAAI,CAAC,WAAW,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAE1C,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,gCAAgC,YAAY,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,KAAK,CAAC,oCAAoC,YAAY,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,KAAa;IAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAEzC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACtD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzD,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,MAAM,IAAI,KAAK,CACb,mBAAmB,KAAK,8CAA8C,CACvE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,WAAoB;IACvD,OAAO,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,WAA+B,EAC/B,QAAgB;IAEhB,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,OAAO,CAAC,sBAAsB,CAAC,WAAW,CAAC,EAAE,QAAQ,CAAC,CAAC;AAChE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@jspm/local-mcp",
3
+ "mcpName": "io.github.jspm/local-mcp",
4
+ "version": "0.1.0",
5
+ "description": "A local-first MCP server for managing JSPM import maps in real projects.",
6
+ "type": "module",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "bin": {
10
+ "jspm-local-mcp": "./dist/index.js"
11
+ },
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "default": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "Readme.md",
21
+ "LICENSE"
22
+ ],
23
+ "engines": {
24
+ "node": ">=18"
25
+ },
26
+ "scripts": {
27
+ "start": "node dist/index.js",
28
+ "build": "tsc",
29
+ "clean": "rm -rf dist",
30
+ "prepublishOnly": "npm run clean && npm run build"
31
+ },
32
+ "author": "JSPM",
33
+ "license": "MIT",
34
+ "homepage": "https://github.com/jspm/mcp#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/jspm/mcp/issues"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/jspm/mcp.git"
41
+ },
42
+ "keywords": [
43
+ "mcp",
44
+ "model-context-protocol",
45
+ "jspm",
46
+ "importmap",
47
+ "import-maps",
48
+ "esm"
49
+ ],
50
+ "devDependencies": {
51
+ "@types/node": "^22.19.17",
52
+ "tsx": "^4.19.2",
53
+ "typescript": "^5.7.2"
54
+ },
55
+ "dependencies": {
56
+ "@jspm/generator": "^2.13.0",
57
+ "@modelcontextprotocol/sdk": "^1.29.0",
58
+ "zod": "^3.25.76"
59
+ }
60
+ }