@mcp-layer/graphql 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 +21 -0
- package/README.md +788 -0
- package/package.json +57 -0
- package/src/config/defaults.js +24 -0
- package/src/config/validate.js +76 -0
- package/src/index.js +3 -0
- package/src/mapping.js +12 -0
- package/src/plugin.js +650 -0
- package/src/schema.js +418 -0
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-layer/graphql",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Fastify GraphQL plugin and schema builder for MCP catalogs with shared gateway runtime primitives.",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/3rd-Eden/mcp-layer"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"mcp",
|
|
12
|
+
"mcp-layer",
|
|
13
|
+
"graphql",
|
|
14
|
+
"fastify",
|
|
15
|
+
"mercurius",
|
|
16
|
+
"schema",
|
|
17
|
+
"adapter",
|
|
18
|
+
"gateway"
|
|
19
|
+
],
|
|
20
|
+
"main": "src/index.js",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"import": "./src/index.js",
|
|
24
|
+
"default": "./src/index.js"
|
|
25
|
+
},
|
|
26
|
+
"./package.json": "./package.json"
|
|
27
|
+
},
|
|
28
|
+
"files": [
|
|
29
|
+
"src",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@graphql-tools/schema": "^10.0.31",
|
|
37
|
+
"fastify-plugin": "^5.0.0",
|
|
38
|
+
"graphql": "^16.12.0",
|
|
39
|
+
"graphql-type-json": "^0.3.2",
|
|
40
|
+
"mercurius": "^16.7.0",
|
|
41
|
+
"uri-template": "^2.0.0",
|
|
42
|
+
"@mcp-layer/gateway": "0.1.0",
|
|
43
|
+
"@mcp-layer/error": "0.2.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"fastify": "^5.0.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"fastify": "^5.7.4",
|
|
50
|
+
"@mcp-layer/manager": "0.2.0",
|
|
51
|
+
"@mcp-layer/test-server": "1.0.1",
|
|
52
|
+
"@mcp-layer/attach": "1.1.1"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"test": "node --test --experimental-test-coverage ./test/**/*.test.js"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defaults as runtimeDefaults } from '@mcp-layer/gateway';
|
|
2
|
+
|
|
3
|
+
const base = runtimeDefaults('mcp-layer-graphql');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Default configuration values for the GraphQL plugin.
|
|
7
|
+
* @type {{ prefix: string | undefined, validation: { trustSchemas: 'auto' | true | false, maxSchemaDepth: number, maxSchemaSize: number, maxPatternLength: number, maxToolNameLength: number, maxTemplateParamLength: number }, resilience: { enabled: boolean, timeout: number, errorThresholdPercentage: number, resetTimeout: number, volumeThreshold: number }, telemetry: { enabled: boolean, serviceName: string, metricPrefix: string, api?: import('@opentelemetry/api') }, errors: { exposeDetails: boolean }, endpoint: string, ide: { enabled: boolean, path: string }, operations: { generated: boolean, generic: boolean } }}
|
|
8
|
+
*/
|
|
9
|
+
export const DEFAULTS = {
|
|
10
|
+
...base,
|
|
11
|
+
telemetry: {
|
|
12
|
+
...base.telemetry,
|
|
13
|
+
metricPrefix: 'graphql'
|
|
14
|
+
},
|
|
15
|
+
endpoint: '/graphql',
|
|
16
|
+
ide: {
|
|
17
|
+
enabled: false,
|
|
18
|
+
path: '/graphiql'
|
|
19
|
+
},
|
|
20
|
+
operations: {
|
|
21
|
+
generated: true,
|
|
22
|
+
generic: true
|
|
23
|
+
}
|
|
24
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { validateRuntimeOptions } from '@mcp-layer/gateway';
|
|
2
|
+
import { LayerError } from '@mcp-layer/error';
|
|
3
|
+
import { DEFAULTS } from './defaults.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Test whether a value is a plain object.
|
|
7
|
+
* @param {unknown} value - Candidate value.
|
|
8
|
+
* @returns {value is Record<string, unknown>}
|
|
9
|
+
*/
|
|
10
|
+
function isRecord(value) {
|
|
11
|
+
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Validate GraphQL adapter options.
|
|
16
|
+
* @param {Record<string, unknown>} opts - User options.
|
|
17
|
+
* @returns {{ session: unknown, manager?: { get: (request: import('fastify').FastifyRequest) => Promise<import('@mcp-layer/session').Session>, close?: () => Promise<void> }, prefix?: string | ((version: string, info: Record<string, unknown> | undefined, name: string) => string), validation: { trustSchemas: 'auto' | true | false, maxSchemaDepth: number, maxSchemaSize: number, maxPatternLength: number, maxToolNameLength: number, maxTemplateParamLength: number }, resilience: { enabled: boolean, timeout: number, errorThresholdPercentage: number, resetTimeout: number, volumeThreshold: number }, telemetry: { enabled: boolean, serviceName: string, metricPrefix: string, api?: import('@opentelemetry/api') }, errors: { exposeDetails: boolean }, endpoint: string, ide: { enabled: boolean, path: string }, operations: { generated: boolean, generic: boolean } }}
|
|
18
|
+
*/
|
|
19
|
+
export function validateOptions(opts) {
|
|
20
|
+
const base = validateRuntimeOptions(opts, {
|
|
21
|
+
name: 'graphql',
|
|
22
|
+
serviceName: DEFAULTS.telemetry.serviceName
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const input = isRecord(opts) ? opts : {};
|
|
26
|
+
const endpoint = typeof input.endpoint === 'string' && input.endpoint.length > 0
|
|
27
|
+
? input.endpoint
|
|
28
|
+
: DEFAULTS.endpoint;
|
|
29
|
+
|
|
30
|
+
if (!endpoint.startsWith('/')) {
|
|
31
|
+
throw new LayerError({
|
|
32
|
+
name: 'graphql',
|
|
33
|
+
method: 'validateOptions',
|
|
34
|
+
message: 'endpoint must start with "/".'
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const ideInput = isRecord(input.ide) ? input.ide : {};
|
|
39
|
+
const ide = {
|
|
40
|
+
enabled: ideInput.enabled === undefined ? DEFAULTS.ide.enabled : Boolean(ideInput.enabled),
|
|
41
|
+
path: typeof ideInput.path === 'string' && ideInput.path.length > 0 ? ideInput.path : DEFAULTS.ide.path
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
if (!ide.path.startsWith('/')) {
|
|
45
|
+
throw new LayerError({
|
|
46
|
+
name: 'graphql',
|
|
47
|
+
method: 'validateOptions',
|
|
48
|
+
message: 'ide.path must start with "/".'
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const operationsInput = isRecord(input.operations) ? input.operations : {};
|
|
53
|
+
const operations = {
|
|
54
|
+
generated: operationsInput.generated === undefined ? DEFAULTS.operations.generated : Boolean(operationsInput.generated),
|
|
55
|
+
generic: operationsInput.generic === undefined ? DEFAULTS.operations.generic : Boolean(operationsInput.generic)
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (!operations.generated && !operations.generic) {
|
|
59
|
+
throw new LayerError({
|
|
60
|
+
name: 'graphql',
|
|
61
|
+
method: 'validateOptions',
|
|
62
|
+
message: 'operations.generated and operations.generic cannot both be false.'
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return {
|
|
67
|
+
...base,
|
|
68
|
+
telemetry: {
|
|
69
|
+
...base.telemetry,
|
|
70
|
+
metricPrefix: 'graphql'
|
|
71
|
+
},
|
|
72
|
+
endpoint,
|
|
73
|
+
ide,
|
|
74
|
+
operations
|
|
75
|
+
};
|
|
76
|
+
}
|
package/src/index.js
ADDED
package/src/mapping.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createMap } from '@mcp-layer/gateway';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Build deterministic GraphQL mapping metadata from a catalog.
|
|
5
|
+
* @param {{ items?: Array<Record<string, unknown>> }} catalog - Extracted catalog.
|
|
6
|
+
* @param {Record<string, unknown>} [options] - Reserved for future mapping customization.
|
|
7
|
+
* @returns {ReturnType<typeof createMap>}
|
|
8
|
+
*/
|
|
9
|
+
export function map(catalog, options = {}) {
|
|
10
|
+
void options;
|
|
11
|
+
return createMap(catalog);
|
|
12
|
+
}
|