ApiLogicServer 15.0.0__py3-none-any.whl → 15.0.9__py3-none-any.whl
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.
- api_logic_server_cli/add_cust/add_cust.py +8 -2
- api_logic_server_cli/api_logic_server.py +2 -1
- api_logic_server_cli/api_logic_server_info.yaml +3 -3
- api_logic_server_cli/create_from_model/__pycache__/dbml.cpython-312.pyc +0 -0
- api_logic_server_cli/create_from_model/dbml.py +1 -0
- api_logic_server_cli/genai/genai_svcs.py +5 -2
- api_logic_server_cli/prototypes/base/api/api_discovery/mcp_discovery.py +63 -24
- api_logic_server_cli/prototypes/base/config/logging.yml +5 -0
- api_logic_server_cli/prototypes/base/config/server_setup.py +73 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_discovery_response.json +150 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_request.prompt +46 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response.json +34 -0
- api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response_get.json +18 -0
- api_logic_server_cli/prototypes/base/integration/mcp/mcp_client_executor.py +129 -275
- api_logic_server_cli/prototypes/basic_demo/customizations/logic/logic_discovery/mcp_client_executor_request.py +11 -282
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/admin.yaml +3 -3
- api_logic_server_cli/prototypes/basic_demo/customizations/ui/admin/home.js +48 -0
- api_logic_server_cli/prototypes/manager/system/genai/mcp_learning/mcp.prompt +12 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/METADATA +1 -1
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/RECORD +25 -31
- api_logic_server_cli/prototypes/base/integration/mcp/README_mcp.md +0 -15
- api_logic_server_cli/prototypes/base/integration/mcp/test_notes.txt +0 -37
- api_logic_server_cli/prototypes/basic_demo/customizations/api/api_discovery/mcp_discovery.py +0 -96
- api_logic_server_cli/prototypes/basic_demo/customizations/config/server_setup.py +0 -388
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/.DS_Store +0 -0
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/README_mcp.md +0 -15
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/Zmcp_client_executor.py +0 -294
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_schema.txt +0 -47
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_server_discovery.json +0 -9
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/mcp_tool_context.json +0 -25
- api_logic_server_cli/prototypes/basic_demo/customizations/integration/mcp/test_notes.txt +0 -37
- /api_logic_server_cli/prototypes/base/integration/mcp/{mcp_schema.txt → examples/mcp_schema.txt} +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/WHEEL +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/entry_points.txt +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/licenses/LICENSE +0 -0
- {apilogicserver-15.0.0.dist-info → apilogicserver-15.0.9.dist-info}/top_level.txt +0 -0
|
@@ -148,9 +148,15 @@ def add_basic_demo_customizations(project: Project, do_show_messages: bool = Tru
|
|
|
148
148
|
|
|
149
149
|
if do_show_messages:
|
|
150
150
|
log.info("\nExplore key customization files:")
|
|
151
|
-
log.info(
|
|
151
|
+
log.info('\033[94m\033[1m..logic/declare_logic.py\033[0m')
|
|
152
152
|
log.info(f'..security/declare_security.py\n')
|
|
153
|
-
|
|
153
|
+
# Make the message blue, bold, and add an attention-getting icon
|
|
154
|
+
log.info('\033[94m\033[1m🔷 Explore MCP (Model Context Protocol): https://apilogicserver.github.io/Docs/Integration-MCP/\033[0m\n')
|
|
155
|
+
log.info('.. restart the server')
|
|
156
|
+
log.info('python integration/mcp/mcp_client_executor.py mcp')
|
|
157
|
+
# log.info(".. Copy/paste this into your terminal (Mac/Linux):")
|
|
158
|
+
# log.info(".. curl -X 'POST' 'http://localhost:5656/api/SysMcp/' -H 'accept: application/vnd.api+json' -H 'Content-Type: application/json' -d '{ \"data\": { \"attributes\": {\"request\": \"List the orders date_shipped is null and CreatedOn before 2023-07-14, and send a discount email (subject: '\\''Discount Offer'\\'') to the customer for each one.\"}, \"type\": \"SysMcp\"}}'")
|
|
159
|
+
log.info('')
|
|
154
160
|
log.info(f'Next Steps: activate security')
|
|
155
161
|
log.info(f'..ApiLogicServer add-auth --db_url=auth')
|
|
156
162
|
if project.is_tutorial == False:
|
|
@@ -12,9 +12,10 @@ ApiLogicServer CLI: given a database url, create [and run] customizable ApiLogic
|
|
|
12
12
|
Called from api_logic_server_cli.py, by instantiating the ProjectRun object.
|
|
13
13
|
'''
|
|
14
14
|
|
|
15
|
-
__version__ = "15.00.
|
|
15
|
+
__version__ = "15.00.09" # last public release: 15.00.00 (14.05.04)
|
|
16
16
|
recent_changes = \
|
|
17
17
|
f'\n\nRecent Changes:\n' +\
|
|
18
|
+
"\t06/08/2024 - 15.00.09: fan-out[] w/log & defaults, s/a or POST, genai cli no rules fix, pptional shortening of stacktrace lines \n"\
|
|
18
19
|
"\t05/28/2024 - 15.00.00: MCP \n"\
|
|
19
20
|
"\t05/16/2024 - 14.05.00: safrs 3.1.7, running mcp preview \n"\
|
|
20
21
|
"\t04/27/2024 - 14.04.00: Graphics preview, Vibe install fix, Improved IDE Chat Logic, MCP Exploration \n"\
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
last_created_date:
|
|
2
|
-
last_created_project_name:
|
|
3
|
-
last_created_version:
|
|
1
|
+
last_created_date: June 07, 2025 20:31:07
|
|
2
|
+
last_created_project_name: ../../../servers/basic_demo
|
|
3
|
+
last_created_version: 15.00.08
|
|
Binary file
|
|
@@ -207,6 +207,7 @@ class DBMLCreator(object):
|
|
|
207
207
|
'''
|
|
208
208
|
"""
|
|
209
209
|
|
|
210
|
+
# copy mcp learning from manager (to enable user to extend)
|
|
210
211
|
docs_path = Path(self.mod_gen.project_directory).joinpath('docs')
|
|
211
212
|
docs_path.mkdir(parents=True, exist_ok=True)
|
|
212
213
|
mcp_learning_src = genai_svcs.get_manager_path(use_env=True).joinpath('system/genai/mcp_learning')
|
|
@@ -152,8 +152,11 @@ def get_code_update_logic_file(rule_list: List[DotMap], logic_file_path: Path =
|
|
|
152
152
|
project (Project): a Project object (unless creating a logic file)
|
|
153
153
|
imports (set): the set of imported classes
|
|
154
154
|
"""
|
|
155
|
-
insert_logic = "\n # Logic from GenAI: (or, use your IDE
|
|
156
|
-
|
|
155
|
+
insert_logic = "\n # Logic from GenAI: (or, use your IDE with code completion)\n"
|
|
156
|
+
insert_import = translated_logic
|
|
157
|
+
if 'import \n' in translated_logic:
|
|
158
|
+
insert_import = " # no rules"
|
|
159
|
+
insert_logic += insert_import
|
|
157
160
|
insert_logic += "\n # End Logic from GenAI\n\n"
|
|
158
161
|
|
|
159
162
|
insert_point = 'discover_logic()' # default for als`
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
from flask import request, jsonify
|
|
2
|
-
from flask import Flask, redirect, send_from_directory, send_file
|
|
3
2
|
import logging
|
|
4
3
|
import os
|
|
5
4
|
import json
|
|
6
|
-
import
|
|
5
|
+
from pathlib import Path
|
|
7
6
|
|
|
8
7
|
import requests
|
|
9
8
|
from config.config import Args # circular import error if at top
|
|
@@ -23,36 +22,76 @@ def add_service(app, api, project_dir, swagger_host: str, PORT: str, method_deco
|
|
|
23
22
|
return result # + '/api'
|
|
24
23
|
|
|
25
24
|
|
|
25
|
+
@app.before_request
|
|
26
|
+
def before_any_request():
|
|
27
|
+
# print(f"[DEBUG] Incoming request: {request.method} {request.url}")
|
|
28
|
+
if activate_openapi_logging := False:
|
|
29
|
+
if request.content_type == 'application/json' and request.method in ['POST', 'PUT', 'PATCH']:
|
|
30
|
+
# openapi: Incoming request: PATCH http://localhost:5656/api/Customer/1/ {'data': {'attributes': {'credit_limit': 5555}, 'type': 'Customer', 'id': '1'}}
|
|
31
|
+
# openapi: Incoming request: PATCH http://6f6f-2601-644-4900-d6f0-ecc9-6df3-8863-c5b2.ngrok-free.app/api/Customer/1 {'credit_limit': 5555}
|
|
32
|
+
|
|
33
|
+
app_logger.info(f"openapi: Incoming request: {request.method} {request.url} {str(request.json)}")
|
|
34
|
+
else:
|
|
35
|
+
app_logger.info(f"openapi: Incoming request: {request.method} {request.url}")
|
|
36
|
+
# app_logger.info(f"openapi: Incoming request headers: {request.headers}")
|
|
37
|
+
|
|
38
|
+
chatgpt_request_json = {
|
|
39
|
+
"credit_limit": 25000,
|
|
40
|
+
}
|
|
41
|
+
standard_request_json = {
|
|
42
|
+
"data": {
|
|
43
|
+
"type": "Customer",
|
|
44
|
+
"id": "ALFKI",
|
|
45
|
+
"attributes": {
|
|
46
|
+
"name": "Alice",
|
|
47
|
+
"credit_limit": 25000,
|
|
48
|
+
"balance": 12345
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
swagger_request_json = {
|
|
53
|
+
'data': {
|
|
54
|
+
'attributes': {
|
|
55
|
+
'credit_limit': 5555
|
|
56
|
+
},
|
|
57
|
+
'type': 'Customer',
|
|
58
|
+
'id': '1'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
pass
|
|
62
|
+
|
|
26
63
|
|
|
27
64
|
@app.route('/.well-known/mcp.json', methods=['GET'])
|
|
28
65
|
def mcp_discovery(path=None):
|
|
29
|
-
''' called by mcp_client_executor for discovery
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
"
|
|
36
|
-
{
|
|
37
|
-
"name": "Customer",
|
|
38
|
-
"path": "/Customer",
|
|
39
|
-
"methods": ["GET", "PATCH"],
|
|
40
|
-
"fields": ["id", "name", "balance", "credit_limit"],
|
|
41
|
-
"filterable": ["name", "credit_limit"],
|
|
42
|
-
"example": "List customers with credit over 5000"
|
|
43
|
-
}
|
|
44
|
-
]
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
test: curl -X GET "http://localhost:5656/.well-known/mcp.json"
|
|
66
|
+
''' called by mcp_client_executor for discovery; read docs/mcp_learning/ for:
|
|
67
|
+
1. learning, including fan-out & response format, and email requests.
|
|
68
|
+
2. schema
|
|
69
|
+
|
|
70
|
+
see: https://apilogicserver.github.io/Docs/Integration-MCP/#1-discovery
|
|
71
|
+
|
|
72
|
+
test: curl -X GET "http://localhost:5656/.well-known/mcp.json"
|
|
48
73
|
'''
|
|
49
74
|
# return docs/mcp_schema.json
|
|
50
|
-
|
|
75
|
+
mcp_learning_path = Path(project_dir + "/docs/mcp_learning")
|
|
51
76
|
try:
|
|
77
|
+
schema_path = mcp_learning_path.joinpath('mcp_schema.json')
|
|
78
|
+
if not schema_path.exists():
|
|
79
|
+
return jsonify({"error": "System Error - /docs/mcp_learning/mcp_schema.json not found"}), 404
|
|
52
80
|
with open(schema_path, "r") as schema_file:
|
|
53
81
|
schema = json.load(schema_file)
|
|
54
|
-
return jsonify(schema), 200
|
|
55
82
|
except Exception as e:
|
|
56
83
|
app_logger.error(f"Error loading MCP schema: {e}")
|
|
57
84
|
return jsonify({"error": "MCP schema not found"}), 404
|
|
58
|
-
|
|
85
|
+
|
|
86
|
+
try:
|
|
87
|
+
learnings_path = mcp_learning_path.joinpath('mcp.prompt')
|
|
88
|
+
if not learnings_path.exists():
|
|
89
|
+
return jsonify({"error": "System Error - /docs/mcp_learning/mcp,prompt not found"}), 404
|
|
90
|
+
with open(learnings_path, "r") as learnings_file:
|
|
91
|
+
learnings = learnings_file.read()
|
|
92
|
+
except Exception as e:
|
|
93
|
+
app_logger.error(f"Error loading MCP learnings: {e}")
|
|
94
|
+
return jsonify({"error": "MCP learnings not found"}), 404
|
|
95
|
+
schema['learning'] = learnings
|
|
96
|
+
|
|
97
|
+
return jsonify(schema), 200
|
|
@@ -174,6 +174,75 @@ def get_args(flask_app: Flask) -> Args:
|
|
|
174
174
|
# LOGGING SETUP
|
|
175
175
|
# ==================================
|
|
176
176
|
|
|
177
|
+
import site
|
|
178
|
+
|
|
179
|
+
# Auto-detect venv site-packages path
|
|
180
|
+
import logging
|
|
181
|
+
import site
|
|
182
|
+
|
|
183
|
+
venv_path = site.getsitepackages()[0]
|
|
184
|
+
venv_alias = "$venv"
|
|
185
|
+
app_path = str(Path(__file__).parent.parent)
|
|
186
|
+
app_alias = ""
|
|
187
|
+
max_len = 100 # max length of a line in stacktrace
|
|
188
|
+
|
|
189
|
+
# Patch stacktrace formatters to replace venv path with alias
|
|
190
|
+
def patch_stacktrace_formatters():
|
|
191
|
+
"""
|
|
192
|
+
Patch only the formatException method of each formatter,
|
|
193
|
+
so only stacktraces are affected, not normal log lines.
|
|
194
|
+
"""
|
|
195
|
+
import logging
|
|
196
|
+
|
|
197
|
+
def short_format_exception(self, exc_info):
|
|
198
|
+
result = logging.Formatter.formatException(self, exc_info)
|
|
199
|
+
lines = result.splitlines('\n')
|
|
200
|
+
line_num = 0
|
|
201
|
+
for each_line in lines:
|
|
202
|
+
follow_link = ""
|
|
203
|
+
if '1906' in each_line:
|
|
204
|
+
pass # good breakpoint
|
|
205
|
+
if venv_path in each_line:
|
|
206
|
+
# get the string inside the double quotes
|
|
207
|
+
if '"' in each_line:
|
|
208
|
+
follow_link = '\tFollow link: ' + each_line.split('"')[1] + ']'
|
|
209
|
+
# Replace the venv_path with venv_alias in the stacktrace line
|
|
210
|
+
each_line = each_line.replace('"' + venv_path, venv_alias)
|
|
211
|
+
each_line = each_line.replace('File ', '') # replace project path with name
|
|
212
|
+
each_line = each_line.replace('", line ', ' @ ')
|
|
213
|
+
each_line = each_line.replace('^', '')
|
|
214
|
+
each_line = each_line.replace('\n', '')
|
|
215
|
+
lines[line_num] = each_line
|
|
216
|
+
elif app_path in each_line:
|
|
217
|
+
if '"' in each_line:
|
|
218
|
+
follow_link = '\tFollow link: ' + each_line.split('"')[1] + ']'
|
|
219
|
+
each_line = each_line.replace('"' + app_path, app_alias)
|
|
220
|
+
each_line = each_line.replace('File ', '')
|
|
221
|
+
each_line = each_line.replace('", line ', ' @ ')
|
|
222
|
+
each_line = each_line.replace('\n', '')
|
|
223
|
+
lines[line_num] = each_line
|
|
224
|
+
elif '^^' in each_line:
|
|
225
|
+
lines[line_num] = ""
|
|
226
|
+
elif 'File "<string>", line' in each_line:
|
|
227
|
+
lines[line_num] = ""
|
|
228
|
+
# add spaces for 90 characters
|
|
229
|
+
if len(lines[line_num]) < max_len and lines[line_num] != "" and follow_link != "":
|
|
230
|
+
lines[line_num] = lines[line_num] + ' ' * (max_len - len(lines[line_num]))
|
|
231
|
+
lines[line_num] += follow_link
|
|
232
|
+
line_num += 1
|
|
233
|
+
result = ''.join(lines)
|
|
234
|
+
return result
|
|
235
|
+
|
|
236
|
+
# Patch the formatException method of all formatters in the root logger
|
|
237
|
+
|
|
238
|
+
root_logger = logging.getLogger()
|
|
239
|
+
for handler in root_logger.handlers:
|
|
240
|
+
fmt = handler.formatter
|
|
241
|
+
if fmt and not hasattr(fmt, "_stacktrace_patched"):
|
|
242
|
+
fmt.formatException = short_format_exception.__get__(fmt)
|
|
243
|
+
fmt._stacktrace_patched = True
|
|
244
|
+
|
|
245
|
+
|
|
177
246
|
def logging_setup() -> logging.Logger:
|
|
178
247
|
"""
|
|
179
248
|
Setup Logging
|
|
@@ -187,6 +256,10 @@ def logging_setup() -> logging.Logger:
|
|
|
187
256
|
f.close()
|
|
188
257
|
logging.config.dictConfig(config) # log levels: notset 0, debug 10, info 20, warn 30, error 40, critical 50
|
|
189
258
|
app_logger = logging.getLogger("api_logic_server_app")
|
|
259
|
+
|
|
260
|
+
if do_truncate_venv_path := True: # use False for standard Python logging in stacktrace
|
|
261
|
+
patch_stacktrace_formatters()
|
|
262
|
+
|
|
190
263
|
debug_value = os.getenv('APILOGICPROJECT_DEBUG')
|
|
191
264
|
if debug_value is not None: # > export APILOGICPROJECT_DEBUG=True
|
|
192
265
|
debug_value = debug_value.upper()
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
{
|
|
2
|
+
"http://localhost:5656/.well-known/mcp.json": {
|
|
3
|
+
"base_url": "http://localhost:5656/api",
|
|
4
|
+
"description": "API Logic Project: basic_demo",
|
|
5
|
+
"learning": [
|
|
6
|
+
"To issue one request per row from a prior step (fan-out), use the syntax:",
|
|
7
|
+
"",
|
|
8
|
+
"\"$<stepIndex>[*].<fieldName>\"",
|
|
9
|
+
"",
|
|
10
|
+
"For example, if step 0 returns orders, and you want to send a POST per customer:",
|
|
11
|
+
"",
|
|
12
|
+
"Before (incorrect):",
|
|
13
|
+
" \"customer_id\": \"{customer_id}\"",
|
|
14
|
+
"",
|
|
15
|
+
"After (correct):",
|
|
16
|
+
" \"customer_id\": \"$0[*].customer_id\"",
|
|
17
|
+
"",
|
|
18
|
+
"Only if 'email' is in the Natural language query, send email by issing a POST request to the SysEmail endpoint, setting the subject, message and customer_id in the body. DO NOT include a POST unless the word ‘email’ appears in the user query.",
|
|
19
|
+
"",
|
|
20
|
+
"Format response as mcp_responseFormat.",
|
|
21
|
+
"",
|
|
22
|
+
"<mcp_responseFormat>",
|
|
23
|
+
"class QueryParam(BaseModel):",
|
|
24
|
+
" name: str # attribute name",
|
|
25
|
+
" op: str # eq, lt, gt",
|
|
26
|
+
" val: str",
|
|
27
|
+
"",
|
|
28
|
+
"class JsonValues(BaseModel):",
|
|
29
|
+
" name: str # name of attribute",
|
|
30
|
+
" value: str # value of attribute",
|
|
31
|
+
"",
|
|
32
|
+
"class Resource(BaseModel):",
|
|
33
|
+
" tool_type: str",
|
|
34
|
+
" base_url: str",
|
|
35
|
+
" path: str # specified use case or requirement name (use 'General' if missing)",
|
|
36
|
+
" method: str # GET, PATCH, POST or DELETE",
|
|
37
|
+
" body: json # data for PATCH or POST",
|
|
38
|
+
" query_params: List(QueryParam) # filter for GET",
|
|
39
|
+
"",
|
|
40
|
+
"class MCPResult(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt",
|
|
41
|
+
" schema_version: str",
|
|
42
|
+
" resources : List[Resource] # list resources",
|
|
43
|
+
"",
|
|
44
|
+
"<mcp_responseFormat/>",
|
|
45
|
+
""
|
|
46
|
+
],
|
|
47
|
+
"resources": [
|
|
48
|
+
{
|
|
49
|
+
"fields": [
|
|
50
|
+
"id",
|
|
51
|
+
"name",
|
|
52
|
+
"balance",
|
|
53
|
+
"credit_limit",
|
|
54
|
+
"email",
|
|
55
|
+
"email_opt_out"
|
|
56
|
+
],
|
|
57
|
+
"filterable": [
|
|
58
|
+
"id",
|
|
59
|
+
"name",
|
|
60
|
+
"balance",
|
|
61
|
+
"credit_limit",
|
|
62
|
+
"email",
|
|
63
|
+
"email_opt_out"
|
|
64
|
+
],
|
|
65
|
+
"methods": [
|
|
66
|
+
"GET",
|
|
67
|
+
"PATCH",
|
|
68
|
+
"POST",
|
|
69
|
+
"DELETE"
|
|
70
|
+
],
|
|
71
|
+
"name": "Customer",
|
|
72
|
+
"path": "/Customer"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"fields": [
|
|
76
|
+
"id",
|
|
77
|
+
"order_id",
|
|
78
|
+
"product_id",
|
|
79
|
+
"quantity",
|
|
80
|
+
"amount",
|
|
81
|
+
"unit_price"
|
|
82
|
+
],
|
|
83
|
+
"filterable": [
|
|
84
|
+
"id",
|
|
85
|
+
"order_id",
|
|
86
|
+
"product_id",
|
|
87
|
+
"quantity",
|
|
88
|
+
"amount",
|
|
89
|
+
"unit_price"
|
|
90
|
+
],
|
|
91
|
+
"methods": [
|
|
92
|
+
"GET",
|
|
93
|
+
"PATCH",
|
|
94
|
+
"POST",
|
|
95
|
+
"DELETE"
|
|
96
|
+
],
|
|
97
|
+
"name": "Item",
|
|
98
|
+
"path": "/Item"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
"fields": [
|
|
102
|
+
"id",
|
|
103
|
+
"notes",
|
|
104
|
+
"customer_id",
|
|
105
|
+
"CreatedOn",
|
|
106
|
+
"date_shipped",
|
|
107
|
+
"amount_total"
|
|
108
|
+
],
|
|
109
|
+
"filterable": [
|
|
110
|
+
"id",
|
|
111
|
+
"notes",
|
|
112
|
+
"customer_id",
|
|
113
|
+
"CreatedOn",
|
|
114
|
+
"date_shipped",
|
|
115
|
+
"amount_total"
|
|
116
|
+
],
|
|
117
|
+
"methods": [
|
|
118
|
+
"GET",
|
|
119
|
+
"PATCH",
|
|
120
|
+
"POST",
|
|
121
|
+
"DELETE"
|
|
122
|
+
],
|
|
123
|
+
"name": "Order",
|
|
124
|
+
"path": "/Order"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"fields": [
|
|
128
|
+
"id",
|
|
129
|
+
"name",
|
|
130
|
+
"unit_price"
|
|
131
|
+
],
|
|
132
|
+
"filterable": [
|
|
133
|
+
"id",
|
|
134
|
+
"name",
|
|
135
|
+
"unit_price"
|
|
136
|
+
],
|
|
137
|
+
"methods": [
|
|
138
|
+
"GET",
|
|
139
|
+
"PATCH",
|
|
140
|
+
"POST",
|
|
141
|
+
"DELETE"
|
|
142
|
+
],
|
|
143
|
+
"name": "Product",
|
|
144
|
+
"path": "/Product"
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"schema_version": "1.0",
|
|
148
|
+
"tool_type": "json-api"
|
|
149
|
+
}
|
|
150
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
Natural language query:
|
|
2
|
+
List the orders date_shipped is null and CreatedOn before 2023-07-14, and send a discount email (subject: 'Discount Offer') to the customer for each one.
|
|
3
|
+
|
|
4
|
+
Learnings_and_Schema:
|
|
5
|
+
{"base_url": "http://localhost:5656/api",
|
|
6
|
+
"description": "API Logic Project: basic_demo",
|
|
7
|
+
"learning": "To issue one request per row from a prior step (fan-out), use the syntax:
|
|
8
|
+
|
|
9
|
+
"$<stepIndex>[*].<fieldName>"
|
|
10
|
+
|
|
11
|
+
For example, if step 0 returns orders, and you want to send a POST per customer:
|
|
12
|
+
|
|
13
|
+
Before (incorrect):
|
|
14
|
+
"customer_id": "{customer_id}"
|
|
15
|
+
|
|
16
|
+
After (correct):
|
|
17
|
+
"customer_id": "$0[*].customer_id"
|
|
18
|
+
|
|
19
|
+
Only if 'email' is in the Natural language query, send email by issing a POST request to the SysEmail endpoint, setting the subject, message and customer_id in the body. DO NOT include a POST unless the word u2018emailu2019 appears in the user query.
|
|
20
|
+
|
|
21
|
+
Format response as mcp_responseFormat.
|
|
22
|
+
|
|
23
|
+
<mcp_responseFormat>
|
|
24
|
+
class QueryParam(BaseModel):
|
|
25
|
+
name: str # attribute name
|
|
26
|
+
op: str # eq, lt, gt
|
|
27
|
+
val: str
|
|
28
|
+
|
|
29
|
+
class JsonValues(BaseMopdel):
|
|
30
|
+
name: str # name of attribute
|
|
31
|
+
value: str # value of attribute
|
|
32
|
+
|
|
33
|
+
class Resource(BaseModel):
|
|
34
|
+
tool_type: str
|
|
35
|
+
base_url: str
|
|
36
|
+
path: str # specified use case or requirement name (use 'General' if missing)
|
|
37
|
+
method: str # GET, PATCH, POST or DELETE
|
|
38
|
+
body: json # data for PATCH or POST
|
|
39
|
+
query_params: List(QueryParam) # filter for GET
|
|
40
|
+
|
|
41
|
+
class MCPResult(BaseModel): # must match system/genai/prompt_inserts/response_format.prompt
|
|
42
|
+
schema_version: str
|
|
43
|
+
resources : List[Resource] # list resources
|
|
44
|
+
|
|
45
|
+
<mcp_responseFormat/>
|
|
46
|
+
", "resources": [{"fields": ["id", "name", "balance", "credit_limit", "email", "email_opt_out"], "filterable": ["id", "name", "balance", "credit_limit", "email", "email_opt_out"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Customer", "path": "/Customer"}, {"fields": ["id", "order_id", "product_id", "quantity", "amount", "unit_price"], "filterable": ["id", "order_id", "product_id", "quantity", "amount", "unit_price"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Item", "path": "/Item"}, {"fields": ["id", "notes", "customer_id", "CreatedOn", "date_shipped", "amount_total"], "filterable": ["id", "notes", "customer_id", "CreatedOn", "date_shipped", "amount_total"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Order", "path": "/Order"}, {"fields": ["id", "name", "unit_price"], "filterable": ["id", "name", "unit_price"], "methods": ["GET", "PATCH", "POST", "DELETE"], "name": "Product", "path": "/Product"}], "schema_version": "1.0", "tool_type": "json-api"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "1.0",
|
|
3
|
+
"resources": [
|
|
4
|
+
{
|
|
5
|
+
"tool_type": "json-api",
|
|
6
|
+
"base_url": "http://localhost:5656/api",
|
|
7
|
+
"path": "/Order",
|
|
8
|
+
"method": "GET",
|
|
9
|
+
"query_params": [
|
|
10
|
+
{
|
|
11
|
+
"name": "date_shipped",
|
|
12
|
+
"op": "eq",
|
|
13
|
+
"val": "null"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"name": "CreatedOn",
|
|
17
|
+
"op": "lt",
|
|
18
|
+
"val": "2023-07-14"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"tool_type": "json-api",
|
|
24
|
+
"base_url": "http://localhost:5656/api",
|
|
25
|
+
"path": "/SysEmail",
|
|
26
|
+
"method": "POST",
|
|
27
|
+
"body": {
|
|
28
|
+
"subject": "Discount Offer",
|
|
29
|
+
"message": "Dear customer, we are offering a discount on your next purchase. Please check your account for more details.",
|
|
30
|
+
"customer_id": "$0[*].customer_id"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
api_logic_server_cli/prototypes/base/integration/mcp/examples/mcp_tool_context_response_get.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "1.0",
|
|
3
|
+
"resources": [
|
|
4
|
+
{
|
|
5
|
+
"tool_type": "json-api",
|
|
6
|
+
"base_url": "http://localhost:5656/api",
|
|
7
|
+
"path": "/Customer",
|
|
8
|
+
"method": "GET",
|
|
9
|
+
"query_params": [
|
|
10
|
+
{
|
|
11
|
+
"name": "credit_limit",
|
|
12
|
+
"op": "gt",
|
|
13
|
+
"val": "1000"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|