-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpython-client.py
More file actions
157 lines (115 loc) · 5.57 KB
/
Copy pathpython-client.py
File metadata and controls
157 lines (115 loc) · 5.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
"""
FundOS MCP — Python client example
Requires: httpx (pip install httpx)
Get a token: https://kela.com/oauth/authorize?client_id=mcp-generic
Or use an API key from: https://kela.com/admin/api-keys
"""
import hashlib
import hmac
import json
import httpx
FUNDOS_MCP_URL = "https://kela.com/mcp"
FUNDOS_API_URL = "https://kela.com/api/v1"
ACCESS_TOKEN = "your-oauth-token-here" # or vdr_<api-key>
headers = {
"Authorization": f"Bearer {ACCESS_TOKEN}",
"Content-Type": "application/json",
}
# ── Webhook helpers ────────────────────────────────────────────────────────────
def verify_fundos_signature(raw_body: bytes, signature_header: str, secret: str) -> bool:
"""Verify an inbound X-FundOS-Signature header on your receiving endpoint."""
expected = "sha256=" + hmac.new(
secret.encode("utf-8"), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected.encode(), signature_header.encode())
def register_webhook(url: str, event_types: list | None = None, name: str = "") -> dict:
"""Register a webhook endpoint. Returns the endpoint record (including secret)."""
resp = httpx.post(
f"{FUNDOS_API_URL}/webhooks/",
headers=headers,
json={"url": url, "name": name, "event_types": event_types},
timeout=15,
)
resp.raise_for_status()
return resp.json()
def list_webhooks() -> list:
resp = httpx.get(f"{FUNDOS_API_URL}/webhooks/", headers=headers, timeout=15)
resp.raise_for_status()
return resp.json()
def webhook_deliveries(endpoint_id: int, page: int = 1) -> dict:
resp = httpx.get(
f"{FUNDOS_API_URL}/webhooks/{endpoint_id}/deliveries",
headers=headers,
params={"page": page},
timeout=15,
)
resp.raise_for_status()
return resp.json()
# ── Example: register and handle webhooks ─────────────────────────────────────
# 1. Register an endpoint (run once, save the returned secret securely)
# endpoint = register_webhook(
# url="https://my-agent.example.com/hooks/fundos",
# event_types=["credit.low", "action.approval_required", "action.approved"],
# name="My agent listener",
# )
# MY_WEBHOOK_SECRET = endpoint["secret"] # SAVE THIS — only shown at creation
# 2. In your Flask/FastAPI receiver:
#
# @app.post("/hooks/fundos")
# def receive(request: Request):
# raw = request.body()
# sig = request.headers.get("X-FundOS-Signature", "")
# if not verify_fundos_signature(raw, sig, MY_WEBHOOK_SECRET):
# raise HTTPException(401)
# event = json.loads(raw)
# delivery_id = event["delivery_id"] # stable UUID across retries — deduplicate here
# print(f"Received {event['event']} delivery_id={delivery_id}")
# return {"ok": True}
def call_tool(name: str, arguments: dict = None) -> dict:
response = httpx.post(
f"{FUNDOS_MCP_URL}/message",
headers=headers,
json={
"jsonrpc": "2.0",
"method": "tools/call",
"params": {"name": name, "arguments": arguments or {}},
"id": 1,
},
timeout=30,
)
response.raise_for_status()
return response.json()
# ── Deal pipeline ─────────────────────────────────────────────────────────────
pipeline = call_tool("fundos_get_pipeline")
print("Pipeline:", pipeline)
diligence_deals = call_tool("fundos_list_deals", {"stage": "diligence"})
print("In diligence:", diligence_deals)
# ── Risk ──────────────────────────────────────────────────────────────────────
alerts = call_tool("fundos_list_risk_alerts", {"open": True})
print("Open risk alerts:", alerts)
covenants = call_tool("fundos_list_covenants")
print("Covenants:", covenants)
# ── LP investors ──────────────────────────────────────────────────────────────
lps = call_tool("fundos_list_lps")
print("LPs:", lps)
# ── Documents (VDR) ───────────────────────────────────────────────────────────
rooms = call_tool("list_deal_rooms")
print("Deal rooms:", rooms)
# Search across all documents in a room
answer = call_tool("search_documents", {
"query": "what are the transfer restrictions in the LPA?",
})
print("Document search:", answer)
# ── Waterfall modelling ───────────────────────────────────────────────────────
waterfall = call_tool("fundos_compute_waterfall", {
"distributable": 50_000_000,
"committed": 20_000_000,
"hurdle_pct": 0.08,
"carry_pct": 0.20,
})
print("Waterfall:", waterfall)
# ── DTCC / HF Ops ─────────────────────────────────────────────────────────────
scorecard = call_tool("hf_ops_dtcc_get_affirmation_scorecard")
print("T+0 scorecard:", scorecard)
unaffirmed = call_tool("hf_ops_dtcc_list_unaffirmed")
print("Unaffirmed confirms:", unaffirmed)