@mctx-ai/mcp-server 0.3.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/dist/completion.js +214 -0
- package/dist/conversation.js +139 -0
- package/dist/index.d.ts +733 -0
- package/dist/index.js +18 -0
- package/dist/log.js +213 -0
- package/dist/progress.js +84 -0
- package/dist/sampling.js +130 -0
- package/dist/security.js +339 -0
- package/dist/server.js +876 -0
- package/dist/types.js +252 -0
- package/dist/uri.js +120 -0
- package/package.json +53 -0
- package/src/completion.js +214 -0
- package/src/conversation.js +139 -0
- package/src/index.d.ts +733 -0
- package/src/index.js +18 -0
- package/src/log.js +213 -0
- package/src/progress.js +84 -0
- package/src/sampling.js +130 -0
- package/src/security.js +339 -0
- package/src/server.js +876 -0
- package/src/types.js +252 -0
- package/src/uri.js +120 -0
package/src/types.js
ADDED
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* T - JSON Schema type system for MCP tool and prompt inputs
|
|
3
|
+
*
|
|
4
|
+
* Provides factory methods to build JSON Schema objects with a clean API.
|
|
5
|
+
* Supports type validation, constraints, and nested schemas.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Creates a string type schema
|
|
10
|
+
* @param {Object} options - Schema options
|
|
11
|
+
* @param {boolean} [options.required] - Mark field as required (metadata for buildInputSchema)
|
|
12
|
+
* @param {string} [options.description] - Field description
|
|
13
|
+
* @param {Array} [options.enum] - Allowed values
|
|
14
|
+
* @param {*} [options.default] - Default value
|
|
15
|
+
* @param {number} [options.minLength] - Minimum string length
|
|
16
|
+
* @param {number} [options.maxLength] - Maximum string length
|
|
17
|
+
* @param {string} [options.pattern] - Regex pattern
|
|
18
|
+
* @param {string} [options.format] - Format (email, uri, date-time, etc.)
|
|
19
|
+
* @returns {Object} JSON Schema object
|
|
20
|
+
*/
|
|
21
|
+
function string(options = {}) {
|
|
22
|
+
const schema = { type: "string" };
|
|
23
|
+
|
|
24
|
+
if (options.description !== undefined)
|
|
25
|
+
schema.description = options.description;
|
|
26
|
+
if (options.enum !== undefined) schema.enum = options.enum;
|
|
27
|
+
if (options.default !== undefined) schema.default = options.default;
|
|
28
|
+
if (options.minLength !== undefined) schema.minLength = options.minLength;
|
|
29
|
+
if (options.maxLength !== undefined) schema.maxLength = options.maxLength;
|
|
30
|
+
if (options.pattern !== undefined) schema.pattern = options.pattern;
|
|
31
|
+
if (options.format !== undefined) schema.format = options.format;
|
|
32
|
+
|
|
33
|
+
// Store required as metadata (not a JSON Schema keyword on properties)
|
|
34
|
+
if (options.required === true) schema._required = true;
|
|
35
|
+
|
|
36
|
+
return schema;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Creates a number type schema
|
|
41
|
+
* @param {Object} options - Schema options
|
|
42
|
+
* @param {boolean} [options.required] - Mark field as required (metadata for buildInputSchema)
|
|
43
|
+
* @param {string} [options.description] - Field description
|
|
44
|
+
* @param {Array} [options.enum] - Allowed values
|
|
45
|
+
* @param {*} [options.default] - Default value
|
|
46
|
+
* @param {number} [options.min] - Minimum value (maps to 'minimum')
|
|
47
|
+
* @param {number} [options.max] - Maximum value (maps to 'maximum')
|
|
48
|
+
* @returns {Object} JSON Schema object
|
|
49
|
+
*/
|
|
50
|
+
function number(options = {}) {
|
|
51
|
+
const schema = { type: "number" };
|
|
52
|
+
|
|
53
|
+
if (options.description !== undefined)
|
|
54
|
+
schema.description = options.description;
|
|
55
|
+
if (options.enum !== undefined) schema.enum = options.enum;
|
|
56
|
+
if (options.default !== undefined) schema.default = options.default;
|
|
57
|
+
if (options.min !== undefined) schema.minimum = options.min;
|
|
58
|
+
if (options.max !== undefined) schema.maximum = options.max;
|
|
59
|
+
|
|
60
|
+
if (options.required === true) schema._required = true;
|
|
61
|
+
|
|
62
|
+
return schema;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Creates a boolean type schema
|
|
67
|
+
* @param {Object} options - Schema options
|
|
68
|
+
* @param {boolean} [options.required] - Mark field as required (metadata for buildInputSchema)
|
|
69
|
+
* @param {string} [options.description] - Field description
|
|
70
|
+
* @param {*} [options.default] - Default value
|
|
71
|
+
* @returns {Object} JSON Schema object
|
|
72
|
+
*/
|
|
73
|
+
function boolean(options = {}) {
|
|
74
|
+
const schema = { type: "boolean" };
|
|
75
|
+
|
|
76
|
+
if (options.description !== undefined)
|
|
77
|
+
schema.description = options.description;
|
|
78
|
+
if (options.default !== undefined) schema.default = options.default;
|
|
79
|
+
|
|
80
|
+
if (options.required === true) schema._required = true;
|
|
81
|
+
|
|
82
|
+
return schema;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Creates an array type schema
|
|
87
|
+
* @param {Object} options - Schema options
|
|
88
|
+
* @param {boolean} [options.required] - Mark field as required (metadata for buildInputSchema)
|
|
89
|
+
* @param {string} [options.description] - Field description
|
|
90
|
+
* @param {Object} [options.items] - Schema for array items
|
|
91
|
+
* @param {*} [options.default] - Default value
|
|
92
|
+
* @returns {Object} JSON Schema object
|
|
93
|
+
*/
|
|
94
|
+
function array(options = {}) {
|
|
95
|
+
const schema = { type: "array" };
|
|
96
|
+
|
|
97
|
+
if (options.description !== undefined)
|
|
98
|
+
schema.description = options.description;
|
|
99
|
+
if (options.default !== undefined) schema.default = options.default;
|
|
100
|
+
if (options.items !== undefined) {
|
|
101
|
+
// Clean _required metadata from items schema
|
|
102
|
+
schema.items = cleanMetadata(options.items);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (options.required === true) schema._required = true;
|
|
106
|
+
|
|
107
|
+
return schema;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Creates an object type schema
|
|
112
|
+
* @param {Object} options - Schema options
|
|
113
|
+
* @param {boolean} [options.required] - Mark field as required (metadata for buildInputSchema)
|
|
114
|
+
* @param {string} [options.description] - Field description
|
|
115
|
+
* @param {Object} [options.properties] - Nested property schemas
|
|
116
|
+
* @param {boolean|Object} [options.additionalProperties] - Allow additional properties
|
|
117
|
+
* @param {*} [options.default] - Default value
|
|
118
|
+
* @returns {Object} JSON Schema object
|
|
119
|
+
*/
|
|
120
|
+
function object(options = {}) {
|
|
121
|
+
const schema = { type: "object" };
|
|
122
|
+
|
|
123
|
+
if (options.description !== undefined)
|
|
124
|
+
schema.description = options.description;
|
|
125
|
+
if (options.default !== undefined) schema.default = options.default;
|
|
126
|
+
|
|
127
|
+
// Handle nested properties
|
|
128
|
+
if (options.properties !== undefined) {
|
|
129
|
+
const { properties, required } = buildProperties(options.properties);
|
|
130
|
+
schema.properties = properties;
|
|
131
|
+
if (required.length > 0) schema.required = required;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (options.additionalProperties !== undefined) {
|
|
135
|
+
if (typeof options.additionalProperties === "boolean") {
|
|
136
|
+
schema.additionalProperties = options.additionalProperties;
|
|
137
|
+
} else {
|
|
138
|
+
// Clean metadata from additionalProperties schema
|
|
139
|
+
schema.additionalProperties = cleanMetadata(options.additionalProperties);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (options.required === true) schema._required = true;
|
|
144
|
+
|
|
145
|
+
return schema;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Builds properties object and extracts required fields
|
|
150
|
+
* Helper for buildInputSchema and object()
|
|
151
|
+
* @param {Object} properties - Properties map
|
|
152
|
+
* @returns {{properties: Object, required: Array<string>}} Cleaned properties and required array
|
|
153
|
+
*/
|
|
154
|
+
function buildProperties(properties) {
|
|
155
|
+
if (!properties || typeof properties !== "object") {
|
|
156
|
+
return { properties: {}, required: [] };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const cleanedProperties = {};
|
|
160
|
+
const required = [];
|
|
161
|
+
|
|
162
|
+
for (const [key, schema] of Object.entries(properties)) {
|
|
163
|
+
if (!schema || typeof schema !== "object") continue;
|
|
164
|
+
|
|
165
|
+
// Extract required metadata
|
|
166
|
+
if (schema._required === true) {
|
|
167
|
+
required.push(key);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Clean the schema (remove metadata)
|
|
171
|
+
cleanedProperties[key] = cleanMetadata(schema);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return { properties: cleanedProperties, required };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Removes framework metadata from schema
|
|
179
|
+
* @param {Object} schema - Schema object
|
|
180
|
+
* @returns {Object} Cleaned schema
|
|
181
|
+
*/
|
|
182
|
+
function cleanMetadata(schema) {
|
|
183
|
+
if (!schema || typeof schema !== "object") return schema;
|
|
184
|
+
|
|
185
|
+
// Create shallow copy
|
|
186
|
+
const cleaned = { ...schema };
|
|
187
|
+
|
|
188
|
+
// Remove metadata
|
|
189
|
+
delete cleaned._required;
|
|
190
|
+
|
|
191
|
+
// Recursively clean nested schemas
|
|
192
|
+
if (cleaned.properties && typeof cleaned.properties === "object") {
|
|
193
|
+
const { properties, required } = buildProperties(cleaned.properties);
|
|
194
|
+
cleaned.properties = properties;
|
|
195
|
+
if (required.length > 0) cleaned.required = required;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (cleaned.items && typeof cleaned.items === "object") {
|
|
199
|
+
cleaned.items = cleanMetadata(cleaned.items);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (
|
|
203
|
+
cleaned.additionalProperties &&
|
|
204
|
+
typeof cleaned.additionalProperties === "object"
|
|
205
|
+
) {
|
|
206
|
+
cleaned.additionalProperties = cleanMetadata(cleaned.additionalProperties);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return cleaned;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Builds a complete MCP input schema from handler input definition
|
|
214
|
+
* @param {Object} input - Handler input definition using T types
|
|
215
|
+
* @returns {Object} Valid JSON Schema for MCP inputSchema
|
|
216
|
+
*/
|
|
217
|
+
export function buildInputSchema(input) {
|
|
218
|
+
// Handle null/undefined input
|
|
219
|
+
if (!input) {
|
|
220
|
+
return {
|
|
221
|
+
type: "object",
|
|
222
|
+
properties: {},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Build properties and extract required fields
|
|
227
|
+
const { properties, required } = buildProperties(input);
|
|
228
|
+
|
|
229
|
+
const schema = {
|
|
230
|
+
type: "object",
|
|
231
|
+
properties,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// Only add required array if not empty
|
|
235
|
+
if (required.length > 0) {
|
|
236
|
+
schema.required = required;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return schema;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* T - Type factory object
|
|
244
|
+
* Exports all type builders
|
|
245
|
+
*/
|
|
246
|
+
export const T = {
|
|
247
|
+
string,
|
|
248
|
+
number,
|
|
249
|
+
boolean,
|
|
250
|
+
array,
|
|
251
|
+
object,
|
|
252
|
+
};
|
package/src/uri.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URI Template Matching Module
|
|
3
|
+
*
|
|
4
|
+
* Implements RFC 6570 Level 1 URI templates (simple string expansion {var}).
|
|
5
|
+
* Provides utilities for matching request URIs against registered resource URIs
|
|
6
|
+
* and extracting template parameters.
|
|
7
|
+
*
|
|
8
|
+
* @module uri
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Checks if a URI contains template variables
|
|
13
|
+
* @param {string} uri - The URI to check
|
|
14
|
+
* @returns {boolean} True if URI contains {param} syntax
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* isTemplate('db://customers/123') // false
|
|
18
|
+
* isTemplate('db://customers/{id}') // true
|
|
19
|
+
* isTemplate('db://products/{id}/reviews') // true
|
|
20
|
+
*/
|
|
21
|
+
export function isTemplate(uri) {
|
|
22
|
+
if (!uri || typeof uri !== "string") return false;
|
|
23
|
+
return /\{[^}]+\}/.test(uri);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Extracts template variable names from a URI
|
|
28
|
+
* @param {string} uri - The URI template
|
|
29
|
+
* @returns {string[]} Array of variable names
|
|
30
|
+
* @throws {Error} If template variable name is invalid
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* extractTemplateVars('db://customers/{id}') // ['id']
|
|
34
|
+
* extractTemplateVars('db://products/{category}/items/{id}') // ['category', 'id']
|
|
35
|
+
* extractTemplateVars('db://customers/123') // []
|
|
36
|
+
*/
|
|
37
|
+
export function extractTemplateVars(uri) {
|
|
38
|
+
if (!uri || typeof uri !== "string") return [];
|
|
39
|
+
|
|
40
|
+
const matches = uri.matchAll(/\{([^}]+)\}/g);
|
|
41
|
+
const vars = [];
|
|
42
|
+
|
|
43
|
+
for (const match of matches) {
|
|
44
|
+
const varName = match[1];
|
|
45
|
+
|
|
46
|
+
// Validate: alphanumeric + underscore only (RFC 6570 Level 1)
|
|
47
|
+
if (!/^[a-zA-Z0-9_]+$/.test(varName)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
`Invalid template variable name: "${varName}". Must contain only alphanumeric characters and underscores.`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
vars.push(varName);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return vars;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Matches a request URI against a registered URI template
|
|
61
|
+
*
|
|
62
|
+
* Returns null for no match, or an object with extracted parameters for match.
|
|
63
|
+
* Handles both static URIs (exact match) and dynamic URIs (template expansion).
|
|
64
|
+
*
|
|
65
|
+
* @param {string} registeredUri - The registered URI (may contain {param} templates)
|
|
66
|
+
* @param {string} requestUri - The incoming request URI (no templates)
|
|
67
|
+
* @returns {Object|null} Match result: { params: { name: value, ... } } or null
|
|
68
|
+
*
|
|
69
|
+
* @example
|
|
70
|
+
* // Static URI - exact match
|
|
71
|
+
* matchUri('db://customers/schema', 'db://customers/schema')
|
|
72
|
+
* // => { params: {} }
|
|
73
|
+
*
|
|
74
|
+
* matchUri('db://customers/schema', 'db://customers/list')
|
|
75
|
+
* // => null
|
|
76
|
+
*
|
|
77
|
+
* // Dynamic URI - parameter extraction
|
|
78
|
+
* matchUri('db://customers/{id}', 'db://customers/123')
|
|
79
|
+
* // => { params: { id: '123' } }
|
|
80
|
+
*
|
|
81
|
+
* matchUri('db://products/{category}/items/{id}', 'db://products/electronics/items/456')
|
|
82
|
+
* // => { params: { category: 'electronics', id: '456' } }
|
|
83
|
+
*
|
|
84
|
+
* matchUri('db://customers/{id}', 'db://products/123')
|
|
85
|
+
* // => null (different path)
|
|
86
|
+
*/
|
|
87
|
+
export function matchUri(registeredUri, requestUri) {
|
|
88
|
+
// Guard clauses
|
|
89
|
+
if (!registeredUri || typeof registeredUri !== "string") return null;
|
|
90
|
+
if (!requestUri || typeof requestUri !== "string") return null;
|
|
91
|
+
|
|
92
|
+
// Static route: exact string match
|
|
93
|
+
if (!isTemplate(registeredUri)) {
|
|
94
|
+
return registeredUri === requestUri ? { params: {} } : null;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Dynamic route: build regex pattern and extract params
|
|
98
|
+
const templateVars = extractTemplateVars(registeredUri);
|
|
99
|
+
|
|
100
|
+
// Escape regex special characters except {placeholders}
|
|
101
|
+
// Convert {var} to named capture group
|
|
102
|
+
let pattern = registeredUri
|
|
103
|
+
.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // Escape regex chars
|
|
104
|
+
.replace(/\\\{([^}]+)\\\}/g, "([^/]+)"); // Convert {var} to capture group
|
|
105
|
+
|
|
106
|
+
pattern = `^${pattern}$`; // Exact match (anchored)
|
|
107
|
+
|
|
108
|
+
const regex = new RegExp(pattern);
|
|
109
|
+
const match = requestUri.match(regex);
|
|
110
|
+
|
|
111
|
+
if (!match) return null;
|
|
112
|
+
|
|
113
|
+
// Extract parameters from capture groups
|
|
114
|
+
const params = {};
|
|
115
|
+
for (let i = 0; i < templateVars.length; i++) {
|
|
116
|
+
params[templateVars[i]] = match[i + 1]; // match[0] is full string, params start at [1]
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { params };
|
|
120
|
+
}
|