@amplis/mcp-server 0.3.2 → 0.4.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/dist/index.js +268 -74
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -431,22 +431,22 @@ async function handleMemorySearch(query) {
|
|
|
431
431
|
return result;
|
|
432
432
|
}
|
|
433
433
|
async function handleRead5(uri) {
|
|
434
|
-
const projectContextMatch = uri.match(/^context:\/\/project\/(
|
|
434
|
+
const projectContextMatch = uri.match(/^context:\/\/project\/([^/]+)$/);
|
|
435
435
|
if (projectContextMatch) {
|
|
436
436
|
return resourceContent(uri, await handleProjectContext(projectContextMatch[1]));
|
|
437
437
|
}
|
|
438
|
-
const clientContextMatch = uri.match(/^context:\/\/client\/(
|
|
438
|
+
const clientContextMatch = uri.match(/^context:\/\/client\/([^/]+)$/);
|
|
439
439
|
if (clientContextMatch) {
|
|
440
440
|
return resourceContent(uri, await handleClientContext(clientContextMatch[1]));
|
|
441
441
|
}
|
|
442
|
-
const projectDecisionsMatch = uri.match(/^decisions:\/\/project\/(
|
|
442
|
+
const projectDecisionsMatch = uri.match(/^decisions:\/\/project\/([^/]+)$/);
|
|
443
443
|
if (projectDecisionsMatch) {
|
|
444
444
|
return resourceContent(uri, await handleProjectDecisions(projectDecisionsMatch[1]));
|
|
445
445
|
}
|
|
446
446
|
if (uri === "decisions://org") {
|
|
447
447
|
return resourceContent(uri, await handleOrgDecisions());
|
|
448
448
|
}
|
|
449
|
-
const projectMeetingsMatch = uri.match(/^meetings:\/\/project\/(
|
|
449
|
+
const projectMeetingsMatch = uri.match(/^meetings:\/\/project\/([^/]+)$/);
|
|
450
450
|
if (projectMeetingsMatch) {
|
|
451
451
|
return resourceContent(uri, await handleProjectMeetings(projectMeetingsMatch[1]));
|
|
452
452
|
}
|
|
@@ -1244,8 +1244,8 @@ var tools4 = [
|
|
|
1244
1244
|
{ name: "pipeline_move", description: "Move an opportunity to a different pipeline stage", inputSchema: { type: "object", properties: { opportunityId: { type: "string" }, stage: { type: "string", enum: ["lead", "discovery", "qualified", "proposal_draft", "proposal_submitted", "negotiation", "won", "lost"] }, notes: { type: "string" } }, required: ["opportunityId", "stage"] } }
|
|
1245
1245
|
];
|
|
1246
1246
|
async function handlePipelineMove(args) {
|
|
1247
|
-
const
|
|
1248
|
-
return await apiPatch(`/pipeline/${
|
|
1247
|
+
const { opportunityId, ...data } = PipelineMoveSchema.parse(args);
|
|
1248
|
+
return await apiPatch(`/pipeline/${encodeURIComponent(opportunityId)}/stage`, data);
|
|
1249
1249
|
}
|
|
1250
1250
|
async function handleToolCall4(name, args) {
|
|
1251
1251
|
try {
|
|
@@ -1335,8 +1335,8 @@ async function handleSiteVisitLog(args) {
|
|
|
1335
1335
|
return await apiPost("/compliance/site-visits", input);
|
|
1336
1336
|
}
|
|
1337
1337
|
async function handleComplianceUpdate(args) {
|
|
1338
|
-
const
|
|
1339
|
-
const updated = await apiPatch(`/compliance/${
|
|
1338
|
+
const { complianceId, ...data } = ComplianceUpdateSchema.parse(args);
|
|
1339
|
+
const updated = await apiPatch(`/compliance/${encodeURIComponent(complianceId)}`, data);
|
|
1340
1340
|
return { id: updated.id, name: updated.name, status: updated.status };
|
|
1341
1341
|
}
|
|
1342
1342
|
async function handleToolCall6(name, args) {
|
|
@@ -1698,8 +1698,8 @@ async function handleCredentialCreate(args) {
|
|
|
1698
1698
|
return { id: cred.id, name: cred.name, type: cred.type, status: cred.status };
|
|
1699
1699
|
}
|
|
1700
1700
|
async function handleCredentialUpdate(args) {
|
|
1701
|
-
const
|
|
1702
|
-
const updated = await apiPatch(`/credentials/${
|
|
1701
|
+
const { credentialId, ...data } = CredentialUpdateSchema.parse(args);
|
|
1702
|
+
const updated = await apiPatch(`/credentials/${encodeURIComponent(credentialId)}`, data);
|
|
1703
1703
|
return { id: updated.id, name: updated.name, status: updated.status, expiresAt: updated.expiresAt };
|
|
1704
1704
|
}
|
|
1705
1705
|
async function handleCredentialSearch(args) {
|
|
@@ -1763,13 +1763,14 @@ async function handleCapabilityAdd(args) {
|
|
|
1763
1763
|
return { id: cap.id, name: cap.name, category: cap.category, proficiency: cap.proficiency };
|
|
1764
1764
|
}
|
|
1765
1765
|
async function handleCapabilityUpdate(args) {
|
|
1766
|
-
const
|
|
1767
|
-
const updated = await apiPatch(`/capabilities/${
|
|
1766
|
+
const { capabilityId, ...data } = CapabilityUpdateSchema.parse(args);
|
|
1767
|
+
const updated = await apiPatch(`/capabilities/${encodeURIComponent(capabilityId)}`, data);
|
|
1768
1768
|
return { id: updated.id, name: updated.name, proficiency: updated.proficiency };
|
|
1769
1769
|
}
|
|
1770
1770
|
async function handleCapabilityEvidenceAdd(args) {
|
|
1771
1771
|
const input = CapabilityEvidenceAddSchema.parse(args);
|
|
1772
|
-
const
|
|
1772
|
+
const { capabilityId, ...data } = input;
|
|
1773
|
+
const evidence = await apiPost(`/capabilities/${encodeURIComponent(capabilityId)}/evidence`, data);
|
|
1773
1774
|
return evidence;
|
|
1774
1775
|
}
|
|
1775
1776
|
async function handleToolCall13(name, args) {
|
|
@@ -1894,7 +1895,7 @@ var tools15 = [
|
|
|
1894
1895
|
notes: { type: "string", description: "Notes" },
|
|
1895
1896
|
linkedInUrl: { type: "string", description: "LinkedIn URL" }
|
|
1896
1897
|
},
|
|
1897
|
-
required: ["firstName"]
|
|
1898
|
+
required: ["firstName", "lastName"]
|
|
1898
1899
|
}
|
|
1899
1900
|
}
|
|
1900
1901
|
];
|
|
@@ -1950,8 +1951,8 @@ async function handleDeliverableCreate(args) {
|
|
|
1950
1951
|
return { id: d.id, name: d.name, type: d.type, status: d.status };
|
|
1951
1952
|
}
|
|
1952
1953
|
async function handleDeliverableUpdate(args) {
|
|
1953
|
-
const
|
|
1954
|
-
const updated = await apiPatch(`/deliverables/${
|
|
1954
|
+
const { deliverableId, ...data } = DeliverableUpdateSchema.parse(args);
|
|
1955
|
+
const updated = await apiPatch(`/deliverables/${encodeURIComponent(deliverableId)}`, data);
|
|
1955
1956
|
return { id: updated.id, name: updated.name, status: updated.status, percentComplete: updated.percentComplete };
|
|
1956
1957
|
}
|
|
1957
1958
|
async function handleToolCall16(name, args) {
|
|
@@ -2033,6 +2034,182 @@ async function handleToolCall17(name, args) {
|
|
|
2033
2034
|
}
|
|
2034
2035
|
}
|
|
2035
2036
|
|
|
2037
|
+
// src/tools/asset-tools.ts
|
|
2038
|
+
var asset_tools_exports = {};
|
|
2039
|
+
__export(asset_tools_exports, {
|
|
2040
|
+
handleToolCall: () => handleToolCall18,
|
|
2041
|
+
tools: () => tools18
|
|
2042
|
+
});
|
|
2043
|
+
import { z as z19 } from "zod";
|
|
2044
|
+
var SiteListSchema = z19.object({
|
|
2045
|
+
query: z19.string().optional(),
|
|
2046
|
+
limit: z19.number().optional()
|
|
2047
|
+
});
|
|
2048
|
+
var SiteGetSchema = z19.object({
|
|
2049
|
+
siteId: z19.string()
|
|
2050
|
+
});
|
|
2051
|
+
var AssetSearchSchema = z19.object({
|
|
2052
|
+
query: z19.string().optional(),
|
|
2053
|
+
siteId: z19.string().optional(),
|
|
2054
|
+
assetClass: z19.string().optional(),
|
|
2055
|
+
assetType: z19.string().optional(),
|
|
2056
|
+
limit: z19.number().optional()
|
|
2057
|
+
});
|
|
2058
|
+
var AssetGetSchema = z19.object({
|
|
2059
|
+
assetId: z19.string()
|
|
2060
|
+
});
|
|
2061
|
+
var AssetDocSearchSchema = z19.object({
|
|
2062
|
+
query: z19.string(),
|
|
2063
|
+
assetId: z19.string().optional(),
|
|
2064
|
+
siteId: z19.string().optional(),
|
|
2065
|
+
limit: z19.number().optional()
|
|
2066
|
+
});
|
|
2067
|
+
var AssetDocListSchema = z19.object({
|
|
2068
|
+
assetId: z19.string().optional(),
|
|
2069
|
+
siteId: z19.string().optional(),
|
|
2070
|
+
limit: z19.number().optional()
|
|
2071
|
+
});
|
|
2072
|
+
var tools18 = [
|
|
2073
|
+
{
|
|
2074
|
+
name: "site_list",
|
|
2075
|
+
description: "List or search sites by name",
|
|
2076
|
+
inputSchema: {
|
|
2077
|
+
type: "object",
|
|
2078
|
+
properties: {
|
|
2079
|
+
query: { type: "string", description: "Search site names" },
|
|
2080
|
+
limit: { type: "number", description: "Max results (default 50)" }
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
},
|
|
2084
|
+
{
|
|
2085
|
+
name: "site_get",
|
|
2086
|
+
description: "Get site details including asset/area counts",
|
|
2087
|
+
inputSchema: {
|
|
2088
|
+
type: "object",
|
|
2089
|
+
properties: {
|
|
2090
|
+
siteId: { type: "string", description: "Site ID" }
|
|
2091
|
+
},
|
|
2092
|
+
required: ["siteId"]
|
|
2093
|
+
}
|
|
2094
|
+
},
|
|
2095
|
+
{
|
|
2096
|
+
name: "asset_search",
|
|
2097
|
+
description: "Search physical assets by name, tag, class, or type. Optionally scope to a site.",
|
|
2098
|
+
inputSchema: {
|
|
2099
|
+
type: "object",
|
|
2100
|
+
properties: {
|
|
2101
|
+
query: { type: "string", description: "Search asset names, tags, descriptions" },
|
|
2102
|
+
siteId: { type: "string", description: "Filter to assets at this site" },
|
|
2103
|
+
assetClass: { type: "string", description: "Filter by asset class (e.g., Rotating Equipment)" },
|
|
2104
|
+
assetType: { type: "string", description: "Filter by asset type (e.g., Pump, Motor)" },
|
|
2105
|
+
limit: { type: "number", description: "Max results (default 50)" }
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
},
|
|
2109
|
+
{
|
|
2110
|
+
name: "asset_get",
|
|
2111
|
+
description: "Get full asset details with hierarchy, failure modes, and reliability metrics",
|
|
2112
|
+
inputSchema: {
|
|
2113
|
+
type: "object",
|
|
2114
|
+
properties: {
|
|
2115
|
+
assetId: { type: "string", description: "Asset ID" }
|
|
2116
|
+
},
|
|
2117
|
+
required: ["assetId"]
|
|
2118
|
+
}
|
|
2119
|
+
},
|
|
2120
|
+
{
|
|
2121
|
+
name: "asset_documentation_search",
|
|
2122
|
+
description: "Semantic search across documents indexed for a specific asset or site",
|
|
2123
|
+
inputSchema: {
|
|
2124
|
+
type: "object",
|
|
2125
|
+
properties: {
|
|
2126
|
+
query: { type: "string", description: "Search query" },
|
|
2127
|
+
assetId: { type: "string", description: "Scope to this asset" },
|
|
2128
|
+
siteId: { type: "string", description: "Scope to this site" },
|
|
2129
|
+
limit: { type: "number", description: "Max results (default 10)" }
|
|
2130
|
+
},
|
|
2131
|
+
required: ["query"]
|
|
2132
|
+
}
|
|
2133
|
+
},
|
|
2134
|
+
{
|
|
2135
|
+
name: "asset_documentation_list",
|
|
2136
|
+
description: "List all indexed documents for an asset or site",
|
|
2137
|
+
inputSchema: {
|
|
2138
|
+
type: "object",
|
|
2139
|
+
properties: {
|
|
2140
|
+
assetId: { type: "string", description: "List docs for this asset" },
|
|
2141
|
+
siteId: { type: "string", description: "List docs for this site" },
|
|
2142
|
+
limit: { type: "number", description: "Max results (default 50)" }
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
];
|
|
2147
|
+
async function handleSiteList(args) {
|
|
2148
|
+
const input = SiteListSchema.parse(args);
|
|
2149
|
+
return apiGet("/sites", {
|
|
2150
|
+
query: input.query,
|
|
2151
|
+
limit: input.limit ?? 50
|
|
2152
|
+
});
|
|
2153
|
+
}
|
|
2154
|
+
async function handleSiteGet(args) {
|
|
2155
|
+
const input = SiteGetSchema.parse(args);
|
|
2156
|
+
return apiGet(`/sites/${encodeURIComponent(input.siteId)}`);
|
|
2157
|
+
}
|
|
2158
|
+
async function handleAssetSearch(args) {
|
|
2159
|
+
const input = AssetSearchSchema.parse(args);
|
|
2160
|
+
return apiGet("/physical-assets", {
|
|
2161
|
+
query: input.query,
|
|
2162
|
+
siteId: input.siteId,
|
|
2163
|
+
assetClass: input.assetClass,
|
|
2164
|
+
assetType: input.assetType,
|
|
2165
|
+
limit: input.limit ?? 50
|
|
2166
|
+
});
|
|
2167
|
+
}
|
|
2168
|
+
async function handleAssetGet(args) {
|
|
2169
|
+
const input = AssetGetSchema.parse(args);
|
|
2170
|
+
return apiGet(`/physical-assets/${encodeURIComponent(input.assetId)}`);
|
|
2171
|
+
}
|
|
2172
|
+
async function handleAssetDocSearch(args) {
|
|
2173
|
+
const input = AssetDocSearchSchema.parse(args);
|
|
2174
|
+
return apiGet("/physical-assets/documentation", {
|
|
2175
|
+
query: input.query,
|
|
2176
|
+
assetId: input.assetId,
|
|
2177
|
+
siteId: input.siteId,
|
|
2178
|
+
limit: input.limit ?? 10
|
|
2179
|
+
});
|
|
2180
|
+
}
|
|
2181
|
+
async function handleAssetDocList(args) {
|
|
2182
|
+
const input = AssetDocListSchema.parse(args);
|
|
2183
|
+
return apiGet("/physical-assets/documentation", {
|
|
2184
|
+
assetId: input.assetId,
|
|
2185
|
+
siteId: input.siteId,
|
|
2186
|
+
limit: input.limit ?? 50
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
async function handleToolCall18(name, args) {
|
|
2190
|
+
try {
|
|
2191
|
+
switch (name) {
|
|
2192
|
+
case "site_list":
|
|
2193
|
+
return success(await handleSiteList(args));
|
|
2194
|
+
case "site_get":
|
|
2195
|
+
return success(await handleSiteGet(args));
|
|
2196
|
+
case "asset_search":
|
|
2197
|
+
return success(await handleAssetSearch(args));
|
|
2198
|
+
case "asset_get":
|
|
2199
|
+
return success(await handleAssetGet(args));
|
|
2200
|
+
case "asset_documentation_search":
|
|
2201
|
+
return success(await handleAssetDocSearch(args));
|
|
2202
|
+
case "asset_documentation_list":
|
|
2203
|
+
return success(await handleAssetDocList(args));
|
|
2204
|
+
default:
|
|
2205
|
+
return null;
|
|
2206
|
+
}
|
|
2207
|
+
} catch (err) {
|
|
2208
|
+
console.error(`Tool ${name} failed:`, err instanceof Error ? err.message : err);
|
|
2209
|
+
return safeError(err);
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2036
2213
|
// src/tools/index.ts
|
|
2037
2214
|
var modules2 = [
|
|
2038
2215
|
task_tools_exports,
|
|
@@ -2051,10 +2228,11 @@ var modules2 = [
|
|
|
2051
2228
|
availability_tools_exports,
|
|
2052
2229
|
contact_tools_exports,
|
|
2053
2230
|
deliverable_tools_exports,
|
|
2054
|
-
memory_tools_exports
|
|
2231
|
+
memory_tools_exports,
|
|
2232
|
+
asset_tools_exports
|
|
2055
2233
|
];
|
|
2056
|
-
var
|
|
2057
|
-
async function
|
|
2234
|
+
var tools19 = modules2.flatMap((m) => [...m.tools]);
|
|
2235
|
+
async function handleToolCall19(name, args) {
|
|
2058
2236
|
try {
|
|
2059
2237
|
checkRateLimit(name);
|
|
2060
2238
|
} catch (err) {
|
|
@@ -3267,11 +3445,11 @@ async function generatePromptContent(name, args) {
|
|
|
3267
3445
|
}
|
|
3268
3446
|
|
|
3269
3447
|
// src/auth/api-key.ts
|
|
3270
|
-
import { z as
|
|
3271
|
-
var apiKeyPayloadSchema =
|
|
3272
|
-
orgId:
|
|
3273
|
-
permissions:
|
|
3274
|
-
expiresAt:
|
|
3448
|
+
import { z as z20 } from "zod";
|
|
3449
|
+
var apiKeyPayloadSchema = z20.object({
|
|
3450
|
+
orgId: z20.string(),
|
|
3451
|
+
permissions: z20.array(z20.enum(["read", "write", "admin"])),
|
|
3452
|
+
expiresAt: z20.date().optional()
|
|
3275
3453
|
});
|
|
3276
3454
|
function isValidApiKeyFormat(key) {
|
|
3277
3455
|
return /^amplis_[a-f0-9]{64}$/.test(key);
|
|
@@ -3446,8 +3624,48 @@ import open from "open";
|
|
|
3446
3624
|
var DEFAULT_API_URL2 = "https://app.amplis.com.au";
|
|
3447
3625
|
var CALLBACK_PORT = 19284;
|
|
3448
3626
|
var TIMEOUT_MS = 12e4;
|
|
3627
|
+
function escapeHtml(s) {
|
|
3628
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
3629
|
+
}
|
|
3630
|
+
function renderPage(opts) {
|
|
3631
|
+
const iconSvg = opts.success ? '<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>' : '<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="#ef4444" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>';
|
|
3632
|
+
const permissionBadges = opts.permissions ? `<div style="display:flex;gap:8px;justify-content:center;margin-top:16px">${opts.permissions.map((p) => {
|
|
3633
|
+
const colors = p === "admin" ? "background:rgba(251,191,36,0.15);color:#f59e0b" : p === "write" ? "background:rgba(74,141,255,0.15);color:#4A8DFF" : "background:rgba(52,211,153,0.15);color:#34d399";
|
|
3634
|
+
return `<span style="padding:4px 12px;border-radius:9999px;font-size:12px;font-weight:500;${colors}">${escapeHtml(p)}</span>`;
|
|
3635
|
+
}).join("")}</div>` : "";
|
|
3636
|
+
const orgLine = opts.orgName ? `<p style="font-size:15px;color:#cbd5e1;line-height:1.5">Logged in to <strong style="color:#f1f5f9">${escapeHtml(opts.orgName)}</strong></p>` : `<p style="font-size:15px;color:#cbd5e1;line-height:1.5">${escapeHtml(opts.message)}</p>`;
|
|
3637
|
+
const autoCloseScript = opts.autoClose ? `<p id="countdown" style="font-size:13px;color:#64748b;margin-top:20px">This window will close in <span id="secs">5</span>s</p>
|
|
3638
|
+
<script>let s=5;const el=document.getElementById('secs');setInterval(()=>{s--;if(el)el.textContent=String(s);if(s<=0)window.close();},1000);</script>` : "";
|
|
3639
|
+
return `<!DOCTYPE html>
|
|
3640
|
+
<html lang="en">
|
|
3641
|
+
<head>
|
|
3642
|
+
<meta charset="utf-8">
|
|
3643
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
3644
|
+
<title>AMPLIS - ${escapeHtml(opts.title)}</title>
|
|
3645
|
+
<style>
|
|
3646
|
+
*{margin:0;padding:0;box-sizing:border-box}
|
|
3647
|
+
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;min-height:100vh;display:flex;align-items:center;justify-content:center;background:#0a0e1a}
|
|
3648
|
+
.card{background:#111827;border:1px solid rgba(255,255,255,0.08);border-radius:16px;padding:48px 40px;max-width:420px;width:100%;text-align:center;box-shadow:0 25px 50px rgba(0,0,0,0.4)}
|
|
3649
|
+
.icon{margin:0 auto 24px}
|
|
3650
|
+
h1{font-size:22px;font-weight:700;color:${opts.success ? "#22c55e" : "#ef4444"};margin-bottom:12px}
|
|
3651
|
+
.hint{font-size:13px;color:#64748b;margin-top:20px}
|
|
3652
|
+
.brand{margin-top:32px;padding-top:20px;border-top:1px solid rgba(255,255,255,0.06);font-size:12px;color:#475569;letter-spacing:0.5px}
|
|
3653
|
+
</style>
|
|
3654
|
+
</head>
|
|
3655
|
+
<body>
|
|
3656
|
+
<div class="card">
|
|
3657
|
+
<div class="icon">${iconSvg}</div>
|
|
3658
|
+
<h1>${escapeHtml(opts.title)}</h1>
|
|
3659
|
+
${orgLine}
|
|
3660
|
+
${permissionBadges}
|
|
3661
|
+
${opts.success ? `<p class="hint">You can close this window and return to your terminal.</p>${autoCloseScript}` : '<p class="hint">Please close this window and try again.</p>'}
|
|
3662
|
+
<div class="brand">AMPLIS</div>
|
|
3663
|
+
</div>
|
|
3664
|
+
</body>
|
|
3665
|
+
</html>`;
|
|
3666
|
+
}
|
|
3449
3667
|
async function browserLoginCommand() {
|
|
3450
|
-
console.log("\n
|
|
3668
|
+
console.log("\n AMPLIS MCP Server - Browser Authentication\n");
|
|
3451
3669
|
const apiUrl = process.env.AMPLIS_API_URL || DEFAULT_API_URL2;
|
|
3452
3670
|
const state = crypto.randomBytes(32).toString("hex");
|
|
3453
3671
|
const callbackUrl = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
@@ -3459,40 +3677,22 @@ async function browserLoginCommand() {
|
|
|
3459
3677
|
const returnedState = url.searchParams.get("state");
|
|
3460
3678
|
const error2 = url.searchParams.get("error");
|
|
3461
3679
|
if (error2) {
|
|
3462
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
3463
|
-
res.end(
|
|
3464
|
-
<html><body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
3465
|
-
<h1 style="color: #dc2626;">\u274C Authentication Failed</h1>
|
|
3466
|
-
<p>${error2}</p>
|
|
3467
|
-
<p>You can close this window.</p>
|
|
3468
|
-
</body></html>
|
|
3469
|
-
`);
|
|
3680
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
3681
|
+
res.end(renderPage({ success: false, title: "Authentication Failed", message: error2 }));
|
|
3470
3682
|
server.close();
|
|
3471
3683
|
reject(new Error(error2));
|
|
3472
3684
|
return;
|
|
3473
3685
|
}
|
|
3474
3686
|
if (returnedState !== state) {
|
|
3475
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
3476
|
-
res.end(
|
|
3477
|
-
<html><body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
3478
|
-
<h1 style="color: #dc2626;">\u274C Invalid State</h1>
|
|
3479
|
-
<p>Security validation failed. Please try again.</p>
|
|
3480
|
-
<p>You can close this window.</p>
|
|
3481
|
-
</body></html>
|
|
3482
|
-
`);
|
|
3687
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
3688
|
+
res.end(renderPage({ success: false, title: "Invalid State", message: "Security validation failed. Please try again." }));
|
|
3483
3689
|
server.close();
|
|
3484
3690
|
reject(new Error("Invalid state parameter"));
|
|
3485
3691
|
return;
|
|
3486
3692
|
}
|
|
3487
3693
|
if (!code) {
|
|
3488
|
-
res.writeHead(400, { "Content-Type": "text/html" });
|
|
3489
|
-
res.end(
|
|
3490
|
-
<html><body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
3491
|
-
<h1 style="color: #dc2626;">\u274C Missing Code</h1>
|
|
3492
|
-
<p>No authorization code received.</p>
|
|
3493
|
-
<p>You can close this window.</p>
|
|
3494
|
-
</body></html>
|
|
3495
|
-
`);
|
|
3694
|
+
res.writeHead(400, { "Content-Type": "text/html; charset=utf-8" });
|
|
3695
|
+
res.end(renderPage({ success: false, title: "Missing Code", message: "No authorization code received." }));
|
|
3496
3696
|
server.close();
|
|
3497
3697
|
reject(new Error("Missing authorization code"));
|
|
3498
3698
|
return;
|
|
@@ -3508,26 +3708,20 @@ async function browserLoginCommand() {
|
|
|
3508
3708
|
throw new Error(errorBody.error || `HTTP ${exchangeResponse.status}`);
|
|
3509
3709
|
}
|
|
3510
3710
|
const result = await exchangeResponse.json();
|
|
3511
|
-
res.writeHead(200, { "Content-Type": "text/html" });
|
|
3512
|
-
res.end(
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3711
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
3712
|
+
res.end(renderPage({
|
|
3713
|
+
success: true,
|
|
3714
|
+
title: "Authentication Successful",
|
|
3715
|
+
orgName: result.orgName,
|
|
3716
|
+
message: "",
|
|
3717
|
+
permissions: result.permissions,
|
|
3718
|
+
autoClose: true
|
|
3719
|
+
}));
|
|
3520
3720
|
server.close();
|
|
3521
3721
|
resolve(result);
|
|
3522
3722
|
} catch (err) {
|
|
3523
|
-
res.writeHead(500, { "Content-Type": "text/html" });
|
|
3524
|
-
res.end(
|
|
3525
|
-
<html><body style="font-family: system-ui; padding: 40px; text-align: center;">
|
|
3526
|
-
<h1 style="color: #dc2626;">\u274C Exchange Failed</h1>
|
|
3527
|
-
<p>${err instanceof Error ? err.message : "Unknown error"}</p>
|
|
3528
|
-
<p>You can close this window.</p>
|
|
3529
|
-
</body></html>
|
|
3530
|
-
`);
|
|
3723
|
+
res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
|
|
3724
|
+
res.end(renderPage({ success: false, title: "Exchange Failed", message: err instanceof Error ? err.message : "Unknown error" }));
|
|
3531
3725
|
server.close();
|
|
3532
3726
|
reject(err);
|
|
3533
3727
|
}
|
|
@@ -3537,7 +3731,7 @@ async function browserLoginCommand() {
|
|
|
3537
3731
|
}
|
|
3538
3732
|
});
|
|
3539
3733
|
server.listen(CALLBACK_PORT, "127.0.0.1", () => {
|
|
3540
|
-
console.log(`
|
|
3734
|
+
console.log(` Callback server listening on port ${CALLBACK_PORT}`);
|
|
3541
3735
|
});
|
|
3542
3736
|
server.on("error", (err) => {
|
|
3543
3737
|
reject(new Error(`Failed to start callback server: ${err.message}`));
|
|
@@ -3550,7 +3744,7 @@ async function browserLoginCommand() {
|
|
|
3550
3744
|
const authUrl = new URL(`${apiUrl}/auth/mcp`);
|
|
3551
3745
|
authUrl.searchParams.set("callback", callbackUrl);
|
|
3552
3746
|
authUrl.searchParams.set("state", state);
|
|
3553
|
-
console.log(`
|
|
3747
|
+
console.log(` Opening browser to authenticate...
|
|
3554
3748
|
`);
|
|
3555
3749
|
console.log(` If the browser doesn't open, visit:`);
|
|
3556
3750
|
console.log(` ${authUrl.toString()}
|
|
@@ -3559,7 +3753,7 @@ async function browserLoginCommand() {
|
|
|
3559
3753
|
await open(authUrl.toString());
|
|
3560
3754
|
} catch {
|
|
3561
3755
|
}
|
|
3562
|
-
console.log("
|
|
3756
|
+
console.log(" Waiting for authentication...\n");
|
|
3563
3757
|
try {
|
|
3564
3758
|
const result = await authPromise;
|
|
3565
3759
|
saveCredentials({
|
|
@@ -3569,14 +3763,14 @@ async function browserLoginCommand() {
|
|
|
3569
3763
|
userId: result.userId,
|
|
3570
3764
|
permissions: result.permissions
|
|
3571
3765
|
});
|
|
3572
|
-
console.log("
|
|
3766
|
+
console.log(" Authentication successful!\n");
|
|
3573
3767
|
console.log(` Organization : ${result.orgName}`);
|
|
3574
3768
|
console.log(` Permissions : ${result.permissions.join(", ")}`);
|
|
3575
3769
|
console.log(` Key prefix : ${result.apiKey.substring(0, 16)}...`);
|
|
3576
3770
|
console.log("\n Credentials saved to ~/.amplis/credentials.json\n");
|
|
3577
3771
|
} catch (err) {
|
|
3578
3772
|
console.error(`
|
|
3579
|
-
|
|
3773
|
+
Authentication failed: ${err instanceof Error ? err.message : "Unknown error"}
|
|
3580
3774
|
`);
|
|
3581
3775
|
process.exit(1);
|
|
3582
3776
|
}
|
|
@@ -3694,7 +3888,7 @@ if (command !== "serve") {
|
|
|
3694
3888
|
const server = new Server(
|
|
3695
3889
|
{
|
|
3696
3890
|
name: "amplis-mcp-server",
|
|
3697
|
-
version: "0.
|
|
3891
|
+
version: "0.4.0"
|
|
3698
3892
|
},
|
|
3699
3893
|
{
|
|
3700
3894
|
capabilities: {
|
|
@@ -3714,10 +3908,10 @@ if (command !== "serve") {
|
|
|
3714
3908
|
return handleReadResource(request.params.uri);
|
|
3715
3909
|
});
|
|
3716
3910
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
3717
|
-
return { tools:
|
|
3911
|
+
return { tools: tools19 };
|
|
3718
3912
|
});
|
|
3719
3913
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
3720
|
-
return
|
|
3914
|
+
return handleToolCall19(request.params.name, request.params.arguments);
|
|
3721
3915
|
});
|
|
3722
3916
|
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
3723
3917
|
return { prompts };
|
package/package.json
CHANGED