alix-graphql-mcp-knowledge-base-tool 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.
- alix_graphql_mcp_knowledge_base_tool-0.1.0/PKG-INFO +10 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/pyproject.toml +22 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/setup.cfg +4 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool/__init__.py +12 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool/__main__.py +6 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool/mcp_server.py +373 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool.egg-info/PKG-INFO +10 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool.egg-info/SOURCES.txt +10 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool.egg-info/dependency_links.txt +1 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool.egg-info/entry_points.txt +2 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool.egg-info/requires.txt +6 -0
- alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alix-graphql-mcp-knowledge-base-tool
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Knowledge Base MCP tool for Alix GraphQL. Fetches institution marshaling plans.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: mcp>=1.9.0
|
|
7
|
+
Requires-Dist: httpx>=0.27
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: build; extra == "dev"
|
|
10
|
+
Requires-Dist: twine; extra == "dev"
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "alix-graphql-mcp-knowledge-base-tool"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Knowledge Base MCP tool for Alix GraphQL. Fetches institution marshaling plans."
|
|
9
|
+
requires-python = ">=3.11"
|
|
10
|
+
dependencies = [
|
|
11
|
+
"mcp>=1.9.0",
|
|
12
|
+
"httpx>=0.27",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
[project.optional-dependencies]
|
|
16
|
+
dev = ["build", "twine"]
|
|
17
|
+
|
|
18
|
+
[project.scripts]
|
|
19
|
+
alix-graphql-mcp-knowledge-base-tool = "alix_graphql_mcp_knowledge_base_tool.mcp_server:main"
|
|
20
|
+
|
|
21
|
+
[tool.setuptools.packages.find]
|
|
22
|
+
where = ["src"]
|
alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool/__init__.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|
|
2
|
+
|
|
3
|
+
from alix_graphql_mcp_knowledge_base_tool.mcp_server import (
|
|
4
|
+
run_get_institution_marshaling_plan,
|
|
5
|
+
run_get_institution_marshaling_plans,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"__version__",
|
|
10
|
+
"run_get_institution_marshaling_plan",
|
|
11
|
+
"run_get_institution_marshaling_plans",
|
|
12
|
+
]
|
alix_graphql_mcp_knowledge_base_tool-0.1.0/src/alix_graphql_mcp_knowledge_base_tool/mcp_server.py
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"""Knowledge Base MCP server for institution marshaling plans.
|
|
2
|
+
|
|
3
|
+
Env vars:
|
|
4
|
+
ALIX_API_URL required. Base URL (e.g. http://localhost:8080) or full
|
|
5
|
+
/graphql URL.
|
|
6
|
+
ALIX_API_KEY required. Master token sent as the Authorization header.
|
|
7
|
+
ALIX_GRAPHQL_TIMEOUT optional. Request timeout in seconds (default 30).
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import json
|
|
13
|
+
import os
|
|
14
|
+
from typing import Any, Literal
|
|
15
|
+
|
|
16
|
+
import httpx
|
|
17
|
+
from mcp.server.fastmcp import FastMCP
|
|
18
|
+
|
|
19
|
+
SERVER_NAME: str = "alix-graphql-mcp-knowledge-base-tool"
|
|
20
|
+
|
|
21
|
+
AssetCategory = Literal[
|
|
22
|
+
"BankAccount",
|
|
23
|
+
"Investment",
|
|
24
|
+
"LifeInsurance",
|
|
25
|
+
"PersonalProperty",
|
|
26
|
+
"RealEstate",
|
|
27
|
+
"Retirement",
|
|
28
|
+
"UnclaimedProperty",
|
|
29
|
+
"Vehicle",
|
|
30
|
+
"Business",
|
|
31
|
+
"Cash",
|
|
32
|
+
"MoneyDueToEstate",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
AssetSubcategory = Literal[
|
|
36
|
+
"Checking",
|
|
37
|
+
"Savings",
|
|
38
|
+
"CD",
|
|
39
|
+
"MoneyMarket",
|
|
40
|
+
"SafetyDepositBox",
|
|
41
|
+
"Trust",
|
|
42
|
+
"IRA",
|
|
43
|
+
"RothIRA",
|
|
44
|
+
"K401",
|
|
45
|
+
"Roth401K",
|
|
46
|
+
"B457",
|
|
47
|
+
"B403",
|
|
48
|
+
"Pension",
|
|
49
|
+
"Annuity",
|
|
50
|
+
"ESOP",
|
|
51
|
+
"Brokerage",
|
|
52
|
+
"Stocks",
|
|
53
|
+
"HSA",
|
|
54
|
+
"PrimaryResidence",
|
|
55
|
+
"VacationHome",
|
|
56
|
+
"ResidentialIncomeProperty",
|
|
57
|
+
"CommercialProperty",
|
|
58
|
+
"UndevelopedParcel",
|
|
59
|
+
"Car",
|
|
60
|
+
"Truck",
|
|
61
|
+
"RV",
|
|
62
|
+
"Boat",
|
|
63
|
+
"Aircraft",
|
|
64
|
+
"Trailer",
|
|
65
|
+
"Motorcycle",
|
|
66
|
+
"SoleProprietorship",
|
|
67
|
+
"Partnership",
|
|
68
|
+
"LLC",
|
|
69
|
+
"Corporation",
|
|
70
|
+
"SCorporation",
|
|
71
|
+
"Income",
|
|
72
|
+
"Refund",
|
|
73
|
+
"Other",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
AssetDesignation = Literal[
|
|
77
|
+
"InTrust",
|
|
78
|
+
"PodTod",
|
|
79
|
+
"Tod",
|
|
80
|
+
"JointOwnership",
|
|
81
|
+
"JointOwnershipWithSurvivorship",
|
|
82
|
+
"JointTenantsWithRightOfSurvivorship",
|
|
83
|
+
"TenancyInCommon",
|
|
84
|
+
"CommunityProperty",
|
|
85
|
+
"InTheEstate",
|
|
86
|
+
"OwnerTransferByOperatingAgreement",
|
|
87
|
+
"Unknown",
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
_MARSHALING_PLAN_SELECTION = """
|
|
91
|
+
id
|
|
92
|
+
createdAt
|
|
93
|
+
updatedAt
|
|
94
|
+
deletedAt
|
|
95
|
+
institutionId
|
|
96
|
+
assetCategory
|
|
97
|
+
assetDesignation
|
|
98
|
+
assetSubcategory
|
|
99
|
+
contactPhone
|
|
100
|
+
faxNumber
|
|
101
|
+
businessHours
|
|
102
|
+
submissionMethods
|
|
103
|
+
submissionInstructions
|
|
104
|
+
onlinePortalUrl
|
|
105
|
+
typicalProcessingTime
|
|
106
|
+
recommendedFollowUpInterval
|
|
107
|
+
additionalNotes
|
|
108
|
+
metadata
|
|
109
|
+
mailingAddress {
|
|
110
|
+
id
|
|
111
|
+
address
|
|
112
|
+
city
|
|
113
|
+
county
|
|
114
|
+
state
|
|
115
|
+
zip
|
|
116
|
+
country
|
|
117
|
+
}
|
|
118
|
+
steps(orderBy: [{ order: asc }]) {
|
|
119
|
+
id
|
|
120
|
+
order
|
|
121
|
+
title
|
|
122
|
+
description
|
|
123
|
+
config
|
|
124
|
+
}
|
|
125
|
+
forms {
|
|
126
|
+
id
|
|
127
|
+
createdAt
|
|
128
|
+
updatedAt
|
|
129
|
+
name
|
|
130
|
+
description
|
|
131
|
+
isFillable
|
|
132
|
+
fieldMap
|
|
133
|
+
fileId
|
|
134
|
+
}
|
|
135
|
+
requiredDocuments {
|
|
136
|
+
id
|
|
137
|
+
createdAt
|
|
138
|
+
updatedAt
|
|
139
|
+
documentType
|
|
140
|
+
notes
|
|
141
|
+
}
|
|
142
|
+
"""
|
|
143
|
+
|
|
144
|
+
_GET_MARSHALING_PLANS_QUERY = f"""
|
|
145
|
+
query GetInstitutionMarshalingPlans($institutionId: String!) {{
|
|
146
|
+
marshalingPlans(
|
|
147
|
+
where: {{
|
|
148
|
+
institutionId: {{ equals: $institutionId }}
|
|
149
|
+
deletedAt: {{ equals: null }}
|
|
150
|
+
}}
|
|
151
|
+
orderBy: [{{ updatedAt: desc }}]
|
|
152
|
+
) {{
|
|
153
|
+
{_MARSHALING_PLAN_SELECTION}
|
|
154
|
+
}}
|
|
155
|
+
}}
|
|
156
|
+
"""
|
|
157
|
+
|
|
158
|
+
_GET_MARSHALING_PLAN_QUERY = f"""
|
|
159
|
+
query GetInstitutionMarshalingPlan($where: MarshalingPlanWhereInput!) {{
|
|
160
|
+
marshalingPlans(
|
|
161
|
+
where: $where
|
|
162
|
+
orderBy: [{{ updatedAt: desc }}]
|
|
163
|
+
take: 2
|
|
164
|
+
) {{
|
|
165
|
+
{_MARSHALING_PLAN_SELECTION}
|
|
166
|
+
}}
|
|
167
|
+
}}
|
|
168
|
+
"""
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def _resolve_endpoint(raw: str) -> str:
|
|
172
|
+
url = raw.rstrip("/")
|
|
173
|
+
if url.endswith("/graphql"):
|
|
174
|
+
return url
|
|
175
|
+
return f"{url}/graphql"
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _read_timeout() -> float:
|
|
179
|
+
raw = os.environ.get("ALIX_GRAPHQL_TIMEOUT")
|
|
180
|
+
if not raw:
|
|
181
|
+
return 30.0
|
|
182
|
+
try:
|
|
183
|
+
return float(raw)
|
|
184
|
+
except ValueError:
|
|
185
|
+
return 30.0
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
def _graphql_request(
|
|
189
|
+
*,
|
|
190
|
+
query: str,
|
|
191
|
+
variables: dict[str, Any],
|
|
192
|
+
operation_name: str,
|
|
193
|
+
) -> dict[str, Any]:
|
|
194
|
+
api_url_raw = os.environ.get("ALIX_API_URL")
|
|
195
|
+
api_key = os.environ.get("ALIX_API_KEY")
|
|
196
|
+
if not api_url_raw:
|
|
197
|
+
return {"errors": [{"message": "ALIX_API_URL is not set."}]}
|
|
198
|
+
if not api_key:
|
|
199
|
+
return {"errors": [{"message": "ALIX_API_KEY is not set."}]}
|
|
200
|
+
|
|
201
|
+
endpoint = _resolve_endpoint(api_url_raw)
|
|
202
|
+
timeout = _read_timeout()
|
|
203
|
+
|
|
204
|
+
payload: dict[str, Any] = {
|
|
205
|
+
"query": query,
|
|
206
|
+
"variables": variables,
|
|
207
|
+
"operationName": operation_name,
|
|
208
|
+
}
|
|
209
|
+
headers = {
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
"Authorization": api_key,
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
try:
|
|
215
|
+
with httpx.Client(timeout=timeout) as client:
|
|
216
|
+
response = client.post(endpoint, json=payload, headers=headers)
|
|
217
|
+
except httpx.HTTPError as exc:
|
|
218
|
+
return {"errors": [{"message": f"Transport error: {exc.__class__.__name__}: {exc}"}]}
|
|
219
|
+
|
|
220
|
+
text = response.text
|
|
221
|
+
try:
|
|
222
|
+
body: Any = response.json()
|
|
223
|
+
except ValueError:
|
|
224
|
+
body = None
|
|
225
|
+
|
|
226
|
+
if response.is_error:
|
|
227
|
+
if isinstance(body, dict) and ("errors" in body or "data" in body):
|
|
228
|
+
return {
|
|
229
|
+
"data": body.get("data"),
|
|
230
|
+
"errors": body.get("errors")
|
|
231
|
+
or [{"message": f"HTTP {response.status_code}: {text or response.reason_phrase}"}],
|
|
232
|
+
"http_status": response.status_code,
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
"data": None,
|
|
236
|
+
"errors": [{"message": f"HTTP {response.status_code}: {text or response.reason_phrase}"}],
|
|
237
|
+
"http_status": response.status_code,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if not isinstance(body, dict):
|
|
241
|
+
return {
|
|
242
|
+
"data": None,
|
|
243
|
+
"errors": [{"message": f"Non-JSON response from GraphQL endpoint: {text[:500]}"}],
|
|
244
|
+
"http_status": response.status_code,
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
"data": body.get("data"),
|
|
249
|
+
"errors": body.get("errors"),
|
|
250
|
+
"extensions": body.get("extensions"),
|
|
251
|
+
"http_status": response.status_code,
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def _clean_optional_enum(value: str | None) -> str | None:
|
|
256
|
+
if value is None:
|
|
257
|
+
return None
|
|
258
|
+
cleaned = value.strip()
|
|
259
|
+
if not cleaned:
|
|
260
|
+
return None
|
|
261
|
+
return cleaned
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def run_get_institution_marshaling_plans(institutionId: str) -> str:
|
|
265
|
+
if not institutionId or not isinstance(institutionId, str):
|
|
266
|
+
return json.dumps({"errors": [{"message": "institutionId is required."}]})
|
|
267
|
+
|
|
268
|
+
result = _graphql_request(
|
|
269
|
+
query=_GET_MARSHALING_PLANS_QUERY,
|
|
270
|
+
variables={"institutionId": institutionId},
|
|
271
|
+
operation_name="GetInstitutionMarshalingPlans",
|
|
272
|
+
)
|
|
273
|
+
return json.dumps(result, default=str)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def run_get_institution_marshaling_plan(
|
|
277
|
+
institutionId: str,
|
|
278
|
+
assetCategory: AssetCategory,
|
|
279
|
+
assetDesignation: AssetDesignation,
|
|
280
|
+
assetSubcategory: AssetSubcategory | None = None,
|
|
281
|
+
) -> str:
|
|
282
|
+
if not institutionId or not isinstance(institutionId, str):
|
|
283
|
+
return json.dumps({"errors": [{"message": "institutionId is required."}]})
|
|
284
|
+
|
|
285
|
+
where: dict[str, Any] = {
|
|
286
|
+
"institutionId": {"equals": institutionId},
|
|
287
|
+
"deletedAt": {"equals": None},
|
|
288
|
+
"assetCategory": {"equals": assetCategory},
|
|
289
|
+
"assetDesignation": {"equals": assetDesignation},
|
|
290
|
+
}
|
|
291
|
+
cleaned_subcategory = _clean_optional_enum(assetSubcategory)
|
|
292
|
+
if cleaned_subcategory is not None:
|
|
293
|
+
where["assetSubcategory"] = {"equals": cleaned_subcategory}
|
|
294
|
+
|
|
295
|
+
result = _graphql_request(
|
|
296
|
+
query=_GET_MARSHALING_PLAN_QUERY,
|
|
297
|
+
variables={"where": where},
|
|
298
|
+
operation_name="GetInstitutionMarshalingPlan",
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
if result.get("errors"):
|
|
302
|
+
return json.dumps(result, default=str)
|
|
303
|
+
|
|
304
|
+
data = result.get("data") if isinstance(result.get("data"), dict) else {}
|
|
305
|
+
plans = data.get("marshalingPlans") if isinstance(data, dict) else None
|
|
306
|
+
|
|
307
|
+
if not isinstance(plans, list):
|
|
308
|
+
return json.dumps(
|
|
309
|
+
{
|
|
310
|
+
**result,
|
|
311
|
+
"errors": [{"message": "Unexpected GraphQL response: `marshalingPlans` is missing."}],
|
|
312
|
+
},
|
|
313
|
+
default=str,
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if not plans:
|
|
317
|
+
return json.dumps(
|
|
318
|
+
{
|
|
319
|
+
**result,
|
|
320
|
+
"data": {"marshalingPlan": None},
|
|
321
|
+
},
|
|
322
|
+
default=str,
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
if len(plans) > 1:
|
|
326
|
+
return json.dumps(
|
|
327
|
+
{
|
|
328
|
+
**result,
|
|
329
|
+
"data": {"marshalingPlan": None},
|
|
330
|
+
"errors": [
|
|
331
|
+
{
|
|
332
|
+
"message": (
|
|
333
|
+
"Multiple marshaling plans match this filter. "
|
|
334
|
+
"Provide additional filters: assetCategory, assetDesignation, assetSubcategory."
|
|
335
|
+
)
|
|
336
|
+
}
|
|
337
|
+
],
|
|
338
|
+
},
|
|
339
|
+
default=str,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
return json.dumps(
|
|
343
|
+
{
|
|
344
|
+
**result,
|
|
345
|
+
"data": {"marshalingPlan": plans[0]},
|
|
346
|
+
},
|
|
347
|
+
default=str,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def main() -> None:
|
|
352
|
+
mcp = FastMCP(SERVER_NAME)
|
|
353
|
+
|
|
354
|
+
mcp.tool(
|
|
355
|
+
name="getInstitutionMarshalingPlans",
|
|
356
|
+
title="Get institution marshaling plans",
|
|
357
|
+
description=(
|
|
358
|
+
"Fetch all active MarshalingPlan records for an institutionId from the Alix GraphQL API. "
|
|
359
|
+
"Returns raw JSON containing `{data, errors, extensions, http_status}`."
|
|
360
|
+
),
|
|
361
|
+
)(run_get_institution_marshaling_plans)
|
|
362
|
+
|
|
363
|
+
mcp.tool(
|
|
364
|
+
name="getInstitutionMarshalingPlan",
|
|
365
|
+
title="Get one institution marshaling plan",
|
|
366
|
+
description=(
|
|
367
|
+
"Fetch a single active MarshalingPlan for an institutionId with optional filters "
|
|
368
|
+
"(assetCategory, assetDesignation, assetSubcategory). Returns raw JSON containing "
|
|
369
|
+
"`{data, errors, extensions, http_status}` and normalizes the payload to `data.marshalingPlan`."
|
|
370
|
+
),
|
|
371
|
+
)(run_get_institution_marshaling_plan)
|
|
372
|
+
|
|
373
|
+
mcp.run()
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: alix-graphql-mcp-knowledge-base-tool
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Knowledge Base MCP tool for Alix GraphQL. Fetches institution marshaling plans.
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: mcp>=1.9.0
|
|
7
|
+
Requires-Dist: httpx>=0.27
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: build; extra == "dev"
|
|
10
|
+
Requires-Dist: twine; extra == "dev"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
pyproject.toml
|
|
2
|
+
src/alix_graphql_mcp_knowledge_base_tool/__init__.py
|
|
3
|
+
src/alix_graphql_mcp_knowledge_base_tool/__main__.py
|
|
4
|
+
src/alix_graphql_mcp_knowledge_base_tool/mcp_server.py
|
|
5
|
+
src/alix_graphql_mcp_knowledge_base_tool.egg-info/PKG-INFO
|
|
6
|
+
src/alix_graphql_mcp_knowledge_base_tool.egg-info/SOURCES.txt
|
|
7
|
+
src/alix_graphql_mcp_knowledge_base_tool.egg-info/dependency_links.txt
|
|
8
|
+
src/alix_graphql_mcp_knowledge_base_tool.egg-info/entry_points.txt
|
|
9
|
+
src/alix_graphql_mcp_knowledge_base_tool.egg-info/requires.txt
|
|
10
|
+
src/alix_graphql_mcp_knowledge_base_tool.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
alix_graphql_mcp_knowledge_base_tool
|