neotoma 0.4.2 → 0.4.3

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/server.js CHANGED
@@ -11,7 +11,7 @@ import * as yaml from "js-yaml";
11
11
  import { config } from "./config.js";
12
12
  import { queryEntitiesWithCount } from "./shared/action_handlers/entity_handlers.js";
13
13
  import { buildCliEquivalentInvocation } from "./shared/contract_mappings.js";
14
- import { getOpenApiInputSchemaOrThrow } from "./shared/openapi_schema.js";
14
+ import { buildToolDefinitions } from "./tool_definitions.js";
15
15
  import { AnalyzeSchemaCandidatesRequestSchema, CorrectEntityRequestSchema, CreateRelationshipRequestSchema, EntitySnapshotRequestSchema, FieldProvenanceRequestSchema, GetSchemaRecommendationsRequestSchema, ListEntityTypesRequestSchema, ListObservationsRequestSchema, ListRelationshipsRequestSchema, MergeEntitiesRequestSchema, DeleteEntityRequestSchema, DeleteRelationshipRequestSchema, RestoreEntityRequestSchema, RestoreRelationshipRequestSchema, RelationshipSnapshotRequestSchema, RetrieveEntitiesRequestSchema, RetrieveEntityByIdentifierSchema, RetrieveGraphNeighborhoodSchema, RetrieveRelatedEntitiesSchema, TimelineEventsRequestSchema, UpdateSchemaIncrementalRequestSchema, RegisterSchemaRequestSchema, } from "./shared/action_schemas.js";
16
16
  import { ensureLocalDevUser } from "./services/local_auth.js";
17
17
  import { extractTextFromBuffer, getPdfFirstPageImageDataUrl, getMimeTypeFromExtension, } from "./services/file_text_extraction.js";
@@ -644,749 +644,13 @@ export class NeotomaServer {
644
644
  }
645
645
  logger.info(`[MCP Server] listTools called for authenticated user: ${userId}`);
