@starascendin/lifeos-mcp 0.7.52 → 0.7.54
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/build-info.d.ts +2 -2
- package/dist/build-info.js +2 -2
- package/dist/index.js +310 -1
- package/package.json +1 -1
package/dist/build-info.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.7.
|
|
2
|
-
export declare const BUILD_TIME = "2026-03-
|
|
1
|
+
export declare const VERSION = "0.7.54";
|
|
2
|
+
export declare const BUILD_TIME = "2026-03-16T18:16:47.653Z";
|
package/dist/build-info.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// AUTO-GENERATED — do not edit. Regenerated on every build.
|
|
2
|
-
export const VERSION = "0.7.
|
|
3
|
-
export const BUILD_TIME = "2026-03-
|
|
2
|
+
export const VERSION = "0.7.54";
|
|
3
|
+
export const BUILD_TIME = "2026-03-16T18:16:47.653Z";
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ import { Command } from "commander";
|
|
|
19
19
|
import { VERSION, BUILD_TIME } from "./build-info.js";
|
|
20
20
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
21
21
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
22
|
-
import { CallToolRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
22
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
23
23
|
// Parse CLI arguments
|
|
24
24
|
const program = new Command();
|
|
25
25
|
program
|
|
@@ -5879,16 +5879,325 @@ async function callConvexJsonEndpoint(path, body) {
|
|
|
5879
5879
|
}
|
|
5880
5880
|
return await response.json();
|
|
5881
5881
|
}
|
|
5882
|
+
const STATIC_RESOURCES = [
|
|
5883
|
+
{
|
|
5884
|
+
uri: "lifeos://customer-success/guide",
|
|
5885
|
+
name: "customer_success_guide",
|
|
5886
|
+
title: "Customer Success Guide",
|
|
5887
|
+
mimeType: "text/markdown",
|
|
5888
|
+
description: "How to use LifeOS customer-success resources, notes, and issue tracking together.",
|
|
5889
|
+
},
|
|
5890
|
+
];
|
|
5891
|
+
const RESOURCE_TEMPLATES = [
|
|
5892
|
+
{
|
|
5893
|
+
uriTemplate: "lifeos://client/{clientIdOrName}/workspace",
|
|
5894
|
+
name: "client_workspace",
|
|
5895
|
+
title: "Client Workspace",
|
|
5896
|
+
mimeType: "text/markdown",
|
|
5897
|
+
description: "Composite customer-success workspace for one client, including projects, open tasks, recent chats, meetings, linked people, and notes.",
|
|
5898
|
+
},
|
|
5899
|
+
{
|
|
5900
|
+
uriTemplate: "lifeos://client/{clientIdOrName}/notes",
|
|
5901
|
+
name: "client_notes",
|
|
5902
|
+
title: "Client Notes",
|
|
5903
|
+
mimeType: "text/markdown",
|
|
5904
|
+
description: "Tracked customer notes for one client, including requirements, decisions, and follow-ups.",
|
|
5905
|
+
},
|
|
5906
|
+
];
|
|
5907
|
+
function asJsonObject(value) {
|
|
5908
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
5909
|
+
? value
|
|
5910
|
+
: {};
|
|
5911
|
+
}
|
|
5912
|
+
function asJsonArray(value) {
|
|
5913
|
+
return Array.isArray(value)
|
|
5914
|
+
? value.filter((entry) => {
|
|
5915
|
+
return !!entry && typeof entry === "object" && !Array.isArray(entry);
|
|
5916
|
+
})
|
|
5917
|
+
: [];
|
|
5918
|
+
}
|
|
5919
|
+
function getString(value) {
|
|
5920
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
5921
|
+
}
|
|
5922
|
+
function getClientId(client) {
|
|
5923
|
+
return getString(client._id) || getString(client.id);
|
|
5924
|
+
}
|
|
5925
|
+
function getClientName(client) {
|
|
5926
|
+
return getString(client.name) || getString(client.title);
|
|
5927
|
+
}
|
|
5928
|
+
function slugifyName(value) {
|
|
5929
|
+
return value
|
|
5930
|
+
.toLowerCase()
|
|
5931
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
5932
|
+
.replace(/^-+|-+$/g, "")
|
|
5933
|
+
.slice(0, 80);
|
|
5934
|
+
}
|
|
5935
|
+
function getItemLabel(item) {
|
|
5936
|
+
return (getString(item.title) ||
|
|
5937
|
+
getString(item.name) ||
|
|
5938
|
+
getString(item.identifier) ||
|
|
5939
|
+
getString(item.host) ||
|
|
5940
|
+
getString(item.status) ||
|
|
5941
|
+
"Untitled");
|
|
5942
|
+
}
|
|
5943
|
+
function getItemMeta(item, keys) {
|
|
5944
|
+
const parts = keys
|
|
5945
|
+
.map((key) => getString(item[key]))
|
|
5946
|
+
.filter((value) => !!value);
|
|
5947
|
+
return parts.length > 0 ? parts.join(" | ") : undefined;
|
|
5948
|
+
}
|
|
5949
|
+
function formatListSection(heading, items, options) {
|
|
5950
|
+
const limit = options?.limit ?? 8;
|
|
5951
|
+
if (items.length === 0) {
|
|
5952
|
+
return `## ${heading}\n${options?.emptyText ?? "None"}\n`;
|
|
5953
|
+
}
|
|
5954
|
+
const rendered = items.slice(0, limit).map((item) => {
|
|
5955
|
+
const label = getItemLabel(item);
|
|
5956
|
+
const meta = options?.metaKeys ? getItemMeta(item, options.metaKeys) : undefined;
|
|
5957
|
+
return meta ? `- ${label} (${meta})` : `- ${label}`;
|
|
5958
|
+
});
|
|
5959
|
+
if (items.length > limit) {
|
|
5960
|
+
rendered.push(`- ... ${items.length - limit} more`);
|
|
5961
|
+
}
|
|
5962
|
+
return `## ${heading}\n${rendered.join("\n")}\n`;
|
|
5963
|
+
}
|
|
5964
|
+
function formatCustomerSuccessGuide() {
|
|
5965
|
+
return [
|
|
5966
|
+
"# Customer Success Resource Guide",
|
|
5967
|
+
"",
|
|
5968
|
+
"Start with the client workspace resource. It pulls the same composite context as `get_client_success_workspace` and is the fastest way to load account state.",
|
|
5969
|
+
"",
|
|
5970
|
+
"Workflow:",
|
|
5971
|
+
"- Open `lifeos://client/{clientIdOrName}/workspace` first.",
|
|
5972
|
+
"- Open `lifeos://client/{clientIdOrName}/notes` to review tracked requirements and decisions.",
|
|
5973
|
+
"- Use raw tools only when the resource snapshot is not enough: `get_beeper_thread_messages`, `get_fathom_meeting`, `get_fathom_transcript`, `get_granola_meeting`, `get_granola_transcript`.",
|
|
5974
|
+
"- Save account memory with `create_client_note` or `update_client_note`.",
|
|
5975
|
+
"- Track execution work with `create_issue` or `update_issue`.",
|
|
5976
|
+
"",
|
|
5977
|
+
"Rules:",
|
|
5978
|
+
"- Notes are for customer asks, decisions, constraints, and follow-ups.",
|
|
5979
|
+
"- Issues are for internal execution work.",
|
|
5980
|
+
"- Prefer updating existing artifacts over creating duplicates.",
|
|
5981
|
+
].join("\n");
|
|
5982
|
+
}
|
|
5983
|
+
async function getClientsList() {
|
|
5984
|
+
const response = asJsonObject(await callConvexTool("get_clients", {}));
|
|
5985
|
+
const clients = asJsonArray(response.clients);
|
|
5986
|
+
return clients
|
|
5987
|
+
.map((client) => {
|
|
5988
|
+
const id = getClientId(client);
|
|
5989
|
+
const name = getClientName(client);
|
|
5990
|
+
if (!id || !name) {
|
|
5991
|
+
return null;
|
|
5992
|
+
}
|
|
5993
|
+
return { id, name, raw: client };
|
|
5994
|
+
})
|
|
5995
|
+
.filter((client) => client !== null);
|
|
5996
|
+
}
|
|
5997
|
+
async function resolveClient(clientIdOrName) {
|
|
5998
|
+
const clients = await getClientsList();
|
|
5999
|
+
const lookup = clientIdOrName.trim().toLowerCase();
|
|
6000
|
+
const exactMatch = clients.find((client) => {
|
|
6001
|
+
return (client.id.toLowerCase() === lookup ||
|
|
6002
|
+
client.name.toLowerCase() === lookup ||
|
|
6003
|
+
slugifyName(client.name) === lookup);
|
|
6004
|
+
});
|
|
6005
|
+
if (exactMatch) {
|
|
6006
|
+
return exactMatch;
|
|
6007
|
+
}
|
|
6008
|
+
const partialMatch = clients.find((client) => client.name.toLowerCase().includes(lookup));
|
|
6009
|
+
if (partialMatch) {
|
|
6010
|
+
return partialMatch;
|
|
6011
|
+
}
|
|
6012
|
+
throw new Error(`Unknown client resource target: ${clientIdOrName}`);
|
|
6013
|
+
}
|
|
6014
|
+
function buildClientResourceUri(clientIdOrName, kind) {
|
|
6015
|
+
return `lifeos://client/${encodeURIComponent(clientIdOrName)}/${kind}`;
|
|
6016
|
+
}
|
|
6017
|
+
async function listCustomerSuccessResources() {
|
|
6018
|
+
const clients = await getClientsList();
|
|
6019
|
+
const clientResources = clients.flatMap((client) => [
|
|
6020
|
+
{
|
|
6021
|
+
uri: buildClientResourceUri(client.id, "workspace"),
|
|
6022
|
+
name: `client_workspace_${slugifyName(client.name) || client.id}`,
|
|
6023
|
+
title: `${client.name} Workspace`,
|
|
6024
|
+
mimeType: "text/markdown",
|
|
6025
|
+
description: "Composite customer-success workspace with account context, activity, and open work.",
|
|
6026
|
+
},
|
|
6027
|
+
{
|
|
6028
|
+
uri: buildClientResourceUri(client.id, "notes"),
|
|
6029
|
+
name: `client_notes_${slugifyName(client.name) || client.id}`,
|
|
6030
|
+
title: `${client.name} Notes`,
|
|
6031
|
+
mimeType: "text/markdown",
|
|
6032
|
+
description: "Tracked customer notes for requirements, decisions, and follow-ups.",
|
|
6033
|
+
},
|
|
6034
|
+
]);
|
|
6035
|
+
return [...STATIC_RESOURCES, ...clientResources];
|
|
6036
|
+
}
|
|
6037
|
+
function parseClientResourceUri(uri) {
|
|
6038
|
+
const parsed = new URL(uri);
|
|
6039
|
+
if (parsed.protocol !== "lifeos:") {
|
|
6040
|
+
return null;
|
|
6041
|
+
}
|
|
6042
|
+
if (parsed.hostname !== "client") {
|
|
6043
|
+
return null;
|
|
6044
|
+
}
|
|
6045
|
+
const parts = parsed.pathname
|
|
6046
|
+
.split("/")
|
|
6047
|
+
.filter(Boolean)
|
|
6048
|
+
.map((part) => decodeURIComponent(part));
|
|
6049
|
+
if (parts.length !== 2) {
|
|
6050
|
+
return null;
|
|
6051
|
+
}
|
|
6052
|
+
const [clientIdOrName, kind] = parts;
|
|
6053
|
+
if (kind !== "workspace" && kind !== "notes") {
|
|
6054
|
+
return null;
|
|
6055
|
+
}
|
|
6056
|
+
return { clientIdOrName, kind };
|
|
6057
|
+
}
|
|
6058
|
+
function formatWorkspaceResource(client, workspace) {
|
|
6059
|
+
const projects = asJsonArray(workspace.projects);
|
|
6060
|
+
const openTasks = asJsonArray(workspace.openTasks);
|
|
6061
|
+
const recentThreads = asJsonArray(workspace.recentThreads);
|
|
6062
|
+
const recentMeetings = asJsonArray(workspace.recentMeetings);
|
|
6063
|
+
const linkedPeople = asJsonArray(workspace.linkedPeople);
|
|
6064
|
+
const notes = asJsonArray(workspace.notes);
|
|
6065
|
+
return [
|
|
6066
|
+
`# ${client.name} Customer Success Workspace`,
|
|
6067
|
+
"",
|
|
6068
|
+
`Client ID: \`${client.id}\``,
|
|
6069
|
+
"",
|
|
6070
|
+
"## Summary",
|
|
6071
|
+
`- Projects: ${projects.length}`,
|
|
6072
|
+
`- Open tasks: ${openTasks.length}`,
|
|
6073
|
+
`- Recent threads: ${recentThreads.length}`,
|
|
6074
|
+
`- Recent meetings: ${recentMeetings.length}`,
|
|
6075
|
+
`- Linked people: ${linkedPeople.length}`,
|
|
6076
|
+
`- Notes: ${notes.length}`,
|
|
6077
|
+
"",
|
|
6078
|
+
formatListSection("Projects", projects, {
|
|
6079
|
+
emptyText: "No linked projects.",
|
|
6080
|
+
metaKeys: ["status", "health", "priority"],
|
|
6081
|
+
}).trimEnd(),
|
|
6082
|
+
"",
|
|
6083
|
+
formatListSection("Open Tasks", openTasks, {
|
|
6084
|
+
emptyText: "No open tasks.",
|
|
6085
|
+
metaKeys: ["identifier", "status", "priority", "dueDate"],
|
|
6086
|
+
}).trimEnd(),
|
|
6087
|
+
"",
|
|
6088
|
+
formatListSection("Recent Threads", recentThreads, {
|
|
6089
|
+
emptyText: "No linked chat threads.",
|
|
6090
|
+
metaKeys: ["platform", "lastMessageAt", "threadId"],
|
|
6091
|
+
}).trimEnd(),
|
|
6092
|
+
"",
|
|
6093
|
+
formatListSection("Recent Meetings", recentMeetings, {
|
|
6094
|
+
emptyText: "No linked meetings.",
|
|
6095
|
+
metaKeys: ["source", "startTime", "meetingDate"],
|
|
6096
|
+
}).trimEnd(),
|
|
6097
|
+
"",
|
|
6098
|
+
formatListSection("Linked People", linkedPeople, {
|
|
6099
|
+
emptyText: "No linked people.",
|
|
6100
|
+
metaKeys: ["relationshipType", "email", "phone"],
|
|
6101
|
+
}).trimEnd(),
|
|
6102
|
+
"",
|
|
6103
|
+
formatListSection("Tracked Notes", notes, {
|
|
6104
|
+
emptyText: "No client notes yet.",
|
|
6105
|
+
metaKeys: ["updatedAt", "createdAt"],
|
|
6106
|
+
}).trimEnd(),
|
|
6107
|
+
].join("\n");
|
|
6108
|
+
}
|
|
6109
|
+
function formatNotesResource(client, notesResponse) {
|
|
6110
|
+
const notes = asJsonArray(notesResponse.notes);
|
|
6111
|
+
if (notes.length === 0) {
|
|
6112
|
+
return [
|
|
6113
|
+
`# ${client.name} Client Notes`,
|
|
6114
|
+
"",
|
|
6115
|
+
"No client notes are currently tracked for this account.",
|
|
6116
|
+
"",
|
|
6117
|
+
"Use `create_client_note` to capture requirements, decisions, and follow-ups.",
|
|
6118
|
+
].join("\n");
|
|
6119
|
+
}
|
|
6120
|
+
const renderedNotes = notes.slice(0, 20).map((note, index) => {
|
|
6121
|
+
const title = getString(note.title) || `Untitled note ${index + 1}`;
|
|
6122
|
+
const content = getString(note.content) || "";
|
|
6123
|
+
const updatedAt = getString(note.updatedAt) || getString(note.createdAt);
|
|
6124
|
+
const meta = updatedAt ? `Updated: ${updatedAt}` : undefined;
|
|
6125
|
+
return [
|
|
6126
|
+
`## ${title}`,
|
|
6127
|
+
meta ?? "",
|
|
6128
|
+
content,
|
|
6129
|
+
]
|
|
6130
|
+
.filter(Boolean)
|
|
6131
|
+
.join("\n");
|
|
6132
|
+
});
|
|
6133
|
+
return [
|
|
6134
|
+
`# ${client.name} Client Notes`,
|
|
6135
|
+
"",
|
|
6136
|
+
`Total notes: ${notes.length}`,
|
|
6137
|
+
"",
|
|
6138
|
+
...renderedNotes,
|
|
6139
|
+
].join("\n\n");
|
|
6140
|
+
}
|
|
6141
|
+
async function readCustomerSuccessResource(uri) {
|
|
6142
|
+
if (uri === "lifeos://customer-success/guide") {
|
|
6143
|
+
return {
|
|
6144
|
+
text: formatCustomerSuccessGuide(),
|
|
6145
|
+
mimeType: "text/markdown",
|
|
6146
|
+
};
|
|
6147
|
+
}
|
|
6148
|
+
const parsed = parseClientResourceUri(uri);
|
|
6149
|
+
if (!parsed) {
|
|
6150
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
6151
|
+
}
|
|
6152
|
+
const client = await resolveClient(parsed.clientIdOrName);
|
|
6153
|
+
if (parsed.kind === "workspace") {
|
|
6154
|
+
const workspace = asJsonObject(await callConvexTool("get_client_success_workspace", {
|
|
6155
|
+
clientIdOrName: client.id,
|
|
6156
|
+
}));
|
|
6157
|
+
return {
|
|
6158
|
+
text: formatWorkspaceResource(client, workspace),
|
|
6159
|
+
mimeType: "text/markdown",
|
|
6160
|
+
};
|
|
6161
|
+
}
|
|
6162
|
+
const notesResponse = asJsonObject(await callConvexTool("get_client_notes", {
|
|
6163
|
+
clientId: client.id,
|
|
6164
|
+
limit: 50,
|
|
6165
|
+
}));
|
|
6166
|
+
return {
|
|
6167
|
+
text: formatNotesResource(client, notesResponse),
|
|
6168
|
+
mimeType: "text/markdown",
|
|
6169
|
+
};
|
|
6170
|
+
}
|
|
5882
6171
|
// Create the MCP server
|
|
5883
6172
|
const server = new Server({
|
|
5884
6173
|
name: "lifeos-pm",
|
|
5885
6174
|
version: VERSION,
|
|
5886
6175
|
}, {
|
|
5887
6176
|
capabilities: {
|
|
6177
|
+
resources: {},
|
|
5888
6178
|
tools: {},
|
|
5889
6179
|
prompts: {},
|
|
5890
6180
|
},
|
|
5891
6181
|
});
|
|
6182
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
6183
|
+
return { resources: await listCustomerSuccessResources() };
|
|
6184
|
+
});
|
|
6185
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => {
|
|
6186
|
+
return { resourceTemplates: RESOURCE_TEMPLATES };
|
|
6187
|
+
});
|
|
6188
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
6189
|
+
const { uri } = request.params;
|
|
6190
|
+
const resource = await readCustomerSuccessResource(uri);
|
|
6191
|
+
return {
|
|
6192
|
+
contents: [
|
|
6193
|
+
{
|
|
6194
|
+
uri,
|
|
6195
|
+
mimeType: resource.mimeType,
|
|
6196
|
+
text: resource.text,
|
|
6197
|
+
},
|
|
6198
|
+
],
|
|
6199
|
+
};
|
|
6200
|
+
});
|
|
5892
6201
|
// Handle list tools request
|
|
5893
6202
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
5894
6203
|
return { tools: TOOLS };
|
package/package.json
CHANGED