{"id":15650220,"url":"https://github.com/dermatologist/pyomop","last_synced_at":"2025-12-24T17:38:15.946Z","repository":{"id":36973119,"uuid":"260724680","full_name":"dermatologist/pyomop","owner":"dermatologist","description":"Python package for managing OHDSI clinical data models. Includes support for LLM based plain text queries, MCP server and FHIR import.","archived":false,"fork":false,"pushed_at":"2025-12-20T13:54:19.000Z","size":2486,"stargazers_count":56,"open_issues_count":0,"forks_count":9,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-12-22T17:17:59.571Z","etag":null,"topics":["cdm","clinical-trials","datawarehouse","hacktoberfest","health-data-analysis","health-informatics","llm","ohdsi","python","text-to-sql"],"latest_commit_sha":null,"homepage":"https://nuchange.ca/2025/08/vibe-coding-fhir-to-omop-cdm.html?github","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dermatologist.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS.md","dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2020-05-02T16:09:27.000Z","updated_at":"2025-12-20T13:54:16.000Z","dependencies_parsed_at":"2023-12-06T03:08:56.924Z","dependency_job_id":"75ea7317-d197-43bc-a183-5aff6518d62f","html_url":"https://github.com/dermatologist/pyomop","commit_stats":{"total_commits":206,"total_committers":5,"mean_commits":41.2,"dds":"0.40291262135922334","last_synced_commit":"776a78e1b0600feec7044ad69ffce8034758a14a"},"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/dermatologist/pyomop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dermatologist%2Fpyomop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dermatologist%2Fpyomop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dermatologist%2Fpyomop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dermatologist%2Fpyomop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dermatologist","download_url":"https://codeload.github.com/dermatologist/pyomop/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dermatologist%2Fpyomop/sbom","scorecard":{"id":49431,"data":{"date":"2025-08-11","repo":{"name":"github.com/dermatologist/pyomop","commit":"867165211b9a6015f75a54f6142e5118a4d08049"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.7,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":10,"reason":"13 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/22 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/bump.yml:1","Warn: no topLevel permission defined: .github/workflows/docs.yml:1","Warn: no topLevel permission defined: .github/workflows/publish.yml:1","Warn: no topLevel permission defined: .github/workflows/pytest.yml:1","Warn: no topLevel permission defined: .github/workflows/tox.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/bump.yml:16: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/bump.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/bump.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/bump.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/bump.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/bump.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/docs.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/docs.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/docs.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/docs.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/docs.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/docs.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/docs.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/publish.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/publish.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/publish.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/publish.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/publish.yml:30: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/publish.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pytest.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/pytest.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/pytest.yml:27: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/pytest.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/pytest.yml:31: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/pytest.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tox.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/tox.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/tox.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/tox.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/tox.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/dermatologist/pyomop/tox.yml/develop?enable=pin","Warn: containerImage not pinned by hash: .devcontainer/Dockerfile:3","Warn: downloadThenRun not pinned by hash: tests/travis_install.sh:30","Warn: pipCommand not pinned by hash: tests/travis_install.sh:44","Warn: pipCommand not pinned by hash: tests/travis_install.sh:45","Warn: pipCommand not pinned by hash: tests/travis_install.sh:48","Info:   0 out of   9 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   8 third-party GitHubAction dependencies pinned","Info:   0 out of   1 containerImage dependencies pinned","Info:   0 out of   1 downloadThenRun dependencies pinned","Info:   0 out of   3 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/publish.yml:9"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'develop'","Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 17 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-14T23:25:27.395Z","repository_id":36973119,"created_at":"2025-08-14T23:25:27.395Z","updated_at":"2025-08-14T23:25:27.395Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28004518,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cdm","clinical-trials","datawarehouse","hacktoberfest","health-data-analysis","health-informatics","llm","ohdsi","python","text-to-sql"],"created_at":"2024-10-03T12:34:01.639Z","updated_at":"2025-12-24T17:38:15.938Z","avatar_url":"https://github.com/dermatologist.png","language":"Python","funding_links":[],"categories":["Python","Medical MCP Servers","Quality Compliance and Regulatory"],"sub_categories":["Clinical Validity Score"],"readme":"# pyomop: OMOP Swiss Army Knife 🔧\n\n\n[![Release](https://img.shields.io/github/v/release/dermatologist/pyomop)](https://img.shields.io/github/v/release/dermatologist/pyomop)\n[![Build status](https://img.shields.io/github/actions/workflow/status/dermatologist/pyomop/pytest.yml?branch=develop)](https://github.com/dermatologist/pyomop/actions/workflows/pytest.yml?query=branch%3Adevelop)\n[![codecov](https://codecov.io/gh/dermatologist/pyomop/branch/develop/graph/badge.svg)](https://codecov.io/gh/dermatologist/pyomop)\n[![Commit activity](https://img.shields.io/github/commit-activity/m/dermatologist/pyomop)](https://img.shields.io/github/commit-activity/m/dermatologist/pyomop)\n[![License](https://img.shields.io/github/license/dermatologist/pyomop)](https://img.shields.io/github/license/dermatologist/pyomop)\n[![Downloads](https://img.shields.io/pypi/dm/pyomop)](https://pypi.org/project/pyomop)\n[![Documentation](https://badgen.net/badge/icon/documentation?icon=libraries\u0026label)](https://dermatologist.github.io/pyomop/)\n\u003c!-- gh-dependents-info-used-by-start --\u003e\n[![Generated by github-dependents-info](https://img.shields.io/static/v1?label=Used%20by\u0026message=3\u0026color=informational\u0026logo=slickpic)](https://github.com/dermatologist/pyomop/blob/develop/docs/github-dependents-info.md)\u003c!-- gh-dependents-info-used-by-end --\u003e\n\n\n## ✨ Overview\n\n**pyomop** is your OMOP Swiss Army Knife 🔧 for working with [OHDSI](https://www.ohdsi.org/) OMOP Common Data Model (CDM) v5.4 or v6 compliant databases using SQLAlchemy as the ORM. It supports converting query results to pandas DataFrames for machine learning pipelines and provides utilities for working with OMOP vocabularies. Table definitions are based on the [omop-cdm](https://github.com/thehyve/omop-cdm) library. Pyomop is designed to be a lightweight, easy-to-use library for researchers and developers experimenting and testing with OMOP CDM databases. It can be used both as a commandline tool and as an imported library in your code.\n\n- Supports SQLite, PostgreSQL, and MySQL. CDM and Vocab tables are created in the same schema. (See usage below for more details)\n- LLM-based natural language queries via langchain. [Usage](examples/llm_example.py).\n- 🔥 FHIR to OMOP conversion utilities. (See usage below for more details)\n- Execute [QueryLibrary](https://github.com/OHDSI/QueryLibrary). (See usage below for more details)\n\nPlease ⭐️ If you find this project useful!\n\n## Installation\n\n**Stable release:**\n```\npip install pyomop\n```\n\n**Development version:**\n```\ngit clone https://github.com/dermatologist/pyomop.git\ncd pyomop\npip install -e .\n```\n\n**LLM support:**\n```\npip install pyomop[llm]\n```\n\n#### ✨ See [this notebook](examples/llm_example.ipynb) or [script](examples/llm_example.py) for examples. 👇 [MCP SERVER](#mcp-server) is recommended for advanced usage.\n\n## Docker\n\n* A [docker-compose](/docker-compose.yml) is provided to quickly set up an environment with postgrs, [webapi](https://github.com/OHDSI/WebAPI), [atlas](https://github.com/OHDSI/atlas) and a [sql script](/examples/webapi_source.sql) to create a source in webapi. The script can be run using the `psql` command line tool or via the webapi UI. Please refresh after running the script by sending a request to /WebAPI/source/refresh.\n\n## 🔧 Usage\n\n\n```python\nimport asyncio\nimport datetime\n\nfrom sqlalchemy import select\n\nfrom pyomop import CdmEngineFactory, CdmVector, CdmVocabulary\n# cdm6 and cdm54 are supported\nfrom pyomop.cdm54 import Base, Cohort, Person, Vocabulary\n\nasync def main():\n    cdm = CdmEngineFactory() # Creates SQLite database by default for fast testing\n    # cdm = CdmEngineFactory(db='pgsql', host='', port=5432,\n    #                       user='', pw='',\n    #                       name='', schema='')\n    # cdm = CdmEngineFactory(db='mysql', host='', port=3306,\n    #                       user='', pw='',\n    #                       name='')\n    engine = cdm.engine\n    # Comment the following line if using an existing database. Both cdm6 and cdm54 are supported, see the import statements above\n    await cdm.init_models(Base.metadata) # Initializes the database with the OMOP CDM tables\n    vocab = CdmVocabulary(cdm, version='cdm54') # or 'cdm6' for v6\n    # Uncomment the following line to create a new vocabulary from CSV files\n    # vocab.create_vocab('/path/to/csv/files')\n\n    async with cdm.session() as session:  # type: ignore\n        # Add Persons\n        async with session.begin():\n            session.add(\n                Person(\n                    person_id=100,\n                    gender_concept_id=8532,\n                    gender_source_concept_id=8512,\n                    year_of_birth=1980,\n                    month_of_birth=1,\n                    day_of_birth=1,\n                    birth_datetime=datetime.datetime(1980, 1, 1),\n                    race_concept_id=8552,\n                    race_source_concept_id=8552,\n                    ethnicity_concept_id=38003564,\n                    ethnicity_source_concept_id=38003564,\n                )\n            )\n            session.add(\n                Person(\n                    person_id=101,\n                    gender_concept_id=8532,\n                    gender_source_concept_id=8512,\n                    year_of_birth=1980,\n                    month_of_birth=1,\n                    day_of_birth=1,\n                    birth_datetime=datetime.datetime(1980, 1, 1),\n                    race_concept_id=8552,\n                    race_source_concept_id=8552,\n                    ethnicity_concept_id=38003564,\n                    ethnicity_source_concept_id=38003564,\n                )\n            )\n\n        # Query the Person\n        stmt = select(Person).where(Person.person_id == 100)\n        result = await session.execute(stmt)\n        for row in result.scalars():\n            print(row)\n            assert row.person_id == 100\n\n        # Query the person pattern 2\n        person = await session.get(Person, 100)\n        print(person)\n        assert person is not None\n        assert person.person_id == 100\n\n    # Convert result to a pandas dataframe\n    vec = CdmVector()\n\n    # https://github.com/OHDSI/QueryLibrary/blob/master/inst/shinyApps/QueryLibrary/queries/person/PE02.md\n    result = await vec.query_library(cdm, resource='person', query_name='PE02')\n    df = vec.result_to_df(result)\n    print(\"DataFrame from result:\")\n    print(df.head())\n\n    result = await vec.execute(cdm, query='SELECT * from person;')\n    print(\"Executing custom query:\")\n    df = vec.result_to_df(result)\n    print(\"DataFrame from result:\")\n    print(df.head())\n\n    # Close engine\n    await engine.dispose() # type: ignore\n\n# Run the main function\nasyncio.run(main())\n```\n\n## 🔥 FHIR to OMOP mapping\n\npyomop can load FHIR Bulk Export (NDJSON) files into an OMOP CDM database.\n\n- Sample datasets: https://github.com/smart-on-fhir/sample-bulk-fhir-datasets\n- Remove any non-FHIR files (for example, `log.ndjson`) from the input folder.\n- Download OMOP vocabulary CSV files (for example from OHDSI Athena) and place them in a folder.\n\nRun:\n\n```bash\npyomop --create --vocab ~/Downloads/omop-vocab/ --input ~/Downloads/fhir/\n```\n\nThis will create an OMOP CDM in SQLite, load the vocabulary files, and import the FHIR data from the input folder and reconcile vocabulary, mapping source_value to concept_id. The mapping is defined in the `mapping.example.json` file. The default mapping is [here](src/pyomop/mapping.default.json). Mapping happens in 5 steps as implemented [here](src/pyomop/loader.py).\n\n* Example using postgres (Docker)\n```bash\npyomop --dbtype pgsql --host localhost --user postgres --pw mypass  --create --vocab ~/Downloads/omop-vocab/ --input ~/Downloads/fhir/\n```\n\n* FHIR to data frame mapping is done with [FHIRy](https://github.com/dermatologist/fhiry)\n* Most of the code for this functionality was written by an LLM agent. The prompts used are [here](notes/prompt.md)\n\n### Command-line\n\n```text\n  -c, --create                Create CDM tables (see --version).\n  -t, --dbtype TEXT           Database Type for creating CDM (sqlite, mysql or\n                              pgsql)\n  -h, --host TEXT             Database host\n  -p, --port TEXT             Database port\n  -u, --user TEXT             Database user\n  -w, --pw TEXT               Database password\n  -v, --version TEXT          CDM version (cdm54 (default) or cdm6)\n  -n, --name TEXT             Database name\n  -s, --schema TEXT           Database schema (for pgsql)\n  -i, --vocab TEXT            Folder with vocabulary files (csv) to import\n  -f, --input DIRECTORY       Input folder with FHIR bundles or ndjson files.\n  -e, --eunomia-dataset TEXT  Download and load Eunomia dataset (e.g.,\n                              'GiBleed', 'Synthea')\n  --eunomia-path TEXT         Path to store/find Eunomia datasets (uses\n                              EUNOMIA_DATA_FOLDER env var if not specified)\n  --connection-info           Display connection information for the database (For R package compatibility)\n  --mcp-server                Start MCP server for stdio interaction\n  --pyhealth-path TEXT        Path to export PyHealth compatible CSV files\n  --help                      Show this message and exit.\n```\n\n## MCP Server\n\npyomop includes an MCP (Model Context Protocol) server that exposes tools for interacting with OMOP CDM databases. This allows MCP clients to create databases, load data, and execute SQL statements.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://github.com/dermatologist/pyomop/blob/develop/notes/pyomop-mcp.gif\" /\u003e\n\u003c/p\u003e\n\n### Starting the MCP Server\n\nTo start the MCP server for stdio interaction:\n\n```bash\n# Using the main CLI\npyomop --mcp-server\n\n```\n\n#### Usage with MCP Clients\n\nThe server communicates via stdio and can be used with any MCP-compatible client. Example configuration for [vscode](/.vscode/mcp.json):\n\n```json\n{\n  \"servers\": {\n      \"pyomop\": {\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"pyomop\", \"--mcp-server\"]\n    }\n  }\n}\n```\n* *If the vocabulary is not installed locally or advanced vocabulary support is required from Athena, it is recommended to combine [omop_mcp](https://github.com/OHNLP/omop_mcp) with PyOMOP.*\n\n\n#### Available MCP Tools\n\n- **create_cdm**: Create an empty CDM database\n- **create_eunomia**: Add Eunomia sample dataset\n- **get_table_columns**: Get column names for a specific table\n- **get_single_table_info**: Get detailed table information, including foreign keys\n- **get_usable_table_names**: Get a list of all available table names\n- **run_sql**: Execute SQL statements with error handling\n\n* create_cdm and create_eunomia support only local sqlite databases to avoid inadvertent data loss in production databases.\n#### Available Prompts\n\n- **query_execution_steps**: Provides step-by-step guidance for executing database queries based on free text instructions\n\n### Eunomia import and cohort creation\n```\npyomop -e Synthea27Nj -v 5.4 --connection-info\npyomop -e GiBleed -v 5.3 --connection-info\n```\n\n## PyHealth and PLP Compatibility (For Machine Learning pipelines)\n\npyomop supports exporting OMOP CDM data (to `--pyhealth-path`) in a format compatible with [PyHealth](https://github.com/sunlabuiuc/PyHealth), a machine learning library for healthcare data analysis ([See Notebook](/examples/pyhealth.ipynb) and usage below). Additionally, you can export the connection information for use with the various R packages such as [PatientLevelPrediction](https://ohdsi.github.io/PatientLevelPrediction/) using the `--connection-info` option.\n\n```bash\npyomop -e GiBleed -v 5.3 --connection-info --pyhealth-path ~/pyhealth\n```\n\n## Additional Tools\n\n- **Convert FHIR to pandas DataFrame:** [fhiry](https://github.com/dermatologist/fhiry)\n- **.NET and Golang OMOP CDM:** [.NET](https://github.com/dermatologist/omopcdm-dot-net), [Golang](https://github.com/E-Health/gocdm)\n\n## Supported Databases\n\n- PostgreSQL\n- MySQL\n- SQLite\n\n## Environment Variables for Database Connection\n\nYou can configure database connection parameters using environment variables. These will be used as defaults by pyomop and the MCP server:\n\n- `PYOMOP_DB`: Database type (`sqlite`, `mysql`, `pgsql`)\n- `PYOMOP_HOST`: Database host\n- `PYOMOP_PORT`: Database port\n- `PYOMOP_USER`: Database user\n- `PYOMOP_PW`: Database password\n- `PYOMOP_SCHEMA`: Database schema (for PostgreSQL)\n\nExample usage:\n\n```bash\nexport PYOMOP_DB=pgsql\nexport PYOMOP_HOST=localhost\nexport PYOMOP_PORT=5432\nexport PYOMOP_USER=postgres\nexport PYOMOP_PW=mypass\nexport PYOMOP_SCHEMA=omop\n```\nThese environment variables will be checked before assigning default values for database connection in pyomop and MCP server tools.\n\n## Contributing\n\nPull requests are welcome! See [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Contributors\n\n- [Bell Eapen](https://nuchange.ca) [![Twitter Follow](https://img.shields.io/twitter/follow/beapen?style=social)](https://twitter.com/beapen)\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdermatologist%2Fpyomop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdermatologist%2Fpyomop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdermatologist%2Fpyomop/lists"}