@savvly/mcp-server 1.0.0 → 1.0.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/dist/cli.js +47 -16
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -22333,17 +22333,9 @@ var AdvisorClientError = class extends Error {
|
|
|
22333
22333
|
status;
|
|
22334
22334
|
responseBody;
|
|
22335
22335
|
};
|
|
22336
|
-
var
|
|
22337
|
-
constructor() {
|
|
22338
|
-
super(
|
|
22339
|
-
"advisor_functions URL is not configured. Set ADVISOR_FUNCTIONS_URL (e.g. https://advisor-functions.example.net/api) to enable projections."
|
|
22340
|
-
);
|
|
22341
|
-
this.name = "AdvisorNotConfigured";
|
|
22342
|
-
}
|
|
22343
|
-
};
|
|
22336
|
+
var DEFAULT_ADVISOR_FUNCTIONS_URL = "https://savvly-estimator.azurewebsites.net";
|
|
22344
22337
|
function getBaseUrl() {
|
|
22345
|
-
const url = process.env.ADVISOR_FUNCTIONS_URL;
|
|
22346
|
-
if (!url) throw new AdvisorNotConfigured();
|
|
22338
|
+
const url = process.env.ADVISOR_FUNCTIONS_URL ?? DEFAULT_ADVISOR_FUNCTIONS_URL;
|
|
22347
22339
|
const trimmed = url.replace(/\/+$/, "");
|
|
22348
22340
|
return trimmed.endsWith("/api") ? trimmed : `${trimmed}/api`;
|
|
22349
22341
|
}
|
|
@@ -22529,6 +22521,17 @@ var RetirementEnvelopeSchema = external_exports.object({
|
|
|
22529
22521
|
"Per-age timeline across the planning horizon (current_age \u2192 life_expectancy). One row per year."
|
|
22530
22522
|
)
|
|
22531
22523
|
});
|
|
22524
|
+
var TopLevelDisclosureSchema = external_exports.object({
|
|
22525
|
+
required: external_exports.literal(true).describe(
|
|
22526
|
+
"Always true. Signals to the calling AI client that the `text` and `url` fields MUST be displayed to the end user whenever any number from this response is shown. Required by SEC Marketing Rule and FINRA Rule 2210."
|
|
22527
|
+
),
|
|
22528
|
+
text: external_exports.string().describe(
|
|
22529
|
+
"Short verbatim SEC disclosure text. Display this string to the user alongside any projection figures from this response. Do not paraphrase, summarize, or omit."
|
|
22530
|
+
),
|
|
22531
|
+
url: external_exports.string().describe(
|
|
22532
|
+
"Canonical full-disclosures URL. Render as a clickable link to the user alongside the `text`. Required by SEC Marketing Rule and FINRA Rule 2210."
|
|
22533
|
+
)
|
|
22534
|
+
});
|
|
22532
22535
|
var DisclaimerMetadataSchema = external_exports.object({
|
|
22533
22536
|
summary: external_exports.string().describe(
|
|
22534
22537
|
"Short illustrative-purposes disclaimer matching the text directly below the chart on estimator.savvly.com. Surface this whenever you summarize the projection to a user."
|
|
@@ -22561,7 +22564,7 @@ var ProjectionSummarySchema = external_exports.object({
|
|
|
22561
22564
|
early_exit_refund_usd: external_exports.number().nullable().describe("Convenience copy of `result.early_withdrawal_value`."),
|
|
22562
22565
|
percentage_gain_upper_percent: external_exports.number().nullable().describe("Convenience copy of `result.percentage_gain_upper`."),
|
|
22563
22566
|
narrative: external_exports.string().describe(
|
|
22564
|
-
"Human-readable English sentence summarizing the projection. Always ends with
|
|
22567
|
+
"Human-readable English sentence summarizing the projection. Always ends with 'Payouts are not guarantees. See full disclosures at <url>.' \u2014 display the URL verbatim alongside any figures."
|
|
22565
22568
|
)
|
|
22566
22569
|
});
|
|
22567
22570
|
var ProjectionResponseSchema = external_exports.object({
|
|
@@ -22572,6 +22575,9 @@ var ProjectionResponseSchema = external_exports.object({
|
|
|
22572
22575
|
summary: ProjectionSummarySchema.describe(
|
|
22573
22576
|
"Convenience summary including a human-readable narrative."
|
|
22574
22577
|
),
|
|
22578
|
+
disclosure: TopLevelDisclosureSchema.describe(
|
|
22579
|
+
"DISCLOSURE REQUIRED: display `disclosure.text` and link `disclosure.url` to the user whenever you present any number from this response. Required by SEC Marketing Rule and FINRA Rule 2210. The richer block under `metadata.disclaimer` is supplementary detail; this top-level field is the must-display."
|
|
22580
|
+
),
|
|
22575
22581
|
metadata: external_exports.object({
|
|
22576
22582
|
disclaimer: DisclaimerMetadataSchema,
|
|
22577
22583
|
field_descriptions: external_exports.record(external_exports.string()).describe(
|
|
@@ -22582,6 +22588,16 @@ var ProjectionResponseSchema = external_exports.object({
|
|
|
22582
22588
|
var RetirementResponseSchema = external_exports.object({
|
|
22583
22589
|
inputs: external_exports.record(external_exports.unknown()),
|
|
22584
22590
|
result: RetirementEnvelopeSchema,
|
|
22591
|
+
summary: external_exports.object({
|
|
22592
|
+
narrative: external_exports.string().describe(
|
|
22593
|
+
"Human-readable English sentence. Always ends with the canonical full-disclosures URL so AI clients that paraphrase past `metadata.disclaimer` still echo the disclosure link."
|
|
22594
|
+
)
|
|
22595
|
+
}).describe(
|
|
22596
|
+
"Convenience summary. The narrative carries the canonical full-disclosures URL inline; display it verbatim alongside any figures from this response."
|
|
22597
|
+
),
|
|
22598
|
+
disclosure: TopLevelDisclosureSchema.describe(
|
|
22599
|
+
"DISCLOSURE REQUIRED: display `disclosure.text` and link `disclosure.url` to the user whenever you present any number from this response. Required by SEC Marketing Rule and FINRA Rule 2210."
|
|
22600
|
+
),
|
|
22585
22601
|
metadata: external_exports.object({
|
|
22586
22602
|
disclaimer: DisclaimerMetadataSchema,
|
|
22587
22603
|
field_descriptions: external_exports.record(external_exports.string())
|
|
@@ -22719,6 +22735,14 @@ function disclaimerBlock() {
|
|
|
22719
22735
|
full_disclosures_url: PRODUCT.disclaimers.full_disclosures_url
|
|
22720
22736
|
};
|
|
22721
22737
|
}
|
|
22738
|
+
function disclosureBlock() {
|
|
22739
|
+
return {
|
|
22740
|
+
required: true,
|
|
22741
|
+
text: PRODUCT.disclaimers.projections,
|
|
22742
|
+
url: PRODUCT.disclaimers.full_disclosures_url
|
|
22743
|
+
};
|
|
22744
|
+
}
|
|
22745
|
+
var DISCLOSURE_REQUIRED_TERSE = "DISCLOSURE REQUIRED: display `disclosure.text` verbatim and link `disclosure.url` to the user alongside any figures from this response. Required by SEC Marketing Rule and FINRA Rule 2210 \u2014 do not paraphrase or omit.";
|
|
22722
22746
|
function summarizePayouts(envelope, depositType, deposited) {
|
|
22723
22747
|
const totalSavvly = envelope.total_savvly_upper ?? null;
|
|
22724
22748
|
const totalMarket = envelope.total_without_savvly_upper ?? null;
|
|
@@ -22726,7 +22750,7 @@ function summarizePayouts(envelope, depositType, deposited) {
|
|
|
22726
22750
|
const refund = envelope.early_withdrawal_value ?? null;
|
|
22727
22751
|
const pctGain = envelope.percentage_gain_upper ?? null;
|
|
22728
22752
|
const depositText = depositType === "single" ? `a single upfront deposit of ${formatUsd(deposited)}` : `monthly deposits totaling ${formatUsd(deposited)}`;
|
|
22729
|
-
const narrative = `With ${depositText}, the Savvly Longevity Benefit could pay out roughly ${formatUsd(totalSavvly)} cumulatively through age 95 \u2014 ${formatUsd(upside)} more than investing in the markets alone (${formatUsd(totalMarket)}). ` + (refund !== null ? `If the investor exits early at the chosen withdrawal age, they would get back about ${formatUsd(refund)}. ` : "") + (pctGain !== null ? `That's an illustrative ${pctGain}% return on the original investment. ` : "") +
|
|
22753
|
+
const narrative = `With ${depositText}, the Savvly Longevity Benefit could pay out roughly ${formatUsd(totalSavvly)} cumulatively through age 95 \u2014 ${formatUsd(upside)} more than investing in the markets alone (${formatUsd(totalMarket)}). ` + (refund !== null ? `If the investor exits early at the chosen withdrawal age, they would get back about ${formatUsd(refund)}. ` : "") + (pctGain !== null ? `That's an illustrative ${pctGain}% return on the original investment. ` : "") + `All Savvly figures are illustrative and presented net of Savvly's management fees (55 bps on purchased shares, 110 bps on allocated shares; typically blended in the 55-70 bps range). Payouts are not guarantees. See full disclosures at ${PRODUCT.disclaimers.full_disclosures_url}.`;
|
|
22730
22754
|
return {
|
|
22731
22755
|
deposit_type: depositType,
|
|
22732
22756
|
deposited_amount_usd: deposited,
|
|
@@ -22743,16 +22767,23 @@ function payoutPayload(inputs, result, depositType, deposited) {
|
|
|
22743
22767
|
inputs,
|
|
22744
22768
|
result,
|
|
22745
22769
|
summary: summarizePayouts(result, depositType, deposited),
|
|
22770
|
+
disclosure: disclosureBlock(),
|
|
22746
22771
|
metadata: {
|
|
22747
22772
|
disclaimer: disclaimerBlock(),
|
|
22748
22773
|
field_descriptions: PAYOUT_FIELD_DESCRIPTIONS
|
|
22749
22774
|
}
|
|
22750
22775
|
};
|
|
22751
22776
|
}
|
|
22777
|
+
function disclosureNarrative(kind) {
|
|
22778
|
+
const lead = kind === "retirement" ? "Hypothetical retirement projection \u2014 projections are based on assumed rates of return and are not guarantees of future performance." : "Hypothetical illustration of Savvly Longevity Benefit growth across the payout ages \u2014 not a guarantee of future performance.";
|
|
22779
|
+
return `${lead} See full disclosures at ${PRODUCT.disclaimers.full_disclosures_url}.`;
|
|
22780
|
+
}
|
|
22752
22781
|
function retirementPayload(inputs, result) {
|
|
22753
22782
|
return {
|
|
22754
22783
|
inputs,
|
|
22755
22784
|
result,
|
|
22785
|
+
summary: { narrative: disclosureNarrative("retirement") },
|
|
22786
|
+
disclosure: disclosureBlock(),
|
|
22756
22787
|
metadata: {
|
|
22757
22788
|
disclaimer: disclaimerBlock(),
|
|
22758
22789
|
field_descriptions: RETIREMENT_FIELD_DESCRIPTIONS
|
|
@@ -22913,7 +22944,7 @@ function searchQaLibrary(opts) {
|
|
|
22913
22944
|
function createMcpServer() {
|
|
22914
22945
|
const server = new McpServer({
|
|
22915
22946
|
name: "savvly",
|
|
22916
|
-
version: "1.0.
|
|
22947
|
+
version: "1.0.1"
|
|
22917
22948
|
});
|
|
22918
22949
|
server.resource(
|
|
22919
22950
|
"product-overview",
|
|
@@ -23026,7 +23057,7 @@ function createMcpServer() {
|
|
|
23026
23057
|
"project_savvly_lumpsum",
|
|
23027
23058
|
{
|
|
23028
23059
|
title: "Project Savvly Lump-Sum Investment",
|
|
23029
|
-
description: "Retirement projection for a lump-sum investment in Savvly's Longevity Benefit Fund. Returns payout amounts at each milestone age (80, 85, 90, 95) with WITH-Savvly vs WITHOUT-Savvly cumulative totals, per-age breakdowns, and server-provided `_lower`/`_upper` range bounds. Use `_upper` as the central illustrative estimate and `_lower` to communicate downside. Suitable for retirement income planning, annuity alternative analysis, and longevity benefit illustration. Response embeds SEC-style disclaimers and per-field interpretation hints under `metadata`.",
|
|
23060
|
+
description: "Retirement projection for a lump-sum investment in Savvly's Longevity Benefit Fund. Returns payout amounts at each milestone age (80, 85, 90, 95) with WITH-Savvly vs WITHOUT-Savvly cumulative totals, per-age breakdowns, and server-provided `_lower`/`_upper` range bounds. Use `_upper` as the central illustrative estimate and `_lower` to communicate downside. Suitable for retirement income planning, annuity alternative analysis, and longevity benefit illustration. Response embeds SEC-style disclaimers and per-field interpretation hints under `metadata`. " + DISCLOSURE_REQUIRED_TERSE,
|
|
23030
23061
|
inputSchema: {
|
|
23031
23062
|
current_age: external_exports.number().int().min(25).max(79).describe("Investor's current age"),
|
|
23032
23063
|
funding_amount: external_exports.number().min(100).describe("Lump sum investment in USD"),
|
|
@@ -23050,7 +23081,7 @@ function createMcpServer() {
|
|
|
23050
23081
|
"project_savvly_monthly",
|
|
23051
23082
|
{
|
|
23052
23083
|
title: "Project Savvly Monthly Contributions",
|
|
23053
|
-
description: "Retirement projection for monthly contributions to Savvly's Longevity Benefit Fund over a number of years. Returns payout amounts at milestone ages 80/85/90/95 with WITH-Savvly vs WITHOUT-Savvly cumulative totals, per-age breakdowns, and server-provided `_lower`/`_upper` range bounds. Use `_upper` as the central illustrative estimate and `_lower` to communicate downside. Suitable for retirement savings planning, annuity alternative comparison, and longevity benefit illustration. Supports an optional annual contribution increase and an optional early-withdrawal age. Disclaimers + per-field hints under `metadata`.",
|
|
23084
|
+
description: "Retirement projection for monthly contributions to Savvly's Longevity Benefit Fund over a number of years. Returns payout amounts at milestone ages 80/85/90/95 with WITH-Savvly vs WITHOUT-Savvly cumulative totals, per-age breakdowns, and server-provided `_lower`/`_upper` range bounds. Use `_upper` as the central illustrative estimate and `_lower` to communicate downside. Suitable for retirement savings planning, annuity alternative comparison, and longevity benefit illustration. Supports an optional annual contribution increase and an optional early-withdrawal age. Disclaimers + per-field hints under `metadata`. " + DISCLOSURE_REQUIRED_TERSE,
|
|
23054
23085
|
inputSchema: {
|
|
23055
23086
|
current_age: external_exports.number().int().min(25).max(79).describe("Investor's current age"),
|
|
23056
23087
|
monthly_amount: external_exports.number().min(10).describe("Monthly contribution in USD"),
|
|
@@ -23094,7 +23125,7 @@ function createMcpServer() {
|
|
|
23094
23125
|
"project_retirement_with_savvly",
|
|
23095
23126
|
{
|
|
23096
23127
|
title: "Project Retirement Trajectory With Savvly",
|
|
23097
|
-
description: "Full retirement simulation showing the projected savings trajectory WITH and WITHOUT a Savvly allocation across the planning horizon (current_age \u2192 life_expectancy). Returns `gap_score`, `possible_higher_monthly_paycheck`, a server-provided headline message, and a per-year `age_dependent_values[]` timeline. Disclaimers + per-field hints under `metadata`.",
|
|
23128
|
+
description: "Full retirement simulation showing the projected savings trajectory WITH and WITHOUT a Savvly allocation across the planning horizon (current_age \u2192 life_expectancy). Returns `gap_score`, `possible_higher_monthly_paycheck`, a server-provided headline message, and a per-year `age_dependent_values[]` timeline. Disclaimers + per-field hints under `metadata`. " + DISCLOSURE_REQUIRED_TERSE,
|
|
23098
23129
|
inputSchema: {
|
|
23099
23130
|
current_age: external_exports.number().int().min(25).max(79).describe("Current age"),
|
|
23100
23131
|
retirement_age: external_exports.number().int().min(50).max(80).describe("Planned retirement age"),
|