#
tokens: 14879/50000 7/7 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── build
│   └── index.js
├── Dockerfile
├── LICENSE
├── main.py
├── node_modules
│   ├── @google
│   │   └── generative-ai
│   │       ├── dist
│   │       │   ├── generative-ai.d.ts
│   │       │   ├── index.js
│   │       │   ├── index.js.map
│   │       │   ├── index.mjs
│   │       │   ├── index.mjs.map
│   │       │   ├── scripts
│   │       │   │   ├── check-format.d.ts
│   │       │   │   ├── format-patterns.d.ts
│   │       │   │   ├── license.d.ts
│   │       │   │   └── run-format.d.ts
│   │       │   ├── server
│   │       │   │   ├── index.js
│   │       │   │   ├── index.js.map
│   │       │   │   ├── index.mjs
│   │       │   │   ├── index.mjs.map
│   │       │   │   ├── scripts
│   │       │   │   │   ├── check-format.d.ts
│   │       │   │   │   ├── format-patterns.d.ts
│   │       │   │   │   ├── license.d.ts
│   │       │   │   │   └── run-format.d.ts
│   │       │   │   ├── server.d.ts
│   │       │   │   ├── src
│   │       │   │   │   ├── errors.d.ts
│   │       │   │   │   ├── gen-ai.d.ts
│   │       │   │   │   ├── index.d.ts
│   │       │   │   │   ├── methods
│   │       │   │   │   │   ├── chat-session-helpers.d.ts
│   │       │   │   │   │   ├── chat-session.d.ts
│   │       │   │   │   │   ├── count-tokens.d.ts
│   │       │   │   │   │   ├── embed-content.d.ts
│   │       │   │   │   │   └── generate-content.d.ts
│   │       │   │   │   ├── models
│   │       │   │   │   │   └── generative-model.d.ts
│   │       │   │   │   ├── requests
│   │       │   │   │   │   ├── request-helpers.d.ts
│   │       │   │   │   │   ├── request.d.ts
│   │       │   │   │   │   ├── response-helpers.d.ts
│   │       │   │   │   │   └── stream-reader.d.ts
│   │       │   │   │   └── server
│   │       │   │   │       ├── cache-manager.d.ts
│   │       │   │   │       ├── constants.d.ts
│   │       │   │   │       ├── file-manager.d.ts
│   │       │   │   │       ├── index.d.ts
│   │       │   │   │       └── request.d.ts
│   │       │   │   └── types
│   │       │   │       ├── content.d.ts
│   │       │   │       ├── enums.d.ts
│   │       │   │       ├── function-calling.d.ts
│   │       │   │       ├── index.d.ts
│   │       │   │       ├── requests.d.ts
│   │       │   │       ├── responses.d.ts
│   │       │   │       ├── search-grounding.d.ts
│   │       │   │       └── server
│   │       │   │           ├── caching.d.ts
│   │       │   │           ├── files.d.ts
│   │       │   │           ├── index.d.ts
│   │       │   │           └── shared.d.ts
│   │       │   ├── src
│   │       │   │   ├── errors.d.ts
│   │       │   │   ├── gen-ai.d.ts
│   │       │   │   ├── index.d.ts
│   │       │   │   ├── methods
│   │       │   │   │   ├── chat-session-helpers.d.ts
│   │       │   │   │   ├── chat-session.d.ts
│   │       │   │   │   ├── count-tokens.d.ts
│   │       │   │   │   ├── embed-content.d.ts
│   │       │   │   │   └── generate-content.d.ts
│   │       │   │   ├── models
│   │       │   │   │   └── generative-model.d.ts
│   │       │   │   ├── requests
│   │       │   │   │   ├── request-helpers.d.ts
│   │       │   │   │   ├── request.d.ts
│   │       │   │   │   ├── response-helpers.d.ts
│   │       │   │   │   └── stream-reader.d.ts
│   │       │   │   └── server
│   │       │   │       ├── cache-manager.d.ts
│   │       │   │       ├── constants.d.ts
│   │       │   │       ├── file-manager.d.ts
│   │       │   │       ├── index.d.ts
│   │       │   │       └── request.d.ts
│   │       │   ├── tsdoc-metadata.json
│   │       │   └── types
│   │       │       ├── content.d.ts
│   │       │       ├── enums.d.ts
│   │       │       ├── function-calling.d.ts
│   │       │       ├── index.d.ts
│   │       │       ├── requests.d.ts
│   │       │       ├── responses.d.ts
│   │       │       ├── search-grounding.d.ts
│   │       │       └── server
│   │       │           ├── caching.d.ts
│   │       │           ├── files.d.ts
│   │       │           ├── index.d.ts
│   │       │           └── shared.d.ts
│   │       ├── LICENSE
│   │       ├── package.json
│   │       ├── README.md
│   │       └── server
│   │           └── package.json
│   ├── @modelcontextprotocol
│   │   └── sdk
│   │       ├── 1
│   │       ├── dist
│   │       │   ├── 1
│   │       │   ├── cjs
│   │       │   │   ├── 1
│   │       │   │   ├── cli.d.ts
│   │       │   │   ├── cli.d.ts.map
│   │       │   │   ├── cli.js
│   │       │   │   ├── cli.js.map
│   │       │   │   ├── client
│   │       │   │   │   ├── auth.d.ts
│   │       │   │   │   ├── auth.d.ts.map
│   │       │   │   │   ├── auth.js
│   │       │   │   │   ├── auth.js.map
│   │       │   │   │   ├── index.d.ts
│   │       │   │   │   ├── index.d.ts.map
│   │       │   │   │   ├── index.js
│   │       │   │   │   ├── index.js.map
│   │       │   │   │   ├── sse.d.ts
│   │       │   │   │   ├── sse.d.ts.map
│   │       │   │   │   ├── sse.js
│   │       │   │   │   ├── sse.js.map
│   │       │   │   │   ├── stdio.d.ts
│   │       │   │   │   ├── stdio.d.ts.map
│   │       │   │   │   ├── stdio.js
│   │       │   │   │   ├── stdio.js.map
│   │       │   │   │   ├── websocket.d.ts
│   │       │   │   │   ├── websocket.d.ts.map
│   │       │   │   │   ├── websocket.js
│   │       │   │   │   └── websocket.js.map
│   │       │   │   ├── inMemory.d.ts
│   │       │   │   ├── inMemory.d.ts.map
│   │       │   │   ├── inMemory.js
│   │       │   │   ├── inMemory.js.map
│   │       │   │   ├── package.json
│   │       │   │   ├── server
│   │       │   │   │   └── auth
│   │       │   │   │       ├── clients.d.ts
│   │       │   │   │       ├── clients.d.ts.map
│   │       │   │   │       ├── clients.js
│   │       │   │   │       ├── clients.js.map
│   │       │   │   │       ├── errors.d.ts
│   │       │   │   │       ├── errors.d.ts.map
│   │       │   │   │       ├── errors.js
│   │       │   │   │       ├── errors.js.map
│   │       │   │   │       ├── handlers
│   │       │   │   │       │   ├── authorize.d.ts
│   │       │   │   │       │   ├── authorize.d.ts.map
│   │       │   │   │       │   ├── authorize.js
│   │       │   │   │       │   ├── authorize.js.map
│   │       │   │   │       │   ├── metadata.d.ts
│   │       │   │   │       │   ├── metadata.d.ts.map
│   │       │   │   │       │   ├── metadata.js
│   │       │   │   │       │   ├── metadata.js.map
│   │       │   │   │       │   ├── register.d.ts
│   │       │   │   │       │   ├── register.d.ts.map
│   │       │   │   │       │   ├── register.js
│   │       │   │   │       │   ├── register.js.map
│   │       │   │   │       │   ├── revoke.d.ts
│   │       │   │   │       │   ├── revoke.d.ts.map
│   │       │   │   │       │   ├── revoke.js
│   │       │   │   │       │   ├── revoke.js.map
│   │       │   │   │       │   ├── token.d.ts
│   │       │   │   │       │   ├── token.d.ts.map
│   │       │   │   │       │   ├── token.js
│   │       │   │   │       │   └── token.js.map
│   │       │   │   │       ├── middleware
│   │       │   │   │       │   ├── allowedMethods.d.ts
│   │       │   │   │       │   ├── allowedMethods.d.ts.map
│   │       │   │   │       │   ├── allowedMethods.js
│   │       │   │   │       │   ├── allowedMethods.js.map
│   │       │   │   │       │   ├── bearerAuth.d.ts
│   │       │   │   │       │   ├── bearerAuth.d.ts.map
│   │       │   │   │       │   ├── bearerAuth.js
│   │       │   │   │       │   ├── bearerAuth.js.map
│   │       │   │   │       │   ├── clientAuth.d.ts
│   │       │   │   │       │   ├── clientAuth.d.ts.map
│   │       │   │   │       │   ├── clientAuth.js
│   │       │   │   │       │   └── clientAuth.js.map
│   │       │   │   │       ├── provider.d.ts
│   │       │   │   │       ├── provider.d.ts.map
│   │       │   │   │       ├── provider.js
│   │       │   │   │       ├── provider.js.map
│   │       │   │   │       ├── providers
│   │       │   │   │       │   ├── proxyProvider.d.ts
│   │       │   │   │       │   ├── proxyProvider.d.ts.map
│   │       │   │   │       │   └── proxyProvider.js
│   │       │   │   │       ├── router.d.ts
│   │       │   │   │       ├── router.d.ts.map
│   │       │   │   │       ├── router.js
│   │       │   │   │       ├── router.js.map
│   │       │   │   │       ├── types.d.ts
│   │       │   │   │       ├── types.d.ts.map
│   │       │   │   │       ├── types.js
│   │       │   │   │       └── types.js.map
│   │       │   │   ├── shared
│   │       │   │   │   ├── auth.d.ts
│   │       │   │   │   ├── auth.d.ts.map
│   │       │   │   │   ├── auth.js
│   │       │   │   │   ├── auth.js.map
│   │       │   │   │   ├── protocol.d.ts
│   │       │   │   │   ├── protocol.d.ts.map
│   │       │   │   │   ├── protocol.js
│   │       │   │   │   ├── protocol.js.map
│   │       │   │   │   ├── stdio.d.ts
│   │       │   │   │   ├── stdio.d.ts.map
│   │       │   │   │   ├── stdio.js
│   │       │   │   │   ├── stdio.js.map
│   │       │   │   │   ├── transport.d.ts
│   │       │   │   │   ├── transport.d.ts.map
│   │       │   │   │   ├── transport.js
│   │       │   │   │   ├── transport.js.map
│   │       │   │   │   ├── uriTemplate.d.ts
│   │       │   │   │   ├── uriTemplate.d.ts.map
│   │       │   │   │   ├── uriTemplate.js
│   │       │   │   │   └── uriTemplate.js.map
│   │       │   │   ├── types.d.ts
│   │       │   │   ├── types.d.ts.map
│   │       │   │   ├── types.js
│   │       │   │   └── types.js.map
│   │       │   └── esm
│   │       │       ├── 1
│   │       │       ├── cli.d.ts
│   │       │       ├── cli.d.ts.map
│   │       │       ├── cli.js
│   │       │       ├── cli.js.map
│   │       │       ├── client
│   │       │       │   ├── auth.d.ts
│   │       │       │   ├── auth.d.ts.map
│   │       │       │   ├── auth.js
│   │       │       │   ├── auth.js.map
│   │       │       │   ├── index.d.ts
│   │       │       │   ├── index.d.ts.map
│   │       │       │   ├── index.js
│   │       │       │   ├── index.js.map
│   │       │       │   ├── sse.d.ts
│   │       │       │   ├── sse.d.ts.map
│   │       │       │   ├── sse.js
│   │       │       │   ├── sse.js.map
│   │       │       │   ├── stdio.d.ts
│   │       │       │   ├── stdio.d.ts.map
│   │       │       │   ├── stdio.js
│   │       │       │   ├── stdio.js.map
│   │       │       │   ├── websocket.d.ts
│   │       │       │   ├── websocket.d.ts.map
│   │       │       │   ├── websocket.js
│   │       │       │   └── websocket.js.map
│   │       │       ├── inMemory.d.ts
│   │       │       ├── inMemory.d.ts.map
│   │       │       ├── inMemory.js
│   │       │       ├── inMemory.js.map
│   │       │       ├── package.json
│   │       │       ├── server
│   │       │       │   ├── auth
│   │       │       │   │   ├── clients.d.ts
│   │       │       │   │   ├── clients.d.ts.map
│   │       │       │   │   ├── clients.js
│   │       │       │   │   ├── clients.js.map
│   │       │       │   │   ├── errors.d.ts
│   │       │       │   │   ├── errors.d.ts.map
│   │       │       │   │   ├── errors.js
│   │       │       │   │   ├── errors.js.map
│   │       │       │   │   ├── handlers
│   │       │       │   │   │   ├── authorize.d.ts
│   │       │       │   │   │   ├── authorize.d.ts.map
│   │       │       │   │   │   ├── authorize.js
│   │       │       │   │   │   ├── authorize.js.map
│   │       │       │   │   │   ├── metadata.d.ts
│   │       │       │   │   │   ├── metadata.d.ts.map
│   │       │       │   │   │   ├── metadata.js
│   │       │       │   │   │   ├── metadata.js.map
│   │       │       │   │   │   ├── register.d.ts
│   │       │       │   │   │   ├── register.d.ts.map
│   │       │       │   │   │   ├── register.js
│   │       │       │   │   │   ├── register.js.map
│   │       │       │   │   │   ├── revoke.d.ts
│   │       │       │   │   │   ├── revoke.d.ts.map
│   │       │       │   │   │   ├── revoke.js
│   │       │       │   │   │   ├── revoke.js.map
│   │       │       │   │   │   ├── token.d.ts
│   │       │       │   │   │   ├── token.d.ts.map
│   │       │       │   │   │   ├── token.js
│   │       │       │   │   │   └── token.js.map
│   │       │       │   │   ├── middleware
│   │       │       │   │   │   ├── allowedMethods.d.ts
│   │       │       │   │   │   ├── allowedMethods.d.ts.map
│   │       │       │   │   │   ├── allowedMethods.js
│   │       │       │   │   │   ├── allowedMethods.js.map
│   │       │       │   │   │   ├── bearerAuth.d.ts
│   │       │       │   │   │   ├── bearerAuth.d.ts.map
│   │       │       │   │   │   ├── bearerAuth.js
│   │       │       │   │   │   ├── bearerAuth.js.map
│   │       │       │   │   │   ├── clientAuth.d.ts
│   │       │       │   │   │   ├── clientAuth.d.ts.map
│   │       │       │   │   │   ├── clientAuth.js
│   │       │       │   │   │   └── clientAuth.js.map
│   │       │       │   │   ├── provider.d.ts
│   │       │       │   │   ├── provider.d.ts.map
│   │       │       │   │   ├── provider.js
│   │       │       │   │   ├── provider.js.map
│   │       │       │   │   └── providers
│   │       │       │   │       ├── proxyProvider.d.ts
│   │       │       │   │       ├── proxyProvider.d.ts.map
│   │       │       │   │       └── proxyProvider.js
│   │       │       │   ├── completable.d.ts
│   │       │       │   ├── completable.d.ts.map
│   │       │       │   ├── completable.js
│   │       │       │   ├── completable.js.map
│   │       │       │   ├── index.d.ts
│   │       │       │   ├── index.d.ts.map
│   │       │       │   ├── index.js
│   │       │       │   ├── index.js.map
│   │       │       │   ├── mcp.d.ts
│   │       │       │   ├── mcp.d.ts.map
│   │       │       │   ├── mcp.js
│   │       │       │   ├── mcp.js.map
│   │       │       │   ├── sse.d.ts
│   │       │       │   ├── sse.d.ts.map
│   │       │       │   ├── sse.js
│   │       │       │   ├── sse.js.map
│   │       │       │   ├── stdio.d.ts
│   │       │       │   ├── stdio.d.ts.map
│   │       │       │   ├── stdio.js
│   │       │       │   └── stdio.js.map
│   │       │       ├── shared
│   │       │       │   ├── auth.d.ts
│   │       │       │   ├── auth.d.ts.map
│   │       │       │   ├── auth.js
│   │       │       │   ├── auth.js.map
│   │       │       │   ├── protocol.d.ts
│   │       │       │   ├── protocol.d.ts.map
│   │       │       │   ├── protocol.js
│   │       │       │   ├── protocol.js.map
│   │       │       │   ├── stdio.d.ts
│   │       │       │   ├── stdio.d.ts.map
│   │       │       │   ├── stdio.js
│   │       │       │   ├── stdio.js.map
│   │       │       │   ├── transport.d.ts
│   │       │       │   ├── transport.d.ts.map
│   │       │       │   ├── transport.js
│   │       │       │   ├── transport.js.map
│   │       │       │   ├── uriTemplate.d.ts
│   │       │       │   ├── uriTemplate.d.ts.map
│   │       │       │   ├── uriTemplate.js
│   │       │       │   └── uriTemplate.js.map
│   │       │       ├── types.d.ts
│   │       │       ├── types.d.ts.map
│   │       │       ├── types.js
│   │       │       └── types.js.map
│   │       ├── LICENSE
│   │       ├── package.json
│   │       └── README.md
│   ├── 1
│   ├── natural
│   │   ├── 1
│   │   ├── CODE_OF_CONDUCT.md
│   │   ├── CONTRIBUTING.md
│   │   ├── gulpfile.js
│   │   ├── index.js
│   │   ├── lib
│   │   │   └── natural
│   │   │       ├── 1
│   │   │       ├── analyzers
│   │   │       │   ├── brill_pos_tagger
│   │   │       │   │   ├── data
│   │   │       │   │   │   ├── Dutch
│   │   │       │   │   │   │   ├── brill_CONTEXTRULES.jg
│   │   │       │   │   │   │   ├── brill_CONTEXTRULES.json
│   │   │       │   │   │   │   ├── brill_LEXICON.jg
│   │   │       │   │   │   │   ├── brill_Lexicon.json
│   │   │       │   │   │   │   └── README.txt
│   │   │       │   │   │   └── English
│   │   │       │   │   │       ├── lexicon_from_posjs.json
│   │   │       │   │   │       ├── README.txt
│   │   │       │   │   │       ├── tr_from_brill_paper.json
│   │   │       │   │   │       ├── tr_from_brill_paper.txt
│   │   │       │   │   │       ├── tr_from_posjs.json
│   │   │       │   │   │       └── tr_from_posjs.txt
│   │   │       │   │   ├── index.d.ts
│   │   │       │   │   ├── index.js
│   │   │       │   │   └── lib
│   │   │       │   │       ├── Brill_POS_Tagger.js
│   │   │       │   │       ├── Brill_POS_Tester.js
│   │   │       │   │       ├── Brill_POS_Trainer.js
│   │   │       │   │       ├── Corpus.js
│   │   │       │   │       ├── Lexicon.js
│   │   │       │   │       ├── Predicate.js
│   │   │       │   │       ├── RuleSet.js
│   │   │       │   │       ├── RuleTemplate.js
│   │   │       │   │       ├── RuleTemplates.js
│   │   │       │   │       ├── Sentence.js
│   │   │       │   │       ├── TF_Parser.js
│   │   │       │   │       ├── TF_Parser.pegjs
│   │   │       │   │       └── TransformationRule.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── sentence_analyzer.js
│   │   │       │   └── SenType.ts
│   │   │       ├── classifiers
│   │   │       │   ├── bayes_classifier.js
│   │   │       │   ├── classifier_train_parallel.js
│   │   │       │   ├── classifier.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── logistic_regression_classifier.js
│   │   │       │   └── maxent
│   │   │       │       ├── Classifier.js
│   │   │       │       ├── Context.js
│   │   │       │       ├── Distribution.js
│   │   │       │       ├── Element.js
│   │   │       │       ├── Feature.js
│   │   │       │       ├── FeatureSet.js
│   │   │       │       ├── GISScaler.js
│   │   │       │       ├── POS
│   │   │       │       │   ├── ME_Corpus.js
│   │   │       │       │   ├── ME_Sentence.js
│   │   │       │       │   └── POS_Element.js
│   │   │       │       ├── Sample.js
│   │   │       │       └── SimpleExample
│   │   │       │           └── SE_Element.js
│   │   │       ├── distance
│   │   │       │   ├── dice_coefficient.js
│   │   │       │   ├── hamming_distance.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── jaro-winkler_distance.js
│   │   │       │   └── levenshtein_distance.js
│   │   │       ├── index.d.ts
│   │   │       ├── index.js
│   │   │       ├── inflectors
│   │   │       │   ├── count_inflector.js
│   │   │       │   ├── form_set.js
│   │   │       │   ├── fr
│   │   │       │   │   ├── count_inflector.js
│   │   │       │   │   └── noun_inflector.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── ja
│   │   │       │   │   └── noun_inflector.js
│   │   │       │   ├── noun_inflector.js
│   │   │       │   ├── present_verb_inflector.js
│   │   │       │   └── singular_plural_inflector.js
│   │   │       ├── ngrams
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── ngrams_zh.js
│   │   │       │   └── ngrams.js
│   │   │       ├── normalizers
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── normalizer_ja.js
│   │   │       │   ├── normalizer_no.js
│   │   │       │   ├── normalizer_sv.js
│   │   │       │   ├── normalizer.js
│   │   │       │   └── remove_diacritics.js
│   │   │       ├── phonetics
│   │   │       │   ├── dm_soundex.js
│   │   │       │   ├── double_metaphone.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── metaphone.js
│   │   │       │   ├── phonetic.js
│   │   │       │   ├── sentiment
│   │   │       │   │   ├── Basque
│   │   │       │   │   │   └── senticon_eu.json
│   │   │       │   │   ├── Catalan
│   │   │       │   │   │   └── senticon_ca.json
│   │   │       │   │   ├── Dutch
│   │   │       │   │   │   ├── negations_du.json
│   │   │       │   │   │   └── pattern-sentiment-nl.json
│   │   │       │   │   ├── English
│   │   │       │   │   │   ├── negations_en.json
│   │   │       │   │   │   ├── pattern-sentiment-en.json
│   │   │       │   │   │   └── senticon_en.json
│   │   │       │   │   ├── French
│   │   │       │   │   │   └── pattern-sentiment-fr.json
│   │   │       │   │   ├── Galician
│   │   │       │   │   │   └── senticon_gl.json
│   │   │       │   │   ├── German
│   │   │       │   │   │   ├── negations_de.json
│   │   │       │   │   │   └── pattern-sentiment-de.json
│   │   │       │   │   ├── index.d.ts
│   │   │       │   │   ├── index.js
│   │   │       │   │   ├── Italian
│   │   │       │   │   │   └── pattern-sentiment-it.json
│   │   │       │   │   ├── Portuguese
│   │   │       │   │   │   ├── afinnShortSortedPortuguese.json
│   │   │       │   │   │   └── negations_pt.json
│   │   │       │   │   ├── SentimentAnalyzer.js
│   │   │       │   │   ├── Spanish
│   │   │       │   │   │   ├── afinnShortSortedSpanish.json
│   │   │       │   │   │   ├── negations_es.json
│   │   │       │   │   │   └── senticon_es.json
│   │   │       │   │   └── tools
│   │   │       │   │       ├── README.md
│   │   │       │   │       ├── sentimentXmlParser.js
│   │   │       │   │       └── XmlParser4PatternData.js
│   │   │       │   └── soundex.js
│   │   │       ├── spellcheck
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   └── spellcheck.js
│   │   │       ├── stemmers
│   │   │       │   ├── Carry
│   │   │       │   │   ├── index.js
│   │   │       │   │   ├── stepConfs.js
│   │   │       │   │   └── utils.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── indonesian
│   │   │       │   │   ├── base_stemmer_id.js
│   │   │       │   │   ├── data
│   │   │       │   │   │   └── kata-dasar.json
│   │   │       │   │   ├── prefix_rules.js
│   │   │       │   │   ├── removal.js
│   │   │       │   │   ├── stemmer_id.js
│   │   │       │   │   └── suffix_rules.js
│   │   │       │   ├── lancaster_rules.js
│   │   │       │   ├── lancaster_stemmer.js
│   │   │       │   ├── porter_stemmer_de.js
│   │   │       │   ├── porter_stemmer_es.js
│   │   │       │   ├── porter_stemmer_fa.js
│   │   │       │   ├── porter_stemmer_fr.js
│   │   │       │   ├── porter_stemmer_it.js
│   │   │       │   ├── porter_stemmer_nl.js
│   │   │       │   ├── porter_stemmer_no.js
│   │   │       │   ├── porter_stemmer_pt.js
│   │   │       │   ├── porter_stemmer_ru.js
│   │   │       │   ├── porter_stemmer_sv.js
│   │   │       │   ├── porter_stemmer_uk.js
│   │   │       │   ├── porter_stemmer.js
│   │   │       │   ├── stemmer_de.js
│   │   │       │   ├── stemmer_es.js
│   │   │       │   ├── stemmer_fa.js
│   │   │       │   ├── stemmer_fr.js
│   │   │       │   ├── stemmer_it.js
│   │   │       │   ├── stemmer_ja.js
│   │   │       │   ├── stemmer_nl.js
│   │   │       │   ├── stemmer_no.js
│   │   │       │   ├── stemmer_pl.js
│   │   │       │   ├── stemmer_pt.js
│   │   │       │   ├── stemmer_ru.js
│   │   │       │   ├── stemmer_sv.js
│   │   │       │   ├── stemmer_uk.js
│   │   │       │   ├── stemmer.js
│   │   │       │   └── token.js
│   │   │       ├── tfidf
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   └── tfidf.js
│   │   │       ├── tokenizers
│   │   │       │   ├── aggressive_tokenizer_de.js
│   │   │       │   ├── aggressive_tokenizer_es.js
│   │   │       │   ├── aggressive_tokenizer_fa.js
│   │   │       │   ├── aggressive_tokenizer_fr.js
│   │   │       │   ├── aggressive_tokenizer_hi.js
│   │   │       │   ├── aggressive_tokenizer_id.js
│   │   │       │   ├── aggressive_tokenizer_it.js
│   │   │       │   ├── aggressive_tokenizer_nl.js
│   │   │       │   ├── aggressive_tokenizer_no.js
│   │   │       │   ├── aggressive_tokenizer_pl.js
│   │   │       │   ├── aggressive_tokenizer_pt.js
│   │   │       │   ├── aggressive_tokenizer_ru.js
│   │   │       │   ├── aggressive_tokenizer_sv.js
│   │   │       │   ├── aggressive_tokenizer_uk.js
│   │   │       │   ├── aggressive_tokenizer_vi.js
│   │   │       │   ├── aggressive_tokenizer.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── orthography_matchers.js
│   │   │       │   ├── regexp_tokenizer.js
│   │   │       │   ├── sentence_tokenizer_deprecated.js
│   │   │       │   ├── sentence_tokenizer.js
│   │   │       │   ├── tokenizer_case.js
│   │   │       │   ├── tokenizer_ja.js
│   │   │       │   ├── tokenizer.js
│   │   │       │   └── treebank_word_tokenizer.js
│   │   │       ├── transliterators
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   └── ja
│   │   │       │       └── index.js
│   │   │       ├── trie
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   └── trie.js
│   │   │       ├── util
│   │   │       │   ├── abbreviations_en.js
│   │   │       │   ├── bag.js
│   │   │       │   ├── directed_edge.js
│   │   │       │   ├── edge_weighted_digraph.js
│   │   │       │   ├── index.d.ts
│   │   │       │   ├── index.js
│   │   │       │   ├── longest_path_tree.js
│   │   │       │   ├── shortest_path_tree.js
│   │   │       │   ├── stopwords_es.js
│   │   │       │   ├── stopwords_fa.js
│   │   │       │   ├── stopwords_fr.js
│   │   │       │   ├── stopwords_id.js
│   │   │       │   ├── stopwords_it.js
│   │   │       │   ├── stopwords_ja.js
│   │   │       │   ├── stopwords_nl.js
│   │   │       │   ├── stopwords_no.js
│   │   │       │   ├── stopwords_pl.js
│   │   │       │   ├── stopwords_pt.js
│   │   │       │   ├── stopwords_ru.js
│   │   │       │   ├── stopwords_sv.js
│   │   │       │   ├── stopwords_uk.js
│   │   │       │   ├── stopwords_zh.js
│   │   │       │   ├── stopwords.js
│   │   │       │   ├── storage
│   │   │       │   │   ├── docker-compose.yml
│   │   │       │   │   ├── File.js
│   │   │       │   │   ├── index.d.ts
│   │   │       │   │   ├── index.js
│   │   │       │   │   ├── Memcached.js
│   │   │       │   │   ├── MongoDB.js
│   │   │       │   │   ├── Postgres.js
│   │   │       │   │   ├── Redis.js
│   │   │       │   │   └── StorageBackend.js
│   │   │       │   ├── topological.js
│   │   │       │   └── utils.js
│   │   │       └── wordnet
│   │   │           ├── data_file.js
│   │   │           ├── index_file.js
│   │   │           ├── index.d.ts
│   │   │           ├── index.js
│   │   │           ├── wordnet_file.js
│   │   │           └── wordnet.js
│   │   ├── LICENSE.txt
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── rollup.config.mjs
│   │   ├── SECURITY.md
│   │   ├── tsconfig.json
│   │   └── webpack.config.js
│   └── string-similarity
│       ├── LICENSE
│       ├── package.json
│       ├── README.md
│       ├── src
│       │   └── index.js
│       └── umd
│           └── string-similarity.min.js
├── package-lock.json
├── package.json
├── README.md
├── Readme中文
├── requirements.txt
├── smithery.yaml
├── src
│   └── index.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # EntityIdentification
 2 | Identify whether two sets of data are from the same entity. 识别两组数据是否来自同一主体
 3 | 
 4 | This is a MCP (Model Context Protocol) server. 这是一个支持MCP协议的服务器。
 5 | 
 6 | 
 7 | # Data Comparison Tool
 8 | 
 9 | This tool provides a comprehensive way to compare two sets of data, evaluating both exact and semantic equality of their values. It leverages text normalization and a language model to determine if the data originates from the same entity.
