mcp-layer 0.2.1 → 0.2.2
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 +55 -93
- package/package.json +21 -21
- package/src/generate.js +47 -14
- package/src/generate.test.js +0 -53
package/README.md
CHANGED
|
@@ -1,123 +1,85 @@
|
|
|
1
|
-
#
|
|
1
|
+
# mcp-layer
|
|
2
2
|
|
|
3
|
-
`mcp-layer`
|
|
3
|
+
`mcp-layer` is the npm entry point for MCP Layer, a toolkit for building production-ready interfaces on top of any MCP server.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Use it to discover MCP configs, connect sessions, normalize catalogs, and expose those capabilities through CLI, REST, GraphQL, and OpenAPI layers in one cohesive stack.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
- [Packages](#packages)
|
|
9
|
-
- [CLI quick try](#cli-quick-try)
|
|
10
|
-
- [Quick start (end-to-end)](#quick-start-end-to-end)
|
|
11
|
-
- [Design principles](#design-principles)
|
|
12
|
-
- [Development](#development)
|
|
13
|
-
- [Releasing](#releasing)
|
|
14
|
-
- [Repository guidelines](#repository-guidelines)
|
|
7
|
+
## Install
|
|
15
8
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
- **CLI layers** that expose MCP tools as commands with validated input.
|
|
19
|
-
- **REST gateways** that generate endpoints and schemas from MCP tool definitions.
|
|
20
|
-
- **GraphQL gateways** that expose generated and generic operations on top of MCP catalogs.
|
|
21
|
-
- **UI renderers** that surface MCP Apps resources using `_meta.ui` metadata.
|
|
22
|
-
- **New MCP layers** that programmatically reason about tool/resource catalogs.
|
|
23
|
-
|
|
24
|
-
## Packages
|
|
25
|
-
|
|
26
|
-
### mcp-layer
|
|
27
|
-
|
|
28
|
-
`mcp-layer` aggregates every workspace package under a single namespace export so you can import from one place when prototyping or composing multiple layers. We still recommend consuming the individual packages by default; the root package exists for teams that want a single install with always-matched versions/majors.
|
|
29
|
-
|
|
30
|
-
```js
|
|
31
|
-
import { attach, cli, config, connect, schema, session, testServer } from 'mcp-layer';
|
|
32
|
-
|
|
33
|
-
const loaded = await config.load(undefined, process.cwd());
|
|
34
|
-
const link = await connect.connect(loaded, 'demo');
|
|
35
|
-
const catalog = await schema.extract(link);
|
|
36
|
-
await link.close();
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
### Infrastructure and utilities
|
|
40
|
-
|
|
41
|
-
| Package | Purpose |
|
|
42
|
-
| --- | --- |
|
|
43
|
-
| [`@mcp-layer/config`](packages/config/README.md) | Discover and normalize MCP server configs across editors/clients. |
|
|
44
|
-
| [`@mcp-layer/session`](packages/session/README.md) | Shared Session handle used by connect and attach. |
|
|
45
|
-
| [`@mcp-layer/connect`](packages/connect/README.md) | Connect to MCP servers over stdio and return a closeable Session. |
|
|
46
|
-
| [`@mcp-layer/attach`](packages/attach/README.md) | Attach to in-process MCP SDK servers or Platformatic Fastify MCP plugins and return a Session. |
|
|
47
|
-
| [`@mcp-layer/schema`](packages/schema/README.md) | Extract tools/resources/prompts/templates into a unified Zod-backed schema (including MCP Apps metadata). |
|
|
48
|
-
| [`@mcp-layer/gateway`](packages/gateway/README.md) | Shared adapter runtime primitives for catalog bootstrap, validation, resilience, telemetry, and deterministic mapping. |
|
|
49
|
-
| [`@mcp-layer/test-server`](packages/test-server/README.md) | Feature-complete MCP server for integration tests and local exploration. |
|
|
50
|
-
| [`@mcp-layer/openapi`](packages/openapi/README.md) | Generate OpenAPI 3.1 specs from MCP catalogs. |
|
|
51
|
-
| [`@mcp-layer/rest`](packages/rest/README.md) | Fastify plugin that exposes MCP servers over REST. |
|
|
52
|
-
|
|
53
|
-
### Layers and interfaces
|
|
54
|
-
|
|
55
|
-
| Package | Purpose |
|
|
56
|
-
| --- | --- |
|
|
57
|
-
| [`@mcp-layer/cli`](packages/cli/README.md) | CLI framework for turning MCP schemas into commands. |
|
|
58
|
-
| [`@mcp-layer/openapi`](packages/openapi/README.md) | OpenAPI 3.1 generation for REST surfaces. |
|
|
59
|
-
| [`@mcp-layer/rest`](packages/rest/README.md) | Fastify plugin for HTTP REST exposure. |
|
|
60
|
-
| [`@mcp-layer/graphql`](packages/graphql/README.md) | Fastify plugin and schema builder for GraphQL exposure on MCP catalogs. |
|
|
61
|
-
|
|
62
|
-
## CLI quick try
|
|
63
|
-
|
|
64
|
-
If you already have an MCP config on disk, you can try the CLI immediately:
|
|
9
|
+
Use your package manager of choice to install `mcp-layer` in any Node.js project.
|
|
65
10
|
|
|
66
11
|
```sh
|
|
67
|
-
mcp-layer
|
|
68
|
-
mcp-layer
|
|
69
|
-
mcp-layer
|
|
12
|
+
npm install mcp-layer
|
|
13
|
+
pnpm add mcp-layer
|
|
14
|
+
yarn add mcp-layer
|
|
70
15
|
```
|
|
71
16
|
|
|
72
|
-
## Quick
|
|
17
|
+
## Quick Start
|
|
73
18
|
|
|
74
|
-
|
|
75
|
-
import { load } from '@mcp-layer/config';
|
|
76
|
-
import { connect } from '@mcp-layer/connect';
|
|
77
|
-
import { extract } from '@mcp-layer/schema';
|
|
19
|
+
This example demonstrates the primary workflow: load MCP configuration, open a session, and extract a normalized catalog from one package import. This matters when you want to wire a prototype quickly without managing multiple top-level dependencies.
|
|
78
20
|
|
|
79
|
-
|
|
80
|
-
|
|
21
|
+
```js
|
|
22
|
+
import { config, connect, schema } from 'mcp-layer';
|
|
81
23
|
|
|
82
|
-
const
|
|
83
|
-
|
|
24
|
+
const cfg = await config.load(undefined, process.cwd());
|
|
25
|
+
const session = await connect.connect(cfg, 'demo');
|
|
26
|
+
const catalog = await schema.extract(session);
|
|
84
27
|
|
|
28
|
+
console.log(catalog.items?.length ?? 0);
|
|
85
29
|
await session.close();
|
|
86
30
|
```
|
|
87
31
|
|
|
88
|
-
|
|
32
|
+
Running this script prints the number of discovered catalog items for the selected server.
|
|
89
33
|
|
|
90
|
-
|
|
91
|
-
- **Layered adapters**: `schema -> gateway -> rest/graphql` keeps protocol logic centralized while adapters stay thin.
|
|
92
|
-
- **Minimal surface area**: each package does one job and composes cleanly with the others.
|
|
93
|
-
- **Real integration tests**: no mocks; the test server is used as a real MCP target.
|
|
34
|
+
## API Reference
|
|
94
35
|
|
|
95
|
-
|
|
36
|
+
`mcp-layer` exports package namespaces. If you are new to MCP Layer, this table explains what each namespace is for and links to full package documentation.
|
|
96
37
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
38
|
+
| Namespace export | Purpose | Documentation |
|
|
39
|
+
| --- | --- | --- |
|
|
40
|
+
| `attach` | Attach to in-process MCP SDK servers without launching external transports. | [`@mcp-layer/attach` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/attach/README.md) |
|
|
41
|
+
| `cli` | Build command-line interfaces for MCP tools, prompts, resources, and templates. | [`@mcp-layer/cli` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/cli/README.md) |
|
|
42
|
+
| `config` | Discover and normalize MCP server configuration across host tools. | [`@mcp-layer/config` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/config/README.md) |
|
|
43
|
+
| `connect` | Connect to MCP servers over stdio, Streamable HTTP, or SSE. | [`@mcp-layer/connect` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/connect/README.md) |
|
|
44
|
+
| `error` | Create structured runtime errors with stable references and docs links. | [`@mcp-layer/error` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/error/README.md) |
|
|
45
|
+
| `gateway` | Reuse shared adapter runtime primitives for mapping, validation, resilience, and telemetry. | [`@mcp-layer/gateway` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/gateway/README.md) |
|
|
46
|
+
| `graphql` | Expose MCP catalogs and operations through GraphQL. | [`@mcp-layer/graphql` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/graphql/README.md) |
|
|
47
|
+
| `manager` | Manage authenticated and shared MCP sessions with reuse and limits. | [`@mcp-layer/manager` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/manager/README.md) |
|
|
48
|
+
| `openapi` | Generate OpenAPI 3.1 documents from MCP catalogs. | [`@mcp-layer/openapi` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/openapi/README.md) |
|
|
49
|
+
| `rest` | Expose MCP sessions as REST endpoints with Fastify. | [`@mcp-layer/rest` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/rest/README.md) |
|
|
50
|
+
| `schema` | Extract and normalize tools, resources, prompts, and templates into a consistent catalog. | [`@mcp-layer/schema` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/schema/README.md) |
|
|
51
|
+
| `session` | Use the shared session abstraction across connectors and adapters. | [`@mcp-layer/session` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/session/README.md) |
|
|
52
|
+
| `testServer` | Run a feature-complete local MCP server for development and integration tests. | [`@mcp-layer/test-server` README](https://github.com/3rd-Eden/mcp-layer/blob/main/packages/test-server/README.md) |
|
|
53
|
+
|
|
54
|
+
### Error Behavior
|
|
55
|
+
|
|
56
|
+
This package does not introduce a custom runtime layer. Errors are raised by whichever namespace package you call.
|
|
101
57
|
|
|
102
|
-
|
|
58
|
+
For structured runtime errors, refer to the package-level error sections in the linked namespace READMEs.
|
|
103
59
|
|
|
104
|
-
|
|
60
|
+
<a id="error-58ed2a"></a>
|
|
61
|
+
#### `findWorkspaceRoot`: Unable to locate workspace root from mcp-layer package.
|
|
105
62
|
|
|
106
|
-
|
|
107
|
-
2) Merge the Changesets PR
|
|
108
|
-
3) GitHub Actions publishes via npm Trusted Publishing (OIDC)
|
|
63
|
+
This error is raised when `mcp-layer` package generation runs in a directory tree that does not contain `pnpm-workspace.yaml`.
|
|
109
64
|
|
|
110
|
-
|
|
65
|
+
Step-by-step resolution:
|
|
66
|
+
1. Run generation from inside a checkout of the MCP Layer repository.
|
|
67
|
+
2. Confirm `pnpm-workspace.yaml` exists at the repository root.
|
|
68
|
+
3. Run `pnpm --filter mcp-layer prepack` from the repository root.
|
|
111
69
|
|
|
112
|
-
|
|
70
|
+
<details>
|
|
71
|
+
<summary>Debug example</summary>
|
|
113
72
|
|
|
114
|
-
|
|
73
|
+
If you copy `packages/mcp-layer` into a standalone folder and run `node src/generate.js`, `findWorkspaceRoot` cannot locate the workspace marker and throws this error.
|
|
74
|
+
</details>
|
|
115
75
|
|
|
116
|
-
|
|
76
|
+
## Standards and Portability
|
|
117
77
|
|
|
118
|
-
|
|
78
|
+
MCP behavior follows the official MCP specification and official TypeScript SDK contracts:
|
|
119
79
|
|
|
120
|
-
|
|
80
|
+
- [Model Context Protocol specification](https://modelcontextprotocol.io/specification)
|
|
81
|
+
- [MCP transport specification](https://modelcontextprotocol.io/specification/latest/basic/transports)
|
|
82
|
+
- [Model Context Protocol TypeScript SDK](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
121
83
|
|
|
122
84
|
## License
|
|
123
85
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-layer",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Build production-ready CLI, REST, GraphQL, and OpenAPI interfaces on top of any MCP server.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/3rd-Eden/mcp-layer"
|
|
@@ -23,16 +23,28 @@
|
|
|
23
23
|
],
|
|
24
24
|
"license": "MIT",
|
|
25
25
|
"author": "Arnout Kazemier",
|
|
26
|
-
"packageManager": "pnpm@8.15.4",
|
|
27
26
|
"type": "module",
|
|
28
|
-
"
|
|
29
|
-
|
|
27
|
+
"main": "./src/index.js",
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"import": "./src/index.js",
|
|
31
|
+
"default": "./src/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./package.json": "./package.json"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"src",
|
|
37
|
+
"README.md",
|
|
38
|
+
"LICENSE"
|
|
39
|
+
],
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
30
42
|
},
|
|
31
43
|
"dependencies": {
|
|
32
44
|
"@mcp-layer/attach": "1.1.1",
|
|
33
|
-
"@mcp-layer/cli": "1.
|
|
45
|
+
"@mcp-layer/cli": "1.3.0",
|
|
34
46
|
"@mcp-layer/config": "1.0.1",
|
|
35
|
-
"@mcp-layer/connect": "1.
|
|
47
|
+
"@mcp-layer/connect": "1.2.0",
|
|
36
48
|
"@mcp-layer/error": "0.2.0",
|
|
37
49
|
"@mcp-layer/manager": "0.2.0",
|
|
38
50
|
"@mcp-layer/graphql": "0.2.0",
|
|
@@ -41,21 +53,9 @@
|
|
|
41
53
|
"@mcp-layer/rest": "1.2.1",
|
|
42
54
|
"@mcp-layer/schema": "1.0.2",
|
|
43
55
|
"@mcp-layer/session": "1.0.0",
|
|
44
|
-
"@mcp-layer/test-server": "1.0.
|
|
45
|
-
},
|
|
46
|
-
"main": "./src/index.js",
|
|
47
|
-
"files": [
|
|
48
|
-
"src",
|
|
49
|
-
"README.md",
|
|
50
|
-
"LICENSE"
|
|
51
|
-
],
|
|
52
|
-
"exports": {
|
|
53
|
-
".": "./src/index.js"
|
|
56
|
+
"@mcp-layer/test-server": "1.0.3"
|
|
54
57
|
},
|
|
55
58
|
"scripts": {
|
|
56
|
-
"test": "node --test"
|
|
57
|
-
"changeset": "changeset",
|
|
58
|
-
"changeset:version": "changeset version",
|
|
59
|
-
"changeset:publish": "changeset publish"
|
|
59
|
+
"test": "node --test ./test/**/*.js"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/src/generate.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { access, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { LayerError } from '@mcp-layer/error';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Convert a package folder name into a namespace export name.
|
|
@@ -55,8 +56,8 @@ export async function hasPackageJson(pkgPath) {
|
|
|
55
56
|
* @param {string} rootDir - Repository root directory.
|
|
56
57
|
* @returns {Promise<string>} Generated index.js content.
|
|
57
58
|
*/
|
|
58
|
-
export async function buildIndex(rootDir) {
|
|
59
|
-
const meta = await collectPackageMeta(rootDir);
|
|
59
|
+
export async function buildIndex(rootDir, selfName = 'mcp-layer') {
|
|
60
|
+
const meta = await collectPackageMeta(rootDir, new Set([selfName]));
|
|
60
61
|
const lines = [];
|
|
61
62
|
|
|
62
63
|
lines.push('/**');
|
|
@@ -84,15 +85,17 @@ export async function buildIndex(rootDir) {
|
|
|
84
85
|
/**
|
|
85
86
|
* Collect package metadata from workspace folders.
|
|
86
87
|
* @param {string} rootDir - Repository root directory.
|
|
88
|
+
* @param {Set<string>} omit - Package names to skip.
|
|
87
89
|
* @returns {Promise<Array<{name: string, dir: string}>>} Package metadata.
|
|
88
90
|
*/
|
|
89
|
-
export async function collectPackageMeta(rootDir) {
|
|
91
|
+
export async function collectPackageMeta(rootDir, omit = new Set()) {
|
|
90
92
|
const packages = await collectPackages(rootDir);
|
|
91
93
|
const meta = [];
|
|
92
94
|
|
|
93
95
|
for (const dir of packages) {
|
|
94
96
|
const pkgPath = path.join(rootDir, 'packages', dir, 'package.json');
|
|
95
97
|
const data = await readJson(pkgPath);
|
|
98
|
+
if (omit.has(data.name)) continue;
|
|
96
99
|
meta.push({ name: data.name, dir });
|
|
97
100
|
}
|
|
98
101
|
|
|
@@ -100,18 +103,21 @@ export async function collectPackageMeta(rootDir) {
|
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
/**
|
|
103
|
-
* Update
|
|
106
|
+
* Update mcp-layer package dependencies to match workspace packages.
|
|
107
|
+
* @param {string} pkgDir - mcp-layer package directory.
|
|
104
108
|
* @param {string} rootDir - Repository root directory.
|
|
109
|
+
* @param {string} selfName - mcp-layer package name.
|
|
105
110
|
* @returns {Promise<void>} Resolves when dependencies are updated.
|
|
106
111
|
*/
|
|
107
|
-
export async function syncDependencies(rootDir) {
|
|
108
|
-
const pkgPath = path.join(
|
|
112
|
+
export async function syncDependencies(pkgDir, rootDir, selfName = 'mcp-layer') {
|
|
113
|
+
const pkgPath = path.join(pkgDir, 'package.json');
|
|
109
114
|
const data = await readJson(pkgPath);
|
|
110
115
|
const deps = { ...(data.dependencies ?? {}) };
|
|
111
|
-
const meta = await collectPackageMeta(rootDir);
|
|
116
|
+
const meta = await collectPackageMeta(rootDir, new Set([selfName]));
|
|
112
117
|
const names = new Set();
|
|
113
118
|
|
|
114
119
|
for (const item of meta) {
|
|
120
|
+
if (!item.name.startsWith('@mcp-layer/')) continue;
|
|
115
121
|
names.add(item.name);
|
|
116
122
|
deps[item.name] = 'workspace:*';
|
|
117
123
|
}
|
|
@@ -130,8 +136,8 @@ export async function syncDependencies(rootDir) {
|
|
|
130
136
|
* @param {string} outFile - Output file path.
|
|
131
137
|
* @returns {Promise<void>} Resolves when the file is written or unchanged.
|
|
132
138
|
*/
|
|
133
|
-
export async function writeIndex(rootDir, outFile) {
|
|
134
|
-
const next = await buildIndex(rootDir);
|
|
139
|
+
export async function writeIndex(rootDir, outFile, selfName = 'mcp-layer') {
|
|
140
|
+
const next = await buildIndex(rootDir, selfName);
|
|
135
141
|
const current = await readMaybe(outFile);
|
|
136
142
|
|
|
137
143
|
if (current === next) return;
|
|
@@ -193,16 +199,43 @@ export function sortObject(input) {
|
|
|
193
199
|
return sorted;
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Find the workspace root directory by locating pnpm-workspace.yaml.
|
|
204
|
+
* @param {string} start - Directory to start searching from.
|
|
205
|
+
* @returns {Promise<string>} Workspace root directory.
|
|
206
|
+
*/
|
|
207
|
+
export async function findWorkspaceRoot(start) {
|
|
208
|
+
let current = path.resolve(start);
|
|
209
|
+
|
|
210
|
+
while (true) {
|
|
211
|
+
const marker = path.join(current, 'pnpm-workspace.yaml');
|
|
212
|
+
if (await hasPackageJson(marker)) return current;
|
|
213
|
+
|
|
214
|
+
const parent = path.dirname(current);
|
|
215
|
+
if (parent === current)
|
|
216
|
+
throw new LayerError({
|
|
217
|
+
name: 'mcp-layer',
|
|
218
|
+
method: 'findWorkspaceRoot',
|
|
219
|
+
message: 'Unable to locate workspace root from mcp-layer package.',
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
current = parent;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
196
226
|
/**
|
|
197
227
|
* Run the generator when executed as a script.
|
|
198
228
|
* @returns {Promise<void>} Resolves when generation completes.
|
|
199
229
|
*/
|
|
200
230
|
export async function run() {
|
|
201
|
-
const
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
await
|
|
231
|
+
const fileDir = path.dirname(fileURLToPath(import.meta.url));
|
|
232
|
+
const pkgDir = path.resolve(fileDir, '..');
|
|
233
|
+
const rootDir = await findWorkspaceRoot(pkgDir);
|
|
234
|
+
const outFile = path.join(pkgDir, 'src', 'index.js');
|
|
235
|
+
const data = await readJson(path.join(pkgDir, 'package.json'));
|
|
236
|
+
|
|
237
|
+
await syncDependencies(pkgDir, rootDir, data.name);
|
|
238
|
+
await writeIndex(rootDir, outFile, data.name);
|
|
206
239
|
}
|
|
207
240
|
|
|
208
241
|
const entry = fileURLToPath(import.meta.url);
|
package/src/generate.test.js
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict';
|
|
2
|
-
import { readFile } from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
|
-
import test from 'node:test';
|
|
5
|
-
import { buildIndex, collectPackageMeta, readJson } from './generate.js';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Ensure the generated index.js matches the committed file.
|
|
9
|
-
* @returns {Promise<void>}
|
|
10
|
-
*/
|
|
11
|
-
async function matchesGeneratedOutput() {
|
|
12
|
-
const rootDir = process.cwd();
|
|
13
|
-
const outFile = path.join(rootDir, 'src', 'index.js');
|
|
14
|
-
const expected = await buildIndex(rootDir);
|
|
15
|
-
const actual = await readFile(outFile, 'utf8');
|
|
16
|
-
|
|
17
|
-
assert.equal(actual, expected);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
test('mcp-layer index matches generator output', matchesGeneratedOutput);
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Ensure root package.json dependencies include all workspace packages.
|
|
24
|
-
* @returns {Promise<void>}
|
|
25
|
-
*/
|
|
26
|
-
async function matchesDependencies() {
|
|
27
|
-
const rootDir = process.cwd();
|
|
28
|
-
const pkgPath = path.join(rootDir, 'package.json');
|
|
29
|
-
const rootPkg = await readJson(pkgPath);
|
|
30
|
-
const deps = rootPkg.dependencies ?? {};
|
|
31
|
-
const meta = await collectPackageMeta(rootDir);
|
|
32
|
-
const names = new Set();
|
|
33
|
-
|
|
34
|
-
for (const item of meta) {
|
|
35
|
-
names.add(item.name);
|
|
36
|
-
assert.equal(
|
|
37
|
-
deps[item.name],
|
|
38
|
-
'workspace:*',
|
|
39
|
-
`Expected dependency ${item.name} to be set to workspace:*`,
|
|
40
|
-
);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
for (const key of Object.keys(deps)) {
|
|
44
|
-
if (key.startsWith('@mcp-layer/')) {
|
|
45
|
-
assert.ok(
|
|
46
|
-
names.has(key),
|
|
47
|
-
`Expected dependency ${key} to map to a workspace package`,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
test('mcp-layer dependencies include workspace packages', matchesDependencies);
|