# 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
# EntityIdentification
Identify whether two sets of data are from the same entity. 识别两组数据是否来自同一主体
This is a MCP (Model Context Protocol) server. 这是一个支持MCP协议的服务器。
# Data Comparison Tool
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.
## Features
- **Text Normalization**: Converts text to lowercase, removes punctuation, and normalizes whitespace.
- **Value Comparison**: Compares values directly and semantically (ignoring order for lists).
- **JSON Traversal**: Iterates through each key in the JSON objects and compares corresponding values.
- **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.
## Installation
To use this tool, ensure you have the necessary dependencies installed. You can install them using pip:
```bash
pip install genai
```
## Usage
### Functions
1. **normalize_text(text)**:
- Normalizes the input text by converting it to lowercase, removing punctuation, and normalizing whitespace.
2. **compare_values(val1, val2)**:
- Compares two values both exactly and semantically.
- If the values are lists, it ignores the order of elements for semantic comparison.
3. **compare_json(json1, json2)**:
- Compares two JSON objects key by key.
- Uses `compare_values` to evaluate each key's values.
- Integrates a language model to assess semantic similarity and provides a final judgment.
### Example
```python
import json
import genai
import re
# Define your JSON objects
json1 = {
"name": "John Doe",
"address": "123 Main St, Anytown, USA",
"hobbies": ["reading", "hiking", "coding"]
}
json2 = {
"name": "john doe",
"address": "123 Main Street, Anytown, USA",
"hobbies": ["coding", "hiking", "reading"]
}
# Compare the JSON objects
comparison_results = compare_json(json1, json2)
# Generate final matching result
model1 = genai.GenerativeModel("gemini-2.0-flash-thinking-exp")
result_matching = model1.generate_content("综合这些信息,你认为可以判断两个数据来自同一主体吗?"+json.dumps(comparison_results, ensure_ascii=False, indent=4))
print(result_matching.text)
```
## Contributing
Contributions are welcome! Please open an issue or submit a pull request.
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
## Contact
If you have any questions or suggestions, please contact me:
- Email: [email protected]
- GitHub: [[email protected]](mailto:[email protected])。
Wechat

