@graphorin/mcp 0.5.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.
Files changed (70) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/LICENSE +21 -0
  3. package/README.md +296 -0
  4. package/dist/client/adapt-result.d.ts +25 -0
  5. package/dist/client/adapt-result.d.ts.map +1 -0
  6. package/dist/client/adapt-result.js +174 -0
  7. package/dist/client/adapt-result.js.map +1 -0
  8. package/dist/client/client-handlers.js +134 -0
  9. package/dist/client/client-handlers.js.map +1 -0
  10. package/dist/client/client.d.ts +21 -0
  11. package/dist/client/client.d.ts.map +1 -0
  12. package/dist/client/client.js +358 -0
  13. package/dist/client/client.js.map +1 -0
  14. package/dist/client/defer-loading.d.ts +7 -0
  15. package/dist/client/defer-loading.d.ts.map +1 -0
  16. package/dist/client/defer-loading.js +81 -0
  17. package/dist/client/defer-loading.js.map +1 -0
  18. package/dist/client/inbound-filters.js +65 -0
  19. package/dist/client/inbound-filters.js.map +1 -0
  20. package/dist/client/index.d.ts +7 -0
  21. package/dist/client/index.js +7 -0
  22. package/dist/client/mcp-resource-reader.d.ts +22 -0
  23. package/dist/client/mcp-resource-reader.d.ts.map +1 -0
  24. package/dist/client/mcp-resource-reader.js +113 -0
  25. package/dist/client/mcp-resource-reader.js.map +1 -0
  26. package/dist/client/pinning.js +41 -0
  27. package/dist/client/pinning.js.map +1 -0
  28. package/dist/client/to-tools.d.ts +41 -0
  29. package/dist/client/to-tools.d.ts.map +1 -0
  30. package/dist/client/to-tools.js +125 -0
  31. package/dist/client/to-tools.js.map +1 -0
  32. package/dist/client/transport-factory.js +86 -0
  33. package/dist/client/transport-factory.js.map +1 -0
  34. package/dist/client/types.d.ts +353 -0
  35. package/dist/client/types.d.ts.map +1 -0
  36. package/dist/errors/index.d.ts +120 -0
  37. package/dist/errors/index.d.ts.map +1 -0
  38. package/dist/errors/index.js +88 -0
  39. package/dist/errors/index.js.map +1 -0
  40. package/dist/helpers/identity.d.ts +22 -0
  41. package/dist/helpers/identity.d.ts.map +1 -0
  42. package/dist/helpers/identity.js +85 -0
  43. package/dist/helpers/identity.js.map +1 -0
  44. package/dist/helpers/index.d.ts +3 -0
  45. package/dist/helpers/index.js +4 -0
  46. package/dist/helpers/validate-config.d.ts +16 -0
  47. package/dist/helpers/validate-config.d.ts.map +1 -0
  48. package/dist/helpers/validate-config.js +61 -0
  49. package/dist/helpers/validate-config.js.map +1 -0
  50. package/dist/index.d.ts +60 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +58 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/oauth/bridge.d.ts +59 -0
  55. package/dist/oauth/bridge.d.ts.map +1 -0
  56. package/dist/oauth/bridge.js +75 -0
  57. package/dist/oauth/bridge.js.map +1 -0
  58. package/dist/oauth/index.d.ts +3 -0
  59. package/dist/oauth/index.js +4 -0
  60. package/dist/oauth/library.d.ts +23 -0
  61. package/dist/oauth/library.d.ts.map +1 -0
  62. package/dist/oauth/library.js +27 -0
  63. package/dist/oauth/library.js.map +1 -0
  64. package/dist/registry/json-schema.js +215 -0
  65. package/dist/registry/json-schema.js.map +1 -0
  66. package/dist/transport/index.d.ts +4 -0
  67. package/dist/transport/index.js +4 -0
  68. package/dist/transport/types.d.ts +93 -0
  69. package/dist/transport/types.d.ts.map +1 -0
  70. package/package.json +105 -0
