@raytio/mcp-server 2.0.0 → 2.2.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/README.md +5 -2
- package/contracts/persist/mcp_resource_contract.json +87457 -0
- package/dist/authorization.d.ts +29 -0
- package/dist/authorization.d.ts.map +1 -0
- package/dist/authorization.js +87 -0
- package/dist/authorization.js.map +1 -0
- package/dist/contracts/persist-resource-contract.d.ts +1121 -0
- package/dist/contracts/persist-resource-contract.d.ts.map +1 -0
- package/dist/contracts/persist-resource-contract.js +261 -0
- package/dist/contracts/persist-resource-contract.js.map +1 -0
- package/dist/index.js +42 -58
- package/dist/index.js.map +1 -1
- package/dist/tools/dispatch.d.ts +18 -0
- package/dist/tools/dispatch.d.ts.map +1 -0
- package/dist/tools/dispatch.js +41 -0
- package/dist/tools/dispatch.js.map +1 -0
- package/dist/tools/role-mapping.d.ts +15 -8
- package/dist/tools/role-mapping.d.ts.map +1 -1
- package/dist/tools/role-mapping.js +28 -29
- package/dist/tools/role-mapping.js.map +1 -1
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +25 -0
- package/dist/version.js.map +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist-resource-contract.d.ts","sourceRoot":"","sources":["../../src/contracts/persist-resource-contract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { dirname, resolve } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
/**
|
|
7
|
+
* Loader and validator for the Persist "MCP resource contract" artifact
|
|
8
|
+
* produced by `persist/export_mcp_contract.py` in raytio/common/persist.
|
|
9
|
+
*
|
|
10
|
+
* The contract pins the set of PostgREST resources — with fields, operations,
|
|
11
|
+
* permission tuples, filter/order capabilities, sensitivity, side effects, and
|
|
12
|
+
* relationships — that MCP downstream tooling may safely surface as tools.
|
|
13
|
+
*
|
|
14
|
+
* MCP consumes the artifact through this module so that:
|
|
15
|
+
*
|
|
16
|
+
* - the file's shape is validated against a Zod schema (fail closed on any
|
|
17
|
+
* structural drift);
|
|
18
|
+
* - the artifact's declared `content_hash` is recomputed from a deterministic
|
|
19
|
+
* canonicalisation and compared (fail closed on any tampering, truncation,
|
|
20
|
+
* or upstream serialiser divergence);
|
|
21
|
+
* - the artifact's `contract_version` major is checked against the range this
|
|
22
|
+
* MCP build understands (fail closed on incompatible upgrades).
|
|
23
|
+
*
|
|
24
|
+
* The runtime never reaches across to the Persist repository — the artifact is
|
|
25
|
+
* vendored under `contracts/persist/mcp_resource_contract.json` at build time
|
|
26
|
+
* and scheduled CI syncs it (see `docs/persist-contract-sync.md`).
|
|
27
|
+
*/
|
|
28
|
+
/** Contract major version this MCP build understands. */
|
|
29
|
+
export const SUPPORTED_CONTRACT_MAJOR = 2;
|
|
30
|
+
const contractPath = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'contracts', 'persist', 'mcp_resource_contract.json');
|
|
31
|
+
// A JSON scalar/array/object graph. Loose enough to survive contract growth,
|
|
32
|
+
// strict enough that the loader catches malformed values before hashing.
|
|
33
|
+
const jsonValueSchema = z.lazy(() => z.union([
|
|
34
|
+
z.null(),
|
|
35
|
+
z.string(),
|
|
36
|
+
z.number(),
|
|
37
|
+
z.boolean(),
|
|
38
|
+
z.array(jsonValueSchema),
|
|
39
|
+
z.record(jsonValueSchema),
|
|
40
|
+
]));
|
|
41
|
+
const permissionSchema = z.object({
|
|
42
|
+
resource_group: z.string().min(1),
|
|
43
|
+
resource_name: z.string().min(1),
|
|
44
|
+
operations: z.array(z.string()),
|
|
45
|
+
});
|
|
46
|
+
const fieldSchema = z
|
|
47
|
+
.object({
|
|
48
|
+
name: z.string().min(1),
|
|
49
|
+
type: z.union([z.string(), z.array(z.string())]),
|
|
50
|
+
required: z.boolean(),
|
|
51
|
+
read_only: z.boolean().optional(),
|
|
52
|
+
description: z.string().nullable().optional(),
|
|
53
|
+
format: z.string().optional(),
|
|
54
|
+
maxLength: z.number().int().nonnegative().optional(),
|
|
55
|
+
})
|
|
56
|
+
.passthrough();
|
|
57
|
+
const resourceSchema = z
|
|
58
|
+
.object({
|
|
59
|
+
resource_id: z.string().min(1),
|
|
60
|
+
module: z.string().min(1),
|
|
61
|
+
table: z.string().min(1),
|
|
62
|
+
schema_name: z.string().nullable(),
|
|
63
|
+
schema_version: z.string().nullable(),
|
|
64
|
+
public_endpoint: z.string().min(1),
|
|
65
|
+
primary_key: z.union([z.string(), z.array(z.string()), z.null()]),
|
|
66
|
+
title: z.string().nullable(),
|
|
67
|
+
title_plural: z.string().nullable(),
|
|
68
|
+
description: z.string().nullable(),
|
|
69
|
+
fields: z.array(fieldSchema).min(1),
|
|
70
|
+
operations: z.array(z.string()).min(1),
|
|
71
|
+
permission: permissionSchema,
|
|
72
|
+
filter_capabilities: z
|
|
73
|
+
.object({
|
|
74
|
+
filterable_fields: z.array(z.string()),
|
|
75
|
+
supported_operators: z.array(z.string()),
|
|
76
|
+
})
|
|
77
|
+
.passthrough(),
|
|
78
|
+
order_capabilities: z
|
|
79
|
+
.object({
|
|
80
|
+
orderable_fields: z.array(z.string()),
|
|
81
|
+
})
|
|
82
|
+
.passthrough(),
|
|
83
|
+
sensitivity: z.enum(['normal', 'sensitive', 'restricted']),
|
|
84
|
+
side_effects: z.array(z.string()),
|
|
85
|
+
relationships: z.array(jsonValueSchema),
|
|
86
|
+
})
|
|
87
|
+
.passthrough();
|
|
88
|
+
const exclusionSchema = z
|
|
89
|
+
.object({
|
|
90
|
+
reason: z.string().min(1),
|
|
91
|
+
detail: z.string().min(1),
|
|
92
|
+
table: z.string().min(1),
|
|
93
|
+
schema_name: z.string().nullable().optional(),
|
|
94
|
+
})
|
|
95
|
+
.passthrough();
|
|
96
|
+
const exclusionRuleSchema = z
|
|
97
|
+
.object({
|
|
98
|
+
reason: z.string().min(1),
|
|
99
|
+
description: z.string().min(1),
|
|
100
|
+
match_substrings: z.array(z.string()),
|
|
101
|
+
})
|
|
102
|
+
.passthrough();
|
|
103
|
+
const provenanceSchema = z
|
|
104
|
+
.object({
|
|
105
|
+
source_commit: z.string().min(7),
|
|
106
|
+
introspection_timestamp: z.string().min(1),
|
|
107
|
+
latest_repo_migration: z.string().nullable(),
|
|
108
|
+
})
|
|
109
|
+
.passthrough();
|
|
110
|
+
export const persistResourceContractSchema = z
|
|
111
|
+
.object({
|
|
112
|
+
contract_version: z.string().regex(/^\d+\.\d+\.\d+$/),
|
|
113
|
+
content_hash: z.string().regex(/^[0-9a-f]{64}$/),
|
|
114
|
+
source_commit: z.string().min(7),
|
|
115
|
+
source_version: z.string().min(1),
|
|
116
|
+
resource_count: z.number().int().nonnegative(),
|
|
117
|
+
excluded_count: z.number().int().nonnegative(),
|
|
118
|
+
resources: z.array(resourceSchema),
|
|
119
|
+
excluded: z.array(exclusionSchema),
|
|
120
|
+
exclusion_rules: z.array(exclusionRuleSchema).min(1),
|
|
121
|
+
modules: z.array(z.string().min(1)),
|
|
122
|
+
provenance: provenanceSchema.optional(),
|
|
123
|
+
})
|
|
124
|
+
.passthrough();
|
|
125
|
+
export class PersistContractError extends Error {
|
|
126
|
+
cause;
|
|
127
|
+
constructor(message, cause) {
|
|
128
|
+
super(message);
|
|
129
|
+
this.cause = cause;
|
|
130
|
+
this.name = 'PersistContractError';
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Canonicalise a JSON value in the exact byte-form the Persist exporter uses
|
|
135
|
+
* for `content_hash` — deep-sorted object keys, ", " / ": " separators, and
|
|
136
|
+
* UTF-8 characters kept literal (ensure_ascii=False in Python).
|
|
137
|
+
*/
|
|
138
|
+
export function canonicalJson(value) {
|
|
139
|
+
if (value === null)
|
|
140
|
+
return 'null';
|
|
141
|
+
if (typeof value === 'boolean')
|
|
142
|
+
return value ? 'true' : 'false';
|
|
143
|
+
if (typeof value === 'number') {
|
|
144
|
+
if (!Number.isFinite(value)) {
|
|
145
|
+
throw new PersistContractError(`Non-finite number in contract body: ${String(value)}`);
|
|
146
|
+
}
|
|
147
|
+
return JSON.stringify(value);
|
|
148
|
+
}
|
|
149
|
+
if (typeof value === 'string')
|
|
150
|
+
return JSON.stringify(value);
|
|
151
|
+
if (Array.isArray(value)) {
|
|
152
|
+
return '[' + value.map(canonicalJson).join(', ') + ']';
|
|
153
|
+
}
|
|
154
|
+
if (typeof value === 'object') {
|
|
155
|
+
const record = value;
|
|
156
|
+
const keys = Object.keys(record).sort();
|
|
157
|
+
return ('{' +
|
|
158
|
+
keys
|
|
159
|
+
.map((k) => `${JSON.stringify(k)}: ${canonicalJson(record[k])}`)
|
|
160
|
+
.join(', ') +
|
|
161
|
+
'}');
|
|
162
|
+
}
|
|
163
|
+
throw new PersistContractError(`Unsupported value in contract body: ${typeof value}`);
|
|
164
|
+
}
|
|
165
|
+
const UNSTABLE_TOP_LEVEL_KEYS = new Set([
|
|
166
|
+
'content_hash',
|
|
167
|
+
'source_commit',
|
|
168
|
+
'source_version',
|
|
169
|
+
'provenance',
|
|
170
|
+
]);
|
|
171
|
+
export function computeContentHash(contract) {
|
|
172
|
+
const body = {};
|
|
173
|
+
for (const [key, value] of Object.entries(contract)) {
|
|
174
|
+
if (!UNSTABLE_TOP_LEVEL_KEYS.has(key))
|
|
175
|
+
body[key] = value;
|
|
176
|
+
}
|
|
177
|
+
return createHash('sha256').update(canonicalJson(body), 'utf8').digest('hex');
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Read, structurally validate, hash-check, and version-check the pinned
|
|
181
|
+
* Persist contract. Throws {@link PersistContractError} on any failure — the
|
|
182
|
+
* caller is expected to fail closed (do not expose tools built on a bad
|
|
183
|
+
* artifact).
|
|
184
|
+
*/
|
|
185
|
+
export function loadPersistResourceContract(options = {}) {
|
|
186
|
+
const path = options.path ?? contractPath;
|
|
187
|
+
const supportedMajor = options.supportedMajor ?? SUPPORTED_CONTRACT_MAJOR;
|
|
188
|
+
let raw;
|
|
189
|
+
try {
|
|
190
|
+
raw = readFileSync(path, 'utf8');
|
|
191
|
+
}
|
|
192
|
+
catch (error) {
|
|
193
|
+
throw new PersistContractError(`Cannot read Persist contract at ${path}`, error);
|
|
194
|
+
}
|
|
195
|
+
let parsed;
|
|
196
|
+
try {
|
|
197
|
+
parsed = JSON.parse(raw);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
throw new PersistContractError(`Persist contract at ${path} is not valid JSON`, error);
|
|
201
|
+
}
|
|
202
|
+
const result = persistResourceContractSchema.safeParse(parsed);
|
|
203
|
+
if (!result.success) {
|
|
204
|
+
throw new PersistContractError(`Persist contract at ${path} failed schema validation: ${result.error.message}`);
|
|
205
|
+
}
|
|
206
|
+
const contract = result.data;
|
|
207
|
+
const [majorText] = contract.contract_version.split('.');
|
|
208
|
+
const major = Number(majorText);
|
|
209
|
+
if (major !== supportedMajor) {
|
|
210
|
+
throw new PersistContractError(`Persist contract_version ${contract.contract_version} is not supported ` +
|
|
211
|
+
`by this MCP build (expects major ${supportedMajor}). Refresh Persist ` +
|
|
212
|
+
'or upgrade MCP.');
|
|
213
|
+
}
|
|
214
|
+
if (contract.resources.length !== contract.resource_count) {
|
|
215
|
+
throw new PersistContractError(`resource_count (${contract.resource_count}) disagrees with ` +
|
|
216
|
+
`resources.length (${contract.resources.length}).`);
|
|
217
|
+
}
|
|
218
|
+
if (contract.excluded.length !== contract.excluded_count) {
|
|
219
|
+
throw new PersistContractError(`excluded_count (${contract.excluded_count}) disagrees with ` +
|
|
220
|
+
`excluded.length (${contract.excluded.length}).`);
|
|
221
|
+
}
|
|
222
|
+
const seen = new Set();
|
|
223
|
+
for (const resource of contract.resources) {
|
|
224
|
+
if (seen.has(resource.resource_id)) {
|
|
225
|
+
throw new PersistContractError(`Duplicate resource_id in Persist contract: ${resource.resource_id}`);
|
|
226
|
+
}
|
|
227
|
+
seen.add(resource.resource_id);
|
|
228
|
+
}
|
|
229
|
+
const expectedHash = computeContentHash(contract);
|
|
230
|
+
if (expectedHash !== contract.content_hash) {
|
|
231
|
+
throw new PersistContractError(`Persist contract content_hash mismatch: file claims ${contract.content_hash} ` +
|
|
232
|
+
`but body hashes to ${expectedHash}. The artifact has been edited by hand or ` +
|
|
233
|
+
'the exporter is out of sync.');
|
|
234
|
+
}
|
|
235
|
+
return contract;
|
|
236
|
+
}
|
|
237
|
+
export function summariseResources(contract) {
|
|
238
|
+
return [...contract.resources]
|
|
239
|
+
.sort((a, b) => a.resource_id.localeCompare(b.resource_id))
|
|
240
|
+
.map((resource) => ({
|
|
241
|
+
resourceId: resource.resource_id,
|
|
242
|
+
module: resource.module,
|
|
243
|
+
table: resource.table,
|
|
244
|
+
publicEndpoint: resource.public_endpoint,
|
|
245
|
+
operations: resource.operations,
|
|
246
|
+
sensitivity: resource.sensitivity,
|
|
247
|
+
sideEffects: resource.side_effects,
|
|
248
|
+
permission: resource.permission,
|
|
249
|
+
fieldCount: resource.fields.length,
|
|
250
|
+
filterableFieldCount: resource.filter_capabilities.filterable_fields.length,
|
|
251
|
+
}));
|
|
252
|
+
}
|
|
253
|
+
/** Group the resource metadata by module for cataloguing tools. */
|
|
254
|
+
export function summariseModules(contract) {
|
|
255
|
+
const grouped = {};
|
|
256
|
+
for (const resource of summariseResources(contract)) {
|
|
257
|
+
(grouped[resource.module] ??= []).push(resource);
|
|
258
|
+
}
|
|
259
|
+
return grouped;
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=persist-resource-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist-resource-contract.js","sourceRoot":"","sources":["../../src/contracts/persist-resource-contract.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -4,12 +4,34 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
|
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
5
|
import { zodToJsonSchema } from 'zod-to-json-schema';
|
|
6
6
|
import { loadConfig } from './config.js';
|
|
7
|
+
import { PersistContractError, loadPersistResourceContract, } from './contracts/persist-resource-contract.js';
|
|
7
8
|
import { CognitoAuth } from './raytio/auth.js';
|
|
8
9
|
import { RaytioApiClient } from './raytio/api-client.js';
|
|
9
10
|
import { resolveDomains } from './tools/domains.js';
|
|
10
|
-
import {
|
|
11
|
+
import { resolveToolDomains } from './authorization.js';
|
|
12
|
+
import { dispatchToolCall } from './tools/dispatch.js';
|
|
13
|
+
import { PACKAGE_VERSION } from './version.js';
|
|
11
14
|
// Load configuration
|
|
12
15
|
const config = loadConfig();
|
|
16
|
+
// Validate the pinned Persist resource contract before touching Cognito or
|
|
17
|
+
// PostgREST. Any structural, hash, or version mismatch is fatal — MCP must
|
|
18
|
+
// never advertise tools built on a malformed or incompatible artifact.
|
|
19
|
+
let persistContract;
|
|
20
|
+
try {
|
|
21
|
+
persistContract = loadPersistResourceContract();
|
|
22
|
+
}
|
|
23
|
+
catch (error) {
|
|
24
|
+
const detail = error instanceof PersistContractError
|
|
25
|
+
? error.message
|
|
26
|
+
: error.message;
|
|
27
|
+
console.error(`Persist resource contract failed validation: ${detail}`);
|
|
28
|
+
console.error('Refusing to start — run `npm run contract:check-resource` to reproduce, or ' +
|
|
29
|
+
'`npm run contract:sync-resource` to refresh from Persist.');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
console.error(`Raytio MCP: pinned Persist contract ${persistContract.contract_version} ` +
|
|
33
|
+
`at ${persistContract.source_commit.slice(0, 8)} ` +
|
|
34
|
+
`(${persistContract.resource_count} resources, ${persistContract.excluded_count} excluded)`);
|
|
13
35
|
// Initialize authentication and API client
|
|
14
36
|
const auth = new CognitoAuth({
|
|
15
37
|
userPoolId: config.raytio.cognito.userPoolId,
|
|
@@ -20,37 +42,22 @@ const auth = new CognitoAuth({
|
|
|
20
42
|
});
|
|
21
43
|
const apiClient = new RaytioApiClient(config.raytio.apiBaseUrl, auth);
|
|
22
44
|
const ctx = { apiClient, auth, config };
|
|
23
|
-
// Resolve tool domains
|
|
24
|
-
//
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
}
|
|
32
|
-
try {
|
|
33
|
-
const dynamicDomains = await resolveUserDomains(apiClient);
|
|
34
|
-
if (dynamicDomains) {
|
|
35
|
-
console.error(`Raytio MCP: resolved domains from user roles: ${dynamicDomains}`);
|
|
36
|
-
return dynamicDomains;
|
|
37
|
-
}
|
|
38
|
-
console.error('Raytio MCP: user has no recognised roles, exposing all domains as fallback');
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
catch (err) {
|
|
42
|
-
console.error(`Raytio MCP: role query failed (${err.message}), falling back to all domains`);
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
const domainSpec = await resolveToolDomains();
|
|
47
|
-
const allTools = resolveDomains(domainSpec);
|
|
45
|
+
// Resolve tool domains. The static RAYTIO_TOOL_DOMAINS override may only
|
|
46
|
+
// restrict the user's resolved roles — it never grants access to a domain
|
|
47
|
+
// the user does not already hold. Any failure to resolve roles fails closed
|
|
48
|
+
// (expose no tools) rather than falling back to the full surface.
|
|
49
|
+
const authorization = await resolveToolDomains(apiClient, process.env.RAYTIO_TOOL_DOMAINS);
|
|
50
|
+
const allTools = authorization.authorized
|
|
51
|
+
? resolveDomains(authorization.domainSpec)
|
|
52
|
+
: [];
|
|
48
53
|
console.error(`Raytio MCP: exposing ${allTools.length} tools` +
|
|
49
|
-
(domainSpec
|
|
54
|
+
(authorization.domainSpec
|
|
55
|
+
? ` (domains: ${authorization.domainSpec})`
|
|
56
|
+
: ' (no domains — fail closed)'));
|
|
50
57
|
// Create MCP server
|
|
51
58
|
const server = new Server({
|
|
52
59
|
name: '@raytio/mcp-server',
|
|
53
|
-
version:
|
|
60
|
+
version: PACKAGE_VERSION,
|
|
54
61
|
}, {
|
|
55
62
|
capabilities: {
|
|
56
63
|
tools: {},
|
|
@@ -66,38 +73,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
66
73
|
})),
|
|
67
74
|
};
|
|
68
75
|
});
|
|
69
|
-
// Handle tool calls
|
|
76
|
+
// Handle tool calls — dispatch centrally so every input is parsed through
|
|
77
|
+
// its Zod schema before the tool handler is invoked.
|
|
70
78
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
71
79
|
const { name, arguments: args = {} } = request.params;
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
type: 'text',
|
|
78
|
-
text: JSON.stringify({ success: false, error: { code: 'TOOL_ERROR', message: `Unknown tool: ${name}` } }, null, 2),
|
|
79
|
-
},
|
|
80
|
-
],
|
|
81
|
-
isError: true,
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
try {
|
|
85
|
-
const result = await tool.handler(args, ctx);
|
|
86
|
-
return {
|
|
87
|
-
content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
catch (error) {
|
|
91
|
-
return {
|
|
92
|
-
content: [
|
|
93
|
-
{
|
|
94
|
-
type: 'text',
|
|
95
|
-
text: JSON.stringify({ success: false, error: { code: 'TOOL_ERROR', message: error.message } }, null, 2),
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
isError: true,
|
|
99
|
-
};
|
|
100
|
-
}
|
|
80
|
+
const response = await dispatchToolCall(allTools, name, args, ctx);
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
|
|
83
|
+
...(response.success ? {} : { isError: true }),
|
|
84
|
+
};
|
|
101
85
|
});
|
|
102
86
|
// Start server
|
|
103
87
|
async function main() {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Tool, ToolContext } from './registry.js';
|
|
2
|
+
import { ToolResponse } from './types.js';
|
|
3
|
+
export declare const INPUT_VALIDATION_ERROR = "INPUT_VALIDATION_ERROR";
|
|
4
|
+
export declare const UNKNOWN_TOOL = "UNKNOWN_TOOL";
|
|
5
|
+
export declare const TOOL_ERROR = "TOOL_ERROR";
|
|
6
|
+
/**
|
|
7
|
+
* Central dispatch entry point for every MCP `tools/call` request.
|
|
8
|
+
*
|
|
9
|
+
* Guarantees:
|
|
10
|
+
* - The advertised Zod schema is parsed before the tool handler runs,
|
|
11
|
+
* so handlers only ever see structurally valid input.
|
|
12
|
+
* - Unknown tool names return a stable `UNKNOWN_TOOL` error rather than
|
|
13
|
+
* passing an arbitrary name deeper into the stack.
|
|
14
|
+
* - Handler exceptions are converted to structured `TOOL_ERROR`
|
|
15
|
+
* responses so the MCP transport always sees a well-formed reply.
|
|
16
|
+
*/
|
|
17
|
+
export declare function dispatchToolCall(tools: Tool[], name: string, args: unknown, ctx: ToolContext): Promise<ToolResponse<unknown>>;
|
|
18
|
+
//# sourceMappingURL=dispatch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.d.ts","sourceRoot":"","sources":["../../src/tools/dispatch.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAiB,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,eAAO,MAAM,sBAAsB,2BAA2B,CAAC;AAC/D,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,UAAU,eAAe,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,IAAI,EAAE,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAqBhC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { errorResponse } from './types.js';
|
|
2
|
+
export const INPUT_VALIDATION_ERROR = 'INPUT_VALIDATION_ERROR';
|
|
3
|
+
export const UNKNOWN_TOOL = 'UNKNOWN_TOOL';
|
|
4
|
+
export const TOOL_ERROR = 'TOOL_ERROR';
|
|
5
|
+
/**
|
|
6
|
+
* Central dispatch entry point for every MCP `tools/call` request.
|
|
7
|
+
*
|
|
8
|
+
* Guarantees:
|
|
9
|
+
* - The advertised Zod schema is parsed before the tool handler runs,
|
|
10
|
+
* so handlers only ever see structurally valid input.
|
|
11
|
+
* - Unknown tool names return a stable `UNKNOWN_TOOL` error rather than
|
|
12
|
+
* passing an arbitrary name deeper into the stack.
|
|
13
|
+
* - Handler exceptions are converted to structured `TOOL_ERROR`
|
|
14
|
+
* responses so the MCP transport always sees a well-formed reply.
|
|
15
|
+
*/
|
|
16
|
+
export async function dispatchToolCall(tools, name, args, ctx) {
|
|
17
|
+
const tool = tools.find((t) => t.name === name);
|
|
18
|
+
if (!tool) {
|
|
19
|
+
return errorResponse(UNKNOWN_TOOL, `Unknown tool: ${name}`);
|
|
20
|
+
}
|
|
21
|
+
const rawInput = args ?? {};
|
|
22
|
+
const parsed = tool.inputSchema.safeParse(rawInput);
|
|
23
|
+
if (!parsed.success) {
|
|
24
|
+
return errorResponse(INPUT_VALIDATION_ERROR, `Invalid arguments for tool "${name}": ${formatZodError(parsed.error)}`, { issues: parsed.error.issues });
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
return await tool.handler(parsed.data, ctx);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
return errorResponse(TOOL_ERROR, error?.message ?? String(error));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function formatZodError(error) {
|
|
34
|
+
return error.issues
|
|
35
|
+
.map((issue) => {
|
|
36
|
+
const path = issue.path.length ? issue.path.join('.') : '(root)';
|
|
37
|
+
return `${path}: ${issue.message}`;
|
|
38
|
+
})
|
|
39
|
+
.join('; ');
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/tools/dispatch.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAgB,MAAM,YAAY,CAAC;AAEzD,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC;AAC/D,MAAM,CAAC,MAAM,YAAY,GAAG,cAAc,CAAC;AAC3C,MAAM,CAAC,MAAM,UAAU,GAAG,YAAY,CAAC;AAEvC;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAAa,EACb,IAAY,EACZ,IAAa,EACb,GAAgB;IAEhB,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,aAAa,CAAC,YAAY,EAAE,iBAAiB,IAAI,EAAE,CAAC,CAAC;IAC9D,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,OAAO,aAAa,CAClB,sBAAsB,EACtB,+BAA+B,IAAI,MAAM,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EACvE,EAAE,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,EAAE,CAChC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC9C,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,aAAa,CAAC,UAAU,EAAE,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAiB;IACvC,OAAO,KAAK,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;QACjE,OAAO,GAAG,IAAI,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;IACrC,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
|
@@ -1,19 +1,25 @@
|
|
|
1
1
|
import { RaytioApiClient } from '../raytio/api-client.js';
|
|
2
2
|
/**
|
|
3
|
-
* Shape returned by `fnd_authz_user_groups()` PostgREST RPC.
|
|
4
|
-
*
|
|
3
|
+
* Shape returned by `fnd_authz_user_groups()` PostgREST RPC. Each row
|
|
4
|
+
* represents one resolved role (direct or inherited via group membership).
|
|
5
|
+
*
|
|
6
|
+
* The Persist function returns a single column named `group_name` — the
|
|
7
|
+
* MCP server previously read `group_code`, which meant no user role ever
|
|
8
|
+
* mapped to a domain. This alignment is an interim compatibility fix
|
|
9
|
+
* pending the versioned Persist contract (see epic WI-0003496).
|
|
5
10
|
*/
|
|
6
11
|
export interface UserGroup {
|
|
7
|
-
|
|
12
|
+
group_name: string;
|
|
8
13
|
[key: string]: unknown;
|
|
9
14
|
}
|
|
10
15
|
/**
|
|
11
|
-
* Given a list of user group
|
|
16
|
+
* Given a list of user group names, resolve the set of tool domain IDs
|
|
12
17
|
* the user should have access to.
|
|
13
18
|
*
|
|
14
|
-
* When both
|
|
19
|
+
* When both a full-access and readonly domain are present (e.g. `ppm`
|
|
20
|
+
* and `ppm-readonly`), the full-access variant wins.
|
|
15
21
|
*/
|
|
16
|
-
export declare function mapRolesToDomains(
|
|
22
|
+
export declare function mapRolesToDomains(groupNames: string[]): string[];
|
|
17
23
|
/**
|
|
18
24
|
* Fetch the authenticated user's resolved role groups from the backend.
|
|
19
25
|
* Calls the `fnd_authz_user_groups()` PostgREST RPC endpoint.
|
|
@@ -24,8 +30,9 @@ export declare function fetchUserGroups(apiClient: RaytioApiClient): Promise<Use
|
|
|
24
30
|
* backend roles. Returns a comma-separated domain spec string compatible
|
|
25
31
|
* with `resolveDomains()`.
|
|
26
32
|
*
|
|
27
|
-
* Returns `undefined` when the user has no recognised roles
|
|
28
|
-
*
|
|
33
|
+
* Returns `undefined` when the user has no recognised roles — the caller
|
|
34
|
+
* (see `src/index.ts`) MUST fail closed in that case rather than fall
|
|
35
|
+
* back to the full tool surface.
|
|
29
36
|
*/
|
|
30
37
|
export declare function resolveUserDomains(apiClient: RaytioApiClient): Promise<string | undefined>;
|
|
31
38
|
//# sourceMappingURL=role-mapping.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-mapping.d.ts","sourceRoot":"","sources":["../../src/tools/role-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D
|
|
1
|
+
{"version":3,"file":"role-mapping.d.ts","sourceRoot":"","sources":["../../src/tools/role-mapping.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE1D;;;;;;;;GAQG;AACH,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAsBD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAqBhE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC,SAAS,EAAE,CAAC,CAEtB;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,eAAe,GACzB,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAO7B"}
|
|
@@ -1,37 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Map role group
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* - PROJECT_USER, PROJECT_ADMINISTRATOR
|
|
6
|
-
*
|
|
7
|
-
* Role codes that grant read-only PPM access (SELECT only):
|
|
8
|
-
* - PROJECT_VIEWER
|
|
9
|
-
*
|
|
10
|
-
* Role codes that grant full DSM access:
|
|
11
|
-
* - DATA_SHARING_USER, DATA_SHARING_ADMINISTRATOR
|
|
2
|
+
* Map role group names (as returned by `fnd_authz_user_groups()`) to the
|
|
3
|
+
* tool domain IDs they unlock. Keys are the exact Persist seed values
|
|
4
|
+
* from `02435-seed-hrm-role-group-inheritance.sql`.
|
|
12
5
|
*/
|
|
13
6
|
const ROLE_TO_DOMAINS = {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
7
|
+
'Project administrator': ['ppm', 'prm', 'wrm'],
|
|
8
|
+
'Project user': ['ppm', 'prm'],
|
|
9
|
+
'Project viewer': ['ppm-readonly', 'wrm-readonly'],
|
|
10
|
+
'Data sharing administrator': ['dsm'],
|
|
11
|
+
'Data sharing user': ['dsm'],
|
|
12
|
+
'Data sharing viewer': ['dsm'],
|
|
13
|
+
'Worker administrator': ['wrm', 'prm'],
|
|
14
|
+
'Worker user': ['wrm', 'prm'],
|
|
15
|
+
'Worker viewer': ['wrm-readonly'],
|
|
16
|
+
'Sales administrator': ['sfa', 'prm'],
|
|
17
|
+
'Sales user': ['sfa', 'prm'],
|
|
18
|
+
'Sales viewer': ['sfa-readonly'],
|
|
24
19
|
};
|
|
25
20
|
/**
|
|
26
|
-
* Given a list of user group
|
|
21
|
+
* Given a list of user group names, resolve the set of tool domain IDs
|
|
27
22
|
* the user should have access to.
|
|
28
23
|
*
|
|
29
|
-
* When both
|
|
24
|
+
* When both a full-access and readonly domain are present (e.g. `ppm`
|
|
25
|
+
* and `ppm-readonly`), the full-access variant wins.
|
|
30
26
|
*/
|
|
31
|
-
export function mapRolesToDomains(
|
|
27
|
+
export function mapRolesToDomains(groupNames) {
|
|
32
28
|
const domains = new Set();
|
|
33
|
-
for (const
|
|
34
|
-
const mapped = ROLE_TO_DOMAINS[
|
|
29
|
+
for (const name of groupNames) {
|
|
30
|
+
const mapped = ROLE_TO_DOMAINS[name];
|
|
35
31
|
if (mapped) {
|
|
36
32
|
for (const d of mapped)
|
|
37
33
|
domains.add(d);
|
|
@@ -61,13 +57,16 @@ export async function fetchUserGroups(apiClient) {
|
|
|
61
57
|
* backend roles. Returns a comma-separated domain spec string compatible
|
|
62
58
|
* with `resolveDomains()`.
|
|
63
59
|
*
|
|
64
|
-
* Returns `undefined` when the user has no recognised roles
|
|
65
|
-
*
|
|
60
|
+
* Returns `undefined` when the user has no recognised roles — the caller
|
|
61
|
+
* (see `src/index.ts`) MUST fail closed in that case rather than fall
|
|
62
|
+
* back to the full tool surface.
|
|
66
63
|
*/
|
|
67
64
|
export async function resolveUserDomains(apiClient) {
|
|
68
65
|
const groups = await fetchUserGroups(apiClient);
|
|
69
|
-
const
|
|
70
|
-
|
|
66
|
+
const names = groups
|
|
67
|
+
.map((g) => g.group_name)
|
|
68
|
+
.filter((n) => typeof n === 'string' && n.length > 0);
|
|
69
|
+
const domains = mapRolesToDomains(names);
|
|
71
70
|
return domains.length > 0 ? domains.join(',') : undefined;
|
|
72
71
|
}
|
|
73
72
|
//# sourceMappingURL=role-mapping.js.map
|