iflow-mcp_ahnlabio-bicscan-mcp 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ BICSCAN_API_KEY=your_api_key
@@ -0,0 +1,176 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py,cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ #Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ #uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ #poetry.lock
109
+
110
+ # pdm
111
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112
+ #pdm.lock
113
+ # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114
+ # in version control.
115
+ # https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116
+ .pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121
+ __pypackages__/
122
+
123
+ # Celery stuff
124
+ celerybeat-schedule
125
+ celerybeat.pid
126
+
127
+ # SageMath parsed files
128
+ *.sage.py
129
+
130
+ # Environments
131
+ .env
132
+ .venv
133
+ env/
134
+ venv/
135
+ ENV/
136
+ env.bak/
137
+ venv.bak/
138
+
139
+ # Spyder project settings
140
+ .spyderproject
141
+ .spyproject
142
+
143
+ # Rope project settings
144
+ .ropeproject
145
+
146
+ # mkdocs documentation
147
+ /site
148
+
149
+ # mypy
150
+ .mypy_cache/
151
+ .dmypy.json
152
+ dmypy.json
153
+
154
+ # Pyre type checker
155
+ .pyre/
156
+
157
+ # pytype static type analyzer
158
+ .pytype/
159
+
160
+ # Cython debug symbols
161
+ cython_debug/
162
+
163
+ # PyCharm
164
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
167
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
168
+ #.idea/
169
+
170
+ # Ruff stuff:
171
+ .ruff_cache/
172
+
173
+ # PyPI configuration file
174
+ .pypirc
175
+
176
+ .history/
@@ -0,0 +1,24 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "MCP BICScan",
9
+ "type": "debugpy",
10
+ "request": "launch",
11
+ "program": "${workspaceFolder}/src/mcp_bicscan/server.py",
12
+ "console": "integratedTerminal",
13
+ "cwd": "${workspaceFolder}"
14
+ },
15
+ // {
16
+ // "name": "MCP Inspector",
17
+ // "request": "launch",
18
+ // "type": "debugpy",
19
+ // "program": "npx @modelcontextprotocol/inspector",
20
+ // "console": "integratedTerminal",
21
+ // "cwd": "${workspaceFolder}"
22
+ // }
23
+ ]
24
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "cSpell.words": [
3
+ "BICSCAN",
4
+ "fastmcp",
5
+ "httpx",
6
+ "levelname",
7
+ "ofac",
8
+ "pyproject",
9
+ "venv"
10
+ ]
11
+ }
@@ -0,0 +1,39 @@
1
+ # Use a Python image with uv pre-installed
2
+ FROM ghcr.io/astral-sh/uv:python3.10-bookworm-slim AS uv
3
+
4
+ # Install the project into `/app`
5
+ WORKDIR /app
6
+
7
+ # Enable bytecode compilation
8
+ ENV UV_COMPILE_BYTECODE=1
9
+
10
+ # Copy from the cache instead of linking since it's a mounted volume
11
+ ENV UV_LINK_MODE=copy
12
+
13
+ # Generate proper TOML lockfile first
14
+ RUN --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
15
+ uv lock
16
+
17
+ # Install the project's dependencies using the lockfile
18
+ RUN --mount=type=cache,target=/root/.cache/uv \
19
+ --mount=type=bind,source=pyproject.toml,target=pyproject.toml \
20
+ --mount=type=bind,source=uv.lock,target=uv.lock \
21
+ uv sync --frozen --no-install-project --no-dev --no-editable
22
+
23
+ # Then, add the rest of the project source code and install it
24
+ ADD . /app
25
+ RUN --mount=type=cache,target=/root/.cache/uv \
26
+ --mount=type=bind,source=uv.lock,target=uv.lock \
27
+ uv sync --frozen --no-dev --no-editable
28
+
29
+ FROM python:3.10-slim
30
+
31
+ WORKDIR /app
32
+
33
+ COPY --from=uv --chown=app:app /app/.venv /app/.venv
34
+ COPY .env.example /app/.env
35
+
36
+ # Place executables in the environment at the front of the path
37
+ ENV PATH="/app/.venv/bin:$PATH"
38
+
39
+ ENTRYPOINT ["bicscan-mcp"]
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AhnLab Blockchain Company, INC.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,66 @@
1
+ PROJECT_NAME := $(shell \
2
+ if [ -f pyproject.toml ]; then \
3
+ NAME_FROM_PYPROJECT=$$(awk '/^\[project\]/{flag=1; next} /^\[/{flag=0} flag && /^name *=/{gsub(/name *= *"|"/, "", $$0); gsub(/ /, "", $$0); print}' pyproject.toml); \
4
+ if [ -n "$$NAME_FROM_PYPROJECT" ]; then \
5
+ echo "$$NAME_FROM_PYPROJECT"; \
6
+ else \
7
+ NAME_FROM_POETRY=$$(awk '/^\[tool\.poetry\]/{flag=1; next} /^\[/{flag=0} flag && /^name *=/{gsub(/name *= *"|"/, "", $$0); gsub(/ /, "", $$0); print}' pyproject.toml); \
8
+ if [ -n "$$NAME_FROM_POETRY" ]; then \
9
+ echo "$$NAME_FROM_POETRY"; \
10
+ else \
11
+ echo $$(basename $$(pwd)); \
12
+ fi; \
13
+ fi; \
14
+ else \
15
+ echo $$(basename $$(pwd)); \
16
+ fi \
17
+ )
18
+
19
+ # Get exposed ports from Dockerfile if it exists
20
+ EXPOSED_PORTS := $(shell if [ -f Dockerfile ]; then grep -oE 'EXPOSE[[:space:]]+[0-9]+' Dockerfile | awk '{print "-p "$$2":"$$2}' | tr '\n' ' '; fi)
21
+
22
+ # Check if .env file exists and set env flag accordingly
23
+ ENV_FLAG := $(shell if [ -f .env ]; then echo "--env-file .env"; fi)
24
+
25
+ all:
26
+ echo "Running for ${PROJECT_NAME}"
27
+ docker image prune -f
28
+ docker build -t ${PROJECT_NAME} .
29
+
30
+ build:
31
+ docker image prune -f
32
+ docker build -t ${PROJECT_NAME} .
33
+
34
+ run:
35
+ echo "stopping previous container"
36
+ -docker stop ${PROJECT_NAME}
37
+ echo "removing ${PROJECT_NAME}"
38
+ -docker container rm ${PROJECT_NAME}
39
+ echo "start running"
40
+ docker run --rm -it ${EXPOSED_PORTS} --name ${PROJECT_NAME} ${ENV_FLAG} ${PROJECT_NAME}:latest
41
+
42
+ serve:
43
+ echo "stopping previous container"
44
+ -docker stop ${PROJECT_NAME}
45
+ echo "removing ${PROJECT_NAME}"
46
+ -docker container rm ${PROJECT_NAME}
47
+ echo "start running"
48
+ docker run -d --restart unless-stopped ${EXPOSED_PORTS} --name ${PROJECT_NAME} ${ENV_FLAG} -v $(PWD)/data:/app/data ${PROJECT_NAME}:latest
49
+
50
+ shell:
51
+ docker exec -it ${PROJECT_NAME}:latest /bin/bash
52
+
53
+ clean:
54
+ docker image prune -f
55
+ # rm -rf __pycache__/ data email.db ${PROJECT_NAME}.tar
56
+
57
+ logs:
58
+ docker logs -f ${PROJECT_NAME}
59
+
60
+ export:
61
+ docker save -o ${PROJECT_NAME}.tar ${PROJECT_NAME}:latest
62
+ echo "Docker image saved as ${PROJECT_NAME}.tar"
63
+
64
+ stop:
65
+ @docker stop ${PROJECT_NAME}
66
+
@@ -0,0 +1,152 @@
1
+ Metadata-Version: 2.4
2
+ Name: iflow-mcp_ahnlabio-bicscan-mcp
3
+ Version: 0.1.0
4
+ Summary: BICScan MCP Server
5
+ License-File: LICENSE
6
+ Requires-Python: >=3.10
7
+ Requires-Dist: httpx>=0.28.1
8
+ Requires-Dist: mcp[cli]>=1.5.0
9
+ Requires-Dist: python-dotenv>=1.0.1
10
+ Description-Content-Type: text/markdown
11
+
12
+ # BICScan MCP Server
13
+
14
+ A powerful and efficient Blockchain address risk scoring API MCP Server, leveraging the BICScan API to provide comprehensive risk assessments and asset information for blockchain addresses, domains, and decentralized applications (dApps).
15
+
16
+ 🎉 We're listed on https://github.com/modelcontextprotocol/servers for official integration 🎉
17
+
18
+
19
+ https://github.com/user-attachments/assets/f9425429-1cb1-4508-b962-81351075258b
20
+
21
+ ## Key Features
22
+ - **Risk Scoring**: Obtain risk scores for various blockchain entities, including crypto addresses, domain names, and decentralized application URLs, with scores ranging from 0 to 100, where 100 indicates high risk.
23
+ - **Asset Information**: Retrieve detailed asset holdings for specified crypto addresses, including cryptocurrencies and tokens, with support for multiple blockchain networks.
24
+ - **Real-time Scanning**: Utilize the BICScan API to perform real-time scans and receive up-to-date information on potential risks and asset holdings.
25
+ - **Secure and Reliable**: Built with robust error handling and logging to ensure secure and reliable operations.
26
+
27
+ ## Example Output
28
+
29
+ ## How to use.
30
+
31
+ You con either use Python with `uv` or `docker` depending on your preference.
32
+
33
+ Depending on your environment, you can choose to use either `uv`, `docker`, or `uvx`.
34
+
35
+ ### 1. Running with `uv`
36
+
37
+ #### 1-1. Requirements
38
+ 1. Python 3.10 or higher
39
+ 2. uv 0.6.x
40
+ 3. git
41
+
42
+ #### 1.2. Clone the repository
43
+ ```sh
44
+ git clone https://github.com/ahnlabio/bicscan-mcp
45
+ ```
46
+
47
+ #### 1.3. Config `claude_desktop_config.json`
48
+
49
+ Append following to `claude_desktop_config.json`.
50
+
51
+ Make sure to replace:
52
+ - `YOUR_BICSCAN_REPO_DIR_HERE`: to something like `C:\\Users\\ABC\\repo\\bicscan-mcp` or `/home/abc/repo/bicscan-mcp` similarly.
53
+ - `YOUR_BICSCAN_API_KEY_HERE`: to free API key can be obtained from https://bicscan.io (details below)
54
+
55
+ ```json
56
+ {
57
+ "mcpServers": {
58
+ ... some other mcp servers ...,
59
+ "bicscan": {
60
+ "command": "uv",
61
+ "args": [
62
+ "--directory",
63
+ "YOUR_BICSCAN_REPO_DIR_HERE",
64
+ "run",
65
+ "bicscan-mcp"
66
+ ],
67
+ "env": {
68
+ "BICSCAN_API_KEY": "YOUR_BICSCAN_API_KEY_HERE"
69
+ }
70
+ }
71
+ }
72
+ }
73
+ ```
74
+
75
+ ### 2. Running with `Docker`
76
+
77
+ #### 2.1. Requirements
78
+ 1. Docker environment
79
+
80
+ #### 2.2. Clone the repository
81
+ ```sh
82
+ git clone https://github.com/ahnlabio/bicscan-mcp
83
+ ```
84
+
85
+ #### 2.3. Build Docker image.
86
+
87
+ Just run `make` in the repository directory to build docker image.
88
+
89
+ #### 2.4. Config
90
+ Append following to `claude_desktop_config.json`
91
+
92
+ Make sure to replace:
93
+ - `YOUR_BICSCAN_API_KEY_HERE` to API key obtained from https://bicscan.io (details below)
94
+
95
+ ```json
96
+ {
97
+ "mcpServers": {
98
+ ... some other mcp servers ...,
99
+ "bicscan": {
100
+ "command": "docker",
101
+ "args": [
102
+ "run",
103
+ "--rm",
104
+ "--interactive",
105
+ "--env", "BICSCAN_API_KEY=YOUR_BICSCAN_API_KEY_HERE",
106
+ "bicscan-mcp"
107
+ ]
108
+ }
109
+ }
110
+ }
111
+ ```
112
+
113
+ ### 3. Running with `uvx`
114
+
115
+ #### 3.1. Requirements
116
+ 1. Python 3.10 or higher
117
+ 2. uv 0.6.x
118
+ 3. git
119
+
120
+ #### 3.2. Config `claude_desktop_config.json`
121
+
122
+ Append following to `claude_desktop_config.json`.
123
+
124
+ Make sure to replace:
125
+ - `YOUR_BICSCAN_API_KEY_HERE`: to free API key can be obtained from https://bicscan.io (details below)
126
+
127
+ ```json
128
+ {
129
+ "mcpServers": {
130
+ ... some other mcp servers ...,
131
+ "bicscan": {
132
+ "command": "uvx",
133
+ "args": [
134
+ "--from",
135
+ "git+https://github.com/ahnlabio/bicscan-mcp",
136
+ "bicscan-mcp"
137
+ ],
138
+ "env": {
139
+ "BICSCAN_API_KEY": "YOUR_BICSCAN_API_KEY_HERE"
140
+ }
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ ## How to obtain Free BICScan API Key?
147
+
148
+ 1. Visit `https://bicscan.io` and register.
149
+ 2. Go to profile and create "Create App"
150
+ 3. Enter name and description on your choice.
151
+ 4. Replace `YOUR_BICSCAN_API_KEY_HERE` part from above config to your newly obtained key.
152
+ 5. restart the Claude Desktop.
@@ -0,0 +1,141 @@
1
+ # BICScan MCP Server
2
+
3
+ A powerful and efficient Blockchain address risk scoring API MCP Server, leveraging the BICScan API to provide comprehensive risk assessments and asset information for blockchain addresses, domains, and decentralized applications (dApps).
4
+
5
+ 🎉 We're listed on https://github.com/modelcontextprotocol/servers for official integration 🎉
6
+
7
+
8
+ https://github.com/user-attachments/assets/f9425429-1cb1-4508-b962-81351075258b
9
+
10
+ ## Key Features
11
+ - **Risk Scoring**: Obtain risk scores for various blockchain entities, including crypto addresses, domain names, and decentralized application URLs, with scores ranging from 0 to 100, where 100 indicates high risk.
12
+ - **Asset Information**: Retrieve detailed asset holdings for specified crypto addresses, including cryptocurrencies and tokens, with support for multiple blockchain networks.
13
+ - **Real-time Scanning**: Utilize the BICScan API to perform real-time scans and receive up-to-date information on potential risks and asset holdings.
14
+ - **Secure and Reliable**: Built with robust error handling and logging to ensure secure and reliable operations.
15
+
16
+ ## Example Output
17
+
18
+ ## How to use.
19
+
20
+ You con either use Python with `uv` or `docker` depending on your preference.
21
+
22
+ Depending on your environment, you can choose to use either `uv`, `docker`, or `uvx`.
23
+
24
+ ### 1. Running with `uv`
25
+
26
+ #### 1-1. Requirements
27
+ 1. Python 3.10 or higher
28
+ 2. uv 0.6.x
29
+ 3. git
30
+
31
+ #### 1.2. Clone the repository
32
+ ```sh
33
+ git clone https://github.com/ahnlabio/bicscan-mcp
34
+ ```
35
+
36
+ #### 1.3. Config `claude_desktop_config.json`
37
+
38
+ Append following to `claude_desktop_config.json`.
39
+
40
+ Make sure to replace:
41
+ - `YOUR_BICSCAN_REPO_DIR_HERE`: to something like `C:\\Users\\ABC\\repo\\bicscan-mcp` or `/home/abc/repo/bicscan-mcp` similarly.
42
+ - `YOUR_BICSCAN_API_KEY_HERE`: to free API key can be obtained from https://bicscan.io (details below)
43
+
44
+ ```json
45
+ {
46
+ "mcpServers": {
47
+ ... some other mcp servers ...,
48
+ "bicscan": {
49
+ "command": "uv",
50
+ "args": [
51
+ "--directory",
52
+ "YOUR_BICSCAN_REPO_DIR_HERE",
53
+ "run",
54
+ "bicscan-mcp"
55
+ ],
56
+ "env": {
57
+ "BICSCAN_API_KEY": "YOUR_BICSCAN_API_KEY_HERE"
58
+ }
59
+ }
60
+ }
61
+ }
62
+ ```
63
+
64
+ ### 2. Running with `Docker`
65
+
66
+ #### 2.1. Requirements
67
+ 1. Docker environment
68
+
69
+ #### 2.2. Clone the repository
70
+ ```sh
71
+ git clone https://github.com/ahnlabio/bicscan-mcp
72
+ ```
73
+
74
+ #### 2.3. Build Docker image.
75
+
76
+ Just run `make` in the repository directory to build docker image.
77
+
78
+ #### 2.4. Config
79
+ Append following to `claude_desktop_config.json`
80
+
81
+ Make sure to replace:
82
+ - `YOUR_BICSCAN_API_KEY_HERE` to API key obtained from https://bicscan.io (details below)
83
+
84
+ ```json
85
+ {
86
+ "mcpServers": {
87
+ ... some other mcp servers ...,
88
+ "bicscan": {
89
+ "command": "docker",
90
+ "args": [
91
+ "run",
92
+ "--rm",
93
+ "--interactive",
94
+ "--env", "BICSCAN_API_KEY=YOUR_BICSCAN_API_KEY_HERE",
95
+ "bicscan-mcp"
96
+ ]
97
+ }
98
+ }
99
+ }
100
+ ```
101
+
102
+ ### 3. Running with `uvx`
103
+
104
+ #### 3.1. Requirements
105
+ 1. Python 3.10 or higher
106
+ 2. uv 0.6.x
107
+ 3. git
108
+
109
+ #### 3.2. Config `claude_desktop_config.json`
110
+
111
+ Append following to `claude_desktop_config.json`.
112
+
113
+ Make sure to replace:
114
+ - `YOUR_BICSCAN_API_KEY_HERE`: to free API key can be obtained from https://bicscan.io (details below)
115
+
116
+ ```json
117
+ {
118
+ "mcpServers": {
119
+ ... some other mcp servers ...,
120
+ "bicscan": {
121
+ "command": "uvx",
122
+ "args": [
123
+ "--from",
124
+ "git+https://github.com/ahnlabio/bicscan-mcp",
125
+ "bicscan-mcp"
126
+ ],
127
+ "env": {
128
+ "BICSCAN_API_KEY": "YOUR_BICSCAN_API_KEY_HERE"
129
+ }
130
+ }
131
+ }
132
+ }
133
+ ```
134
+
135
+ ## How to obtain Free BICScan API Key?
136
+
137
+ 1. Visit `https://bicscan.io` and register.
138
+ 2. Go to profile and create "Create App"
139
+ 3. Enter name and description on your choice.
140
+ 4. Replace `YOUR_BICSCAN_API_KEY_HERE` part from above config to your newly obtained key.
141
+ 5. restart the Claude Desktop.
@@ -0,0 +1,20 @@
1
+ # Security Policy
2
+
3
+ ## Reporting Issues
4
+
5
+ Please report security vulnerabilities to "help at bicscan.io"
6
+
7
+ ## Best Practices
8
+
9
+ 1. **API Tokens**
10
+ - Never commit tokens to version control
11
+ - Rotate tokens regularly
12
+ - Use minimal required permissions
13
+
14
+ 2. **Environment Variables**
15
+ - Keep .env files secure and private
16
+ - Use separate tokens for development/production
17
+
18
+ 3. **Access Control**
19
+ - Regularly audit Confluence space access
20
+ - Follow principle of least privilege
@@ -0,0 +1 @@
1
+ python
@@ -0,0 +1 @@
1
+ iflow-mcp_ahnlabio-bicscan-mcp
@@ -0,0 +1,5 @@
1
+ {
2
+ "push_platform": "github",
3
+ "fork_url": "https://github.com/iflow-mcp/ahnlabio-bicscan-mcp",
4
+ "fork_branch": "iflow"
5
+ }
@@ -0,0 +1,21 @@
1
+ [project]
2
+ name = "iflow-mcp_ahnlabio-bicscan-mcp"
3
+ version = "0.1.0"
4
+ description = "BICScan MCP Server"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "httpx>=0.28.1",
9
+ "mcp[cli]>=1.5.0",
10
+ "python-dotenv>=1.0.1",
11
+ ]
12
+
13
+ [project.scripts]
14
+ bicscan-mcp = "bicscan_mcp:main"
15
+
16
+ [build-system]
17
+ requires = ["hatchling"]
18
+ build-backend = "hatchling.build"
19
+
20
+ [tool.hatch.build.targets.wheel]
21
+ packages = ["src/bicscan_mcp"]
@@ -0,0 +1,10 @@
1
+ import asyncio
2
+
3
+ from . import server
4
+
5
+
6
+ def main() -> None:
7
+ asyncio.run(server.main())
8
+
9
+
10
+ __all__ = ["main", "server"]
@@ -0,0 +1,131 @@
1
+ import asyncio
2
+ import logging
3
+ import os
4
+ from typing import Any
5
+ from urllib.parse import urljoin
6
+
7
+ import httpx
8
+ from dotenv import load_dotenv
9
+ from mcp.server import FastMCP
10
+
11
+ load_dotenv()
12
+
13
+ logger = logging.getLogger("bicscan-mcp")
14
+ logger.setLevel(logging.INFO)
15
+
16
+ # add console handler
17
+ console_handler = logging.StreamHandler()
18
+ formatter = logging.Formatter(
19
+ "%(asctime)s - %(name)s:%(lineno)s - %(levelname)s - %(message)s"
20
+ )
21
+ console_handler.setFormatter(formatter)
22
+ logger.addHandler(console_handler)
23
+
24
+ # add file handler
25
+ # file_handler = logging.FileHandler("./data/bicscan-mcp.log")
26
+ # file_handler.setFormatter(formatter)
27
+ # logger.addHandler(file_handler)
28
+
29
+ # Add more detailed logging
30
+ logger.info("FastMCP server initialized with name: BICScan")
31
+
32
+ # Initialize FastMCP server
33
+ mcp = FastMCP("BICScan")
34
+
35
+ # Constants
36
+ BICSCAN_API_BASE = "https://api.bicscan.io"
37
+ BICSCAN_API_KEY = os.getenv("BICSCAN_API_KEY")
38
+ TEST_MODE = os.getenv("TEST_MODE", "false").lower() == "true"
39
+
40
+
41
+ async def post_request(
42
+ endpoint: str, data: dict[str, Any] | None = None
43
+ ) -> dict[str, Any] | None:
44
+ """Make a request to BICScan API with proper error handling."""
45
+ # Test mode: return mock data
46
+ if TEST_MODE:
47
+ logger.info(f"TEST_MODE: Returning mock data for {endpoint}")
48
+ return {
49
+ "summary": {
50
+ "bicscan_score": 0,
51
+ "risk_level": "low",
52
+ "address": data.get("query", "unknown") if data else "unknown"
53
+ },
54
+ "assets": [],
55
+ "status": "test_mode"
56
+ }
57
+
58
+ headers = {
59
+ "User-Agent": "bicscan-mcp/1.0",
60
+ "Accept": "application/json",
61
+ "X-Api-Key": BICSCAN_API_KEY,
62
+ }
63
+ url = urljoin(BICSCAN_API_BASE, endpoint)
64
+
65
+ async with httpx.AsyncClient() as client:
66
+ try:
67
+ logger.info(f"Making request to {url}")
68
+ logger.debug(f"{headers=} {data=}")
69
+ response = await client.post(url, headers=headers, json=data, timeout=30)
70
+ response.raise_for_status()
71
+ logger.info(f"Received response: {response.status_code}")
72
+ return response.json()
73
+ except httpx.HTTPStatusError as http_err:
74
+ logger.error(f"Received response: {http_err}, {response.text}")
75
+ return response.json()
76
+ except Exception as e:
77
+ logger.exception(f"Received response: {e}, {response.text}")
78
+ return {}
79
+
80
+
81
+ @mcp.tool()
82
+ async def get_risk_score(address: str) -> dict:
83
+ """Get Risk Score for Crypto, Domain Name, ENS, CNS, KNS or even Hostname Address
84
+
85
+ Args:
86
+ address: EOA, CA, ENS, CNS, KNS or even HostName
87
+ Returns:
88
+ Dict: where summary.bicscan_score is from 0 to 100. 100 is high risk.
89
+ """
90
+
91
+ logger.info(f"Getting risk score for address: {address}")
92
+ endpoint = "/v1/scan"
93
+ data = {
94
+ "query": address,
95
+ "sync": True,
96
+ "assets": False,
97
+ }
98
+
99
+ return await post_request(endpoint, data=data)
100
+
101
+
102
+ @mcp.tool()
103
+ async def get_assets(address: str) -> dict:
104
+ """Get Assets holdings by CryptoAddress
105
+
106
+ Args:
107
+ address: EOA, CA, ENS, CNS, KNS.
108
+ Returns:
109
+ Dict: where assets is a list of assets
110
+ """
111
+
112
+ logger.info(f"Getting assets for address: {address}")
113
+ endpoint = "/v1/scan"
114
+ data = {
115
+ "query": address,
116
+ "sync": True,
117
+ "assets": True,
118
+ "engines": ["ofac"],
119
+ }
120
+
121
+ return await post_request(endpoint, data=data)
122
+
123
+
124
+ async def main() -> None:
125
+ """Run the MCP BICScan server."""
126
+ # Import here to avoid issues with event loops
127
+ await mcp.run_stdio_async()
128
+
129
+
130
+ if __name__ == "__main__":
131
+ asyncio.run(main())
@@ -0,0 +1 @@
1
+ TEST_MODE=true
@@ -0,0 +1,399 @@
1
+ version = 1
2
+ revision = 1
3
+ requires-python = ">=3.10"
4
+
5
+ [[package]]
6
+ name = "annotated-types"
7
+ version = "0.7.0"
8
+ source = { registry = "https://pypi.org/simple" }
9
+ sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081 }
10
+ wheels = [
11
+ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 },
12
+ ]
13
+
14
+ [[package]]
15
+ name = "anyio"
16
+ version = "4.9.0"
17
+ source = { registry = "https://pypi.org/simple" }
18
+ dependencies = [
19
+ { name = "exceptiongroup", marker = "python_full_version < '3.11'" },
20
+ { name = "idna" },
21
+ { name = "sniffio" },
22
+ { name = "typing-extensions", marker = "python_full_version < '3.13'" },
23
+ ]
24
+ sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949 }
25
+ wheels = [
26
+ { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916 },
27
+ ]
28
+
29
+ [[package]]
30
+ name = "certifi"
31
+ version = "2025.1.31"
32
+ source = { registry = "https://pypi.org/simple" }
33
+ sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 }
34
+ wheels = [
35
+ { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 },
36
+ ]
37
+
38
+ [[package]]
39
+ name = "click"
40
+ version = "8.1.8"
41
+ source = { registry = "https://pypi.org/simple" }
42
+ dependencies = [
43
+ { name = "colorama", marker = "sys_platform == 'win32'" },
44
+ ]
45
+ sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
46
+ wheels = [
47
+ { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
48
+ ]
49
+
50
+ [[package]]
51
+ name = "colorama"
52
+ version = "0.4.6"
53
+ source = { registry = "https://pypi.org/simple" }
54
+ sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
55
+ wheels = [
56
+ { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
57
+ ]
58
+
59
+ [[package]]
60
+ name = "exceptiongroup"
61
+ version = "1.2.2"
62
+ source = { registry = "https://pypi.org/simple" }
63
+ sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 }
64
+ wheels = [
65
+ { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 },
66
+ ]
67
+
68
+ [[package]]
69
+ name = "h11"
70
+ version = "0.14.0"
71
+ source = { registry = "https://pypi.org/simple" }
72
+ sdist = { url = "https://files.pythonhosted.org/packages/f5/38/3af3d3633a34a3316095b39c8e8fb4853a28a536e55d347bd8d8e9a14b03/h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d", size = 100418 }
73
+ wheels = [
74
+ { url = "https://files.pythonhosted.org/packages/95/04/ff642e65ad6b90db43e668d70ffb6736436c7ce41fcc549f4e9472234127/h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761", size = 58259 },
75
+ ]
76
+
77
+ [[package]]
78
+ name = "httpcore"
79
+ version = "1.0.7"
80
+ source = { registry = "https://pypi.org/simple" }
81
+ dependencies = [
82
+ { name = "certifi" },
83
+ { name = "h11" },
84
+ ]
85
+ sdist = { url = "https://files.pythonhosted.org/packages/6a/41/d7d0a89eb493922c37d343b607bc1b5da7f5be7e383740b4753ad8943e90/httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c", size = 85196 }
86
+ wheels = [
87
+ { url = "https://files.pythonhosted.org/packages/87/f5/72347bc88306acb359581ac4d52f23c0ef445b57157adedb9aee0cd689d2/httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd", size = 78551 },
88
+ ]
89
+
90
+ [[package]]
91
+ name = "httpx"
92
+ version = "0.28.1"
93
+ source = { registry = "https://pypi.org/simple" }
94
+ dependencies = [
95
+ { name = "anyio" },
96
+ { name = "certifi" },
97
+ { name = "httpcore" },
98
+ { name = "idna" },
99
+ ]
100
+ sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406 }
101
+ wheels = [
102
+ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517 },
103
+ ]
104
+
105
+ [[package]]
106
+ name = "httpx-sse"
107
+ version = "0.4.0"
108
+ source = { registry = "https://pypi.org/simple" }
109
+ sdist = { url = "https://files.pythonhosted.org/packages/4c/60/8f4281fa9bbf3c8034fd54c0e7412e66edbab6bc74c4996bd616f8d0406e/httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721", size = 12624 }
110
+ wheels = [
111
+ { url = "https://files.pythonhosted.org/packages/e1/9b/a181f281f65d776426002f330c31849b86b31fc9d848db62e16f03ff739f/httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f", size = 7819 },
112
+ ]
113
+
114
+ [[package]]
115
+ name = "idna"
116
+ version = "3.10"
117
+ source = { registry = "https://pypi.org/simple" }
118
+ sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 }
119
+ wheels = [
120
+ { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 },
121
+ ]
122
+
123
+ [[package]]
124
+ name = "markdown-it-py"
125
+ version = "3.0.0"
126
+ source = { registry = "https://pypi.org/simple" }
127
+ dependencies = [
128
+ { name = "mdurl" },
129
+ ]
130
+ sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596 }
131
+ wheels = [
132
+ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 },
133
+ ]
134
+
135
+ [[package]]
136
+ name = "mcp"
137
+ version = "1.5.0"
138
+ source = { registry = "https://pypi.org/simple" }
139
+ dependencies = [
140
+ { name = "anyio" },
141
+ { name = "httpx" },
142
+ { name = "httpx-sse" },
143
+ { name = "pydantic" },
144
+ { name = "pydantic-settings" },
145
+ { name = "sse-starlette" },
146
+ { name = "starlette" },
147
+ { name = "uvicorn" },
148
+ ]
149
+ sdist = { url = "https://files.pythonhosted.org/packages/6d/c9/c55764824e893fdebe777ac7223200986a275c3191dba9169f8eb6d7c978/mcp-1.5.0.tar.gz", hash = "sha256:5b2766c05e68e01a2034875e250139839498c61792163a7b221fc170c12f5aa9", size = 159128 }
150
+ wheels = [
151
+ { url = "https://files.pythonhosted.org/packages/c1/d1/3ff566ecf322077d861f1a68a1ff025cad337417bd66ad22a7c6f7dfcfaf/mcp-1.5.0-py3-none-any.whl", hash = "sha256:51c3f35ce93cb702f7513c12406bbea9665ef75a08db909200b07da9db641527", size = 73734 },
152
+ ]
153
+
154
+ [package.optional-dependencies]
155
+ cli = [
156
+ { name = "python-dotenv" },
157
+ { name = "typer" },
158
+ ]
159
+
160
+ [[package]]
161
+ name = "bicscan-mcp"
162
+ version = "0.1.0"
163
+ source = { editable = "." }
164
+ dependencies = [
165
+ { name = "httpx" },
166
+ { name = "mcp", extra = ["cli"] },
167
+ { name = "python-dotenv" },
168
+ ]
169
+
170
+ [package.metadata]
171
+ requires-dist = [
172
+ { name = "httpx", specifier = ">=0.28.1" },
173
+ { name = "mcp", extras = ["cli"], specifier = ">=1.5.0" },
174
+ { name = "python-dotenv", specifier = ">=1.0.1" },
175
+ ]
176
+
177
+ [[package]]
178
+ name = "mdurl"
179
+ version = "0.1.2"
180
+ source = { registry = "https://pypi.org/simple" }
181
+ sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729 }
182
+ wheels = [
183
+ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 },
184
+ ]
185
+
186
+ [[package]]
187
+ name = "pydantic"
188
+ version = "2.10.6"
189
+ source = { registry = "https://pypi.org/simple" }
190
+ dependencies = [
191
+ { name = "annotated-types" },
192
+ { name = "pydantic-core" },
193
+ { name = "typing-extensions" },
194
+ ]
195
+ sdist = { url = "https://files.pythonhosted.org/packages/b7/ae/d5220c5c52b158b1de7ca89fc5edb72f304a70a4c540c84c8844bf4008de/pydantic-2.10.6.tar.gz", hash = "sha256:ca5daa827cce33de7a42be142548b0096bf05a7e7b365aebfa5f8eeec7128236", size = 761681 }
196
+ wheels = [
197
+ { url = "https://files.pythonhosted.org/packages/f4/3c/8cc1cc84deffa6e25d2d0c688ebb80635dfdbf1dbea3e30c541c8cf4d860/pydantic-2.10.6-py3-none-any.whl", hash = "sha256:427d664bf0b8a2b34ff5dd0f5a18df00591adcee7198fbd71981054cef37b584", size = 431696 },
198
+ ]
199
+
200
+ [[package]]
201
+ name = "pydantic-core"
202
+ version = "2.27.2"
203
+ source = { registry = "https://pypi.org/simple" }
204
+ dependencies = [
205
+ { name = "typing-extensions" },
206
+ ]
207
+ sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443 }
208
+ wheels = [
209
+ { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938 },
210
+ { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684 },
211
+ { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169 },
212
+ { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227 },
213
+ { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695 },
214
+ { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662 },
215
+ { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370 },
216
+ { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813 },
217
+ { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287 },
218
+ { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414 },
219
+ { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301 },
220
+ { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685 },
221
+ { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876 },
222
+ { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421 },
223
+ { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998 },
224
+ { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167 },
225
+ { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071 },
226
+ { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244 },
227
+ { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470 },
228
+ { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291 },
229
+ { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613 },
230
+ { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355 },
231
+ { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661 },
232
+ { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261 },
233
+ { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361 },
234
+ { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484 },
235
+ { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102 },
236
+ { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127 },
237
+ { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340 },
238
+ { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900 },
239
+ { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177 },
240
+ { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046 },
241
+ { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386 },
242
+ { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060 },
243
+ { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870 },
244
+ { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822 },
245
+ { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364 },
246
+ { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303 },
247
+ { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064 },
248
+ { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046 },
249
+ { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092 },
250
+ { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709 },
251
+ { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273 },
252
+ { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027 },
253
+ { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888 },
254
+ { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738 },
255
+ { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138 },
256
+ { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025 },
257
+ { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633 },
258
+ { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404 },
259
+ { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130 },
260
+ { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946 },
261
+ { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387 },
262
+ { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453 },
263
+ { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186 },
264
+ { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159 },
265
+ { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331 },
266
+ { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467 },
267
+ { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797 },
268
+ { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839 },
269
+ { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861 },
270
+ { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582 },
271
+ { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985 },
272
+ { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715 },
273
+ ]
274
+
275
+ [[package]]
276
+ name = "pydantic-settings"
277
+ version = "2.8.1"
278
+ source = { registry = "https://pypi.org/simple" }
279
+ dependencies = [
280
+ { name = "pydantic" },
281
+ { name = "python-dotenv" },
282
+ ]
283
+ sdist = { url = "https://files.pythonhosted.org/packages/88/82/c79424d7d8c29b994fb01d277da57b0a9b09cc03c3ff875f9bd8a86b2145/pydantic_settings-2.8.1.tar.gz", hash = "sha256:d5c663dfbe9db9d5e1c646b2e161da12f0d734d422ee56f567d0ea2cee4e8585", size = 83550 }
284
+ wheels = [
285
+ { url = "https://files.pythonhosted.org/packages/0b/53/a64f03044927dc47aafe029c42a5b7aabc38dfb813475e0e1bf71c4a59d0/pydantic_settings-2.8.1-py3-none-any.whl", hash = "sha256:81942d5ac3d905f7f3ee1a70df5dfb62d5569c12f51a5a647defc1c3d9ee2e9c", size = 30839 },
286
+ ]
287
+
288
+ [[package]]
289
+ name = "pygments"
290
+ version = "2.19.1"
291
+ source = { registry = "https://pypi.org/simple" }
292
+ sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581 }
293
+ wheels = [
294
+ { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293 },
295
+ ]
296
+
297
+ [[package]]
298
+ name = "python-dotenv"
299
+ version = "1.0.1"
300
+ source = { registry = "https://pypi.org/simple" }
301
+ sdist = { url = "https://files.pythonhosted.org/packages/bc/57/e84d88dfe0aec03b7a2d4327012c1627ab5f03652216c63d49846d7a6c58/python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca", size = 39115 }
302
+ wheels = [
303
+ { url = "https://files.pythonhosted.org/packages/6a/3e/b68c118422ec867fa7ab88444e1274aa40681c606d59ac27de5a5588f082/python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a", size = 19863 },
304
+ ]
305
+
306
+ [[package]]
307
+ name = "rich"
308
+ version = "13.9.4"
309
+ source = { registry = "https://pypi.org/simple" }
310
+ dependencies = [
311
+ { name = "markdown-it-py" },
312
+ { name = "pygments" },
313
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
314
+ ]
315
+ sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149 }
316
+ wheels = [
317
+ { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424 },
318
+ ]
319
+
320
+ [[package]]
321
+ name = "shellingham"
322
+ version = "1.5.4"
323
+ source = { registry = "https://pypi.org/simple" }
324
+ sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310 }
325
+ wheels = [
326
+ { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755 },
327
+ ]
328
+
329
+ [[package]]
330
+ name = "sniffio"
331
+ version = "1.3.1"
332
+ source = { registry = "https://pypi.org/simple" }
333
+ sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372 }
334
+ wheels = [
335
+ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235 },
336
+ ]
337
+
338
+ [[package]]
339
+ name = "sse-starlette"
340
+ version = "2.2.1"
341
+ source = { registry = "https://pypi.org/simple" }
342
+ dependencies = [
343
+ { name = "anyio" },
344
+ { name = "starlette" },
345
+ ]
346
+ sdist = { url = "https://files.pythonhosted.org/packages/71/a4/80d2a11af59fe75b48230846989e93979c892d3a20016b42bb44edb9e398/sse_starlette-2.2.1.tar.gz", hash = "sha256:54470d5f19274aeed6b2d473430b08b4b379ea851d953b11d7f1c4a2c118b419", size = 17376 }
347
+ wheels = [
348
+ { url = "https://files.pythonhosted.org/packages/d9/e0/5b8bd393f27f4a62461c5cf2479c75a2cc2ffa330976f9f00f5f6e4f50eb/sse_starlette-2.2.1-py3-none-any.whl", hash = "sha256:6410a3d3ba0c89e7675d4c273a301d64649c03a5ef1ca101f10b47f895fd0e99", size = 10120 },
349
+ ]
350
+
351
+ [[package]]
352
+ name = "starlette"
353
+ version = "0.46.1"
354
+ source = { registry = "https://pypi.org/simple" }
355
+ dependencies = [
356
+ { name = "anyio" },
357
+ ]
358
+ sdist = { url = "https://files.pythonhosted.org/packages/04/1b/52b27f2e13ceedc79a908e29eac426a63465a1a01248e5f24aa36a62aeb3/starlette-0.46.1.tar.gz", hash = "sha256:3c88d58ee4bd1bb807c0d1acb381838afc7752f9ddaec81bbe4383611d833230", size = 2580102 }
359
+ wheels = [
360
+ { url = "https://files.pythonhosted.org/packages/a0/4b/528ccf7a982216885a1ff4908e886b8fb5f19862d1962f56a3fce2435a70/starlette-0.46.1-py3-none-any.whl", hash = "sha256:77c74ed9d2720138b25875133f3a2dae6d854af2ec37dceb56aef370c1d8a227", size = 71995 },
361
+ ]
362
+
363
+ [[package]]
364
+ name = "typer"
365
+ version = "0.15.2"
366
+ source = { registry = "https://pypi.org/simple" }
367
+ dependencies = [
368
+ { name = "click" },
369
+ { name = "rich" },
370
+ { name = "shellingham" },
371
+ { name = "typing-extensions" },
372
+ ]
373
+ sdist = { url = "https://files.pythonhosted.org/packages/8b/6f/3991f0f1c7fcb2df31aef28e0594d8d54b05393a0e4e34c65e475c2a5d41/typer-0.15.2.tar.gz", hash = "sha256:ab2fab47533a813c49fe1f16b1a370fd5819099c00b119e0633df65f22144ba5", size = 100711 }
374
+ wheels = [
375
+ { url = "https://files.pythonhosted.org/packages/7f/fc/5b29fea8cee020515ca82cc68e3b8e1e34bb19a3535ad854cac9257b414c/typer-0.15.2-py3-none-any.whl", hash = "sha256:46a499c6107d645a9c13f7ee46c5d5096cae6f5fc57dd11eccbbb9ae3e44ddfc", size = 45061 },
376
+ ]
377
+
378
+ [[package]]
379
+ name = "typing-extensions"
380
+ version = "4.12.2"
381
+ source = { registry = "https://pypi.org/simple" }
382
+ sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 }
383
+ wheels = [
384
+ { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 },
385
+ ]
386
+
387
+ [[package]]
388
+ name = "uvicorn"
389
+ version = "0.34.0"
390
+ source = { registry = "https://pypi.org/simple" }
391
+ dependencies = [
392
+ { name = "click" },
393
+ { name = "h11" },
394
+ { name = "typing-extensions", marker = "python_full_version < '3.11'" },
395
+ ]
396
+ sdist = { url = "https://files.pythonhosted.org/packages/4b/4d/938bd85e5bf2edeec766267a5015ad969730bb91e31b44021dfe8b22df6c/uvicorn-0.34.0.tar.gz", hash = "sha256:404051050cd7e905de2c9a7e61790943440b3416f49cb409f965d9dcd0fa73e9", size = 76568 }
397
+ wheels = [
398
+ { url = "https://files.pythonhosted.org/packages/61/14/33a3a1352cfa71812a3a21e8c9bfb83f60b0011f5e36f2b1399d51928209/uvicorn-0.34.0-py3-none-any.whl", hash = "sha256:023dc038422502fa28a09c7a30bf2b6991512da7dcdb8fd35fe57cfc154126f4", size = 62315 },
399
+ ]