@@ -0,0 +1,215 @@
1
+ //#region src/registry/json-schema.ts
2
+ /**
3
+ * Build a {@link ZodLikeSchema} that validates `data` against
4
+ * `schema`. The returned instance follows the structural Zod
5
+ * contract from `@graphorin/core` (a `parse` method that throws + a
6
+ * `safeParse` method that returns a `ZodLikeSafeParseResult`).
7
+ *
8
+ * @stable
9
+ */
10
+ function buildJsonSchemaValidator(schema) {
11
+ function parse(data) {
12
+ const issues = validate(data, schema, []);
13
+ if (issues.length === 0) return data;
14
+ throw buildError(issues);
15
+ }
16
+ function safeParse(data) {
17
+ const issues = validate(data, schema, []);
18
+ if (issues.length === 0) return {
19
+ success: true,
20
+ data
21
+ };
22
+ return {
23
+ success: false,
24
+ error: buildError(issues)
25
+ };
26
+ }
27
+ return Object.freeze({
28
+ parse,
29
+ safeParse
30
+ });
31
+ }
32
+ function validate(value, schema, path) {
33
+ if (schema === true) return [];
34
+ if (schema === false) return [{
35
+ path,
36
+ message: "rejected by schema (false)"
37
+ }];
38
+ const issues = [];
39
+ if ("const" in schema && schema.const !== void 0) {
40
+ if (!equalsDeep(value, schema.const)) issues.push({
41
+ path,
42
+ message: `expected const ${formatValue(schema.const)}`
43
+ });
44
+ }
45
+ if (Array.isArray(schema.enum)) {
46
+ if (!schema.enum.some((candidate) => equalsDeep(value, candidate))) issues.push({
47
+ path,
48
+ message: "value does not match any enum entry"
49
+ });
50
+ }
51
+ if (Array.isArray(schema.allOf)) for (const sub of schema.allOf) issues.push(...validate(value, sub, path));
52
+ if (Array.isArray(schema.anyOf)) {
53
+ if (!schema.anyOf.some((sub) => validate(value, sub, path).length === 0)) issues.push({
54
+ path,
55
+ message: "value did not match any of the anyOf branches"
56
+ });
57
+ }
58
+ if (Array.isArray(schema.oneOf)) {
59
+ const matchCount = schema.oneOf.filter((sub) => validate(value, sub, path).length === 0).length;
60
+ if (matchCount !== 1) issues.push({
61
+ path,
62
+ message: `expected exactly one oneOf branch to match (got ${matchCount})`
63
+ });
64
+ }
65
+ if (schema.type !== void 0) {
66
+ const typeIssues = validateType(value, schema, path);
67
+ issues.push(...typeIssues);
68
+ }
69
+ return issues;
70
+ }
71
+ function validateType(value, schema, path) {
72
+ if (schema === true || schema === false) return [];
73
+ const types = Array.isArray(schema.type) ? schema.type : schema.type === void 0 ? [] : [schema.type];
74
+ if (types.length === 0) return [];
75
+ if (!types.some((t) => matchesType(value, t))) return [{
76
+ path,
77
+ message: `expected type ${types.join(" | ")}`
78
+ }];
79
+ if (matchesType(value, "object") && (schema.properties !== void 0 || schema.required !== void 0 || schema.additionalProperties !== void 0)) return validateObject(value, schema, path);
80
+ if (matchesType(value, "array")) return validateArray(value, schema, path);
81
+ if (matchesType(value, "string")) return validateString(value, schema, path);
82
+ if (matchesType(value, "number") || matchesType(value, "integer")) return validateNumber(value, schema, path);
83
+ return [];
84
+ }
85
+ function validateObject(value, schema, path) {
86
+ if (schema === true || schema === false) return [];
87
+ const issues = [];
88
+ const required = Array.isArray(schema.required) ? schema.required : [];
89
+ for (const key of required) if (!(key in value)) issues.push({
90
+ path: [...path, key],
91
+ message: "is required"
92
+ });
93
+ const properties = schema.properties ?? {};
94
+ for (const [key, subSchema] of Object.entries(properties)) {
95
+ if (!(key in value)) continue;
96
+ issues.push(...validate(value[key], subSchema, [...path, key]));
97
+ }
98
+ if (schema.additionalProperties === false) {
99
+ for (const key of Object.keys(value)) if (!(key in properties)) issues.push({
100
+ path: [...path, key],
101
+ message: "unexpected additional property"
102
+ });
103
+ } else if (typeof schema.additionalProperties === "object" && schema.additionalProperties !== null) for (const key of Object.keys(value)) {
104
+ if (key in properties) continue;
105
+ issues.push(...validate(value[key], schema.additionalProperties, [...path, key]));
106
+ }
107
+ return issues;
108
+ }
109
+ function validateArray(value, schema, path) {
110
+ if (schema === true || schema === false) return [];
111
+ const issues = [];
112
+ if (typeof schema.minItems === "number" && value.length < schema.minItems) issues.push({
113
+ path,
114
+ message: `expected at least ${schema.minItems} items`
115
+ });
116
+ if (typeof schema.maxItems === "number" && value.length > schema.maxItems) issues.push({
117
+ path,
118
+ message: `expected at most ${schema.maxItems} items`
119
+ });
120
+ const items = schema.items;
121
+ if (items === void 0) return issues;
122
+ if (Array.isArray(items)) for (let i = 0; i < items.length; i++) {
123
+ if (i >= value.length) break;
124
+ const sub = items[i];
125
+ if (sub === void 0) continue;
126
+ issues.push(...validate(value[i], sub, [...path, i]));
127
+ }
128
+ else for (let i = 0; i < value.length; i++) issues.push(...validate(value[i], items, [...path, i]));
129
+ return issues;
130
+ }
131
+ function validateString(value, schema, path) {
132
+ if (schema === true || schema === false) return [];
133
+ const issues = [];
134
+ if (typeof schema.minLength === "number" && value.length < schema.minLength) issues.push({
135
+ path,
136
+ message: `expected at least ${schema.minLength} characters`
137
+ });
138
+ if (typeof schema.maxLength === "number" && value.length > schema.maxLength) issues.push({
139
+ path,
140
+ message: `expected at most ${schema.maxLength} characters`
141
+ });
142
+ if (typeof schema.pattern === "string") try {
143
+ if (!new RegExp(schema.pattern).test(value)) issues.push({
144
+ path,
145
+ message: `did not match pattern ${schema.pattern}`
146
+ });
147
+ } catch {}
148
+ return issues;
149
+ }
150
+ function validateNumber(value, schema, path) {
151
+ if (schema === true || schema === false) return [];
152
+ const issues = [];
153
+ if ((Array.isArray(schema.type) ? schema.type : schema.type === void 0 ? [] : [schema.type]).includes("integer") && !Number.isInteger(value)) issues.push({
154
+ path,
155
+ message: "expected an integer"
156
+ });
157
+ if (typeof schema.minimum === "number" && value < schema.minimum) issues.push({
158
+ path,
159
+ message: `expected >= ${schema.minimum}`
160
+ });
161
+ if (typeof schema.maximum === "number" && value > schema.maximum) issues.push({
162
+ path,
163
+ message: `expected <= ${schema.maximum}`
164
+ });
165
+ return issues;
166
+ }
167
+ function matchesType(value, type) {
168
+ switch (type) {
169
+ case "string": return typeof value === "string";
170
+ case "number": return typeof value === "number" && Number.isFinite(value);
171
+ case "integer": return typeof value === "number" && Number.isFinite(value);
172
+ case "boolean": return typeof value === "boolean";
173
+ case "null": return value === null;
174
+ case "array": return Array.isArray(value);
175
+ case "object": return typeof value === "object" && value !== null && !Array.isArray(value);
176
+ default: return true;
177
+ }
178
+ }
179
+ function equalsDeep(a, b) {
180
+ if (a === b) return true;
181
+ if (a === null || b === null) return a === b;
182
+ if (typeof a !== typeof b) return false;
183
+ if (Array.isArray(a) && Array.isArray(b)) {
184
+ if (a.length !== b.length) return false;
185
+ return a.every((item, i) => equalsDeep(item, b[i]));
186
+ }
187
+ if (typeof a === "object" && typeof b === "object") {
188
+ const ak = Object.keys(a);
189
+ const bk = Object.keys(b);
190
+ if (ak.length !== bk.length) return false;
191
+ return ak.every((key) => equalsDeep(a[key], b[key]));
192
+ }
193
+ return false;
194
+ }
195
+ function formatValue(value) {
196
+ try {
197
+ return JSON.stringify(value);
198
+ } catch {
199
+ return Object.prototype.toString.call(value);
200
+ }
201
+ }
202
+ function buildError(issues) {
203
+ return {
204
+ name: "GraphorinMCPSchemaError",
205
+ message: issues.map((i) => `${i.path.length === 0 ? "." : i.path.join(".")}: ${i.message}`).join("; "),
206
+ issues: Object.freeze(issues.map((i) => ({
207
+ path: Object.freeze([...i.path]),
208
+ message: i.message
209
+ })))
210
+ };
211
+ }
212
+
213
+ //#endregion
214
+ export { buildJsonSchemaValidator };
215
+ //# sourceMappingURL=json-schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-schema.js","names":["issues: Issue[]","types: ReadonlyArray<string>"],"sources":["../../src/registry/json-schema.ts"],"sourcesContent":["/**\n * Lightweight JSON-Schema -> {@link ZodLikeSchema} adapter.\n *\n * The Model Context Protocol carries tool input + output schemas as\n * JSON Schema documents; the Graphorin tool registry types its\n * schemas via the `ZodLikeSchema` structural contract from\n * `@graphorin/core`. This module bridges the two without pulling\n * `zod` into the MCP boundary or relying on code generation +\n * runtime `eval` (the popular `json-schema-to-zod` package generates\n * source code that needs `new Function(...)` to execute).\n *\n * The adapter validates the canonical subset of JSON Schema the MCP\n * spec uses: `object` (with `properties`, `required`,\n * `additionalProperties`), `array` (with `items`, `minItems`,\n * `maxItems`), `string` (with `enum`, `minLength`, `maxLength`,\n * `pattern`), `number` / `integer` (with `enum`, `minimum`,\n * `maximum`), `boolean`, `null`, and the primitive composition\n * keywords `enum`, `const`, `oneOf`, `anyOf`, `allOf`. Unknown keys\n * are accepted permissively so newer MCP server schemas that ship\n * additional vocabulary do not break the adapter.\n *\n * @packageDocumentation\n */\n\nimport type { ZodLikeError, ZodLikeSafeParseResult, ZodLikeSchema } from '@graphorin/core';\n\n/** JSON Schema document subset accepted by {@link buildJsonSchemaValidator}. */\nexport type JsonSchemaLike =\n | boolean\n | (Readonly<Record<string, unknown>> & {\n readonly type?: string | ReadonlyArray<string>;\n readonly properties?: Readonly<Record<string, JsonSchemaLike>>;\n readonly required?: ReadonlyArray<string>;\n readonly additionalProperties?: boolean | JsonSchemaLike;\n readonly items?: JsonSchemaLike | ReadonlyArray<JsonSchemaLike>;\n readonly minItems?: number;\n readonly maxItems?: number;\n readonly minimum?: number;\n readonly maximum?: number;\n readonly minLength?: number;\n readonly maxLength?: number;\n readonly pattern?: string;\n readonly enum?: ReadonlyArray<unknown>;\n readonly const?: unknown;\n readonly oneOf?: ReadonlyArray<JsonSchemaLike>;\n readonly anyOf?: ReadonlyArray<JsonSchemaLike>;\n readonly allOf?: ReadonlyArray<JsonSchemaLike>;\n });\n\n/**\n * Build a {@link ZodLikeSchema} that validates `data` against\n * `schema`. The returned instance follows the structural Zod\n * contract from `@graphorin/core` (a `parse` method that throws + a\n * `safeParse` method that returns a `ZodLikeSafeParseResult`).\n *\n * @stable\n */\nexport function buildJsonSchemaValidator<T = unknown>(schema: JsonSchemaLike): ZodLikeSchema<T> {\n function parse(data: unknown): T {\n const issues = validate(data, schema, []);\n if (issues.length === 0) return data as T;\n throw buildError(issues);\n }\n function safeParse(data: unknown): ZodLikeSafeParseResult<T, unknown> {\n const issues = validate(data, schema, []);\n if (issues.length === 0) {\n return { success: true, data: data as T };\n }\n return { success: false, error: buildError(issues) };\n }\n return Object.freeze({ parse, safeParse });\n}\n\ninterface Issue {\n readonly path: ReadonlyArray<string | number>;\n readonly message: string;\n}\n\nfunction validate(\n value: unknown,\n schema: JsonSchemaLike,\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true) return [];\n if (schema === false) return [{ path, message: 'rejected by schema (false)' }];\n\n const issues: Issue[] = [];\n\n if ('const' in schema && schema.const !== undefined) {\n if (!equalsDeep(value, schema.const)) {\n issues.push({ path, message: `expected const ${formatValue(schema.const)}` });\n }\n }\n if (Array.isArray(schema.enum)) {\n if (!schema.enum.some((candidate) => equalsDeep(value, candidate))) {\n issues.push({ path, message: 'value does not match any enum entry' });\n }\n }\n if (Array.isArray(schema.allOf)) {\n for (const sub of schema.allOf) {\n issues.push(...validate(value, sub, path));\n }\n }\n if (Array.isArray(schema.anyOf)) {\n const anyOk = schema.anyOf.some((sub) => validate(value, sub, path).length === 0);\n if (!anyOk) issues.push({ path, message: 'value did not match any of the anyOf branches' });\n }\n if (Array.isArray(schema.oneOf)) {\n const matchCount = schema.oneOf.filter((sub) => validate(value, sub, path).length === 0).length;\n if (matchCount !== 1) {\n issues.push({\n path,\n message: `expected exactly one oneOf branch to match (got ${matchCount})`,\n });\n }\n }\n\n if (schema.type !== undefined) {\n const typeIssues = validateType(value, schema, path);\n issues.push(...typeIssues);\n }\n\n return issues;\n}\n\nfunction validateType(\n value: unknown,\n schema: JsonSchemaLike,\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const types: ReadonlyArray<string> = Array.isArray(schema.type)\n ? schema.type\n : schema.type === undefined\n ? []\n : [schema.type];\n if (types.length === 0) return [];\n if (!types.some((t) => matchesType(value, t))) {\n return [{ path, message: `expected type ${types.join(' | ')}` }];\n }\n\n if (\n matchesType(value, 'object') &&\n (schema.properties !== undefined ||\n schema.required !== undefined ||\n schema.additionalProperties !== undefined)\n ) {\n return validateObject(value as Record<string, unknown>, schema, path);\n }\n if (matchesType(value, 'array')) {\n return validateArray(value as unknown[], schema, path);\n }\n if (matchesType(value, 'string')) {\n return validateString(value as string, schema, path);\n }\n if (matchesType(value, 'number') || matchesType(value, 'integer')) {\n return validateNumber(value as number, schema, path);\n }\n return [];\n}\n\nfunction validateObject(\n value: Record<string, unknown>,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n const required = Array.isArray(schema.required) ? schema.required : [];\n for (const key of required) {\n if (!(key in value)) {\n issues.push({ path: [...path, key], message: 'is required' });\n }\n }\n const properties = schema.properties ?? {};\n for (const [key, subSchema] of Object.entries(properties)) {\n if (!(key in value)) continue;\n issues.push(...validate(value[key], subSchema, [...path, key]));\n }\n if (schema.additionalProperties === false) {\n for (const key of Object.keys(value)) {\n if (!(key in properties)) {\n issues.push({ path: [...path, key], message: 'unexpected additional property' });\n }\n }\n } else if (\n typeof schema.additionalProperties === 'object' &&\n schema.additionalProperties !== null\n ) {\n for (const key of Object.keys(value)) {\n if (key in properties) continue;\n issues.push(\n ...validate(value[key], schema.additionalProperties as JsonSchemaLike, [...path, key]),\n );\n }\n }\n return issues;\n}\n\nfunction validateArray(\n value: unknown[],\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n if (typeof schema.minItems === 'number' && value.length < schema.minItems) {\n issues.push({ path, message: `expected at least ${schema.minItems} items` });\n }\n if (typeof schema.maxItems === 'number' && value.length > schema.maxItems) {\n issues.push({ path, message: `expected at most ${schema.maxItems} items` });\n }\n const items = schema.items;\n if (items === undefined) return issues;\n if (Array.isArray(items)) {\n for (let i = 0; i < items.length; i++) {\n if (i >= value.length) break;\n const sub = items[i];\n if (sub === undefined) continue;\n issues.push(...validate(value[i], sub, [...path, i]));\n }\n } else {\n for (let i = 0; i < value.length; i++) {\n issues.push(...validate(value[i], items as JsonSchemaLike, [...path, i]));\n }\n }\n return issues;\n}\n\nfunction validateString(\n value: string,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n if (typeof schema.minLength === 'number' && value.length < schema.minLength) {\n issues.push({ path, message: `expected at least ${schema.minLength} characters` });\n }\n if (typeof schema.maxLength === 'number' && value.length > schema.maxLength) {\n issues.push({ path, message: `expected at most ${schema.maxLength} characters` });\n }\n if (typeof schema.pattern === 'string') {\n try {\n const re = new RegExp(schema.pattern);\n if (!re.test(value))\n issues.push({ path, message: `did not match pattern ${schema.pattern}` });\n } catch {\n // Treat malformed patterns as permissive (mirrors Ajv default).\n }\n }\n return issues;\n}\n\nfunction validateNumber(\n value: number,\n schema: JsonSchemaLike & { readonly type?: unknown },\n path: ReadonlyArray<string | number>,\n): Issue[] {\n if (schema === true || schema === false) return [];\n const issues: Issue[] = [];\n const types: ReadonlyArray<string> = Array.isArray(schema.type)\n ? schema.type\n : schema.type === undefined\n ? []\n : [schema.type];\n if (types.includes('integer') && !Number.isInteger(value)) {\n issues.push({ path, message: 'expected an integer' });\n }\n if (typeof schema.minimum === 'number' && value < schema.minimum) {\n issues.push({ path, message: `expected >= ${schema.minimum}` });\n }\n if (typeof schema.maximum === 'number' && value > schema.maximum) {\n issues.push({ path, message: `expected <= ${schema.maximum}` });\n }\n return issues;\n}\n\nfunction matchesType(value: unknown, type: string): boolean {\n switch (type) {\n case 'string':\n return typeof value === 'string';\n case 'number':\n return typeof value === 'number' && Number.isFinite(value);\n case 'integer':\n return typeof value === 'number' && Number.isFinite(value);\n case 'boolean':\n return typeof value === 'boolean';\n case 'null':\n return value === null;\n case 'array':\n return Array.isArray(value);\n case 'object':\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n default:\n return true;\n }\n}\n\nfunction equalsDeep(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (a === null || b === null) return a === b;\n if (typeof a !== typeof b) return false;\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) return false;\n return a.every((item, i) => equalsDeep(item, b[i]));\n }\n if (typeof a === 'object' && typeof b === 'object') {\n const ak = Object.keys(a as Record<string, unknown>);\n const bk = Object.keys(b as Record<string, unknown>);\n if (ak.length !== bk.length) return false;\n return ak.every((key) =>\n equalsDeep((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key]),\n );\n }\n return false;\n}\n\nfunction formatValue(value: unknown): string {\n try {\n return JSON.stringify(value);\n } catch {\n return Object.prototype.toString.call(value);\n }\n}\n\nfunction buildError(issues: ReadonlyArray<Issue>): ZodLikeError {\n return {\n name: 'GraphorinMCPSchemaError',\n message: issues\n .map((i) => `${i.path.length === 0 ? '.' : i.path.join('.')}: ${i.message}`)\n .join('; '),\n issues: Object.freeze(\n issues.map((i) => ({ path: Object.freeze([...i.path]), message: i.message })),\n ),\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { MCPTransportConfig, ServerIdentity, SseTransportConfig, StdioTransportConfig, StreamableHttpTransportConfig } from "./types.js";
2
+ import { deriveServerIdentity, formatMCPServerName } from "../helpers/identity.js";
3
+ import { validateMCPServerConfig } from "../helpers/validate-config.js";
4
+ export { type MCPTransportConfig, type ServerIdentity, type SseTransportConfig, type StdioTransportConfig, type StreamableHttpTransportConfig, deriveServerIdentity, formatMCPServerName, validateMCPServerConfig };
@@ -0,0 +1,4 @@
1
+ import { deriveServerIdentity, formatMCPServerName } from "../helpers/identity.js";
2
+ import { validateMCPServerConfig } from "../helpers/validate-config.js";
3
+
4
+ export { deriveServerIdentity, formatMCPServerName, validateMCPServerConfig };
@@ -0,0 +1,93 @@
1
+ //#region src/transport/types.d.ts
2
+ /**
3
+ * Transport descriptors accepted by {@link createMCPClient}.
4
+ *
5
+ * The discriminated union mirrors the three transports the
6
+ * `@modelcontextprotocol/sdk@^1.29.0` package exports:
7
+ *
8
+ * - `'stdio'` — the primary transport for local MCP servers
9
+ * started as a child process. The transport spawns the configured
10
+ * command, pipes JSON-RPC over stdio, and tears the child down on
11
+ * `client.close()`.
12
+ * - `'streamable-http'` — the current default transport for remote MCP
13
+ * servers (the spec-recommended replacement for the legacy SSE
14
+ * transport). Supports server-assigned `Mcp-Session-Id` + the
15
+ * `Last-Event-ID` resume handshake when the server advertises it on
16
+ * `initialize`.
17
+ * - `'sse'` — the deprecated legacy transport. Kept for
18
+ * back-compat with MCP servers that have not yet migrated to the
19
+ * streamable HTTP transport. The runtime emits one WARN-per-process
20
+ * on transport selection; the transport is not eligible for the
21
+ * resumable-session features.
22
+ *
23
+ * @stable
24
+ */
25
+ type MCPTransportConfig = StdioTransportConfig | StreamableHttpTransportConfig | SseTransportConfig;
26
+ /** Options for the `'stdio'` transport. */
27
+ interface StdioTransportConfig {
28
+ readonly kind: 'stdio';
29
+ readonly command: string;
30
+ readonly args?: ReadonlyArray<string>;
31
+ readonly env?: Readonly<Record<string, string>>;
32
+ readonly cwd?: string;
33
+ /**
34
+ * How to handle the spawned child's stderr stream. Defaults to
35
+ * `'inherit'` so operator-supplied servers print diagnostics to the
36
+ * host process's stderr; `'pipe'` collects stderr into the
37
+ * transport for in-process logging; `'ignore'` discards it.
38
+ */
39
+ readonly stderr?: 'inherit' | 'pipe' | 'ignore';
40
+ }
41
+ /** Options for the `'streamable-http'` transport. */
42
+ interface StreamableHttpTransportConfig {
43
+ readonly kind: 'streamable-http';
44
+ readonly url: string | URL;
45
+ readonly headers?: Readonly<Record<string, string>>;
46
+ /**
47
+ * Optional pre-existing session id. Most operators leave this
48
+ * unset — the server assigns one on `initialize` and the client
49
+ * persists it for the lifetime of the connection.
50
+ */
51
+ readonly sessionId?: string;
52
+ /** Custom `fetch` implementation; defaults to the global `fetch`. */
53
+ readonly fetch?: typeof fetch;
54
+ }
55
+ /** Options for the deprecated `'sse'` transport. */
56
+ interface SseTransportConfig {
57
+ readonly kind: 'sse';
58
+ readonly url: string | URL;
59
+ readonly headers?: Readonly<Record<string, string>>;
60
+ readonly fetch?: typeof fetch;
61
+ }
62
+ /**
63
+ * Server identity descriptor attached to every MCP-derived `Tool`.
64
+ * Mirrors the shape consumed by the tool-registry collision
65
+ * resolver; the `argsHash` / `urlHostname` fields are the
66
+ * disambiguation keys the registry uses when surfacing collision
67
+ * resolutions, while the canonical `id` field is the operator-
68
+ * facing label.
69
+ *
70
+ * @stable
71
+ */
72
+ type ServerIdentity = {
73
+ readonly kind: 'mcp-stdio';
74
+ readonly id: string;
75
+ readonly command: string;
76
+ readonly argsHash: string;
77
+ readonly serverInfoName?: string;
78
+ } | {
79
+ readonly kind: 'mcp-streamable-http';
80
+ readonly id: string;
81
+ readonly urlHostname: string;
82
+ readonly urlPath: string;
83
+ readonly serverInfoName?: string;
84
+ } | {
85
+ readonly kind: 'mcp-sse';
86
+ readonly id: string;
87
+ readonly urlHostname: string;
88
+ readonly urlPath: string;
89
+ readonly serverInfoName?: string;
90
+ };
91
+ //#endregion
92
+ export { MCPTransportConfig, ServerIdentity, SseTransportConfig, StdioTransportConfig, StreamableHttpTransportConfig };
93
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../src/transport/types.ts"],"sourcesContent":[],"mappings":";;AAuBA;;;;;AAMA;;;;;AAgBA;;;;;;AAeA;;;;;;AAiBY,KAtDA,kBAAA,GACR,oBAqDsB,GApDtB,6BAoDsB,GAnDtB,kBAmDsB;;UAhDT,oBAAA;;;kBAGC;iBACD,SAAS;;;;;;;;;;;UAYT,6BAAA;;yBAEQ;qBACJ,SAAS;;;;;;;;0BAQJ;;;UAIT,kBAAA;;yBAEQ;qBACJ,SAAS;0BACJ;;;;;;;;;;;;KAad,cAAA"}
package/package.json ADDED
@@ -0,0 +1,105 @@
1
+ {
2
+ "name": "@graphorin/mcp",
3
+ "version": "0.5.0",
4
+ "description": "Model Context Protocol client for the Graphorin framework: stdio + Streamable HTTP + SSE transports, typed `MCPClient` (`listTools` / `listResources` / `listPrompts` / `callTool`), `toTools()` adapter (per-server inbound prompt-injection sanitization, deferred-loading auto-default at the 10-tool threshold, structured-content + outputSchema round-trip with backward-compatible TextContent mirror, per-server result envelope overrides, per-server call timeout, mcp provenance stamping for the dataflow policy, per-server preferredModel and side-effect class overrides), OAuth integration backed by @graphorin/security/oauth, typed errors, and library helpers consumed by the upcoming graphorin auth CLI.",
5
+ "license": "MIT",
6
+ "author": "Oleksiy Stepurenko",
7
+ "homepage": "https://github.com/o-stepper/graphorin/tree/main/packages/mcp",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/o-stepper/graphorin.git",
11
+ "directory": "packages/mcp"
12
+ },
13
+ "bugs": {
14
+ "url": "https://github.com/o-stepper/graphorin/issues"
15
+ },
16
+ "keywords": [
17
+ "graphorin",
18
+ "ai",
19
+ "agents",
20
+ "framework",
21
+ "mcp",
22
+ "model-context-protocol",
23
+ "mcp-client",
24
+ "stdio",
25
+ "streamable-http",
26
+ "sse",
27
+ "oauth",
28
+ "structured-content",
29
+ "resumable-sessions",
30
+ "tool-collision",
31
+ "deferred-loading",
32
+ "inbound-sanitization"
33
+ ],
34
+ "type": "module",
35
+ "engines": {
36
+ "node": ">=22.0.0"
37
+ },
38
+ "main": "./dist/index.js",
39
+ "module": "./dist/index.js",
40
+ "types": "./dist/index.d.ts",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./dist/index.d.ts",
44
+ "import": "./dist/index.js"
45
+ },
46
+ "./client": {
47
+ "types": "./dist/client/index.d.ts",
48
+ "import": "./dist/client/index.js"
49
+ },
50
+ "./transport": {
51
+ "types": "./dist/transport/index.d.ts",
52
+ "import": "./dist/transport/index.js"
53
+ },
54
+ "./oauth": {
55
+ "types": "./dist/oauth/index.d.ts",
56
+ "import": "./dist/oauth/index.js"
57
+ },
58
+ "./helpers": {
59
+ "types": "./dist/helpers/index.d.ts",
60
+ "import": "./dist/helpers/index.js"
61
+ },
62
+ "./errors": {
63
+ "types": "./dist/errors/index.d.ts",
64
+ "import": "./dist/errors/index.js"
65
+ },
66
+ "./package.json": "./package.json"
67
+ },
68
+ "files": [
69
+ "dist",
70
+ "README.md",
71
+ "CHANGELOG.md",
72
+ "LICENSE"
73
+ ],
74
+ "dependencies": {
75
+ "@modelcontextprotocol/sdk": "^1.29.0",
76
+ "@graphorin/core": "0.5.0",
77
+ "@graphorin/observability": "0.5.0",
78
+ "@graphorin/security": "0.5.0",
79
+ "@graphorin/tools": "0.5.0"
80
+ },
81
+ "peerDependencies": {
82
+ "zod": "^3.23.0 || ^4.0.0"
83
+ },
84
+ "peerDependenciesMeta": {
85
+ "zod": {
86
+ "optional": false
87
+ }
88
+ },
89
+ "publishConfig": {
90
+ "access": "public",
91
+ "provenance": true
92
+ },
93
+ "devDependencies": {
94
+ "fast-check": "^3.23.0",
95
+ "hono": "^4.12.21",
96
+ "zod": "^3.25.0"
97
+ },
98
+ "scripts": {
99
+ "build": "tsdown",
100
+ "typecheck": "tsc --noEmit && tsc -p tsconfig.tests.json",
101
+ "test": "vitest run",
102
+ "lint": "biome check .",
103
+ "clean": "rimraf dist .turbo *.tsbuildinfo"
104
+ }
105
+ }