@telora/mcp-products 0.21.1
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 +276 -0
- package/dist/cli/init.d.ts +2 -0
- package/dist/cli/init.js +94 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/handlers/agentHandlers.d.ts +3 -0
- package/dist/handlers/agentHandlers.js +97 -0
- package/dist/handlers/agentHandlers.js.map +1 -0
- package/dist/handlers/connectorHandlers.d.ts +3 -0
- package/dist/handlers/connectorHandlers.js +401 -0
- package/dist/handlers/connectorHandlers.js.map +1 -0
- package/dist/handlers/contextHandlers.d.ts +8 -0
- package/dist/handlers/contextHandlers.js +169 -0
- package/dist/handlers/contextHandlers.js.map +1 -0
- package/dist/handlers/deliveryHandlers.d.ts +3 -0
- package/dist/handlers/deliveryHandlers.js +122 -0
- package/dist/handlers/deliveryHandlers.js.map +1 -0
- package/dist/handlers/deploymentProfileHandlers.d.ts +3 -0
- package/dist/handlers/deploymentProfileHandlers.js +104 -0
- package/dist/handlers/deploymentProfileHandlers.js.map +1 -0
- package/dist/handlers/discoverHandler.d.ts +23 -0
- package/dist/handlers/discoverHandler.js +83 -0
- package/dist/handlers/discoverHandler.js.map +1 -0
- package/dist/handlers/factoryHandlers.d.ts +3 -0
- package/dist/handlers/factoryHandlers.js +484 -0
- package/dist/handlers/factoryHandlers.js.map +1 -0
- package/dist/handlers/ideaHandlers.d.ts +3 -0
- package/dist/handlers/ideaHandlers.js +245 -0
- package/dist/handlers/ideaHandlers.js.map +1 -0
- package/dist/handlers/index.d.ts +15 -0
- package/dist/handlers/index.js +19 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/infrastructureHandlers.d.ts +3 -0
- package/dist/handlers/infrastructureHandlers.js +335 -0
- package/dist/handlers/infrastructureHandlers.js.map +1 -0
- package/dist/handlers/issueHandlers.d.ts +3 -0
- package/dist/handlers/issueHandlers.js +94 -0
- package/dist/handlers/issueHandlers.js.map +1 -0
- package/dist/handlers/okrHandlers.d.ts +3 -0
- package/dist/handlers/okrHandlers.js +194 -0
- package/dist/handlers/okrHandlers.js.map +1 -0
- package/dist/handlers/playbookHandlers.d.ts +3 -0
- package/dist/handlers/playbookHandlers.js +93 -0
- package/dist/handlers/playbookHandlers.js.map +1 -0
- package/dist/handlers/productHandlers.d.ts +3 -0
- package/dist/handlers/productHandlers.js +129 -0
- package/dist/handlers/productHandlers.js.map +1 -0
- package/dist/handlers/reportHandlers.d.ts +3 -0
- package/dist/handlers/reportHandlers.js +59 -0
- package/dist/handlers/reportHandlers.js.map +1 -0
- package/dist/handlers/strategyHandlers.d.ts +3 -0
- package/dist/handlers/strategyHandlers.js +116 -0
- package/dist/handlers/strategyHandlers.js.map +1 -0
- package/dist/handlers/workflowHandlers.d.ts +3 -0
- package/dist/handlers/workflowHandlers.js +93 -0
- package/dist/handlers/workflowHandlers.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +284 -0
- package/dist/index.js.map +1 -0
- package/dist/shared.d.ts +77 -0
- package/dist/shared.js +147 -0
- package/dist/shared.js.map +1 -0
- package/package.json +47 -0
- package/scripts/postinstall.js +96 -0
package/dist/shared.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Shared types, credential loading, and API client used by all handler modules
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Credential loading -- env vars only
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
export function loadCredentials() {
|
|
8
|
+
// Support both new TELORA_TRACKER_ID (profile-based UUID) and legacy TELORA_ACCESS_TOKEN
|
|
9
|
+
const accessToken = process.env.TELORA_TRACKER_ID || process.env.TELORA_ACCESS_TOKEN;
|
|
10
|
+
if (!process.env.TELORA_TRACKER_ID && process.env.TELORA_ACCESS_TOKEN) {
|
|
11
|
+
console.error("[telora-products] Warning: TELORA_ACCESS_TOKEN is deprecated. Use TELORA_TRACKER_ID instead.");
|
|
12
|
+
}
|
|
13
|
+
const teloraUrl = process.env.TELORA_URL;
|
|
14
|
+
if (accessToken && teloraUrl) {
|
|
15
|
+
return { accessToken, teloraUrl };
|
|
16
|
+
}
|
|
17
|
+
throw new Error("MCP server not configured. Run: npx @telora/mcp-products init");
|
|
18
|
+
}
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// API client
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
export async function callProductApi(creds, body) {
|
|
23
|
+
const url = `${creds.teloraUrl}/functions/v1/product-api`;
|
|
24
|
+
const response = await fetch(url, {
|
|
25
|
+
method: "POST",
|
|
26
|
+
headers: {
|
|
27
|
+
Authorization: `Bearer ${creds.accessToken}`,
|
|
28
|
+
"Content-Type": "application/json",
|
|
29
|
+
},
|
|
30
|
+
body: JSON.stringify(body),
|
|
31
|
+
});
|
|
32
|
+
const data = await response.json();
|
|
33
|
+
if (!response.ok || !data.success) {
|
|
34
|
+
throw new Error(data.error || `API error (${response.status})`);
|
|
35
|
+
}
|
|
36
|
+
return data;
|
|
37
|
+
}
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Helper to build MCP tool responses
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
export function successResult(data) {
|
|
42
|
+
return {
|
|
43
|
+
content: [
|
|
44
|
+
{
|
|
45
|
+
type: "text",
|
|
46
|
+
text: typeof data === "string" ? data : JSON.stringify(data, null, 2),
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
export function errorResult(err) {
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: err.message }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
export function validationError(message) {
|
|
58
|
+
return {
|
|
59
|
+
content: [{ type: "text", text: message }],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Compact entity helper -- minimize token usage in mutation responses
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
/**
|
|
67
|
+
* Strip an entity response to only the ID + fields the caller requested.
|
|
68
|
+
* Used by create/update handlers to minimize token usage in agent responses.
|
|
69
|
+
*/
|
|
70
|
+
export function compactEntity(entity, requestedFields, returnFull) {
|
|
71
|
+
if (returnFull)
|
|
72
|
+
return entity;
|
|
73
|
+
const compact = { id: entity.id };
|
|
74
|
+
for (const key of requestedFields) {
|
|
75
|
+
if (key in entity)
|
|
76
|
+
compact[key] = entity[key];
|
|
77
|
+
}
|
|
78
|
+
return compact;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Build a fields object from params, only including defined values.
|
|
82
|
+
* Replaces the repetitive `if (x !== undefined) fields.x = x` pattern.
|
|
83
|
+
*
|
|
84
|
+
* @param params - Object with all tool parameters
|
|
85
|
+
* @param fieldNames - Names of fields to include (defaults to all params)
|
|
86
|
+
* @param required - Names of required fields to always include
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // Before:
|
|
90
|
+
* const fields: Record<string, unknown> = {};
|
|
91
|
+
* if (name !== undefined) fields.name = name;
|
|
92
|
+
* if (description !== undefined) fields.description = description;
|
|
93
|
+
* if (status !== undefined) fields.status = status;
|
|
94
|
+
*
|
|
95
|
+
* // After:
|
|
96
|
+
* const fields = buildFields(params, ['name', 'description', 'status']);
|
|
97
|
+
*/
|
|
98
|
+
export function buildFields(params, fieldNames, required) {
|
|
99
|
+
const fields = {};
|
|
100
|
+
const keys = fieldNames ?? Object.keys(params);
|
|
101
|
+
for (const key of keys) {
|
|
102
|
+
if (params[key] !== undefined) {
|
|
103
|
+
fields[key] = params[key];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Always include required fields even if undefined
|
|
107
|
+
if (required) {
|
|
108
|
+
for (const key of required) {
|
|
109
|
+
if (!(key in fields) && key in params) {
|
|
110
|
+
fields[key] = params[key];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return fields;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Wrap an async handler with standard try/catch error handling.
|
|
118
|
+
* Replaces the repetitive try { ... } catch (err) { return errorResult(err); } pattern.
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* // Before:
|
|
122
|
+
* async (params) => {
|
|
123
|
+
* try {
|
|
124
|
+
* const result = await callProductApi(getCreds(), { action: "create", ... });
|
|
125
|
+
* return successResult(result.product);
|
|
126
|
+
* } catch (err) {
|
|
127
|
+
* return errorResult(err);
|
|
128
|
+
* }
|
|
129
|
+
* }
|
|
130
|
+
*
|
|
131
|
+
* // After:
|
|
132
|
+
* wrapHandler(async (params) => {
|
|
133
|
+
* const result = await callProductApi(getCreds(), { action: "create", ... });
|
|
134
|
+
* return successResult(result.product);
|
|
135
|
+
* })
|
|
136
|
+
*/
|
|
137
|
+
export function wrapHandler(handler) {
|
|
138
|
+
return async (params) => {
|
|
139
|
+
try {
|
|
140
|
+
return await handler(params);
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
return errorResult(err);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@telora/mcp-products",
|
|
3
|
+
"version": "0.21.1",
|
|
4
|
+
"description": "MCP server exposing Telora product operations to Claude Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"telora-mcp-products": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"scripts",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"postinstall": "node scripts/postinstall.js || true",
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"start": "node dist/index.js",
|
|
19
|
+
"dev": "npx tsx src/index.ts",
|
|
20
|
+
"lint": "eslint .",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"test": "echo 'No tests implemented - MCP server is manually tested via Claude Code integration'",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"prepublishOnly": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public",
|
|
28
|
+
"registry": "https://registry.npmjs.org/"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "ssh://git@10.1.1.250:3122/syntelyos/telora.git",
|
|
37
|
+
"directory": "mcp/telora-products"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
41
|
+
"zod": "^4.3.6"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^22.13.1",
|
|
45
|
+
"typescript": "^5.7.3"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// ---------------------------------------------------------------------------
|
|
3
|
+
// postinstall: wire up Claude Code hooks if telora-ai binaries are on PATH
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// Runs after `npm install -g @telora/mcp-products`. If telora-ai-hook and
|
|
6
|
+
// telora-ai-human-hook are available, configures them in ~/.claude/settings.json.
|
|
7
|
+
// Never fails the install -- all errors are swallowed silently.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
"use strict";
|
|
11
|
+
|
|
12
|
+
const { execSync } = require("child_process");
|
|
13
|
+
const { readFileSync, writeFileSync, mkdirSync, existsSync } = require("fs");
|
|
14
|
+
const { join } = require("path");
|
|
15
|
+
const { homedir } = require("os");
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
// Resolve full paths to hook binaries (bare names may not work in Claude Code subprocesses)
|
|
19
|
+
const resolveHook = (name) => {
|
|
20
|
+
try {
|
|
21
|
+
return execSync(`which ${name}`, { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const hookPath = resolveHook("telora-ai-hook");
|
|
28
|
+
const humanHookPath = resolveHook("telora-ai-human-hook");
|
|
29
|
+
|
|
30
|
+
if (!hookPath || !humanHookPath) {
|
|
31
|
+
// telora-ai not installed -- skip silently
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Read or create ~/.claude/settings.json
|
|
36
|
+
const claudeDir = join(homedir(), ".claude");
|
|
37
|
+
const settingsPath = join(claudeDir, "settings.json");
|
|
38
|
+
|
|
39
|
+
let settings = {};
|
|
40
|
+
if (existsSync(settingsPath)) {
|
|
41
|
+
try {
|
|
42
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
43
|
+
} catch {
|
|
44
|
+
// Malformed JSON -- start fresh but preserve file
|
|
45
|
+
settings = {};
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (!settings.hooks || typeof settings.hooks !== "object") {
|
|
50
|
+
settings.hooks = {};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Ensure hook arrays exist
|
|
54
|
+
if (!Array.isArray(settings.hooks.PostToolUse)) {
|
|
55
|
+
settings.hooks.PostToolUse = [];
|
|
56
|
+
}
|
|
57
|
+
if (!Array.isArray(settings.hooks.UserPromptSubmit)) {
|
|
58
|
+
settings.hooks.UserPromptSubmit = [];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Check if a telora hook is already configured in a rules array.
|
|
62
|
+
// Each entry has { matcher, hooks: [{ type, command }] } structure.
|
|
63
|
+
// Also updates the path if the binary moved.
|
|
64
|
+
const ensureHook = (rulesArr, binaryName, fullPath) => {
|
|
65
|
+
let found = false;
|
|
66
|
+
for (const rule of rulesArr) {
|
|
67
|
+
for (const h of (rule && rule.hooks) || []) {
|
|
68
|
+
const cmd = h.command || "";
|
|
69
|
+
if (cmd.includes(binaryName)) {
|
|
70
|
+
if (cmd !== fullPath) {
|
|
71
|
+
h.command = fullPath;
|
|
72
|
+
}
|
|
73
|
+
found = true;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!found) {
|
|
78
|
+
rulesArr.push({
|
|
79
|
+
matcher: "",
|
|
80
|
+
hooks: [{ type: "command", command: fullPath }],
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
ensureHook(settings.hooks.PostToolUse, "telora-ai-hook", hookPath);
|
|
86
|
+
ensureHook(settings.hooks.UserPromptSubmit, "telora-ai-human-hook", humanHookPath);
|
|
87
|
+
|
|
88
|
+
// Write back
|
|
89
|
+
if (!existsSync(claudeDir)) {
|
|
90
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
93
|
+
} catch {
|
|
94
|
+
// Never fail the install
|
|
95
|
+
process.exit(0);
|
|
96
|
+
}
|