smartbill-interface 0.1.1__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.
- smartbill_interface-0.1.1/.gitignore +29 -0
- smartbill_interface-0.1.1/BUILD.md +27 -0
- smartbill_interface-0.1.1/PKG-INFO +108 -0
- smartbill_interface-0.1.1/README.md +97 -0
- smartbill_interface-0.1.1/pyproject.toml +22 -0
- smartbill_interface-0.1.1/requirements.txt +4 -0
- smartbill_interface-0.1.1/src/smartbillinterface/__init__.py +1 -0
- smartbill_interface-0.1.1/src/smartbillinterface/main.py +93 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
ENV/
|
|
16
|
+
|
|
17
|
+
# IDE
|
|
18
|
+
.idea/
|
|
19
|
+
.vscode/
|
|
20
|
+
*.swp
|
|
21
|
+
*.swo
|
|
22
|
+
|
|
23
|
+
# Environment variables
|
|
24
|
+
.env
|
|
25
|
+
.env.*
|
|
26
|
+
|
|
27
|
+
# OS
|
|
28
|
+
.DS_Store
|
|
29
|
+
Thumbs.db
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# SmartBill Interface
|
|
2
|
+
|
|
3
|
+
## Build and Publish
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
uv build
|
|
7
|
+
|
|
8
|
+
#test publish
|
|
9
|
+
uv publish --token xxxxTESTxxxxxxx --publish-url https://test.pypi.org/legacy/
|
|
10
|
+
uvx --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ smartbill-interface
|
|
11
|
+
|
|
12
|
+
#publish
|
|
13
|
+
uv publish --token xxxxxxxxxxxxxxx
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Run Locally
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
uvx --from . smartbill-interface
|
|
20
|
+
|
|
21
|
+
#or
|
|
22
|
+
|
|
23
|
+
uvx --from /mnt/c/projects/smartbill-mcp-server smartbill-interface
|
|
24
|
+
|
|
25
|
+
#or run from wheel file
|
|
26
|
+
uvx --from ./dist/smartbill_interface-0.1.1-py3-none-any.whl smartbill-interface
|
|
27
|
+
```
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: smartbill-interface
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: MCP server for interfacing with smartbill.ro for conducting financial operations
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Requires-Dist: fastmcp>=2.14.5
|
|
7
|
+
Requires-Dist: requests>=2.32.5
|
|
8
|
+
Requires-Dist: starlette>=0.52.1
|
|
9
|
+
Requires-Dist: uvicorn>=0.40.0
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# SmartBill Interface MCP Server
|
|
13
|
+
|
|
14
|
+
MCP server for interfacing with smartbill.ro for conducting financial operations.
|
|
15
|
+
|
|
16
|
+
## MCP Server - Stdio
|
|
17
|
+
|
|
18
|
+
### Run
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
export SMARTBILL_USERNAME="myname@mycompany.ro"
|
|
22
|
+
export SMARTBILL_TOKEN="xxxxxxxxxxxxxx"
|
|
23
|
+
uvx smartbill-interface
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Use from Claude Code
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"smartbill-interface": {
|
|
31
|
+
"type": "stdio",
|
|
32
|
+
"command": "uvx",
|
|
33
|
+
"args": [
|
|
34
|
+
"smartbill-interface"
|
|
35
|
+
]
|
|
36
|
+
"env": {
|
|
37
|
+
"SMARTBILL_USERNAME": "${SMARTBILL_USERNAME}",
|
|
38
|
+
"SMARTBILL_TOKEN": "${SMARTBILL_TOKEN}"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Before running `claude`, export the 2 environment variables with the real values for your smartbill account:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
export SMARTBILL_USERNAME="myname@mycompany.ro"
|
|
48
|
+
export SMARTBILL_TOKEN="xxxxxxxxxxxxxx"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
#### Sample Prompt 1
|
|
52
|
+
|
|
53
|
+
`Get the payment status for a bill with CIF RO39999999, series XX2025, number 0003`
|
|
54
|
+
|
|
55
|
+
Response:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
● smartbill-interface - _get_payment_status (MCP)(cif: "RO39999999", series: "XX2025", number: "0003")
|
|
59
|
+
|
|
60
|
+
● Here's the payment status for the bill:
|
|
61
|
+
|
|
62
|
+
┌───────────────┬────────┐
|
|
63
|
+
│ Field │ Amount │
|
|
64
|
+
├───────────────┼────────┤
|
|
65
|
+
│ Total Amount │ 111.62 │
|
|
66
|
+
├───────────────┼────────┤
|
|
67
|
+
│ Paid Amount │ 0.00 │
|
|
68
|
+
├───────────────┼────────┤
|
|
69
|
+
│ Unpaid Amount │ 111.62 │
|
|
70
|
+
└───────────────┴────────┘
|
|
71
|
+
|
|
72
|
+
The bill (series XX2025, number 0003, CIF RO39999999) is fully unpaid — no payments have been recorded against the total of 111.62.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Sample Prompt 2
|
|
76
|
+
|
|
77
|
+
`Get the bill with CIF RO39999999, series XX2025, number 0003`
|
|
78
|
+
|
|
79
|
+
Response:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
smartbill-interface - _get_bill (MCP)(cif: "RO39999999", series: "XX2025", number: "0003")
|
|
83
|
+
|
|
84
|
+
● The bill was retrieved as a PDF blob. Let me extract and save it as a PDF file for you.
|
|
85
|
+
|
|
86
|
+
● Read 1 file (ctrl+o to expand)
|
|
87
|
+
|
|
88
|
+
● Bash(cat /home/mio/.claude/projects/myproject/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/tool-results/mcp-smartbill-interface-_get_bill-1111111111111.txt | python3 -c…)
|
|
89
|
+
|
|
90
|
+
● The bill has been saved as bill_XX2025_0003.pdf (59 KB) in your working directory (/myproject/). You can open it directly from there.
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Test
|
|
94
|
+
|
|
95
|
+
Test using MCP Inspector UI:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npx @modelcontextprotocol/inspector uvx smartbill-interface
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Test from the command line:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npx @modelcontextprotocol/inspector --cli --method tools/list uvx smartbill-interface | jq -r .tools.[].name
|
|
105
|
+
|
|
106
|
+
_get_payment_status
|
|
107
|
+
_get_bill
|
|
108
|
+
```
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# SmartBill Interface MCP Server
|
|
2
|
+
|
|
3
|
+
MCP server for interfacing with smartbill.ro for conducting financial operations.
|
|
4
|
+
|
|
5
|
+
## MCP Server - Stdio
|
|
6
|
+
|
|
7
|
+
### Run
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
export SMARTBILL_USERNAME="myname@mycompany.ro"
|
|
11
|
+
export SMARTBILL_TOKEN="xxxxxxxxxxxxxx"
|
|
12
|
+
uvx smartbill-interface
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
### Use from Claude Code
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
"mcpServers": {
|
|
19
|
+
"smartbill-interface": {
|
|
20
|
+
"type": "stdio",
|
|
21
|
+
"command": "uvx",
|
|
22
|
+
"args": [
|
|
23
|
+
"smartbill-interface"
|
|
24
|
+
]
|
|
25
|
+
"env": {
|
|
26
|
+
"SMARTBILL_USERNAME": "${SMARTBILL_USERNAME}",
|
|
27
|
+
"SMARTBILL_TOKEN": "${SMARTBILL_TOKEN}"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Before running `claude`, export the 2 environment variables with the real values for your smartbill account:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
export SMARTBILL_USERNAME="myname@mycompany.ro"
|
|
37
|
+
export SMARTBILL_TOKEN="xxxxxxxxxxxxxx"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Sample Prompt 1
|
|
41
|
+
|
|
42
|
+
`Get the payment status for a bill with CIF RO39999999, series XX2025, number 0003`
|
|
43
|
+
|
|
44
|
+
Response:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
● smartbill-interface - _get_payment_status (MCP)(cif: "RO39999999", series: "XX2025", number: "0003")
|
|
48
|
+
|
|
49
|
+
● Here's the payment status for the bill:
|
|
50
|
+
|
|
51
|
+
┌───────────────┬────────┐
|
|
52
|
+
│ Field │ Amount │
|
|
53
|
+
├───────────────┼────────┤
|
|
54
|
+
│ Total Amount │ 111.62 │
|
|
55
|
+
├───────────────┼────────┤
|
|
56
|
+
│ Paid Amount │ 0.00 │
|
|
57
|
+
├───────────────┼────────┤
|
|
58
|
+
│ Unpaid Amount │ 111.62 │
|
|
59
|
+
└───────────────┴────────┘
|
|
60
|
+
|
|
61
|
+
The bill (series XX2025, number 0003, CIF RO39999999) is fully unpaid — no payments have been recorded against the total of 111.62.
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Sample Prompt 2
|
|
65
|
+
|
|
66
|
+
`Get the bill with CIF RO39999999, series XX2025, number 0003`
|
|
67
|
+
|
|
68
|
+
Response:
|
|
69
|
+
|
|
70
|
+
```
|
|
71
|
+
smartbill-interface - _get_bill (MCP)(cif: "RO39999999", series: "XX2025", number: "0003")
|
|
72
|
+
|
|
73
|
+
● The bill was retrieved as a PDF blob. Let me extract and save it as a PDF file for you.
|
|
74
|
+
|
|
75
|
+
● Read 1 file (ctrl+o to expand)
|
|
76
|
+
|
|
77
|
+
● Bash(cat /home/mio/.claude/projects/myproject/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/tool-results/mcp-smartbill-interface-_get_bill-1111111111111.txt | python3 -c…)
|
|
78
|
+
|
|
79
|
+
● The bill has been saved as bill_XX2025_0003.pdf (59 KB) in your working directory (/myproject/). You can open it directly from there.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Test
|
|
83
|
+
|
|
84
|
+
Test using MCP Inspector UI:
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npx @modelcontextprotocol/inspector uvx smartbill-interface
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Test from the command line:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
npx @modelcontextprotocol/inspector --cli --method tools/list uvx smartbill-interface | jq -r .tools.[].name
|
|
94
|
+
|
|
95
|
+
_get_payment_status
|
|
96
|
+
_get_bill
|
|
97
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "smartbill-interface"
|
|
3
|
+
version = "0.1.1"
|
|
4
|
+
description = "MCP server for interfacing with smartbill.ro for conducting financial operations"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"fastmcp>=2.14.5",
|
|
9
|
+
"starlette>=0.52.1",
|
|
10
|
+
"uvicorn>=0.40.0",
|
|
11
|
+
"requests>=2.32.5",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
[project.scripts]
|
|
15
|
+
smartbill-interface = "smartbillinterface.main:main"
|
|
16
|
+
|
|
17
|
+
[build-system]
|
|
18
|
+
requires = ["hatchling"]
|
|
19
|
+
build-backend = "hatchling.build"
|
|
20
|
+
|
|
21
|
+
[tool.hatch.build.targets.wheel]
|
|
22
|
+
packages = ["src/smartbillinterface"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""SmartBill Interface MCP Server - Interfacing with smartbill.ro for conducting financial operations."""
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
#MCP server for interfacing with smartbill.ro for conducting financial operations
|
|
3
|
+
from urllib.request import urlopen, Request
|
|
4
|
+
from urllib.error import HTTPError
|
|
5
|
+
import mcp.server.fastmcp
|
|
6
|
+
import mcp.types
|
|
7
|
+
import logging
|
|
8
|
+
import xml.etree.ElementTree as ET
|
|
9
|
+
import os
|
|
10
|
+
import base64
|
|
11
|
+
|
|
12
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
SMARTBILL_BASE_URL = "https://ws.smartbill.ro/SBORO/api"
|
|
16
|
+
SMARTBILL_BILL_ID = "cif={cif}&seriesname={series}&number={number}"
|
|
17
|
+
SMARTBILL_PAYMENT_STATUS_URL = SMARTBILL_BASE_URL + "/invoice/paymentstatus?" + SMARTBILL_BILL_ID
|
|
18
|
+
SMARTBILL_GET_BILL_URL = SMARTBILL_BASE_URL + "/invoice/pdf?" + SMARTBILL_BILL_ID
|
|
19
|
+
|
|
20
|
+
def _build_auth() -> str:
|
|
21
|
+
username = os.environ["SMARTBILL_USERNAME"]
|
|
22
|
+
token = os.environ["SMARTBILL_TOKEN"]
|
|
23
|
+
return base64.b64encode(f"{username}:{token}".encode()).decode()
|
|
24
|
+
|
|
25
|
+
mymcp = mcp.server.fastmcp.FastMCP("SmartBill Interface Server")
|
|
26
|
+
|
|
27
|
+
@mymcp.tool()
|
|
28
|
+
def _get_payment_status(cif: str, series: str, number: str) -> tuple[float, float, float]:
|
|
29
|
+
"""Get the payment status for a bill.
|
|
30
|
+
|
|
31
|
+
Returns total amount, paid amount and unpaid amount.
|
|
32
|
+
"""
|
|
33
|
+
logger.debug(f"_get_payment_status for bill with cif: {cif}, series: {series} and number: {number}")
|
|
34
|
+
url = SMARTBILL_PAYMENT_STATUS_URL.format(cif=cif, series=series, number=number)
|
|
35
|
+
req = Request(url, headers={
|
|
36
|
+
"Content-Type": "application/xml",
|
|
37
|
+
"Accept": "application/xml",
|
|
38
|
+
"Authorization": f"Basic {_build_auth()}",
|
|
39
|
+
})
|
|
40
|
+
try:
|
|
41
|
+
with urlopen(req) as response:
|
|
42
|
+
xml_data = response.read()
|
|
43
|
+
logger.debug(f"Received answer: {xml_data}")
|
|
44
|
+
root = ET.fromstring(xml_data)
|
|
45
|
+
total_amount = float(root.findtext("invoiceTotalAmount"))
|
|
46
|
+
logger.debug(f"Answer contains total amount: {total_amount}")
|
|
47
|
+
paid_amount = float(root.findtext("paidAmount"))
|
|
48
|
+
logger.debug(f"Answer contains paid amount: {paid_amount}")
|
|
49
|
+
unpaid_amount = float(root.findtext("unpaidAmount"))
|
|
50
|
+
logger.debug(f"Answer contains unpaid amount: {unpaid_amount}")
|
|
51
|
+
return total_amount, paid_amount, unpaid_amount
|
|
52
|
+
except HTTPError as e:
|
|
53
|
+
logger.error(f"HTTP error {e.code} for URL {url}: {e.reason}")
|
|
54
|
+
raise
|
|
55
|
+
|
|
56
|
+
@mymcp.tool()
|
|
57
|
+
def _get_bill(cif: str, series: str, number: str) -> mcp.types.BlobResourceContents:
|
|
58
|
+
"""Get a bill.
|
|
59
|
+
|
|
60
|
+
Returns the bill in PDF format as a blob.
|
|
61
|
+
"""
|
|
62
|
+
logger.debug(f"_get_bill for bill with cif: {cif}, series: {series} and number: {number}")
|
|
63
|
+
url = SMARTBILL_GET_BILL_URL.format(cif=cif, series=series, number=number)
|
|
64
|
+
req = Request(url, headers={
|
|
65
|
+
"Content-Type": "application/xml",
|
|
66
|
+
"Accept": "application/xml",
|
|
67
|
+
"Accept": "application/octet-stream",
|
|
68
|
+
"Authorization": f"Basic {_build_auth()}",
|
|
69
|
+
"Content-Disposition": "attachment; filename=\"bill.pdf\"",
|
|
70
|
+
})
|
|
71
|
+
try:
|
|
72
|
+
with urlopen(req) as response:
|
|
73
|
+
bill = response.read()
|
|
74
|
+
logger.debug(f"Received {len(bill)} bytes")
|
|
75
|
+
return mcp.types.BlobResourceContents(
|
|
76
|
+
uri=url,
|
|
77
|
+
blob=base64.b64encode(bill).decode(),
|
|
78
|
+
mimeType="application/pdf",
|
|
79
|
+
)
|
|
80
|
+
except HTTPError as e:
|
|
81
|
+
logger.error(f"HTTP error {e.code} for URL {url}: {e.reason}")
|
|
82
|
+
raise
|
|
83
|
+
|
|
84
|
+
def main():
|
|
85
|
+
"""Entry point for the SmartBill MCP server."""
|
|
86
|
+
missing = [v for v in ("SMARTBILL_USERNAME", "SMARTBILL_TOKEN") if not os.environ.get(v)]
|
|
87
|
+
if missing:
|
|
88
|
+
logger.error(f"Missing required environment variables: {', '.join(missing)}")
|
|
89
|
+
return
|
|
90
|
+
mymcp.run(transport="stdio")
|
|
91
|
+
|
|
92
|
+
if __name__ == "__main__":
|
|
93
|
+
main()
|