10 | 
11 | ## Features
12 | 
13 | - **Text Normalization**: Converts text to lowercase, removes punctuation, and normalizes whitespace.
14 | - **Value Comparison**: Compares values directly and semantically (ignoring order for lists).
15 | - **JSON Traversal**: Iterates through each key in the JSON objects and compares corresponding values.
16 | - **Language Model Integration**: Uses a generative language model to assess semantic similarity and provide a final judgment on whether the data comes from the same entity.
17 | 
18 | ## Installation
19 | 
20 | To use this tool, ensure you have the necessary dependencies installed. You can install them using pip:
21 | 
22 | ```bash
23 | pip install genai
24 | ```
25 | 
26 | ## Usage
27 | 
28 | ### Functions
29 | 
30 | 1. **normalize_text(text)**:
31 |    - Normalizes the input text by converting it to lowercase, removing punctuation, and normalizing whitespace.
32 | 
33 | 2. **compare_values(val1, val2)**:
34 |    - Compares two values both exactly and semantically.
35 |    - If the values are lists, it ignores the order of elements for semantic comparison.
36 | 
37 | 3. **compare_json(json1, json2)**:
38 |    - Compares two JSON objects key by key.
39 |    - Uses `compare_values` to evaluate each key's values.
40 |    - Integrates a language model to assess semantic similarity and provides a final judgment.
41 | 
42 | ### Example
43 | 
44 | ```python
45 | import json
46 | import genai
47 | import re
48 | 
49 | # Define your JSON objects
50 | json1 = {
51 |     "name": "John Doe",
52 |     "address": "123 Main St, Anytown, USA",
53 |     "hobbies": ["reading", "hiking", "coding"]
54 | }
55 | 
56 | json2 = {
57 |     "name": "john doe",
58 |     "address": "123 Main Street, Anytown, USA",
59 |     "hobbies": ["coding", "hiking", "reading"]
60 | }
61 | 
62 | # Compare the JSON objects
63 | comparison_results = compare_json(json1, json2)
64 | 
65 | # Generate final matching result
66 | model1 = genai.GenerativeModel("gemini-2.0-flash-thinking-exp")
67 | result_matching = model1.generate_content("综合这些信息,你认为可以判断两个数据来自同一主体吗?"+json.dumps(comparison_results, ensure_ascii=False, indent=4))
68 | print(result_matching.text)
69 | ```
70 | 
71 | ## Contributing
72 | 
73 | Contributions are welcome! Please open an issue or submit a pull request.
74 | 
75 | ## License
76 | 
77 | This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
78 | ## Contact
79 | 
80 | If you have any questions or suggestions, please contact me:
81 | - Email: [email protected]
82 | - GitHub: [[email protected]](mailto:[email protected])。
83 | 
84 | Wechat
85 | ![qrcode_for_gh_643efb7db5bc_344(1)](https://github.com/u3588064/LLMemory/assets/53069671/8bb26c0f-4cab-438b-9f8c-16b1c26b3587)
86 | 
```

--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------

```
1 | flask>=2.0.0
2 | mcp>=0.1.0
3 | google-generativeai>=0.3.0
4 | python-dotenv>=1.0.0
5 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "ES2020",
 5 |     "moduleResolution": "node",
 6 |     "esModuleInterop": true,
 7 |     "strict": true,
 8 |     "outDir": "build",
 9 |     "skipLibCheck": true,
10 |     "forceConsistentCasingInFileNames": true
11 |   },
12 |   "include": ["src/**/*"],
13 |   "exclude": ["node_modules"]
14 | }
15 | 
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | 
 2 | # Smithery.ai configuration
 3 | startCommand:
 4 |   type: stdio
 5 |   configSchema:
 6 | 
 7 |   commandFunction:
 8 |     # A function that produces the CLI command to start the MCP on stdio.
 9 |     |-