646
646
  return {
647
- tools: [
648
- {
649
- name: "retrieve_file_url",
650
- description: this.toolDescriptions.get("retrieve_file_url") ??
651
- "Retrieve a signed URL for accessing a file",
652
- inputSchema: getOpenApiInputSchemaOrThrow("retrieve_file_url"),
653
- },
654
- {
655
- name: "retrieve_entity_snapshot",
656
- description: this.toolDescriptions.get("retrieve_entity_snapshot") ??
657
- "Retrieve the current snapshot of an entity with provenance information. Supports historical snapshots via 'at' parameter.",
658
- inputSchema: getOpenApiInputSchemaOrThrow("retrieve_entity_snapshot"),
659
- },
660
- {
661
- name: "list_observations",
662
- description: this.toolDescriptions.get("list_observations") ??
663
- "List all observations for a given entity",
664
- inputSchema: getOpenApiInputSchemaOrThrow("list_observations"),
665
- },
666
- {
667
- name: "retrieve_field_provenance",
668
- description: this.toolDescriptions.get("retrieve_field_provenance") ??
669
- "Retrieve the provenance chain for a specific field in an entity snapshot",
670
- inputSchema: getOpenApiInputSchemaOrThrow("retrieve_field_provenance"),
671
- },
672
- {
673
- name: "create_relationship",
674
- description: this.toolDescriptions.get("create_relationship") ??
675
- "Create a typed relationship between two entities",
676
- inputSchema: getOpenApiInputSchemaOrThrow("create_relationship"),
677
- },
678
- {
679
- name: "list_relationships",
680
- description: this.toolDescriptions.get("list_relationships") ?? "List relationships for an entity",
681
- inputSchema: getOpenApiInputSchemaOrThrow("list_relationships"),
682
- },
683
- {
684
- name: "get_relationship_snapshot",
685
- description: this.toolDescriptions.get("get_relationship_snapshot") ??
686
- "Get the current snapshot of a specific relationship with provenance",
687
- inputSchema: {
688
- type: "object",
689
- properties: {
690
- relationship_type: {
691
- type: "string",
692
- enum: [
693
- "PART_OF",
694
- "CORRECTS",
695
- "REFERS_TO",
696
- "SETTLES",
697
- "DUPLICATE_OF",
698
- "DEPENDS_ON",
699
- "SUPERSEDES",
700
- "EMBEDS",
701
- ],
702
- description: "Type of relationship",
703
- },
704
- source_entity_id: {
705
- type: "string",
706
- description: "Source entity ID",
707
- },
708
- target_entity_id: {
709
- type: "string",
710
- description: "Target entity ID",
711
- },
712
- },
713
- required: ["relationship_type", "source_entity_id", "target_entity_id"],
714
- },
715
- },
716
- {
717
- name: "retrieve_entities",
718
- description: this.toolDescriptions.get("retrieve_entities") ??
719
- "Query entities with filters (type, pagination). Returns entities with their snapshots.",
720
- inputSchema: {
721
- type: "object",
722
- properties: {
723
- entity_type: {
724
- type: "string",
725
- description: "Optional entity type filter (for example: post, task, contact).",
726
- },
727
- search: {
728
- type: "string",
729
- description: "Canonical free-text query for lexical/semantic retrieval. Cannot be combined with published filters or non-default sorting.",
730
- },
731
- search_query: {
732
- type: "string",
733
- description: "Compatibility alias for `search`.",
734
- },
735
- query: {
736
- type: "string",
737
- description: "Compatibility alias for `search`.",
738
- },
739
- similarity_threshold: {
740
- type: "number",
741
- description: "Semantic distance threshold when `search` is used. Lower is stricter (typical 1.0-1.05).",
742
- },
743
- limit: {
744
- type: "integer",
745
- minimum: 1,
746
- description: "Maximum number of entities to return (default 100).",
747
- },
748
- offset: {
749
- type: "integer",
750
- minimum: 0,
751
- description: "Pagination offset (default 0).",
752
- },
753
- sort_by: {
754
- type: "string",
755
- enum: ["entity_id", "canonical_name", "observation_count", "last_observation_at"],
756
- description: "Sort field. Non-default values cannot be combined with `search`.",
757
- },
758
- sort_order: {
759
- type: "string",
760
- enum: ["asc", "desc"],
761
- description: "Sort direction. `desc` cannot be combined with `search`.",
762
- },
763
- published: {
764
- type: "boolean",
765
- description: "Filter by snapshot.published. Cannot be combined with `search`.",
766
- },
767
- published_after: {
768
- type: "string",
769
- description: "Inclusive lower bound for snapshot.published_date (ISO date/datetime). Cannot be combined with `search`.",
770
- },
771
- published_before: {
772
- type: "string",
773
- description: "Inclusive upper bound for snapshot.published_date (ISO date/datetime). Cannot be combined with `search`.",
774
- },
775
- include_snapshots: {
776
- type: "boolean",
777
- description: "When false, omit snapshot/provenance/raw_fragments payloads for lightweight responses.",
778
- },
779
- include_merged: {
780
- type: "boolean",
781
- description: "Whether to include merged entities (default false).",
782
- },
783
- user_id: {
784
- type: "string",
785
- description: "Optional explicit user ID (normally inferred from auth context).",
786
- },
787
- },
788
- required: [],
789
- },
790
- },
791
- {
792
- name: "list_timeline_events",
793
- description: "Query timeline events with filters (type, date range, source). Returns chronological events derived from date fields in sources.",
794
- inputSchema: getOpenApiInputSchemaOrThrow("list_timeline_events"),
795
- annotations: {
796
- readOnlyHint: true,
797
- },
798
- _meta: {
799
- ui: {
800
- resourceUri: TIMELINE_WIDGET_RESOURCE_URI,
801
- },
802
- "openai/outputTemplate": TIMELINE_WIDGET_RESOURCE_URI,
803
- },
804
- },
805
- {
806
- name: "retrieve_entity_by_identifier",
807
- description: this.toolDescriptions.get("retrieve_entity_by_identifier") ??
808
- "Retrieve entity by identifier (name, email, etc.) across entity types or specific type.",
809
- inputSchema: {
810
- type: "object",
811
- properties: {
812
- identifier: {
813
- type: "string",
814
- description: "Identifier to search for (name, email, tax_id, etc.) - will be normalized",
815
- },
816
- entity_type: {
817
- type: "string",
818
- description: "Optional: Limit search to specific entity type (e.g., 'company', 'person')",
819
- },
820
- },
821
- required: ["identifier"],
822
- },
823
- },
824
- {
825
- name: "retrieve_related_entities",
826
- description: this.toolDescriptions.get("retrieve_related_entities") ??
827
- "Retrieve entities connected to a given entity via relationships. Supports n-hop traversal.",
828
- inputSchema: {
829
- type: "object",
830
- properties: {
831
- entity_id: {
832
- type: "string",
833
- description: "Starting entity ID",
834
- },
835
- relationship_types: {
836
- type: "array",
837
- items: { type: "string" },
838
- description: "Filter by relationship types (e.g., ['PART_OF', 'REFERS_TO']). If empty, includes all types.",
839
- },
840
- direction: {
841
- type: "string",
842
- enum: ["inbound", "outbound", "both"],
843
- description: "Direction of relationships to traverse",
844
- default: "both",
845
- },
846
- max_hops: {
847
- type: "number",
848
- description: "Maximum number of relationship hops (1 = direct, 2 = 2-hop, etc.)",
849
- default: 1,
850
- },
851
- include_entities: {
852
- type: "boolean",
853
- description: "Whether to include full entity snapshots in response",
854
- default: true,
855
- },
856
- },
857
- required: ["entity_id"],
858
- },
859
- },
860
- {
861
- name: "retrieve_graph_neighborhood",
862
- description: this.toolDescriptions.get("retrieve_graph_neighborhood") ??
863
- "Retrieve complete graph neighborhood around a node (entity or source): related entities, relationships, sources, and events.",
864
- inputSchema: {
865
- type: "object",
866
- properties: {
867
- node_id: {
868
- type: "string",
869
- description: "Node ID (entity_id or source_id) to get neighborhood for",
870
- },
871
- node_type: {
872
- type: "string",
873
- enum: ["entity", "source"],
874
- description: "Type of node ('entity' for entities, 'source' for sources)",
875
- default: "entity",
876
- },
877
- include_relationships: {
878
- type: "boolean",
879
- description: "Include relationships in response",
880
- default: true,
881
- },
882
- include_sources: {
883
- type: "boolean",
884
- description: "Include related sources in response",
885
- default: true,
886
- },
887
- include_events: {
888
- type: "boolean",
889
- description: "Include timeline events in response",
890
- default: true,
891
- },
892
- include_observations: {
893
- type: "boolean",
894
- description: "Include observations (for entities only)",
895
- default: false,
896
- },
897
- },
898
- required: ["node_id"],
899
- },
900
- },
901
- {
902
- name: "store",
903
- description: this.toolDescriptions.get("store") ??
904
- "Unified storing for both file-backed and structured sources. For files: provide EITHER file_content (base64-encoded) + mime_type OR file_path. For structured data: provide entities array. File inputs are stored raw with content-addressed SHA-256 deduplication per user. Agents should parse and extract entities before storing when they need structured data from a file; the server no longer performs AI interpretation during store. IMPORTANT FOR STRUCTURED DATA: When storing structured entities with an unregistered entity_type, the system automatically infers and creates a user-specific schema from the data structure. Agents must include ALL fields from the source data, not just fields that match the entity schema. Schema fields are stored in observations (validated), while non-schema fields are automatically stored in raw_fragments.",
905
- inputSchema: (() => {
906
- const baseSchema = getOpenApiInputSchemaOrThrow("store");
907
- const baseProperties = (baseSchema.properties ?? {});
908
- return {
909
- ...baseSchema,
910
- type: "object",
911
- properties: {
912
- ...baseProperties,
913
- file_content: {
914
- type: "string",
915
- description: "Base64-encoded file content. Use file_path for local files instead of base64 encoding.",
916
- },
917
- file_path: {
918
- type: "string",
919
- description: "Local file path (alternative to file_content). If provided, file will be read from filesystem. MIME type will be auto-detected from extension if not provided. Works in local environments (Cursor, Claude Code) where MCP server has filesystem access. Does NOT work in web-based environments (claude.ai, chatgpt.com) - use file_content for those.",
920
- },
921
- mime_type: {
922
- type: "string",
923
- description: "MIME type (e.g., 'application/pdf', 'text/csv') - required with file_content, optional with file_path (auto-detected from extension)",
924
- },
925
- original_filename: {
926
- type: "string",
927
- description: "Original filename or source label (optional). For unstructured: auto-detected from file_path if not provided. For structured (entities): omit when data is agent-provided (no file origin); the source will have no filename. Pass only when mirroring a real file name or when a display label is desired.",
928
- },
929
- },
930
- };
931
- })(),
932
- },
933
- {
934
- name: "store_structured",
935
- description: this.toolDescriptions.get("store_structured") ??
936
- "Store structured entities only. Use this when you already have entity objects and do not need file ingestion.",
937
- inputSchema: getOpenApiInputSchemaOrThrow("store_structured"),
938
- },
939
- {
940
- name: "store_unstructured",
941
- description: this.toolDescriptions.get("store_unstructured") ??
942
- "Store raw files only. Provide file_content (base64) + mime_type or file_path.",
943
- inputSchema: {
944
- type: "object",
945
- properties: {
946
- idempotency_key: {
947
- type: "string",
948
- description: "Required. Client-provided idempotency key for replay-safe storing.",
949
- },
950
- file_content: {
951
- type: "string",
952
- description: "Base64-encoded file content (for unstructured storage). Use file_path for local files instead of base64 encoding.",
953
- },
954
- file_path: {
955
- type: "string",
956
- description: "Local file path (alternative to file_content). If provided, file will be read from filesystem.",
957
- },
958
- mime_type: {
959
- type: "string",
960
- description: "MIME type (e.g., 'application/pdf', 'text/csv') - required with file_content, optional with file_path",
961
- },
962
- original_filename: {
963
- type: "string",
964
- description: "Original filename (optional, auto-detected from file_path if not provided)",
965
- },
966
- },
967
- required: ["idempotency_key"],
968
- },
969
- },
970
- {
971
- name: "parse_file",
972
- description: this.toolDescriptions.get("parse_file") ??
973
- "Parse local or base64-encoded files into agent-readable text and page images without storing anything. Use for PDFs or other files you need to inspect before structured storing.",
974
- inputSchema: {
975
- type: "object",
976
- properties: {
977
- file_content: {
978
- type: "string",
979
- description: "Base64-encoded file content.",
980
- },
981
- file_path: {
982
- type: "string",
983
- description: "Local file path. Preferred in local environments.",
984
- },
985
- mime_type: {
986
- type: "string",
987
- description: "Optional MIME type. Auto-detected from file_path when omitted.",
988
- },
989
- original_filename: {
990
- type: "string",
991
- description: "Optional filename hint for MIME detection and PDF parsing.",
992
- },
993
- },
994
- required: [],
995
- },
996
- },
997
- {
998
- name: "correct",
999
- description: "Create high-priority correction observation to override AI-extracted fields. Corrections always win in snapshot computation.",
1000
- inputSchema: {
1001
- type: "object",
1002
- properties: {
1003
- user_id: {
1004
- type: "string",
1005
- description: "Optional. Inferred from authentication if omitted.",
1006
- },
1007
- entity_id: {
1008
- type: "string",
1009
- description: "Entity ID to correct",
1010
- },
1011
- entity_type: {
1012
- type: "string",
1013
- description: "Entity type",
1014
- },
1015
- field: {
1016
- type: "string",
1017
- description: "Field name to correct",
1018
- },
1019
- value: {
1020
- description: "Corrected value",
1021
- },
1022
- idempotency_key: {
1023
- type: "string",
1024
- description: "Required. Client-provided idempotency key for replay-safe corrections.",
1025
- },
1026
- },
1027
- required: ["entity_id", "entity_type", "field", "value", "idempotency_key"],
1028
- },
1029
- },
1030
- {
1031
- name: "merge_entities",
1032
- description: this.toolDescriptions.get("merge_entities") ??
1033
- "Merge duplicate entities. Rewrites observations from source entity to target entity and marks source as merged.",
1034
- inputSchema: getOpenApiInputSchemaOrThrow("merge_entities"),
1035
- },
1036
- {
1037
- name: "delete_entity",
1038
- description: this.toolDescriptions.get("delete_entity") ??
1039
- "Delete an entity. Creates a deletion observation so the entity is excluded from snapshots and queries. Immutable and reversible for audit; use for user-initiated or GDPR-style removal from active use.",
1040
- inputSchema: {
1041
- type: "object",
1042
- properties: {
1043
- entity_id: {
1044
- type: "string",
1045
- description: "Entity ID to delete",
1046
- },
1047
- entity_type: {
1048
- type: "string",
1049
- description: "Entity type (e.g. company, person)",
1050
- },
1051
- reason: {
1052
- type: "string",
1053
- description: "Optional reason for deletion (audit)",
1054
- },
1055
- user_id: {
1056
- type: "string",
1057
- description: "Optional. Inferred from authentication if omitted.",
1058
- },
1059
- },
1060
- required: ["entity_id", "entity_type"],
1061
- },
1062
- },
1063
- {
1064
- name: "delete_relationship",
1065
- description: this.toolDescriptions.get("delete_relationship") ??
1066
- "Delete a relationship. Creates a deletion observation so the relationship is excluded from snapshots and queries. Immutable and reversible for audit.",
1067
- inputSchema: {
1068
- type: "object",
1069
- properties: {
1070
- relationship_type: {
1071
- type: "string",
1072
- description: "Relationship type (e.g. PART_OF, REFERS_TO, EMBEDS)",
1073
- enum: [
1074
- "PART_OF",
1075
- "CORRECTS",
1076
- "REFERS_TO",
1077
- "SETTLES",
1078
- "DUPLICATE_OF",
1079
- "DEPENDS_ON",
1080
- "SUPERSEDES",
1081
- "EMBEDS",
1082
- ],
1083
- },
1084
- source_entity_id: {
1085
- type: "string",
1086
- description: "Source entity ID",
1087
- },
1088
- target_entity_id: {
1089
- type: "string",
1090
- description: "Target entity ID",
1091
- },
1092
- reason: {
1093
- type: "string",
1094
- description: "Optional reason for deletion (audit)",
1095
- },
1096
- user_id: {
1097
- type: "string",
1098
- description: "Optional. Inferred from authentication if omitted.",
1099
- },
1100
- },
1101
- required: ["relationship_type", "source_entity_id", "target_entity_id"],
1102
- },
1103
- },
1104
- {
1105
- name: "restore_entity",
1106
- description: this.toolDescriptions.get("restore_entity") ??
1107
- "Restore a deleted entity. Creates a restoration observation (priority 1001) that overrides the deletion. Entity becomes visible in snapshots and queries again. Immutable restoration for audit.",
1108
- inputSchema: {
1109
- type: "object",
1110
- properties: {
1111
- entity_id: {
1112
- type: "string",
1113
- description: "Entity ID to restore",
1114
- },
1115
- entity_type: {
1116
- type: "string",
1117
- description: "Entity type (e.g. company, person)",
1118
- },
1119
- reason: {
1120
- type: "string",
1121
- description: "Optional reason for restoration (audit)",
1122
- },
1123
- user_id: {
1124
- type: "string",
1125
- description: "Optional. Inferred from authentication if omitted.",
1126
- },
1127
- },
1128
- required: ["entity_id", "entity_type"],
1129
- },
1130
- },
1131
- {
1132
- name: "restore_relationship",
1133
- description: this.toolDescriptions.get("restore_relationship") ??
1134
- "Restore a deleted relationship. Creates a restoration observation (priority 1001) that overrides the deletion. Relationship becomes visible in snapshots and queries again. Immutable restoration for audit.",
1135
- inputSchema: {
1136
- type: "object",
1137
- properties: {
1138
- relationship_type: {
1139
- type: "string",
1140
- description: "Relationship type (e.g. PART_OF, REFERS_TO, EMBEDS)",
1141
- enum: [
1142
- "PART_OF",
1143
- "CORRECTS",
1144
- "REFERS_TO",
1145
- "SETTLES",
1146
- "DUPLICATE_OF",
1147
- "DEPENDS_ON",
1148
- "SUPERSEDES",
1149
- "EMBEDS",
1150
- ],
1151
- },
1152
- source_entity_id: {
1153
- type: "string",
1154
- description: "Source entity ID",
1155
- },
1156
- target_entity_id: {
1157
- type: "string",
1158
- description: "Target entity ID",
1159
- },
1160
- reason: {
1161
- type: "string",
1162
- description: "Optional reason for restoration (audit)",
1163
- },
1164
- user_id: {
1165
- type: "string",
1166
- description: "Optional. Inferred from authentication if omitted.",
1167
- },
1168
- },
1169
- required: ["relationship_type", "source_entity_id", "target_entity_id"],
1170
- },
1171
- },
1172
- {
1173
- name: "get_entity_type_counts",
1174
- description: this.toolDescriptions.get("get_entity_type_counts") ??
1175
- "Return canonical entity counts by entity_type for the authenticated user, sorted by count descending. Use this when you need row counts by type; do not infer counts from list_entity_types field_count.",
1176
- inputSchema: {
1177
- type: "object",
1178
- properties: {
1179
- user_id: {
1180
- type: "string",
1181
- description: "Optional. Inferred from authentication if omitted.",
1182
- },
1183
- },
1184
- required: [],
1185
- },
1186
- },
1187
- {
1188
- name: "list_entity_types",
1189
- description: this.toolDescriptions.get("list_entity_types") ??
1190
- "List all available entity types with their schema information. Optionally filter by keyword to find entity types relevant to your data. Uses hybrid search: keyword matching first (deterministic), then vector semantic search (semantic similarity). Use this action before storing structured data to determine the correct entity_type.",
1191
- inputSchema: getOpenApiInputSchemaOrThrow("list_entity_types"),
1192
- },
1193
- {
1194
- name: "analyze_schema_candidates",
1195
- description: this.toolDescriptions.get("analyze_schema_candidates") ??
1196
- "Analyze raw_fragments to identify fields that should be promoted to schema fields. Returns recommendations with confidence scores based on frequency and type consistency.",
1197
- inputSchema: {
1198
- type: "object",
1199
- properties: {
1200
- entity_type: {
1201
- type: "string",
1202
- description: "Entity type to analyze (optional, analyzes all if not provided)",
1203
- },
1204
- user_id: {
1205
- type: "string",
1206
- description: "User ID for user-specific analysis (optional)",
1207
- },
1208
- min_frequency: {
1209
- type: "number",
1210
- description: "Minimum frequency threshold (default: 5)",
1211
- default: 5,
1212
- },
1213
- min_confidence: {
1214
- type: "number",
1215
- description: "Minimum confidence score 0-1 (default: 0.8)",
1216
- default: 0.8,
1217
- },
1218
- },
1219
- required: [],
1220
- },
1221
- },
1222
- {
1223
- name: "get_schema_recommendations",
1224
- description: "Get schema update recommendations for an entity type from raw_fragments analysis, agent suggestions, or inference.",
1225
- inputSchema: {
1226
- type: "object",
1227
- properties: {
1228
- entity_type: {
1229
- type: "string",
1230
- description: "Entity type to get recommendations for",
1231
- },
1232
- user_id: {
1233
- type: "string",
1234
- description: "User ID for user-specific recommendations (optional)",
1235
- },
1236
- source: {
1237
- type: "string",
1238
- enum: ["raw_fragments", "agent", "inference", "all"],
1239
- description: "Recommendation source (default: all)",
1240
- },
1241
- status: {
1242
- type: "string",
1243
- enum: ["pending", "approved", "rejected"],
1244
- description: "Filter by recommendation status (default: pending)",
1245
- },
1246
- },
1247
- required: ["entity_type"],
1248
- },
1249
- },
1250
- {
1251
- name: "update_schema_incremental",
1252
- description: this.toolDescriptions.get("update_schema_incremental") ??
1253
- "Incrementally update a schema by adding or removing fields. Adding fields creates a minor version bump; removing fields creates a major version bump. Removed fields are excluded from future snapshots via schema-projection filtering, but all observation data is preserved and can be restored by re-adding the field. Optionally migrates existing raw_fragments to observations for historical data backfill.",
1254
- inputSchema: {
1255
- type: "object",
1256
- properties: {
1257
- entity_type: {
1258
- type: "string",
1259
- description: "Entity type to update",
1260
- },
1261
- fields_to_add: {
1262
- type: "array",
1263
- description: "Fields to add to schema",
1264
- items: {
1265
- type: "object",
1266
- properties: {
1267
- field_name: { type: "string" },
1268
- field_type: {
1269
- type: "string",
1270
- enum: ["string", "number", "date", "boolean", "array", "object"],
1271
- },
1272
- required: { type: "boolean", default: false },
1273
- reducer_strategy: {
1274
- type: "string",
1275
- enum: ["last_write", "highest_priority", "most_specific", "merge_array"],
1276
- },
1277
- },
1278
- required: ["field_name", "field_type"],
1279
- },
1280
- },
1281
- fields_to_remove: {
1282
- type: "array",
1283
- description: "Field names to remove from schema (triggers major version bump). Observation data is preserved; fields can be restored by re-adding them later.",
1284
- items: { type: "string" },
1285
- },
1286
- schema_version: {
1287
- type: "string",
1288
- description: "New schema version (auto-increments if not provided)",
1289
- },
1290
- user_specific: {
1291
- type: "boolean",
1292
- description: "Create user-specific schema variant (default: false)",
1293
- default: false,
1294
- },
1295
- user_id: {
1296
- type: "string",
1297
- description: "User ID for user-specific schema (required if user_specific=true)",
1298
- },
1299
- activate: {
1300
- type: "boolean",
1301
- description: "Activate schema immediately so it applies to new data (default: true). If false, schema is registered but not active.",
1302
- default: true,
1303
- },
1304
- migrate_existing: {
1305
- type: "boolean",
1306
- description: "Migrate existing raw_fragments to observations for historical data backfill (default: false). Note: New data automatically uses updated schema after activation, migration is only for old data.",
1307
- default: false,
1308
- },
1309
- },
1310
- required: ["entity_type"],
1311
- },
1312
- },
1313
- {
1314
- name: "register_schema",
1315
- description: this.toolDescriptions.get("register_schema") ??
1316
- "Register a new schema or schema version. Supports both global and user-specific schemas.",
1317
- inputSchema: {
1318
- type: "object",
1319
- properties: {
1320
- entity_type: { type: "string" },
1321
- schema_definition: {
1322
- type: "object",
1323
- description: "Schema definition with fields object",
1324
- },
1325
- reducer_config: {
1326
- type: "object",
1327
- description: "Reducer configuration with merge policies",
1328
- },
1329
- schema_version: { type: "string", default: "1.0" },
1330
- user_specific: { type: "boolean", default: false },
1331
- user_id: {
1332
- type: "string",
1333
- description: "User ID for user-specific schema (required if user_specific=true)",
1334
- },
1335
- activate: { type: "boolean", default: false },
1336
- },
1337
- required: ["entity_type", "schema_definition", "reducer_config"],
1338
- },
1339
- },
1340
- {
1341
- name: "get_authenticated_user",
1342
- description: "Get the authenticated user ID for the current MCP session. Returns the user_id that is automatically used for all authenticated actions.",
1343
- inputSchema: {
1344
- type: "object",
1345
- properties: {},
1346
- required: [],
1347
- },
1348
- },
1349
- {
1350
- name: "health_check_snapshots",
1351
- description: this.toolDescriptions.get("health_check_snapshots") ??
1352
- "Check for stale entity snapshots (snapshots with observation_count=0 but observations exist). Returns health status and count of stale snapshots.",
1353
- inputSchema: {
1354
- type: "object",
1355
- properties: {
1356
- auto_fix: {
1357
- type: "boolean",
1358
- description: "If true, automatically recompute stale snapshots (default: false)",
1359
- default: false,
1360
- },
1361
- },
1362
- required: [],
1363
- },
1364
- },
1365
- {
1366
- name: "npm_check_update",
1367
- description: this.toolDescriptions.get("npm_check_update") ??
1368
- "Check if a newer npm version is available. Returns updateAvailable, message, and suggestedCommand. Call at session start to encourage user to upgrade.",
1369
- inputSchema: {
1370
- type: "object",
1371
- properties: {
1372
- packageName: {
1373
- type: "string",
1374
- description: "npm package name (e.g. neotoma)",
1375
- },
1376
- currentVersion: {
1377
- type: "string",
1378
- description: "Current version reported by the client",
1379
- },
1380
- distTag: {
1381
- type: "string",
1382
- description: "Dist tag to check (default: latest)",
1383
- default: "latest",
1384
- },
1385
- },
1386
- required: ["packageName", "currentVersion"],
1387
- },
1388
- },
1389
- ],
647
+ tools: buildToolDefinitions(this.toolDescriptions, TIMELINE_WIDGET_RESOURCE_URI).map((def) => ({
648
+ name: def.name,
649
+ description: def.description,
650
+ inputSchema: def.inputSchema,
651
+ ...(def.annotations ? { annotations: def.annotations } : {}),
652
+ ...(def._meta ? { _meta: def._meta } : {}),
653
+ })),
1390
654
  };
1391
655
  });
1392
656
  const summarizeToolResultForLog = (toolName, result) => {