@raytio/mcp-server 1.23.1 → 2.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/README.md +4 -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-contract.d.ts +42 -0
- package/dist/contracts/persist-contract.d.ts.map +1 -0
- package/dist/contracts/persist-contract.js +30 -0
- package/dist/contracts/persist-contract.js.map +1 -0
- package/dist/index.js +22 -58
- package/dist/index.js.map +1 -1
- package/dist/ppm/__fixtures__/work-item.js +1 -1
- package/dist/ppm/__fixtures__/work-item.js.map +1 -1
- package/dist/ppm/projection.js +1 -1
- package/dist/ppm/projection.js.map +1 -1
- package/dist/ppm/types.d.ts +1 -1
- package/dist/ppm/types.d.ts.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/ppm/template-get.js +1 -1
- package/dist/tools/ppm/template-get.js.map +1 -1
- package/dist/tools/ppm/template-slot-create.d.ts.map +1 -1
- package/dist/tools/ppm/template-slot-create.js +5 -5
- package/dist/tools/ppm/template-slot-create.js.map +1 -1
- package/dist/tools/ppm/template-slot-list.js +2 -2
- package/dist/tools/ppm/template-slot-list.js.map +1 -1
- package/dist/tools/ppm/work-item-create.d.ts.map +1 -1
- package/dist/tools/ppm/work-item-create.js +4 -2
- package/dist/tools/ppm/work-item-create.js.map +1 -1
- 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 +4 -1
package/README.md
CHANGED
|
@@ -296,6 +296,10 @@ The full catalogue of exposed tools — names, descriptions, and parameters —
|
|
|
296
296
|
npm run docs:tools
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
+
Persist-backed input requirements are checked separately with
|
|
300
|
+
`npm run contract:check`. See [Persist contract synchronization](./docs/persist-contract-sync.md)
|
|
301
|
+
for the scheduled draft-MR workflow and its GitLab configuration.
|
|
302
|
+
|
|
299
303
|
### Error codes
|
|
300
304
|
|
|
301
305
|
Tools return structured responses; error codes common across domains:
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { RaytioApiClient } from './raytio/api-client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Result of resolving the effective tool domain set for the authenticated
|
|
4
|
+
* user. When `authorized` is `false`, the caller MUST expose no tools.
|
|
5
|
+
*/
|
|
6
|
+
export interface AuthorizationResult {
|
|
7
|
+
/** Comma-separated domain spec suitable for `resolveDomains()`, or `undefined` when no tools should be exposed. */
|
|
8
|
+
domainSpec: string | undefined;
|
|
9
|
+
/** Human-readable reason for the decision. Emitted to stderr for operator visibility. */
|
|
10
|
+
reason: string;
|
|
11
|
+
/** `true` when the caller should expose tools. `false` means fail closed — expose nothing. */
|
|
12
|
+
authorized: boolean;
|
|
13
|
+
}
|
|
14
|
+
type StderrLogger = Pick<Console, 'error'>;
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the tool domain surface for the authenticated user.
|
|
17
|
+
*
|
|
18
|
+
* Behaviour:
|
|
19
|
+
* - Always queries the backend for the user's resolved roles. On any
|
|
20
|
+
* failure, fails closed and exposes no tools.
|
|
21
|
+
* - The static `RAYTIO_TOOL_DOMAINS` override may only *restrict* the
|
|
22
|
+
* user's resolved domain set. It never grants access to domains the
|
|
23
|
+
* user does not have.
|
|
24
|
+
* - If the intersection is empty (or the user has no recognised roles),
|
|
25
|
+
* fails closed.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveToolDomains(apiClient: RaytioApiClient, envSpec: string | undefined, logger?: StderrLogger): Promise<AuthorizationResult>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=authorization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.d.ts","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,mHAAmH;IACnH,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,yFAAyF;IACzF,MAAM,EAAE,MAAM,CAAC;IACf,8FAA8F;IAC9F,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,KAAK,YAAY,GAAG,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;AAgD3C;;;;;;;;;;;GAWG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,eAAe,EAC1B,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,MAAM,GAAE,YAAsB,GAC7B,OAAO,CAAC,mBAAmB,CAAC,CAyC9B"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { resolveUserDomains } from './tools/role-mapping.js';
|
|
2
|
+
/**
|
|
3
|
+
* Domains that a static override may resolve to when the user only holds
|
|
4
|
+
* the full-access parent. This preserves the useful "further restrict a
|
|
5
|
+
* privileged user to read-only tools" case without ever letting a static
|
|
6
|
+
* override grant access the user does not already have.
|
|
7
|
+
*/
|
|
8
|
+
const READONLY_PARENTS = {
|
|
9
|
+
'ppm-readonly': 'ppm',
|
|
10
|
+
'wrm-readonly': 'wrm',
|
|
11
|
+
'sfa-readonly': 'sfa',
|
|
12
|
+
};
|
|
13
|
+
function parseSpec(spec) {
|
|
14
|
+
if (!spec)
|
|
15
|
+
return [];
|
|
16
|
+
return spec
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((s) => s.trim())
|
|
19
|
+
.filter(Boolean);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Intersect a static domain list with the user's resolved domain list.
|
|
23
|
+
* Static entries that ask for a read-only sub-domain of a full-access
|
|
24
|
+
* domain the user already holds are permitted (a further restriction).
|
|
25
|
+
* Anything else the user does not have is silently dropped — a static
|
|
26
|
+
* override is a restriction, never a grant.
|
|
27
|
+
*/
|
|
28
|
+
function restrictToUserDomains(staticDomains, userDomains) {
|
|
29
|
+
const userSet = new Set(userDomains);
|
|
30
|
+
const allowed = [];
|
|
31
|
+
for (const d of staticDomains) {
|
|
32
|
+
if (userSet.has(d)) {
|
|
33
|
+
allowed.push(d);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
const parent = READONLY_PARENTS[d];
|
|
37
|
+
if (parent && userSet.has(parent)) {
|
|
38
|
+
allowed.push(d);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return allowed;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve the tool domain surface for the authenticated user.
|
|
45
|
+
*
|
|
46
|
+
* Behaviour:
|
|
47
|
+
* - Always queries the backend for the user's resolved roles. On any
|
|
48
|
+
* failure, fails closed and exposes no tools.
|
|
49
|
+
* - The static `RAYTIO_TOOL_DOMAINS` override may only *restrict* the
|
|
50
|
+
* user's resolved domain set. It never grants access to domains the
|
|
51
|
+
* user does not have.
|
|
52
|
+
* - If the intersection is empty (or the user has no recognised roles),
|
|
53
|
+
* fails closed.
|
|
54
|
+
*/
|
|
55
|
+
export async function resolveToolDomains(apiClient, envSpec, logger = console) {
|
|
56
|
+
const staticDomains = parseSpec(envSpec);
|
|
57
|
+
let dynamicSpec;
|
|
58
|
+
try {
|
|
59
|
+
dynamicSpec = await resolveUserDomains(apiClient);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
const reason = `role query failed: ${err?.message ?? err}`;
|
|
63
|
+
logger.error(`Raytio MCP: authorization resolution failed (${reason}) — exposing no tools (fail closed)`);
|
|
64
|
+
return { domainSpec: undefined, reason, authorized: false };
|
|
65
|
+
}
|
|
66
|
+
const userDomains = parseSpec(dynamicSpec);
|
|
67
|
+
if (userDomains.length === 0) {
|
|
68
|
+
const reason = 'user has no recognised roles';
|
|
69
|
+
logger.error(`Raytio MCP: ${reason} — exposing no tools (fail closed)`);
|
|
70
|
+
return { domainSpec: undefined, reason, authorized: false };
|
|
71
|
+
}
|
|
72
|
+
if (staticDomains.length === 0) {
|
|
73
|
+
const spec = userDomains.join(',');
|
|
74
|
+
logger.error(`Raytio MCP: resolved domains from user roles: ${spec}`);
|
|
75
|
+
return { domainSpec: spec, reason: 'resolved from user roles', authorized: true };
|
|
76
|
+
}
|
|
77
|
+
const allowed = restrictToUserDomains(staticDomains, userDomains);
|
|
78
|
+
if (allowed.length === 0) {
|
|
79
|
+
const reason = `static RAYTIO_TOOL_DOMAINS "${staticDomains.join(',')}" does not intersect user roles "${userDomains.join(',')}"`;
|
|
80
|
+
logger.error(`Raytio MCP: ${reason} — exposing no tools (fail closed)`);
|
|
81
|
+
return { domainSpec: undefined, reason, authorized: false };
|
|
82
|
+
}
|
|
83
|
+
const spec = allowed.join(',');
|
|
84
|
+
logger.error(`Raytio MCP: static RAYTIO_TOOL_DOMAINS restricted user roles (${userDomains.join(',')}) to ${spec}`);
|
|
85
|
+
return { domainSpec: spec, reason: 'restricted by static override', authorized: true };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=authorization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"authorization.js","sourceRoot":"","sources":["../src/authorization.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export interface PersistColumnContract {
|
|
3
|
+
sourcePath: string;
|
|
4
|
+
table: string;
|
|
5
|
+
column: string;
|
|
6
|
+
sqlType: string;
|
|
7
|
+
nullable: boolean;
|
|
8
|
+
hasDefault: boolean;
|
|
9
|
+
requiredOnInsert: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface PersistContract {
|
|
12
|
+
project: string;
|
|
13
|
+
sourceCommit: string;
|
|
14
|
+
fields: Record<string, PersistColumnContract>;
|
|
15
|
+
}
|
|
16
|
+
export declare const persistContract: {
|
|
17
|
+
readonly project: "raytio/common/persist";
|
|
18
|
+
readonly sourceCommit: "1dbd9a1f3749c700df0eaa87392a35ce28673b07";
|
|
19
|
+
readonly fields: {
|
|
20
|
+
readonly ppmWorkItemCreateRoleId: {
|
|
21
|
+
readonly sourcePath: "db/init/raytio_custom_db_entities/15010-ppm-work-items.sql";
|
|
22
|
+
readonly table: "GLOBAL.t_ppm_work_items";
|
|
23
|
+
readonly column: "role_id";
|
|
24
|
+
readonly sqlType: "UUID";
|
|
25
|
+
readonly nullable: false;
|
|
26
|
+
readonly hasDefault: false;
|
|
27
|
+
readonly requiredOnInsert: true;
|
|
28
|
+
};
|
|
29
|
+
readonly ppmTemplateSlotCreateRoleId: {
|
|
30
|
+
readonly sourcePath: "db/init/raytio_custom_db_entities/15210-ppm-epic-template-slots.sql";
|
|
31
|
+
readonly table: "GLOBAL.t_ppm_epic_template_slots";
|
|
32
|
+
readonly column: "role_id";
|
|
33
|
+
readonly sqlType: "UUID";
|
|
34
|
+
readonly nullable: false;
|
|
35
|
+
readonly hasDefault: false;
|
|
36
|
+
readonly requiredOnInsert: true;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
/** Apply Persist insert nullability to an MCP input field. */
|
|
41
|
+
export declare function withPersistInsertRequirement<T extends z.ZodTypeAny>(schema: T, contract: PersistColumnContract): T | z.ZodOptional<T>;
|
|
42
|
+
//# sourceMappingURL=persist-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist-contract.d.ts","sourceRoot":"","sources":["../../src/contracts/persist-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;CAC/C;AAGD,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;CAuBQ,CAAC;AAErC,8DAA8D;AAC9D,wBAAgB,4BAA4B,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACjE,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,qBAAqB,GAC9B,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAEtB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Generated by scripts/sync-persist-contract.ts. Do not edit by hand.
|
|
2
|
+
export const persistContract = {
|
|
3
|
+
"project": "raytio/common/persist",
|
|
4
|
+
"sourceCommit": "1dbd9a1f3749c700df0eaa87392a35ce28673b07",
|
|
5
|
+
"fields": {
|
|
6
|
+
"ppmWorkItemCreateRoleId": {
|
|
7
|
+
"sourcePath": "db/init/raytio_custom_db_entities/15010-ppm-work-items.sql",
|
|
8
|
+
"table": "GLOBAL.t_ppm_work_items",
|
|
9
|
+
"column": "role_id",
|
|
10
|
+
"sqlType": "UUID",
|
|
11
|
+
"nullable": false,
|
|
12
|
+
"hasDefault": false,
|
|
13
|
+
"requiredOnInsert": true
|
|
14
|
+
},
|
|
15
|
+
"ppmTemplateSlotCreateRoleId": {
|
|
16
|
+
"sourcePath": "db/init/raytio_custom_db_entities/15210-ppm-epic-template-slots.sql",
|
|
17
|
+
"table": "GLOBAL.t_ppm_epic_template_slots",
|
|
18
|
+
"column": "role_id",
|
|
19
|
+
"sqlType": "UUID",
|
|
20
|
+
"nullable": false,
|
|
21
|
+
"hasDefault": false,
|
|
22
|
+
"requiredOnInsert": true
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
/** Apply Persist insert nullability to an MCP input field. */
|
|
27
|
+
export function withPersistInsertRequirement(schema, contract) {
|
|
28
|
+
return contract.requiredOnInsert ? schema : schema.optional();
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=persist-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"persist-contract.js","sourceRoot":"","sources":["../../src/contracts/persist-contract.ts"],"names":[],"mappings":"AAkBA,sEAAsE;AACtE,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,SAAS,EAAE,uBAAuB;IAClC,cAAc,EAAE,0CAA0C;IAC1D,QAAQ,EAAE;QACR,yBAAyB,EAAE;YACzB,YAAY,EAAE,4DAA4D;YAC1E,OAAO,EAAE,yBAAyB;YAClC,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,MAAM;YACjB,UAAU,EAAE,KAAK;YACjB,YAAY,EAAE,KAAK;YACnB,kBAAkB,EAAE,IAAI;SACzB;QACD,6BAA6B,EAAE;YAC7B,YAAY,EAAE,qEAAqE;YACnF,OAAO,EAAE,kCAAkC;YAC3C,QAAQ,EAAE,SAAS;YACnB,SAAS,EAAE,MAAM;YACjB,UAAU,EAAE,KAAK;YACjB,YAAY,EAAE,KAAK;YACnB,kBAAkB,EAAE,IAAI;SACzB;KACF;CACiC,CAAC;AAErC,8DAA8D;AAC9D,MAAM,UAAU,4BAA4B,CAC1C,MAAS,EACT,QAA+B;IAE/B,OAAO,QAAQ,CAAC,gBAAgB,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;AAChE,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,9 @@ import { loadConfig } from './config.js';
|
|
|
7
7
|
import { CognitoAuth } from './raytio/auth.js';
|
|
8
8
|
import { RaytioApiClient } from './raytio/api-client.js';
|
|
9
9
|
import { resolveDomains } from './tools/domains.js';
|
|
10
|
-
import {
|
|
10
|
+
import { resolveToolDomains } from './authorization.js';
|
|
11
|
+
import { dispatchToolCall } from './tools/dispatch.js';
|
|
12
|
+
import { PACKAGE_VERSION } from './version.js';
|
|
11
13
|
// Load configuration
|
|
12
14
|
const config = loadConfig();
|
|
13
15
|
// Initialize authentication and API client
|
|
@@ -20,37 +22,22 @@ const auth = new CognitoAuth({
|
|
|
20
22
|
});
|
|
21
23
|
const apiClient = new RaytioApiClient(config.raytio.apiBaseUrl, auth);
|
|
22
24
|
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);
|
|
25
|
+
// Resolve tool domains. The static RAYTIO_TOOL_DOMAINS override may only
|
|
26
|
+
// restrict the user's resolved roles — it never grants access to a domain
|
|
27
|
+
// the user does not already hold. Any failure to resolve roles fails closed
|
|
28
|
+
// (expose no tools) rather than falling back to the full surface.
|
|
29
|
+
const authorization = await resolveToolDomains(apiClient, process.env.RAYTIO_TOOL_DOMAINS);
|
|
30
|
+
const allTools = authorization.authorized
|
|
31
|
+
? resolveDomains(authorization.domainSpec)
|
|
32
|
+
: [];
|
|
48
33
|
console.error(`Raytio MCP: exposing ${allTools.length} tools` +
|
|
49
|
-
(domainSpec
|
|
34
|
+
(authorization.domainSpec
|
|
35
|
+
? ` (domains: ${authorization.domainSpec})`
|
|
36
|
+
: ' (no domains — fail closed)'));
|
|
50
37
|
// Create MCP server
|
|
51
38
|
const server = new Server({
|
|
52
39
|
name: '@raytio/mcp-server',
|
|
53
|
-
version:
|
|
40
|
+
version: PACKAGE_VERSION,
|
|
54
41
|
}, {
|
|
55
42
|
capabilities: {
|
|
56
43
|
tools: {},
|
|
@@ -66,38 +53,15 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
66
53
|
})),
|
|
67
54
|
};
|
|
68
55
|
});
|
|
69
|
-
// Handle tool calls
|
|
56
|
+
// Handle tool calls — dispatch centrally so every input is parsed through
|
|
57
|
+
// its Zod schema before the tool handler is invoked.
|
|
70
58
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
71
59
|
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
|
-
}
|
|
60
|
+
const response = await dispatchToolCall(allTools, name, args, ctx);
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: 'text', text: JSON.stringify(response, null, 2) }],
|
|
63
|
+
...(response.success ? {} : { isError: true }),
|
|
64
|
+
};
|
|
101
65
|
});
|
|
102
66
|
// Start server
|
|
103
67
|
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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"}
|
|
@@ -78,7 +78,7 @@ export function makeEpicTemplate(overrides) {
|
|
|
78
78
|
export function makeEpicTemplateSlot(overrides) {
|
|
79
79
|
return {
|
|
80
80
|
id: 'ets-uuid-123',
|
|
81
|
-
|
|
81
|
+
template_id: 'et-uuid-123',
|
|
82
82
|
slot_key: 'api_docs',
|
|
83
83
|
slot_label: 'API Documentation',
|
|
84
84
|
slot_description: 'Describe the REST surface the tools wrap',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-item.js","sourceRoot":"","sources":["../../../src/ppm/__fixtures__/work-item.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,SAA6B;IACxD,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,EAAE,QAAQ;QACvB,cAAc,EAAE,MAAM;QACtB,gBAAgB,EAAE,SAAS;QAC3B,yBAAyB,EAAE,WAAW;QACtC,kBAAkB,EAAE,QAAQ;QAC5B,cAAc,EAAE,gBAAgB;QAChC,qBAAqB,EAAE,IAAI;QAC3B,UAAU,EAAE,WAAW;QACvB,mBAAmB,EAAE,IAAI;QACzB,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,IAAI;QACd,gBAAgB,EAAE,IAAI;QACtB,sBAAsB,EAAE,IAAI;QAC5B,mBAAmB,EAAE,CAAC;QACtB,iBAAiB,EAAE,IAAI;QACvB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,IAAI;QAClB,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,IAAI;QACd,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiC;IAChE,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,mBAAmB,EAAE,gBAAgB;QACrC,mBAAmB,EAAE,gBAAgB;QACrC,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,SAAuC;IAC5E,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,mBAAmB,EAAE,gBAAgB;QACrC,mBAAmB,EAAE,gBAAgB;QACrC,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,sBAAsB,EAAE,IAAI;QAC5B,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,SAAmC;IACpE,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,EAAE,QAAQ;QACvB,iBAAiB,EAAE,aAAa;QAChC,UAAU,EAAE,oBAAoB;QAChC,WAAW,EAAE,aAAa;QAC1B,WAAW,EAAE,IAAI;QACjB,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiC;IAChE,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,EAAE,cAAc;QAC7B,aAAa,EAAE,cAAc;QAC7B,oBAAoB,EAAE,oCAAoC;QAC1D,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAAqC;IACxE,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,
|
|
1
|
+
{"version":3,"file":"work-item.js","sourceRoot":"","sources":["../../../src/ppm/__fixtures__/work-item.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,YAAY,CAAC,SAA6B;IACxD,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,EAAE,QAAQ;QACvB,cAAc,EAAE,MAAM;QACtB,gBAAgB,EAAE,SAAS;QAC3B,yBAAyB,EAAE,WAAW;QACtC,kBAAkB,EAAE,QAAQ;QAC5B,cAAc,EAAE,gBAAgB;QAChC,qBAAqB,EAAE,IAAI;QAC3B,UAAU,EAAE,WAAW;QACvB,mBAAmB,EAAE,IAAI;QACzB,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,IAAI;QACd,gBAAgB,EAAE,IAAI;QACtB,sBAAsB,EAAE,IAAI;QAC5B,mBAAmB,EAAE,CAAC;QACtB,iBAAiB,EAAE,IAAI;QACvB,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,IAAI;QACxB,gBAAgB,EAAE,IAAI;QACtB,YAAY,EAAE,IAAI;QAClB,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,IAAI;QACZ,YAAY,EAAE,IAAI;QAClB,QAAQ,EAAE,IAAI;QACd,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiC;IAChE,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,mBAAmB,EAAE,gBAAgB;QACrC,mBAAmB,EAAE,gBAAgB;QACrC,SAAS,EAAE,QAAQ;QACnB,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,SAAuC;IAC5E,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,mBAAmB,EAAE,gBAAgB;QACrC,mBAAmB,EAAE,gBAAgB;QACrC,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,CAAC;QACd,eAAe,EAAE,IAAI;QACrB,sBAAsB,EAAE,IAAI;QAC5B,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,SAAmC;IACpE,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,EAAE,QAAQ;QACvB,iBAAiB,EAAE,aAAa;QAChC,UAAU,EAAE,oBAAoB;QAChC,WAAW,EAAE,aAAa;QAC1B,WAAW,EAAE,IAAI;QACjB,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,SAAiC;IAChE,OAAO;QACL,EAAE,EAAE,aAAa;QACjB,aAAa,EAAE,cAAc;QAC7B,aAAa,EAAE,cAAc;QAC7B,oBAAoB,EAAE,oCAAoC;QAC1D,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAAqC;IACxE,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,WAAW,EAAE,aAAa;QAC1B,QAAQ,EAAE,UAAU;QACpB,UAAU,EAAE,mBAAmB;QAC/B,gBAAgB,EAAE,0CAA0C;QAC5D,cAAc,EAAE,MAAM;QACtB,OAAO,EAAE,IAAI;QACb,UAAU,EAAE,CAAC;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,IAAI;QACZ,GAAG,SAAS;KACb,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAA6B;IACxD,OAAO;QACL,EAAE,EAAE,cAAc;QAClB,YAAY,EAAE,aAAa;QAC3B,aAAa,EAAE,SAAS;QACxB,aAAa,EAAE,eAAe;QAC9B,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,WAAW;QACvB,YAAY,EAAE,sBAAsB;QACpC,GAAG,SAAS;KACb,CAAC;AACJ,CAAC"}
|
package/dist/ppm/projection.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../../src/ppm/projection.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI;IACJ,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,2BAA2B;IAC3B,oBAAoB;IACpB,gBAAgB;IAChB,uBAAuB;IACvB,YAAY;IACZ,qBAAqB;IACrB,cAAc;IACd,UAAU;IACV,kBAAkB;IAClB,wBAAwB;IACxB,qBAAqB;IACrB,mBAAmB;IACnB,iBAAiB;IACjB,oBAAoB;IACpB,kBAAkB;IAClB,cAAc;IACd,SAAS;IACT,QAAQ;IACR,cAAc;IACd,UAAU;CACX,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI;IACJ,qBAAqB;IACrB,qBAAqB;IACrB,WAAW;IACX,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,IAAI;IACJ,qBAAqB;IACrB,qBAAqB;IACrB,iBAAiB;IACjB,aAAa;IACb,iBAAiB;IACjB,wBAAwB;IACxB,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI;IACJ,eAAe;IACf,mBAAmB;IACnB,YAAY;IACZ,aAAa;IACb,aAAa;IACb,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI;IACJ,eAAe;IACf,eAAe;IACf,sBAAsB;IACtB,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,IAAI;IACJ,
|
|
1
|
+
{"version":3,"file":"projection.js","sourceRoot":"","sources":["../../src/ppm/projection.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,IAAI;IACJ,eAAe;IACf,gBAAgB;IAChB,kBAAkB;IAClB,2BAA2B;IAC3B,oBAAoB;IACpB,gBAAgB;IAChB,uBAAuB;IACvB,YAAY;IACZ,qBAAqB;IACrB,cAAc;IACd,UAAU;IACV,kBAAkB;IAClB,wBAAwB;IACxB,qBAAqB;IACrB,mBAAmB;IACnB,iBAAiB;IACjB,oBAAoB;IACpB,kBAAkB;IAClB,cAAc;IACd,SAAS;IACT,QAAQ;IACR,cAAc;IACd,UAAU;CACX,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,IAAI;IACJ,qBAAqB;IACrB,qBAAqB;IACrB,WAAW;IACX,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,IAAI;IACJ,qBAAqB;IACrB,qBAAqB;IACrB,iBAAiB;IACjB,aAAa;IACb,iBAAiB;IACjB,wBAAwB;IACxB,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,IAAI;IACJ,eAAe;IACf,mBAAmB;IACnB,YAAY;IACZ,aAAa;IACb,aAAa;IACb,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI;IACJ,eAAe;IACf,eAAe;IACf,sBAAsB;IACtB,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,yBAAyB,GAAG;IACvC,IAAI;IACJ,aAAa;IACb,UAAU;IACV,YAAY;IACZ,kBAAkB;IAClB,gBAAgB;IAChB,SAAS;IACT,YAAY;IACZ,UAAU;IACV,QAAQ;CACT,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAEZ,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,IAAI;IACJ,cAAc;IACd,eAAe;IACf,eAAe;IACf,eAAe;IACf,YAAY;IACZ,cAAc;CACf,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC"}
|
package/dist/ppm/types.d.ts
CHANGED
package/dist/ppm/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ppm/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,yBAAyB,EAAE,MAAM,CAAC;IAClC,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,qBAAqB,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC1C;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,mBAAmB,EAAE,MAAM,CAAC;IAC5B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;IACzB,sBAAsB,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IACzC,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/ppm/types.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"}
|
|
@@ -22,7 +22,7 @@ export const templateGetTool = {
|
|
|
22
22
|
return errorResponse(PPM_NOT_FOUND, `Template not found`);
|
|
23
23
|
}
|
|
24
24
|
const template = templates[0];
|
|
25
|
-
const slots = await ctx.apiClient.get(`/db/v1/ppm_epic_template_slots?
|
|
25
|
+
const slots = await ctx.apiClient.get(`/db/v1/ppm_epic_template_slots?template_id=eq.${template.id}&select=${EPIC_TEMPLATE_SLOT_SELECT}&order=sort_order.asc`);
|
|
26
26
|
return successResponse({ ...template, slots });
|
|
27
27
|
}
|
|
28
28
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-get.js","sourceRoot":"","sources":["../../../src/tools/ppm/template-get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAG1F,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,mEAAmE;IAChF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QACxF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;KAC3G,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,IAA+C,CAAC;QAE9D,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YACtC,OAAO,aAAa,CAAC,gBAAgB,EAAE,wCAAwC,CAAC,CAAC;QACnF,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE;gBACrB,CAAC,CAAC,SAAS,KAAK,CAAC,EAAE,EAAE;gBACrB,CAAC,CAAC,oBAAoB,KAAK,CAAC,aAAa,EAAE,CAAC;YAE9C,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,CACvC,6BAA6B,MAAM,WAAW,oBAAoB,EAAE,CACrE,CAAC;YAEF,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzC,OAAO,aAAa,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;YAC5D,CAAC;YAED,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAE9B,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,CACnC,
|
|
1
|
+
{"version":3,"file":"template-get.js","sourceRoot":"","sources":["../../../src/tools/ppm/template-get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACvF,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAG1F,MAAM,CAAC,MAAM,eAAe,GAAS;IACnC,IAAI,EAAE,kBAAkB;IACxB,WAAW,EAAE,mEAAmE;IAChF,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oDAAoD,CAAC;QACxF,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;KAC3G,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,IAA+C,CAAC;QAE9D,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,CAAC;YACtC,OAAO,aAAa,CAAC,gBAAgB,EAAE,wCAAwC,CAAC,CAAC;QACnF,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE;gBACrB,CAAC,CAAC,SAAS,KAAK,CAAC,EAAE,EAAE;gBACrB,CAAC,CAAC,oBAAoB,KAAK,CAAC,aAAa,EAAE,CAAC;YAE9C,MAAM,SAAS,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,CACvC,6BAA6B,MAAM,WAAW,oBAAoB,EAAE,CACrE,CAAC;YAEF,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzC,OAAO,aAAa,CAAC,aAAa,EAAE,oBAAoB,CAAC,CAAC;YAC5D,CAAC;YAED,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;YAE9B,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,CACnC,iDAAiD,QAAQ,CAAC,EAAE,WAAW,yBAAyB,uBAAuB,CACxH,CAAC;YAEF,OAAO,eAAe,CAAC,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,aAAa,CAAC,SAAS,EAAE,2BAA2B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-slot-create.d.ts","sourceRoot":"","sources":["../../../src/tools/ppm/template-slot-create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"template-slot-create.d.ts","sourceRoot":"","sources":["../../../src/tools/ppm/template-slot-create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAMtC,eAAO,MAAM,sBAAsB,EAAE,IA2CpC,CAAC"}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { successResponse, errorResponse, API_ERROR } from '../types.js';
|
|
3
3
|
import { EPIC_TEMPLATE_SLOT_SELECT } from '../../ppm/projection.js';
|
|
4
|
+
import { persistContract, withPersistInsertRequirement } from '../../contracts/persist-contract.js';
|
|
4
5
|
export const templateSlotCreateTool = {
|
|
5
6
|
name: 'ppm_template_slot_create',
|
|
6
7
|
description: 'Create a new slot within a PPM epic template',
|
|
7
8
|
inputSchema: z.object({
|
|
8
|
-
|
|
9
|
+
template_id: z.string().describe('UUID of the parent epic template'),
|
|
9
10
|
slot_key: z.string().describe('Unique key for this slot within the template'),
|
|
10
11
|
slot_label: z.string().describe('Display label for this slot'),
|
|
11
12
|
slot_description: z.string().optional().describe('Description of what this slot represents'),
|
|
12
13
|
work_item_type: z.string().describe('Work item type created for this slot (e.g. TASK, STORY)'),
|
|
13
|
-
role_id: z.string().
|
|
14
|
+
role_id: withPersistInsertRequirement(z.string(), persistContract.fields.ppmTemplateSlotCreateRoleId).describe('UUID of the WRM role for this slot'),
|
|
14
15
|
sort_order: z.number().optional().describe('Sort order within the template (default 0)'),
|
|
15
16
|
metadata: z.record(z.unknown()).optional().describe('Optional structured metadata (JSONB)'),
|
|
16
17
|
}),
|
|
@@ -18,15 +19,14 @@ export const templateSlotCreateTool = {
|
|
|
18
19
|
const input = args;
|
|
19
20
|
try {
|
|
20
21
|
const body = {
|
|
21
|
-
|
|
22
|
+
template_id: input.template_id,
|
|
22
23
|
slot_key: input.slot_key,
|
|
23
24
|
slot_label: input.slot_label,
|
|
24
25
|
work_item_type: input.work_item_type,
|
|
26
|
+
role_id: input.role_id,
|
|
25
27
|
};
|
|
26
28
|
if (input.slot_description !== undefined)
|
|
27
29
|
body.slot_description = input.slot_description;
|
|
28
|
-
if (input.role_id !== undefined)
|
|
29
|
-
body.role_id = input.role_id;
|
|
30
30
|
if (input.sort_order !== undefined)
|
|
31
31
|
body.sort_order = input.sort_order;
|
|
32
32
|
if (input.metadata !== undefined)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-slot-create.js","sourceRoot":"","sources":["../../../src/tools/ppm/template-slot-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"template-slot-create.js","sourceRoot":"","sources":["../../../src/tools/ppm/template-slot-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAEpG,MAAM,CAAC,MAAM,sBAAsB,GAAS;IAC1C,IAAI,EAAE,0BAA0B;IAChC,WAAW,EAAE,8CAA8C;IAC3D,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QACpE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAC7E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;QAC9D,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QAC5F,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yDAAyD,CAAC;QAC9F,OAAO,EAAE,4BAA4B,CACnC,CAAC,CAAC,MAAM,EAAE,EACV,eAAe,CAAC,MAAM,CAAC,2BAA2B,CACnD,CAAC,QAAQ,CAAC,oCAAoC,CAAC;QAChD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACxF,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;KAC5F,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,IAA2B,CAAC;QAE1C,IAAI,CAAC;YACH,MAAM,IAAI,GAAwB;gBAChC,WAAW,EAAE,KAAK,CAAC,WAAW;gBAC9B,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,cAAc,EAAE,KAAK,CAAC,cAAc;gBACpC,OAAO,EAAE,KAAK,CAAC,OAAO;aACvB,CAAC;YAEF,IAAI,KAAK,CAAC,gBAAgB,KAAK,SAAS;gBAAE,IAAI,CAAC,gBAAgB,GAAG,KAAK,CAAC,gBAAgB,CAAC;YACzF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;gBAAE,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;YACvE,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS;gBAAE,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAC;YAEjE,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,IAAI,CACpC,yCAAyC,yBAAyB,EAAE,EACpE,IAAI,EACJ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,EAAE,CACjD,CAAC;YAEF,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,aAAa,CAAC,SAAS,EAAE,mCAAmC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -5,14 +5,14 @@ export const templateSlotListTool = {
|
|
|
5
5
|
name: 'ppm_template_slot_list',
|
|
6
6
|
description: 'List slots for a given PPM epic template',
|
|
7
7
|
inputSchema: z.object({
|
|
8
|
-
|
|
8
|
+
template_id: z.string().describe('UUID of the epic template'),
|
|
9
9
|
active: z.boolean().optional().describe('Filter by active flag (default true)'),
|
|
10
10
|
}),
|
|
11
11
|
handler: async (args, ctx) => {
|
|
12
12
|
const input = args;
|
|
13
13
|
try {
|
|
14
14
|
const parts = [];
|
|
15
|
-
parts.push(`
|
|
15
|
+
parts.push(`template_id=eq.${input.template_id}`);
|
|
16
16
|
const active = input.active ?? true;
|
|
17
17
|
parts.push(`active=eq.${active}`);
|
|
18
18
|
parts.push('order=sort_order.asc');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template-slot-list.js","sourceRoot":"","sources":["../../../src/tools/ppm/template-slot-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAGpE,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACxC,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EAAE,0CAA0C;IACvD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,
|
|
1
|
+
{"version":3,"file":"template-slot-list.js","sourceRoot":"","sources":["../../../src/tools/ppm/template-slot-list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AAGpE,MAAM,CAAC,MAAM,oBAAoB,GAAS;IACxC,IAAI,EAAE,wBAAwB;IAC9B,WAAW,EAAE,0CAA0C;IACvD,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC;QACpB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QAC7D,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;KAChF,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,IAGb,CAAC;QAEF,IAAI,CAAC;YACH,MAAM,KAAK,GAAa,EAAE,CAAC;YAC3B,KAAK,CAAC,IAAI,CAAC,kBAAkB,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;YAElD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,IAAI,CAAC;YACpC,KAAK,CAAC,IAAI,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC;YAElC,KAAK,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YAEnC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,SAAS,CAAC,GAAG,CACnC,yCAAyC,yBAAyB,IAAI,KAAK,EAAE,CAC9E,CAAC;YAEF,OAAO,eAAe,CAAC;gBACrB,KAAK;gBACL,KAAK,EAAE,KAAK,CAAC,MAAM;aACpB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,aAAa,CAAC,SAAS,EAAE,kCAAkC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;CACF,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-item-create.d.ts","sourceRoot":"","sources":["../../../src/tools/ppm/work-item-create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"work-item-create.d.ts","sourceRoot":"","sources":["../../../src/tools/ppm/work-item-create.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAMtC,eAAO,MAAM,kBAAkB,EAAE,IAoDhC,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { successResponse, errorResponse, API_ERROR } from '../types.js';
|
|
3
3
|
import { WORK_ITEM_SELECT } from '../../ppm/projection.js';
|
|
4
|
+
import { persistContract, withPersistInsertRequirement } from '../../contracts/persist-contract.js';
|
|
4
5
|
export const workItemCreateTool = {
|
|
5
6
|
name: 'ppm_work_item_create',
|
|
6
7
|
description: 'Create a new PPM work item',
|
|
@@ -18,7 +19,7 @@ export const workItemCreateTool = {
|
|
|
18
19
|
external_system_id: z.string().optional().describe('External system UUID (FK → ppm_external_systems)'),
|
|
19
20
|
external_item_id: z.string().optional().describe('Identifier of this item in the external system (e.g. GitLab issue number, Jira key)'),
|
|
20
21
|
confidential: z.boolean().optional().describe('Whether the item is confidential'),
|
|
21
|
-
role_id: z.string().
|
|
22
|
+
role_id: withPersistInsertRequirement(z.string(), persistContract.fields.ppmWorkItemCreateRoleId).describe('UUID of the WRM role for this work item'),
|
|
22
23
|
metadata: z.record(z.unknown()).optional().describe('Arbitrary JSON metadata object'),
|
|
23
24
|
}),
|
|
24
25
|
handler: async (args, ctx) => {
|
|
@@ -27,11 +28,12 @@ export const workItemCreateTool = {
|
|
|
27
28
|
const body = {
|
|
28
29
|
work_item_type: input.work_item_type,
|
|
29
30
|
work_item_name: input.work_item_name,
|
|
31
|
+
role_id: input.role_id,
|
|
30
32
|
};
|
|
31
33
|
const optionalFields = ['project_id',
|
|
32
34
|
'work_item_description', 'parent_work_item_id', 'milestone_id',
|
|
33
35
|
'work_item_priority', 'due_date', 'weight', 'estimated_work_minutes',
|
|
34
|
-
'external_system_id', 'external_item_id', 'confidential', '
|
|
36
|
+
'external_system_id', 'external_item_id', 'confidential', 'metadata',
|
|
35
37
|
];
|
|
36
38
|
for (const field of optionalFields) {
|
|
37
39
|
if (input[field] !== undefined)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-item-create.js","sourceRoot":"","sources":["../../../src/tools/ppm/work-item-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"work-item-create.js","sourceRoot":"","sources":["../../../src/tools/ppm/work-item-create.ts"],"names":[],"mappings":"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"}
|
|
@@ -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
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role-mapping.js","sourceRoot":"","sources":["../../src/tools/role-mapping.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"role-mapping.js","sourceRoot":"","sources":["../../src/tools/role-mapping.ts"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,MAAM,eAAe,GAA6B;IAChD,uBAAuB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC;IAC9C,cAAc,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;IAC9B,gBAAgB,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;IAClD,4BAA4B,EAAE,CAAC,KAAK,CAAC;IACrC,mBAAmB,EAAE,CAAC,KAAK,CAAC;IAC5B,qBAAqB,EAAE,CAAC,KAAK,CAAC;IAC9B,sBAAsB,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;IACtC,aAAa,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;IAC7B,eAAe,EAAE,CAAC,cAAc,CAAC;IACjC,qBAAqB,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;IACrC,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC;IAC5B,cAAc,EAAE,CAAC,cAAc,CAAC;CACjC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAoB;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,MAAM,CAAC,IAAI,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;IACH,CAAC;IAED,kFAAkF;IAClF,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACjC,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC;QACtD,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,CAAC,GAAG,OAAO,CAAC,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,SAA0B;IAE1B,OAAO,SAAS,CAAC,IAAI,CAAc,kCAAkC,EAAE,EAAE,CAAC,CAAC;AAC7E,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,SAA0B;IAE1B,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,KAAK,GAAG,MAAM;SACjB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;SACxB,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC;IACzC,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC5D,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AA6BA,eAAO,MAAM,eAAe,EAAE,MAA6B,CAAC"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { dirname, resolve } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
/**
|
|
5
|
+
* Resolve the running package version from `package.json` at load time.
|
|
6
|
+
*
|
|
7
|
+
* The MCP server previously reported a hard-coded `1.0.0`, which desynced
|
|
8
|
+
* from the value clients had installed and made version-based bug reports
|
|
9
|
+
* impossible to triage. Reading `package.json` keeps the reported version
|
|
10
|
+
* in step with the shipped artifact.
|
|
11
|
+
*
|
|
12
|
+
* `package.json` lives one directory above both `src/` (dev via tsx) and
|
|
13
|
+
* `dist/` (built), so the relative path is identical in both layouts.
|
|
14
|
+
*/
|
|
15
|
+
function readPackageVersion() {
|
|
16
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
17
|
+
const packageJsonPath = resolve(here, '..', 'package.json');
|
|
18
|
+
const parsed = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
19
|
+
if (typeof parsed.version !== 'string' || parsed.version.length === 0) {
|
|
20
|
+
throw new Error(`Unable to read package version from ${packageJsonPath}: missing "version"`);
|
|
21
|
+
}
|
|
22
|
+
return parsed.version;
|
|
23
|
+
}
|
|
24
|
+
export const PACKAGE_VERSION = readPackageVersion();
|
|
25
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC;;;;;;;;;;GAUG;AACH,SAAS,kBAAkB;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,CAAC;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,eAAe,EAAE,MAAM,CAAC,CAE9D,CAAC;IACF,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CACb,uCAAuC,eAAe,qBAAqB,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAW,kBAAkB,EAAE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@raytio/mcp-server",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "MCP server for secure AI agent access to Raytio user data",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -20,6 +20,9 @@
|
|
|
20
20
|
"start": "node dist/index.js",
|
|
21
21
|
"test": "vitest --run",
|
|
22
22
|
"test:ui": "vitest --ui",
|
|
23
|
+
"contract:check": "tsx scripts/check-persist-contract.ts",
|
|
24
|
+
"contract:sync": "tsx scripts/sync-persist-contract.ts",
|
|
25
|
+
"contract:mr": "tsx scripts/open-contract-sync-mr.ts",
|
|
23
26
|
"docs:tools": "tsx scripts/generate-tool-docs.ts",
|
|
24
27
|
"sdk:generate": "tsx scripts/generate-tool-docs.ts --emit-types",
|
|
25
28
|
"prepublishOnly": "npm run build"
|