```
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
```
flask>=2.0.0
mcp>=0.1.0
google-generativeai>=0.3.0
python-dotenv>=1.0.0
```
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
```json
{
"compilerOptions": {
"target": "ES2020",
"module": "ES2020",
"moduleResolution": "node",
"esModuleInterop": true,
"strict": true,
"outDir": "build",
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
```
--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------
```yaml
# Smithery.ai configuration
startCommand:
type: stdio
configSchema:
commandFunction:
# A function that produces the CLI command to start the MCP on stdio.
|-
(config) => ({
"command": "node",
"args": [
"dist/index.js"
],
"env": {
}
})
```
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
```dockerfile
# Use an official Node.js runtime as a parent image
FROM node:18-alpine
# Set the working directory in the container
WORKDIR /app
# Copy package.json and package-lock.json
COPY package*.json ./
# Install production dependencies only
# Use --ignore-scripts for potentially improved security
RUN npm install
# Copy the compiled application code
COPY build ./build
# Define the command to run the application
CMD ["node", "dist/index.js"]
```
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
```json
{
"name": "entity-resolution-mcp",
"version": "1.0.0",
"type": "module",
"scripts": {
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\""
},
"dependencies": {
"@google/generative-ai": "^0.24.0",
"@modelcontextprotocol/sdk": "^1.0.0",
"@types/natural": "^5.1.5",
"natural": "^8.0.1",
"string-similarity": "^4.0.4"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/string-similarity": "^4.0.0",
"typescript": "^5.0.0"
}
}
```
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
```typescript
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
McpError,
TextContent, // Corrected Import
} from '@modelcontextprotocol/sdk/types.js';
import stringSimilarity from 'string-similarity';
import natural from 'natural';
import { inspect } from 'util'; // For better debugging if needed
import { GoogleGenerativeAI, HarmCategory, HarmBlockThreshold } from '@google/generative-ai';
interface EntityInfo {
[key: string]: any; // Allow various types, handle conversion later
}
// Function to normalize text: lowercase, remove punctuation, normalize whitespace
function normalizeText(text: any): string {
let str = String(text).toLowerCase();
// Keep letters, numbers, and CJK characters, remove other punctuation
str = str.replace(/[^\p{L}\p{N}\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\s]/gu, '');
str = str.replace(/\s+/g, ' ').trim(); // Normalize whitespace
return str;
}
// Helper to safely get text from Gemini response
function getGeminiResponseText(response: any): string | null {
try {
// Check for different possible response structures
if (response?.response?.candidates?.[0]?.content?.parts?.[0]?.text) {
return response.response.candidates[0].content.parts[0].text.trim();
}
if (response?.text) { // Simpler structure if generateContent returns directly
return typeof response.text === 'function' ? response.text().trim() : String(response.text).trim();
}
// Add more checks if needed based on actual Gemini SDK behavior
} catch (e) {
console.error("Error parsing Gemini response:", e);
}
return null; // Return null if text cannot be extracted
}
class EntityResolutionServer {
private server: Server;
constructor() {
this.server = new Server(
{
name: 'entity-resolution-server',
version: '0.2.1', // Incremented version for fix
},
{
capabilities: {
tools: {},
},
}
);
this.setupToolHandlers();
this.server.onerror = (error) => console.error('[MCP Error]', error);
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
// Calculates syntactic similarity scores and prepares data for LLM
private calculateSyntacticSimilarities(entity1: EntityInfo, entity2: EntityInfo): {
dice: number;
levenshtein: number;
fieldDetails: Record<string, {
dice: number;
levenshtein: number;
normalized1: string;
normalized2: string;
value1: any; // Keep original value
value2: any; // Keep original value
}>
} {
let totalWeight = 0;
let weightedDiceSimilarity = 0;
let weightedLevenshteinSimilarity = 0;
const fieldDetails: Record<string, { dice: number; levenshtein: number; normalized1: string; normalized2: string; value1: any; value2: any }> = {};
const keys1 = Object.keys(entity1);
const keys2 = Object.keys(entity2);
const commonKeys = keys1.filter(key => keys2.includes(key));
if (commonKeys.length === 0) {
return { dice: 0, levenshtein: 0, fieldDetails: {} };
}
for (const key of commonKeys) {
const value1 = entity1[key];
const value2 = entity2[key];
// Normalize values before comparison
const normalized1 = normalizeText(value1);
const normalized2 = normalizeText(value2);
// Calculate Dice similarity
const diceSim = stringSimilarity.compareTwoStrings(normalized1, normalized2);
// Calculate Levenshtein similarity (normalized to 0-1 range)
const levenshteinDist = natural.LevenshteinDistance(normalized1, normalized2, { insertion_cost: 1, deletion_cost: 1, substitution_cost: 1 });
const maxLength = Math.max(normalized1.length, normalized2.length);
const levenshteinSim = maxLength === 0 ? 1 : 1 - (levenshteinDist / maxLength);
// Apply field weights (currently uniform)
const weight = 1.0; // TODO: Make weights configurable
totalWeight += weight;
weightedDiceSimilarity += diceSim * weight;
weightedLevenshteinSimilarity += levenshteinSim * weight;
fieldDetails[key] = {
dice: diceSim,
levenshtein: levenshteinSim,
normalized1: normalized1,
normalized2: normalized2,
value1: value1, // Store original value
value2: value2, // Store original value
};
}
const overallDice = totalWeight > 0 ? weightedDiceSimilarity / totalWeight : 0;
const overallLevenshtein = totalWeight > 0 ? weightedLevenshteinSimilarity / totalWeight : 0;
return {
dice: overallDice,
levenshtein: overallLevenshtein,
fieldDetails: fieldDetails
};
}
private setupToolHandlers() {
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'compare_entities',
description: 'Compare two entities using syntactic and optional semantic (LLM) methods.',
inputSchema: {
type: 'object',
properties: {
entity1: {
type: 'object',
description: 'First entity information',
additionalProperties: true
},
entity2: {
type: 'object',
description: 'Second entity information',
additionalProperties: true
},
threshold: {
type: 'number',
description: 'Syntactic similarity threshold (0-1, based on Dice) to consider entities as matching',
minimum: 0,
maximum: 1,
default: 0.8
},
apiKey: {
type: 'string',
description: '(Optional) Google Generative AI API Key for semantic comparison'
},
},
// Make apiKey optional
required: ['entity1', 'entity2']
}
}
]
}));
this.server.setRequestHandler(CallToolRequestSchema, async (request): Promise<{ content: TextContent[] }> => { // Corrected return type
if (request.params.name !== 'compare_entities') {
throw new McpError(
ErrorCode.MethodNotFound,
`Unknown tool: ${request.params.name}`
);
}
// --- Input Validation ---
const args = request.params.arguments as any;
const entity1 = args.entity1 as EntityInfo;
const entity2 = args.entity2 as EntityInfo;
const threshold = typeof args.threshold === 'number' ? args.threshold : 0.8;
const apiKey = args.apiKey as string | undefined; // apiKey is optional
if (!entity1 || typeof entity1 !== 'object' || !entity2 || typeof entity2 !== 'object') {
throw new McpError(ErrorCode.InvalidParams, 'Invalid entity format. Both entity1 and entity2 must be objects.');
}
// --- Syntactic Comparison ---
const syntacticSimilarities = this.calculateSyntacticSimilarities(entity1, entity2);
const isMatchSyntactic = syntacticSimilarities.dice >= threshold;
// --- Semantic (LLM) Comparison ---
let llmFieldResults: Record<string, { llmSaysEqual: boolean | string | null; error?: string }> = {};
let finalLlmAnalysis: string | null = null;
let llmError: string | null = null;
// --- Semantic (LLM) Comparison (only if apiKey is provided) ---
if (apiKey) {
try {
const genAI = new GoogleGenerativeAI(apiKey);
const safetySettings = [
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE },
];
const comparisonModel = genAI.getGenerativeModel({ model: "gemini-1.5-flash-latest", safetySettings });
const fieldComparisonPromises = Object.entries(syntacticSimilarities.fieldDetails).map(async ([key, details]) => {
const prompt = `请判断这两个值在语义层面是否一致,仅返回 "true" 或 "false":\n值1: ${JSON.stringify(details.value1)}\n值2: ${JSON.stringify(details.value2)}`;
try {
const result = await comparisonModel.generateContent(prompt);
const textResult = getGeminiResponseText(result);
let llmSaysEqual: boolean | string | null = null;
if (textResult !== null) {
if (textResult.toLowerCase() === 'true') {
llmSaysEqual = true;
} else if (textResult.toLowerCase() === 'false') {
llmSaysEqual = false;
} else {
llmSaysEqual = `Unexpected LLM response: ${textResult}`;
}
}
llmFieldResults[key] = { llmSaysEqual };
} catch (error: any) {
console.error(`LLM error comparing field ${key}:`, error);
llmFieldResults[key] = { llmSaysEqual: null, error: error.message || 'Unknown LLM error' };
}
});
await Promise.all(fieldComparisonPromises);
// --- Final LLM Analysis ---
const combinedResultsForFinalAnalysis = {
syntactic: syntacticSimilarities,
semanticFieldChecks: llmFieldResults
};
const finalPrompt = `综合以下字段的语法和语义比较信息,判断这两个实体是否可能指向同一个真实世界的主体?请提供简要分析和最终判断 (可能匹配/不太可能匹配)。\n\n比较详情:\n${JSON.stringify(combinedResultsForFinalAnalysis, null, 2)}`;
try {
const finalResult = await comparisonModel.generateContent(finalPrompt);
finalLlmAnalysis = getGeminiResponseText(finalResult);
} catch (error: any) {
console.error(`LLM error during final analysis:`, error);
finalLlmAnalysis = `Error during final analysis: ${error.message || 'Unknown LLM error'}`;
}
} catch (error: any) {
console.error("Error during LLM processing:", error);
llmError = `LLM Initialization or Processing Error: ${error.message || 'Unknown error'}`;
// Ensure field results reflect the error if initialization failed
Object.keys(syntacticSimilarities.fieldDetails).forEach(key => {
if (!llmFieldResults[key]) {
llmFieldResults[key] = { llmSaysEqual: null, error: llmError ?? 'Skipped due to init error' };
}
});
finalLlmAnalysis = `Analysis skipped due to error: ${llmError}`;
}
} else {
// --- Case where apiKey is NOT provided ---
llmError = "API Key not provided. Skipping semantic analysis.";
finalLlmAnalysis = "Semantic analysis skipped (no API key).";
// Populate llmFieldResults to indicate skipping
Object.keys(syntacticSimilarities.fieldDetails).forEach(key => {
llmFieldResults[key] = { llmSaysEqual: null, error: 'Skipped (no API key)' };
});
}
// --- Format Final Response ---
const responseJson = {
overallSyntacticSimilarity: {
dice: syntacticSimilarities.dice,
levenshtein: syntacticSimilarities.levenshtein,
},
isMatchSyntactic: isMatchSyntactic,
threshold: threshold,
matchDetailsSyntactic: `Entities are ${isMatchSyntactic ? 'likely' : 'unlikely'} to be the same based ONLY on Dice similarity (${(syntacticSimilarities.dice * 100).toFixed(2)}%) and threshold ${threshold}.`,
fieldDetails: Object.entries(syntacticSimilarities.fieldDetails).reduce((acc, [key, details]) => {
acc[key] = {
...details, // dice, levenshtein, normalized1/2, value1/2
llmSemanticCheck: llmFieldResults[key] || { llmSaysEqual: null, error: 'Not processed' } // Add LLM result per field
};
return acc;
}, {} as Record<string, any>),
finalLlmAnalysis: finalLlmAnalysis, // Use the value determined above
llmProcessingError: llmError // Include LLM error message if any
};
return {
content: [
{
type: 'text',
text: JSON.stringify(responseJson, null, 2) // Pretty print JSON
}
]
};
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
console.error('Entity Resolution MCP server running on stdio (v0.2.1)'); // Updated log
}
}
const server = new EntityResolutionServer();
server.run().catch(console.error);
```