mcp-layer 0.0.0 → 0.1.1
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 +21 -0
- package/README.md +120 -0
- package/package.json +49 -10
- package/src/generate.js +209 -0
- package/src/generate.test.js +53 -0
- package/src/index.js +72 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arnout Kazemier
|
|
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,120 @@
|
|
|
1
|
+
# MCP Layer
|
|
2
|
+
|
|
3
|
+
`mcp-layer` helps engineers bolt extra behaviors on top of existing MCP servers without reimplementing transport or schema parsing. It is a small, focused toolbox for discovering MCP configs, connecting to servers, and extracting a unified schema that can drive CLIs, REST APIs, UI renderers, or additional MCP layers.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [What you can build with this repo](#what-you-can-build-with-this-repo)
|
|
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)
|
|
15
|
+
|
|
16
|
+
## What you can build with this repo
|
|
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
|
+
- **UI renderers** that surface MCP Apps resources using `_meta.ui` metadata.
|
|
21
|
+
- **New MCP layers** that programmatically reason about tool/resource catalogs.
|
|
22
|
+
|
|
23
|
+
## Packages
|
|
24
|
+
|
|
25
|
+
### mcp-layer
|
|
26
|
+
|
|
27
|
+
`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.
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import { attach, cli, config, connect, schema, session, testServer } from 'mcp-layer';
|
|
31
|
+
|
|
32
|
+
const loaded = await config.load(undefined, process.cwd());
|
|
33
|
+
const link = await connect.connect(loaded, 'demo');
|
|
34
|
+
const catalog = await schema.extract(link);
|
|
35
|
+
await link.close();
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Infrastructure and utilities
|
|
39
|
+
|
|
40
|
+
| Package | Purpose |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| [`@mcp-layer/config`](packages/config/README.md) | Discover and normalize MCP server configs across editors/clients. |
|
|
43
|
+
| [`@mcp-layer/session`](packages/session/README.md) | Shared Session handle used by connect and attach. |
|
|
44
|
+
| [`@mcp-layer/connect`](packages/connect/README.md) | Connect to MCP servers over stdio and return a closeable Session. |
|
|
45
|
+
| [`@mcp-layer/attach`](packages/attach/README.md) | Attach to in-process MCP SDK servers or Platformatic Fastify MCP plugins and return a Session. |
|
|
46
|
+
| [`@mcp-layer/schema`](packages/schema/README.md) | Extract tools/resources/prompts/templates into a unified Zod-backed schema (including MCP Apps metadata). |
|
|
47
|
+
| [`@mcp-layer/test-server`](packages/test-server/README.md) | Feature-complete MCP server for integration tests and local exploration. |
|
|
48
|
+
| [`@mcp-layer/openapi`](packages/openapi/README.md) | Generate OpenAPI 3.1 specs from MCP catalogs. |
|
|
49
|
+
| [`@mcp-layer/rest`](packages/rest/README.md) | Fastify plugin that exposes MCP servers over REST. |
|
|
50
|
+
|
|
51
|
+
### Layers and interfaces
|
|
52
|
+
|
|
53
|
+
| Package | Purpose |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| [`@mcp-layer/cli`](packages/cli/README.md) | CLI framework for turning MCP schemas into commands. |
|
|
56
|
+
| [`@mcp-layer/openapi`](packages/openapi/README.md) | OpenAPI 3.1 generation for REST surfaces. |
|
|
57
|
+
| [`@mcp-layer/rest`](packages/rest/README.md) | Fastify plugin for HTTP REST exposure. |
|
|
58
|
+
|
|
59
|
+
## CLI quick try
|
|
60
|
+
|
|
61
|
+
If you already have an MCP config on disk, you can try the CLI immediately:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
mcp-layer servers list
|
|
65
|
+
mcp-layer tools list --server <name>
|
|
66
|
+
mcp-layer tools <tool> --help
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Quick start (end-to-end)
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { load } from '@mcp-layer/config';
|
|
73
|
+
import { connect } from '@mcp-layer/connect';
|
|
74
|
+
import { extract } from '@mcp-layer/schema';
|
|
75
|
+
|
|
76
|
+
const config = await load(undefined, process.cwd());
|
|
77
|
+
const session = await connect(config, 'demo');
|
|
78
|
+
|
|
79
|
+
const schema = await extract(session);
|
|
80
|
+
console.log(schema.items.map((item) => item.name));
|
|
81
|
+
|
|
82
|
+
await session.close();
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Design principles
|
|
86
|
+
|
|
87
|
+
- **Single source of truth**: normalized schemas flow from the MCP server, not from tool-specific parsing.
|
|
88
|
+
- **Minimal surface area**: each package does one job and composes cleanly with the others.
|
|
89
|
+
- **Real integration tests**: no mocks; the test server is used as a real MCP target.
|
|
90
|
+
|
|
91
|
+
## Development
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
pnpm install
|
|
95
|
+
pnpm test
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Releasing
|
|
99
|
+
|
|
100
|
+
We use Changesets to manage versions and a GitHub Actions release workflow to publish packages. In short:
|
|
101
|
+
|
|
102
|
+
1) Add a changeset: `pnpm changeset`
|
|
103
|
+
2) Merge the Changesets PR
|
|
104
|
+
3) GitHub Actions publishes via npm Trusted Publishing (OIDC)
|
|
105
|
+
|
|
106
|
+
Before publishing, configure npm Trusted Publishers for each package in the npm registry and ensure the release workflow has `id-token: write` permissions.
|
|
107
|
+
|
|
108
|
+
The root package runs `prepack` to regenerate `src/index.js` and sync root `package.json` dependencies to the workspace packages before publishing.
|
|
109
|
+
|
|
110
|
+
See `.github/workflows/release.yml` for the pipeline details.
|
|
111
|
+
|
|
112
|
+
The publish guard at `.github/workflows/publish-guard.yml` runs after the `Release` workflow completes and locates the open `Version Packages` PR (`changeset-release/main`). It checks npm for workspace package existence and upserts a single PR comment when packages still need first-time bootstrap publishing.
|
|
113
|
+
|
|
114
|
+
## Repository guidelines
|
|
115
|
+
|
|
116
|
+
See `AGENTS.md` for coding style, testing requirements, and documentation expectations.
|
|
117
|
+
|
|
118
|
+
## License
|
|
119
|
+
|
|
120
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,20 +1,59 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mcp-layer",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Layers
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Layers of functionality that can be add to any MCP server. ",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/3rd-Eden/mcp-layer"
|
|
8
|
+
},
|
|
5
9
|
"keywords": [
|
|
6
|
-
"layer",
|
|
7
10
|
"mcp",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
11
|
+
"layer",
|
|
12
|
+
"mcp-layer",
|
|
13
|
+
"communication",
|
|
14
|
+
"cli",
|
|
15
|
+
"api",
|
|
16
|
+
"http",
|
|
17
|
+
"graphql",
|
|
18
|
+
"openapi",
|
|
19
|
+
"swagger",
|
|
20
|
+
"protocol",
|
|
21
|
+
"ui",
|
|
22
|
+
"rendering"
|
|
12
23
|
],
|
|
13
24
|
"license": "MIT",
|
|
14
25
|
"author": "Arnout Kazemier",
|
|
26
|
+
"packageManager": "pnpm@8.15.4",
|
|
15
27
|
"type": "module",
|
|
16
|
-
"
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@changesets/cli": "^2.29.2"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@mcp-layer/attach": "1.1.1",
|
|
33
|
+
"@mcp-layer/cli": "1.1.1",
|
|
34
|
+
"@mcp-layer/config": "1.0.1",
|
|
35
|
+
"@mcp-layer/connect": "1.0.1",
|
|
36
|
+
"@mcp-layer/error": "0.2.0",
|
|
37
|
+
"@mcp-layer/manager": "0.2.0",
|
|
38
|
+
"@mcp-layer/openapi": "1.1.1",
|
|
39
|
+
"@mcp-layer/rest": "1.2.0",
|
|
40
|
+
"@mcp-layer/schema": "1.0.2",
|
|
41
|
+
"@mcp-layer/session": "1.0.0",
|
|
42
|
+
"@mcp-layer/test-server": "1.0.1"
|
|
43
|
+
},
|
|
44
|
+
"main": "./src/index.js",
|
|
45
|
+
"files": [
|
|
46
|
+
"src",
|
|
47
|
+
"README.md",
|
|
48
|
+
"LICENSE"
|
|
49
|
+
],
|
|
50
|
+
"exports": {
|
|
51
|
+
".": "./src/index.js"
|
|
52
|
+
},
|
|
17
53
|
"scripts": {
|
|
18
|
-
"test": "
|
|
54
|
+
"test": "node --test",
|
|
55
|
+
"changeset": "changeset",
|
|
56
|
+
"changeset:version": "changeset version",
|
|
57
|
+
"changeset:publish": "changeset publish"
|
|
19
58
|
}
|
|
20
|
-
}
|
|
59
|
+
}
|
package/src/generate.js
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { access, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Convert a package folder name into a namespace export name.
|
|
7
|
+
* @param {string} name - Package folder name.
|
|
8
|
+
* @returns {string} Namespace export name.
|
|
9
|
+
*/
|
|
10
|
+
export function toNamespace(name) {
|
|
11
|
+
return name.replace(/-([a-z0-9])/g, function toCamel(_, next) {
|
|
12
|
+
return next.toUpperCase();
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Collect package folder names from the workspace packages directory.
|
|
18
|
+
* @param {string} rootDir - Repository root directory.
|
|
19
|
+
* @returns {Promise<string[]>} Package folder names.
|
|
20
|
+
*/
|
|
21
|
+
export async function collectPackages(rootDir) {
|
|
22
|
+
const packagesDir = path.join(rootDir, 'packages');
|
|
23
|
+
const entries = await readdir(packagesDir, { withFileTypes: true });
|
|
24
|
+
const packages = [];
|
|
25
|
+
|
|
26
|
+
for (const entry of entries) {
|
|
27
|
+
if (!entry.isDirectory()) continue;
|
|
28
|
+
|
|
29
|
+
const pkgPath = path.join(packagesDir, entry.name, 'package.json');
|
|
30
|
+
const exists = await hasPackageJson(pkgPath);
|
|
31
|
+
|
|
32
|
+
if (exists) packages.push(entry.name);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
packages.sort();
|
|
36
|
+
return packages;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check whether a package.json exists for the given path.
|
|
41
|
+
* @param {string} pkgPath - Expected package.json path.
|
|
42
|
+
* @returns {Promise<boolean>} Whether the package.json exists.
|
|
43
|
+
*/
|
|
44
|
+
export async function hasPackageJson(pkgPath) {
|
|
45
|
+
try {
|
|
46
|
+
await access(pkgPath);
|
|
47
|
+
return true;
|
|
48
|
+
} catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Build the root index.js content from workspace packages.
|
|
55
|
+
* @param {string} rootDir - Repository root directory.
|
|
56
|
+
* @returns {Promise<string>} Generated index.js content.
|
|
57
|
+
*/
|
|
58
|
+
export async function buildIndex(rootDir) {
|
|
59
|
+
const meta = await collectPackageMeta(rootDir);
|
|
60
|
+
const lines = [];
|
|
61
|
+
|
|
62
|
+
lines.push('/**');
|
|
63
|
+
lines.push(' * @module mcp-layer');
|
|
64
|
+
lines.push(' * @description Aggregate entrypoint for the MCP Layer workspace packages.');
|
|
65
|
+
lines.push(' * @note This file is autogenerated by src/generate.js. Manual edits will be overwritten.');
|
|
66
|
+
lines.push(' */');
|
|
67
|
+
lines.push('');
|
|
68
|
+
|
|
69
|
+
for (const item of meta) {
|
|
70
|
+
const namespace = toNamespace(item.dir);
|
|
71
|
+
const importPath = item.name;
|
|
72
|
+
|
|
73
|
+
lines.push('/**');
|
|
74
|
+
lines.push(` * Package namespace from \`${item.name}\`.`);
|
|
75
|
+
lines.push(` * @type {typeof import('${importPath}')}`);
|
|
76
|
+
lines.push(' */');
|
|
77
|
+
lines.push(`export * as ${namespace} from '${importPath}';`);
|
|
78
|
+
lines.push('');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return `${lines.join('\n')}\n`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Collect package metadata from workspace folders.
|
|
86
|
+
* @param {string} rootDir - Repository root directory.
|
|
87
|
+
* @returns {Promise<Array<{name: string, dir: string}>>} Package metadata.
|
|
88
|
+
*/
|
|
89
|
+
export async function collectPackageMeta(rootDir) {
|
|
90
|
+
const packages = await collectPackages(rootDir);
|
|
91
|
+
const meta = [];
|
|
92
|
+
|
|
93
|
+
for (const dir of packages) {
|
|
94
|
+
const pkgPath = path.join(rootDir, 'packages', dir, 'package.json');
|
|
95
|
+
const data = await readJson(pkgPath);
|
|
96
|
+
meta.push({ name: data.name, dir });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return meta;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Update root package.json dependencies to match workspace packages.
|
|
104
|
+
* @param {string} rootDir - Repository root directory.
|
|
105
|
+
* @returns {Promise<void>} Resolves when dependencies are updated.
|
|
106
|
+
*/
|
|
107
|
+
export async function syncDependencies(rootDir) {
|
|
108
|
+
const pkgPath = path.join(rootDir, 'package.json');
|
|
109
|
+
const data = await readJson(pkgPath);
|
|
110
|
+
const deps = { ...(data.dependencies ?? {}) };
|
|
111
|
+
const meta = await collectPackageMeta(rootDir);
|
|
112
|
+
const names = new Set();
|
|
113
|
+
|
|
114
|
+
for (const item of meta) {
|
|
115
|
+
names.add(item.name);
|
|
116
|
+
deps[item.name] = 'workspace:*';
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
for (const key of Object.keys(deps)) {
|
|
120
|
+
if (key.startsWith('@mcp-layer/') && !names.has(key)) delete deps[key];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
data.dependencies = sortObject(deps);
|
|
124
|
+
await writeJson(pkgPath, data);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Write the generated index.js file if contents differ.
|
|
129
|
+
* @param {string} rootDir - Repository root directory.
|
|
130
|
+
* @param {string} outFile - Output file path.
|
|
131
|
+
* @returns {Promise<void>} Resolves when the file is written or unchanged.
|
|
132
|
+
*/
|
|
133
|
+
export async function writeIndex(rootDir, outFile) {
|
|
134
|
+
const next = await buildIndex(rootDir);
|
|
135
|
+
const current = await readMaybe(outFile);
|
|
136
|
+
|
|
137
|
+
if (current === next) return;
|
|
138
|
+
|
|
139
|
+
await writeFile(outFile, next, 'utf8');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Read a file if it exists, otherwise return null.
|
|
144
|
+
* @param {string} filePath - File path to read.
|
|
145
|
+
* @returns {Promise<string | null>} File contents or null.
|
|
146
|
+
*/
|
|
147
|
+
export async function readMaybe(filePath) {
|
|
148
|
+
try {
|
|
149
|
+
return await readFile(filePath, 'utf8');
|
|
150
|
+
} catch {
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Read and parse a JSON file.
|
|
157
|
+
* @param {string} filePath - JSON file path.
|
|
158
|
+
* @returns {Promise<Record<string, any>>} Parsed JSON data.
|
|
159
|
+
*/
|
|
160
|
+
export async function readJson(filePath) {
|
|
161
|
+
const raw = await readFile(filePath, 'utf8');
|
|
162
|
+
return JSON.parse(raw);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Write a JSON file with stable formatting.
|
|
167
|
+
* @param {string} filePath - JSON file path.
|
|
168
|
+
* @param {Record<string, any>} data - JSON data to write.
|
|
169
|
+
* @returns {Promise<void>} Resolves when the file is written.
|
|
170
|
+
*/
|
|
171
|
+
export async function writeJson(filePath, data) {
|
|
172
|
+
const next = `${JSON.stringify(data, null, 2)}\n`;
|
|
173
|
+
const current = await readMaybe(filePath);
|
|
174
|
+
|
|
175
|
+
if (current === next) return;
|
|
176
|
+
|
|
177
|
+
await writeFile(filePath, next, 'utf8');
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Sort an object's keys alphabetically.
|
|
182
|
+
* @param {Record<string, string>} input - Object to sort.
|
|
183
|
+
* @returns {Record<string, string>} Sorted object.
|
|
184
|
+
*/
|
|
185
|
+
export function sortObject(input) {
|
|
186
|
+
const keys = Object.keys(input).sort();
|
|
187
|
+
const sorted = {};
|
|
188
|
+
|
|
189
|
+
for (const key of keys) {
|
|
190
|
+
sorted[key] = input[key];
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return sorted;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Run the generator when executed as a script.
|
|
198
|
+
* @returns {Promise<void>} Resolves when generation completes.
|
|
199
|
+
*/
|
|
200
|
+
export async function run() {
|
|
201
|
+
const rootDir = process.cwd();
|
|
202
|
+
const outFile = path.join(rootDir, 'src', 'index.js');
|
|
203
|
+
|
|
204
|
+
await syncDependencies(rootDir);
|
|
205
|
+
await writeIndex(rootDir, outFile);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const entry = fileURLToPath(import.meta.url);
|
|
209
|
+
if (process.argv[1] === entry) run();
|
|
@@ -0,0 +1,53 @@
|
|
|
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);
|
package/src/index.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module mcp-layer
|
|
3
|
+
* @description Aggregate entrypoint for the MCP Layer workspace packages.
|
|
4
|
+
* @note This file is autogenerated by src/generate.js. Manual edits will be overwritten.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Package namespace from `@mcp-layer/attach`.
|
|
9
|
+
* @type {typeof import('@mcp-layer/attach')}
|
|
10
|
+
*/
|
|
11
|
+
export * as attach from '@mcp-layer/attach';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Package namespace from `@mcp-layer/cli`.
|
|
15
|
+
* @type {typeof import('@mcp-layer/cli')}
|
|
16
|
+
*/
|
|
17
|
+
export * as cli from '@mcp-layer/cli';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Package namespace from `@mcp-layer/config`.
|
|
21
|
+
* @type {typeof import('@mcp-layer/config')}
|
|
22
|
+
*/
|
|
23
|
+
export * as config from '@mcp-layer/config';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Package namespace from `@mcp-layer/connect`.
|
|
27
|
+
* @type {typeof import('@mcp-layer/connect')}
|
|
28
|
+
*/
|
|
29
|
+
export * as connect from '@mcp-layer/connect';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Package namespace from `@mcp-layer/error`.
|
|
33
|
+
* @type {typeof import('@mcp-layer/error')}
|
|
34
|
+
*/
|
|
35
|
+
export * as error from '@mcp-layer/error';
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Package namespace from `@mcp-layer/manager`.
|
|
39
|
+
* @type {typeof import('@mcp-layer/manager')}
|
|
40
|
+
*/
|
|
41
|
+
export * as manager from '@mcp-layer/manager';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Package namespace from `@mcp-layer/openapi`.
|
|
45
|
+
* @type {typeof import('@mcp-layer/openapi')}
|
|
46
|
+
*/
|
|
47
|
+
export * as openapi from '@mcp-layer/openapi';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Package namespace from `@mcp-layer/rest`.
|
|
51
|
+
* @type {typeof import('@mcp-layer/rest')}
|
|
52
|
+
*/
|
|
53
|
+
export * as rest from '@mcp-layer/rest';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Package namespace from `@mcp-layer/schema`.
|
|
57
|
+
* @type {typeof import('@mcp-layer/schema')}
|
|
58
|
+
*/
|
|
59
|
+
export * as schema from '@mcp-layer/schema';
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Package namespace from `@mcp-layer/session`.
|
|
63
|
+
* @type {typeof import('@mcp-layer/session')}
|
|
64
|
+
*/
|
|
65
|
+
export * as session from '@mcp-layer/session';
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Package namespace from `@mcp-layer/test-server`.
|
|
69
|
+
* @type {typeof import('@mcp-layer/test-server')}
|
|
70
|
+
*/
|
|
71
|
+
export * as testServer from '@mcp-layer/test-server';
|
|
72
|
+
|