10 |     (config) => ({
11 |     "command": "node",
12 |     "args": [
13 |       "dist/index.js"
14 |       ],
15 |       "env": {
16 |        
17 |       }
18 |     })
19 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Use an official Node.js runtime as a parent image
 2 | FROM node:18-alpine
 3 | 
 4 | # Set the working directory in the container
 5 | WORKDIR /app
 6 | 
 7 | # Copy package.json and package-lock.json
 8 | COPY package*.json ./
 9 | 
10 | # Install production dependencies only
11 | # Use --ignore-scripts for potentially improved security
12 | RUN npm install
13 | 
14 | # Copy the compiled application code
15 | COPY build ./build
16 | 
17 | 
18 | 
19 | # Define the command to run the application
20 | CMD ["node", "dist/index.js"]
21 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "entity-resolution-mcp",
 3 |   "version": "1.0.0",
 4 |   "type": "module",
 5 |   "scripts": {
 6 |     "build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\""
 7 |   },
 8 |   "dependencies": {
 9 |     "@google/generative-ai": "^0.24.0",
10 |     "@modelcontextprotocol/sdk": "^1.0.0",
11 |     "@types/natural": "^5.1.5",
12 |     "natural": "^8.0.1",
13 |     "string-similarity": "^4.0.4"
14 |   },
15 |   "devDependencies": {
16 |     "@types/node": "^20.0.0",
17 |     "@types/string-similarity": "^4.0.0",
18 |     "typescript": "^5.0.0"
19 |   }
20 | }
21 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | import { Server } from '@modelcontextprotocol/sdk/server/index.js';
  3 | import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
  4 | import {
  5 |   CallToolRequestSchema,
  6 |   ErrorCode,
  7 |   ListToolsRequestSchema,
  8 |   McpError,
  9 |   TextContent, // Corrected Import
 10 | } from '@modelcontextprotocol/sdk/types.js';
 11 | import stringSimilarity from 'string-similarity';
 12 | import natural from 'natural';
 13 | import { inspect } from 'util'; // For better debugging if needed
 14 | import { GoogleGenerativeAI, HarmCategory, HarmBlockThreshold } from '@google/generative-ai';
 15 | 
 16 | interface EntityInfo {
 17 |   [key: string]: any; // Allow various types, handle conversion later
 18 | }
 19 | 
 20 | // Function to normalize text: lowercase, remove punctuation, normalize whitespace
 21 | function normalizeText(text: any): string {
 22 |   let str = String(text).toLowerCase();
 23 |   // Keep letters, numbers, and CJK characters, remove other punctuation
 24 |   str = str.replace(/[^\p{L}\p{N}\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\s]/gu, '');
 25 |   str = str.replace(/\s+/g, ' ').trim(); // Normalize whitespace
 26 |   return str;
 27 | }
 28 | 
 29 | // Helper to safely get text from Gemini response
 30 | function getGeminiResponseText(response: any): string | null {
 31 |     try {
 32 |         // Check for different possible response structures
 33 |         if (response?.response?.candidates?.[0]?.content?.parts?.[0]?.text) {
 34 |             return response.response.candidates[0].content.parts[0].text.trim();
 35 |         }
 36 |         if (response?.text) { // Simpler structure if generateContent returns directly
 37 |              return typeof response.text === 'function' ? response.text().trim() : String(response.text).trim();
 38 |         }
 39 |          // Add more checks if needed based on actual Gemini SDK behavior
 40 |     } catch (e) {
 41 |         console.error("Error parsing Gemini response:", e);
 42 |     }
 43 |     return null; // Return null if text cannot be extracted
 44 | }
 45 | 
 46 | class EntityResolutionServer {
 47 |   private server: Server;
 48 | 
 49 |   constructor() {
 50 |     this.server = new Server(
 51 |       {
 52 |         name: 'entity-resolution-server',
 53 |         version: '0.2.1', // Incremented version for fix
 54 |       },
 55 |       {
 56 |         capabilities: {
 57 |           tools: {},
 58 |         },
 59 |       }
 60 |     );
 61 | 
 62 |     this.setupToolHandlers();
 63 | 
 64 |     this.server.onerror = (error) => console.error('[MCP Error]', error);
 65 |     process.on('SIGINT', async () => {
 66 |       await this.server.close();
 67 |       process.exit(0);
 68 |     });
 69 |   }
 70 | 
 71 |   // Calculates syntactic similarity scores and prepares data for LLM
 72 |   private calculateSyntacticSimilarities(entity1: EntityInfo, entity2: EntityInfo): {
 73 |     dice: number;
 74 |     levenshtein: number;
 75 |     fieldDetails: Record<string, {
 76 |       dice: number;
 77 |       levenshtein: number;
 78 |       normalized1: string;
 79 |       normalized2: string;
 80 |       value1: any; // Keep original value
 81 |       value2: any; // Keep original value
 82 |     }>
 83 |   } {
 84 |     let totalWeight = 0;
 85 |     let weightedDiceSimilarity = 0;
 86 |     let weightedLevenshteinSimilarity = 0;
 87 |     const fieldDetails: Record<string, { dice: number; levenshtein: number; normalized1: string; normalized2: string; value1: any; value2: any }> = {};
 88 | 
 89 |     const keys1 = Object.keys(entity1);
 90 |     const keys2 = Object.keys(entity2);
 91 |     const commonKeys = keys1.filter(key => keys2.includes(key));
 92 | 
 93 |     if (commonKeys.length === 0) {
 94 |       return { dice: 0, levenshtein: 0, fieldDetails: {} };
 95 |     }
 96 | 
 97 |     for (const key of commonKeys) {
 98 |       const value1 = entity1[key];
 99 |       const value2 = entity2[key];
100 | 
101 |       // Normalize values before comparison
102 |       const normalized1 = normalizeText(value1);
103 |       const normalized2 = normalizeText(value2);
104 | 
105 |       // Calculate Dice similarity
106 |       const diceSim = stringSimilarity.compareTwoStrings(normalized1, normalized2);
107 | 
108 |       // Calculate Levenshtein similarity (normalized to 0-1 range)
109 |       const levenshteinDist = natural.LevenshteinDistance(normalized1, normalized2, { insertion_cost: 1, deletion_cost: 1, substitution_cost: 1 });
110 |       const maxLength = Math.max(normalized1.length, normalized2.length);
111 |       const levenshteinSim = maxLength === 0 ? 1 : 1 - (levenshteinDist / maxLength);
112 | 
113 |       // Apply field weights (currently uniform)
114 |       const weight = 1.0; // TODO: Make weights configurable
115 |       totalWeight += weight;
116 |       weightedDiceSimilarity += diceSim * weight;
117 |       weightedLevenshteinSimilarity += levenshteinSim * weight;
118 | 
119 |       fieldDetails[key] = {
120 |         dice: diceSim,
121 |         levenshtein: levenshteinSim,
122 |         normalized1: normalized1,
123 |         normalized2: normalized2,
124 |         value1: value1, // Store original value
125 |         value2: value2, // Store original value
126 |       };
127 |     }
128 | 
129 |     const overallDice = totalWeight > 0 ? weightedDiceSimilarity / totalWeight : 0;
130 |     const overallLevenshtein = totalWeight > 0 ? weightedLevenshteinSimilarity / totalWeight : 0;
131 | 
132 |     return {
133 |       dice: overallDice,
134 |       levenshtein: overallLevenshtein,
135 |       fieldDetails: fieldDetails
136 |     };
137 |   }
138 | 
139 |   private setupToolHandlers() {
140 |     this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
141 |       tools: [
142 |         {
143 |           name: 'compare_entities',
144 |           description: 'Compare two entities using syntactic and optional semantic (LLM) methods.',
145 |           inputSchema: {
146 |             type: 'object',
147 |             properties: {
148 |               entity1: {
149 |                 type: 'object',
150 |                 description: 'First entity information',
151 |                 additionalProperties: true
152 |               },
153 |               entity2: {
154 |                 type: 'object',
155 |                 description: 'Second entity information',
156 |                 additionalProperties: true
157 |               },
158 |               threshold: {
159 |                 type: 'number',
160 |                 description: 'Syntactic similarity threshold (0-1, based on Dice) to consider entities as matching',
161 |                 minimum: 0,
162 |                 maximum: 1,
163 |                 default: 0.8
164 |               },
165 |               apiKey: {
166 |                 type: 'string',
167 |                 description: '(Optional) Google Generative AI API Key for semantic comparison'
168 |               },
169 |             },
170 |             // Make apiKey optional
171 |             required: ['entity1', 'entity2']
172 |           }
173 |         }
174 |       ]
175 |     }));
176 | 
177 |     this.server.setRequestHandler(CallToolRequestSchema, async (request): Promise<{ content: TextContent[] }> => { // Corrected return type
178 |       if (request.params.name !== 'compare_entities') {
179 |         throw new McpError(
180 |           ErrorCode.MethodNotFound,
181 |           `Unknown tool: ${request.params.name}`
182 |         );
183 |       }
184 | 
185 |       // --- Input Validation ---
186 |       const args = request.params.arguments as any;
187 |       const entity1 = args.entity1 as EntityInfo;
188 |       const entity2 = args.entity2 as EntityInfo;
189 |       const threshold = typeof args.threshold === 'number' ? args.threshold : 0.8;
190 |       const apiKey = args.apiKey as string | undefined; // apiKey is optional
191 | 
192 |       if (!entity1 || typeof entity1 !== 'object' || !entity2 || typeof entity2 !== 'object') {
193 |         throw new McpError(ErrorCode.InvalidParams, 'Invalid entity format. Both entity1 and entity2 must be objects.');
194 |       }
195 | 
196 |       // --- Syntactic Comparison ---
197 |       const syntacticSimilarities = this.calculateSyntacticSimilarities(entity1, entity2);
198 |       const isMatchSyntactic = syntacticSimilarities.dice >= threshold;
199 | 
200 |       // --- Semantic (LLM) Comparison ---
201 |       let llmFieldResults: Record<string, { llmSaysEqual: boolean | string | null; error?: string }> = {};
202 |       let finalLlmAnalysis: string | null = null;
203 |       let llmError: string | null = null;
204 | 
205 |       // --- Semantic (LLM) Comparison (only if apiKey is provided) ---
206 |       if (apiKey) {
207 |         try {
208 |           const genAI = new GoogleGenerativeAI(apiKey);
209 |           const safetySettings = [
210 |             { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
211 |             { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
212 |             { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
213 |             { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE },
214 |           ];
215 | 
216 |           const comparisonModel = genAI.getGenerativeModel({ model: "gemini-1.5-flash-latest", safetySettings });
217 | 
218 |           const fieldComparisonPromises = Object.entries(syntacticSimilarities.fieldDetails).map(async ([key, details]) => {
219 |             const prompt = `请判断这两个值在语义层面是否一致,仅返回 "true" 或 "false":\n值1: ${JSON.stringify(details.value1)}\n值2: ${JSON.stringify(details.value2)}`;
220 |             try {
221 |               const result = await comparisonModel.generateContent(prompt);
222 |               const textResult = getGeminiResponseText(result);
223 |               let llmSaysEqual: boolean | string | null = null;
224 |               if (textResult !== null) {
225 |                 if (textResult.toLowerCase() === 'true') {
226 |                     llmSaysEqual = true;
227 |                 } else if (textResult.toLowerCase() === 'false') {
228 |                     llmSaysEqual = false;
229 |                 } else {
230 |                     llmSaysEqual = `Unexpected LLM response: ${textResult}`;
231 |                 }
232 |               }
233 |               llmFieldResults[key] = { llmSaysEqual };
234 |             } catch (error: any) {
235 |               console.error(`LLM error comparing field ${key}:`, error);
236 |               llmFieldResults[key] = { llmSaysEqual: null, error: error.message || 'Unknown LLM error' };
237 |             }
238 |           });
239 | 
240 |           await Promise.all(fieldComparisonPromises);
241 | 
242 |           // --- Final LLM Analysis ---
243 |           const combinedResultsForFinalAnalysis = {
244 |               syntactic: syntacticSimilarities,
245 |               semanticFieldChecks: llmFieldResults
246 |           };
247 |           const finalPrompt = `综合以下字段的语法和语义比较信息,判断这两个实体是否可能指向同一个真实世界的主体?请提供简要分析和最终判断 (可能匹配/不太可能匹配)。\n\n比较详情:\n${JSON.stringify(combinedResultsForFinalAnalysis, null, 2)}`;
248 |           try {
249 |               const finalResult = await comparisonModel.generateContent(finalPrompt);
250 |               finalLlmAnalysis = getGeminiResponseText(finalResult);
251 |           } catch (error: any) {
252 |               console.error(`LLM error during final analysis:`, error);
253 |               finalLlmAnalysis = `Error during final analysis: ${error.message || 'Unknown LLM error'}`;
254 |           }
255 | 
256 |         } catch (error: any) {
257 |             console.error("Error during LLM processing:", error);
258 |             llmError = `LLM Initialization or Processing Error: ${error.message || 'Unknown error'}`;
259 |             // Ensure field results reflect the error if initialization failed
260 |             Object.keys(syntacticSimilarities.fieldDetails).forEach(key => {
261 |                 if (!llmFieldResults[key]) {
262 |                     llmFieldResults[key] = { llmSaysEqual: null, error: llmError ?? 'Skipped due to init error' };
263 |                 }
264 |             });
265 |             finalLlmAnalysis = `Analysis skipped due to error: ${llmError}`;
266 |         }
267 |       } else {
268 |           // --- Case where apiKey is NOT provided ---
269 |           llmError = "API Key not provided. Skipping semantic analysis.";
270 |           finalLlmAnalysis = "Semantic analysis skipped (no API key).";
271 |           // Populate llmFieldResults to indicate skipping
272 |           Object.keys(syntacticSimilarities.fieldDetails).forEach(key => {
273 |               llmFieldResults[key] = { llmSaysEqual: null, error: 'Skipped (no API key)' };
274 |           });
275 |       }
276 | 
277 |       // --- Format Final Response ---
278 |       const responseJson = {
279 |         overallSyntacticSimilarity: {
280 |           dice: syntacticSimilarities.dice,
281 |           levenshtein: syntacticSimilarities.levenshtein,
282 |         },
283 |         isMatchSyntactic: isMatchSyntactic,
284 |         threshold: threshold,
285 |         matchDetailsSyntactic: `Entities are ${isMatchSyntactic ? 'likely' : 'unlikely'} to be the same based ONLY on Dice similarity (${(syntacticSimilarities.dice * 100).toFixed(2)}%) and threshold ${threshold}.`,
286 |         fieldDetails: Object.entries(syntacticSimilarities.fieldDetails).reduce((acc, [key, details]) => {
287 |             acc[key] = {
288 |                 ...details, // dice, levenshtein, normalized1/2, value1/2
289 |                 llmSemanticCheck: llmFieldResults[key] || { llmSaysEqual: null, error: 'Not processed' } // Add LLM result per field
290 |             };
291 |             return acc;
292 |         }, {} as Record<string, any>),
293 |         finalLlmAnalysis: finalLlmAnalysis, // Use the value determined above
294 |         llmProcessingError: llmError // Include LLM error message if any
295 |       };
296 | 
297 |       return {
298 |         content: [
299 |           {
300 |             type: 'text',
301 |             text: JSON.stringify(responseJson, null, 2) // Pretty print JSON
302 |           }
303 |         ]
304 |       };
305 |     });
306 |   }
307 | 
308 |   async run() {
309 |     const transport = new StdioServerTransport();
310 |     await this.server.connect(transport);
311 |     console.error('Entity Resolution MCP server running on stdio (v0.2.1)'); // Updated log
312 |   }
313 | }
314 | 
315 | const server = new EntityResolutionServer();
316 | server.run().catch(console.error);
317 | 
```