abstract-toolserver 0.0.44__tar.gz → 0.0.45__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.
- {abstract_toolserver-0.0.44/src/abstract_toolserver.egg-info → abstract_toolserver-0.0.45}/PKG-INFO +1 -1
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/setup.py +1 -1
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/app.py +7 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/catalog.py +39 -29
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/mcp.py +21 -15
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/seat.py +1 -2
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45/src/abstract_toolserver.egg-info}/PKG-INFO +1 -1
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_catalog_start.py +1 -1
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/LICENSE +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/README.md +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/pyproject.toml +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/setup.cfg +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/__init__.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/__main__.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/assess.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/board_format.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/browser.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/canvas.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/channels.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/claudeauth.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/claudedirs.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/cli.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/client.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/clients.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/comms.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/conversation_archive.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/db.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/discovery.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/events.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/exchanges.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/gates.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/grid.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/handoff.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/image.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/instructions.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/issues.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/ledgers.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/loci.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/messages.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/metrics.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/pkg_versions.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/prompt.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/provider.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/reuse_gate.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/rolling.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/rolling_reduce.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/routes/__init__.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/sessions.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/todo.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/tools.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/uitools.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/vl.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/vmgui.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/vmhosts.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/vmpage.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/vmpool.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver.egg-info/SOURCES.txt +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver.egg-info/dependency_links.txt +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver.egg-info/entry_points.txt +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver.egg-info/requires.txt +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver.egg-info/top_level.txt +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_auth.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_board_format.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_channels.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_client.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_comms.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_comms_claim.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_comms_claim_live.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_db_query_errors.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_discovery.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_exchanges_ledgers.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_gate_ufw_apply.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_handoff.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_instructions.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_issues.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_mcp_governor.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_mct_archive.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_metrics.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_rolling_reduce.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_sessions.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_todo_id_prefix.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_ui_tools.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_vmgui.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_vmgui_live.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_vmhosts.py +0 -0
- {abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/tests/test_vms_page.py +0 -0
{abstract_toolserver-0.0.44/src/abstract_toolserver.egg-info → abstract_toolserver-0.0.45}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abstract_toolserver
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.45
|
|
4
4
|
Summary: The abstract_* ecosystem exposed as an API-callable AI toolset: functions become self-describing Flask endpoints with /endpoints discovery and ?help.
|
|
5
5
|
Home-page: https://github.com/AbstractEndeavors/abstract-toolserver
|
|
6
6
|
Author: putkoff
|
|
@@ -7,7 +7,7 @@ SERVER = ['abstract_flask', 'abstract_utilities']
|
|
|
7
7
|
|
|
8
8
|
setuptools.setup(
|
|
9
9
|
name='abstract_toolserver',
|
|
10
|
-
version='0.0.
|
|
10
|
+
version='0.0.45',
|
|
11
11
|
author='putkoff',
|
|
12
12
|
author_email='partners@abstractendeavors.com',
|
|
13
13
|
description="The abstract_* ecosystem exposed as an API-callable AI toolset: functions become self-describing Flask endpoints with /endpoints discovery and ?help.",
|
|
@@ -67,6 +67,13 @@ def _install_operator_gate(app):
|
|
|
67
67
|
"instance": ident.get("instance", ""),
|
|
68
68
|
"version": ident.get("version") or _discovery.package_version()})
|
|
69
69
|
|
|
70
|
+
@app.route("/handoff/<session_id>", methods=["GET"])
|
|
71
|
+
def _handoff_get(session_id):
|
|
72
|
+
# the canonical dereference of a handoff pointer: /toolserver/handoff/{id}
|
|
73
|
+
from .seat import session_resume
|
|
74
|
+
doc = session_resume(session_id)
|
|
75
|
+
return jsonify({"result": doc})
|
|
76
|
+
|
|
70
77
|
@app.before_request
|
|
71
78
|
def _require_operator_token():
|
|
72
79
|
if request.method == "OPTIONS":
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/catalog.py
RENAMED
|
@@ -5,7 +5,7 @@ Two consumers share everything here:
|
|
|
5
5
|
|
|
6
6
|
* the ``ts`` toolset (POST /ts/categories, /ts/list, /ts/call) — served by the
|
|
7
7
|
same register_categories machinery as every other tool, so the public names
|
|
8
|
-
are
|
|
8
|
+
are toolserver_categories / toolserver_list / toolserver_call.
|
|
9
9
|
* POST /mcp — the MCP Streamable-HTTP JSON-RPC transport (routes/__init__.py).
|
|
10
10
|
|
|
11
11
|
The catalog is the UNION of
|
|
@@ -25,7 +25,8 @@ import json
|
|
|
25
25
|
|
|
26
26
|
from . import clients
|
|
27
27
|
|
|
28
|
-
_META_CATEGORY = "
|
|
28
|
+
_META_CATEGORY = "toolserver"
|
|
29
|
+
_META_CATEGORY_ALIAS = "ts" # pre-rename routes /ts/*, still served
|
|
29
30
|
_DELEGATE_MARK = "[delegated " # proxy docstrings start "[delegated → <base>] ..."
|
|
30
31
|
|
|
31
32
|
# Curated one-liners for the known categories (fallback = first few tool names).
|
|
@@ -210,9 +211,9 @@ def _short(name, category):
|
|
|
210
211
|
# ══════════════════════════════════════════════════════════
|
|
211
212
|
# ts_* tool functions (registered under TOOLSETS["ts"])
|
|
212
213
|
# ══════════════════════════════════════════════════════════
|
|
213
|
-
def
|
|
214
|
+
def toolserver_categories():
|
|
214
215
|
"""List every tool category (local + online clients) with a tool count and a
|
|
215
|
-
short summary. Call this first, then
|
|
216
|
+
short summary. Call this first, then toolserver_list(category), then toolserver_call(name)."""
|
|
216
217
|
local = _local_tools()
|
|
217
218
|
cats = {} # cat -> set(names)
|
|
218
219
|
for name, (cat, _route, _func) in local.items():
|
|
@@ -229,7 +230,7 @@ def ts_categories():
|
|
|
229
230
|
return out
|
|
230
231
|
|
|
231
232
|
|
|
232
|
-
def
|
|
233
|
+
def toolserver_list(category=None):
|
|
233
234
|
"""Start here, or list exact tools in one category.
|
|
234
235
|
|
|
235
236
|
With no category, returns a guided category index and copyable next-call
|
|
@@ -239,13 +240,13 @@ def ts_list(category=None):
|
|
|
239
240
|
"""
|
|
240
241
|
category = str(category or "").strip().strip("/").lower()
|
|
241
242
|
if not category:
|
|
242
|
-
categories =
|
|
243
|
+
categories = toolserver_categories()
|
|
243
244
|
return {
|
|
244
245
|
"start_here": True,
|
|
245
246
|
"workflow": [
|
|
246
247
|
"Choose a category from categories below.",
|
|
247
|
-
"Call
|
|
248
|
-
"Call
|
|
248
|
+
"Call toolserver_list again with that category to get exact tool schemas.",
|
|
249
|
+
"Call toolserver_call with a returned full tool name and an arguments object.",
|
|
249
250
|
],
|
|
250
251
|
"categories": categories,
|
|
251
252
|
"examples": {
|
|
@@ -259,7 +260,7 @@ def ts_list(category=None):
|
|
|
259
260
|
"arguments": {"path": "tools/toolserver"},
|
|
260
261
|
},
|
|
261
262
|
},
|
|
262
|
-
"naming": "
|
|
263
|
+
"naming": "toolserver_call name = <category>_<route>; use names exactly as returned",
|
|
263
264
|
}
|
|
264
265
|
tools, seen = [], set()
|
|
265
266
|
for name, (cat, _route, func) in sorted(_local_tools().items()):
|
|
@@ -277,26 +278,26 @@ def ts_list(category=None):
|
|
|
277
278
|
seen.add(name)
|
|
278
279
|
if not tools:
|
|
279
280
|
return {"category": category, "count": 0, "tools": [],
|
|
280
|
-
"error": f"unknown or empty category: {category}", "hint": "
|
|
281
|
+
"error": f"unknown or empty category: {category}", "hint": "toolserver_categories"}
|
|
281
282
|
return {
|
|
282
283
|
"category": category,
|
|
283
284
|
"count": len(tools),
|
|
284
285
|
"tools": tools,
|
|
285
|
-
"next": {"tool": "
|
|
286
|
+
"next": {"tool": "toolserver_call", "shape": {"name": "<tool name above>",
|
|
286
287
|
"arguments": "<object matching its parameters>"}},
|
|
287
288
|
}
|
|
288
289
|
|
|
289
290
|
|
|
290
|
-
def
|
|
291
|
+
def toolserver_call(name=None, arguments=None, client=None, tags=None):
|
|
291
292
|
"""Invoke a tool by full name (e.g. 'fs_read_file', 'ui_capture'). Args:
|
|
292
|
-
name, arguments (object of the tool's params, from
|
|
293
|
+
name, arguments (object of the tool's params, from toolserver_list), optional client
|
|
293
294
|
(route a client-provided tool to a specific client id/name) and tags (pick an
|
|
294
295
|
online client matching these tags). Local tools run in-process with the same
|
|
295
296
|
argument coercion and result shape a direct POST to the tool's endpoint gives;
|
|
296
297
|
client tools route to an online provider. Unknown name -> error as data."""
|
|
297
298
|
name = str(name or "").strip()
|
|
298
299
|
if not name:
|
|
299
|
-
return {"error": "name is required", "hint": "
|
|
300
|
+
return {"error": "name is required", "hint": "toolserver_categories → toolserver_list"}
|
|
300
301
|
arguments = arguments if isinstance(arguments, dict) else {}
|
|
301
302
|
local = _local_tools()
|
|
302
303
|
if name in local and not client:
|
|
@@ -305,7 +306,7 @@ def ts_call(name=None, arguments=None, client=None, tags=None):
|
|
|
305
306
|
return func(*args, **kwargs) # raw value; exceptions propagate to the endpoint
|
|
306
307
|
# client-provided (or an explicit client override)
|
|
307
308
|
if name not in local and name not in _client_index() and not client:
|
|
308
|
-
return {"error": f"unknown tool: {name}", "hint": "
|
|
309
|
+
return {"error": f"unknown tool: {name}", "hint": "toolserver_categories → toolserver_list"}
|
|
309
310
|
return clients.dispatch(name, _coerce_args(arguments), client=client, tags=tags)
|
|
310
311
|
|
|
311
312
|
|
|
@@ -317,24 +318,29 @@ def _prune(func, coerced):
|
|
|
317
318
|
return (), coerced
|
|
318
319
|
|
|
319
320
|
|
|
321
|
+
# pre-rename import aliases (tests, external callers)
|
|
322
|
+
ts_categories, ts_list, ts_call = toolserver_categories, toolserver_list, toolserver_call
|
|
323
|
+
|
|
324
|
+
|
|
320
325
|
def get_toolset():
|
|
321
|
-
|
|
326
|
+
routes = {"categories": toolserver_categories, "list": toolserver_list, "call": toolserver_call}
|
|
327
|
+
return {_META_CATEGORY: routes, _META_CATEGORY_ALIAS: dict(routes)}
|
|
322
328
|
|
|
323
329
|
|
|
324
330
|
# ══════════════════════════════════════════════════════════
|
|
325
331
|
# MCP Streamable-HTTP (JSON-RPC 2.0 over POST /mcp)
|
|
326
332
|
# ══════════════════════════════════════════════════════════
|
|
327
333
|
_META_TOOL_SCHEMAS = [
|
|
328
|
-
{"name": "
|
|
334
|
+
{"name": "toolserver_categories",
|
|
329
335
|
"description": "List toolserver tool categories (local + online clients) with counts. "
|
|
330
|
-
"Call this first, then
|
|
336
|
+
"Call this first, then toolserver_list.",
|
|
331
337
|
"inputSchema": {"type": "object", "properties": {}}},
|
|
332
|
-
{"name": "
|
|
338
|
+
{"name": "toolserver_list",
|
|
333
339
|
"description": "List the tools in one category, with each tool's parameters. "
|
|
334
|
-
"Arg: category (from
|
|
340
|
+
"Arg: category (from toolserver_categories).",
|
|
335
341
|
"inputSchema": {"type": "object", "properties": {"category": {"type": "string"}},
|
|
336
342
|
"required": ["category"]}},
|
|
337
|
-
{"name": "
|
|
343
|
+
{"name": "toolserver_call",
|
|
338
344
|
"description": "Invoke a toolserver tool by full name. Args: name, arguments "
|
|
339
345
|
"(object of the tool's params), optional client (id/name) and tags "
|
|
340
346
|
"(list) to route a client-provided tool to a specific online client.",
|
|
@@ -346,6 +352,9 @@ _META_TOOL_SCHEMAS = [
|
|
|
346
352
|
"required": ["name"]}},
|
|
347
353
|
]
|
|
348
354
|
_META_NAMES = {t["name"] for t in _META_TOOL_SCHEMAS}
|
|
355
|
+
_META_NAME_ALIASES = {"ts_categories": "toolserver_categories", "ts_list": "toolserver_list",
|
|
356
|
+
"ts_call": "toolserver_call"} # pre-rename names, still accepted
|
|
357
|
+
_META_NAMES |= set(_META_NAME_ALIASES)
|
|
349
358
|
|
|
350
359
|
|
|
351
360
|
def _server_version():
|
|
@@ -384,22 +393,23 @@ def _as_text(result):
|
|
|
384
393
|
|
|
385
394
|
def mcp_tools_call(name, arguments):
|
|
386
395
|
"""(result_obj, is_error) for an MCP tools/call. Handles the three meta tools
|
|
387
|
-
by name and, in flat mode, any tool by its full name (via
|
|
396
|
+
by name and, in flat mode, any tool by its full name (via toolserver_call)."""
|
|
388
397
|
name = str(name or "")
|
|
398
|
+
name = _META_NAME_ALIASES.get(name, name)
|
|
389
399
|
arguments = arguments if isinstance(arguments, dict) else {}
|
|
390
400
|
try:
|
|
391
|
-
if name == "
|
|
392
|
-
return
|
|
393
|
-
if name == "
|
|
394
|
-
r =
|
|
401
|
+
if name == "toolserver_categories":
|
|
402
|
+
return toolserver_categories(), False
|
|
403
|
+
if name == "toolserver_list":
|
|
404
|
+
r = toolserver_list(category=arguments.get("category"))
|
|
395
405
|
return r, bool(r.get("error"))
|
|
396
|
-
if name == "
|
|
397
|
-
r =
|
|
406
|
+
if name == "toolserver_call":
|
|
407
|
+
r = toolserver_call(name=arguments.get("name"),
|
|
398
408
|
arguments=arguments.get("arguments") or {},
|
|
399
409
|
client=arguments.get("client"), tags=arguments.get("tags"))
|
|
400
410
|
return r, bool(isinstance(r, dict) and "error" in r)
|
|
401
411
|
# flat-mode: name is the tool itself
|
|
402
|
-
r =
|
|
412
|
+
r = toolserver_call(name=name, arguments=arguments)
|
|
403
413
|
return r, bool(isinstance(r, dict) and "error" in r)
|
|
404
414
|
except Exception as e: # noqa: BLE001 — tool raised → MCP isError
|
|
405
415
|
return {"error": str(e)}, True
|
|
@@ -449,25 +449,25 @@ def load_tools():
|
|
|
449
449
|
# ── categorical mode ────────────────────────────────────────────────────────
|
|
450
450
|
# Flat mode exposes all ~146 endpoints as distinct tools — every schema rides in
|
|
451
451
|
# the prompt EVERY turn (~5k tok) whether used or not. Categorical mode exposes 3
|
|
452
|
-
# meta-tools and lets the model discover on demand:
|
|
453
|
-
# →
|
|
452
|
+
# meta-tools and lets the model discover on demand: toolserver_categories → toolserver_list(cat)
|
|
453
|
+
# → toolserver_call(name), cutting the standing toolset cost to a few hundred tokens.
|
|
454
454
|
# Enable with AC_MCP_MODE=categorical. (Schemas come from the same cached
|
|
455
|
-
# discovery, so
|
|
455
|
+
# discovery, so toolserver_list is instant.)
|
|
456
456
|
CATEGORICAL = os.environ.get("AC_MCP_MODE", "flat").lower() in ("cat", "categorical", "category")
|
|
457
457
|
|
|
458
458
|
META_TOOLS = [
|
|
459
|
-
{"name": "
|
|
459
|
+
{"name": "toolserver_categories",
|
|
460
460
|
"description": "List abstract_toolserver tool categories (e.g. web, vm, vmpool, ui, "
|
|
461
|
-
"todo, fs, seat, session, db) with counts. Call this first, then
|
|
461
|
+
"todo, fs, seat, session, db) with counts. Call this first, then toolserver_list.",
|
|
462
462
|
"inputSchema": {"type": "object", "properties": {}}},
|
|
463
|
-
{"name": "
|
|
463
|
+
{"name": "toolserver_list",
|
|
464
464
|
"description": "List the toolserver tools in one category, with each tool's parameters. "
|
|
465
|
-
"Args: category (from
|
|
465
|
+
"Args: category (from toolserver_categories).",
|
|
466
466
|
"inputSchema": {"type": "object", "properties": {"category": {"type": "string"}},
|
|
467
467
|
"required": ["category"]}},
|
|
468
|
-
{"name": "
|
|
468
|
+
{"name": "toolserver_call",
|
|
469
469
|
"description": "Invoke a toolserver tool by full name (e.g. 'fs_read_file'). Args: name, "
|
|
470
|
-
"arguments (object of the tool's params, from
|
|
470
|
+
"arguments (object of the tool's params, from toolserver_list).",
|
|
471
471
|
"inputSchema": {"type": "object",
|
|
472
472
|
"properties": {"name": {"type": "string"}, "arguments": {"type": "object"}},
|
|
473
473
|
"required": ["name"]}},
|
|
@@ -500,17 +500,22 @@ def _categories(tools):
|
|
|
500
500
|
return [{"category": k, "tools": n} for k, n in sorted(c.items())]
|
|
501
501
|
|
|
502
502
|
|
|
503
|
+
_META_ALIASES = {"ts_categories": "toolserver_categories", "ts_list": "toolserver_list",
|
|
504
|
+
"ts_call": "toolserver_call"} # pre-rename names, still accepted
|
|
505
|
+
|
|
506
|
+
|
|
503
507
|
def _handle_meta(name, args, tools, url_by_name):
|
|
504
508
|
"""(out, is_error) for a categorical meta-tool call."""
|
|
505
|
-
|
|
509
|
+
name = _META_ALIASES.get(name, name)
|
|
510
|
+
if name == "toolserver_categories":
|
|
506
511
|
return _categories(tools), False
|
|
507
|
-
if name == "
|
|
512
|
+
if name == "toolserver_list":
|
|
508
513
|
cat = str(args.get("category", "")).strip().strip("/").lower()
|
|
509
514
|
sel = [t for t in tools if _category_of(t) == cat]
|
|
510
515
|
listing = [{"name": t["name"], "description": t.get("description", ""),
|
|
511
516
|
"inputSchema": t.get("inputSchema", {})} for t in sel]
|
|
512
517
|
return {"category": cat, "count": len(listing), "tools": listing}, (not sel)
|
|
513
|
-
if name == "
|
|
518
|
+
if name == "toolserver_call":
|
|
514
519
|
target = args.get("name")
|
|
515
520
|
call_args = _coerce(args.get("arguments") or {})
|
|
516
521
|
url = url_by_name.get(target)
|
|
@@ -697,14 +702,15 @@ def serve_mcp():
|
|
|
697
702
|
"text": json.dumps(out, indent=2, default=str)}],
|
|
698
703
|
"isError": bool(is_err)})
|
|
699
704
|
continue
|
|
700
|
-
if CATEGORICAL and name in ("
|
|
705
|
+
if CATEGORICAL and name in ("toolserver_categories", "toolserver_list", "toolserver_call",
|
|
706
|
+
"ts_categories", "ts_list", "ts_call"):
|
|
701
707
|
try:
|
|
702
708
|
out, is_err = _handle_meta(name, args, tools_cache, url_by_name)
|
|
703
709
|
except Exception as e:
|
|
704
710
|
out, is_err = {"error": str(e)}, True
|
|
705
|
-
gov_tool = str(args.get("name") or "") if name
|
|
711
|
+
gov_tool = str(args.get("name") or "") if name in ("toolserver_call", "ts_call") else name
|
|
706
712
|
text = govern_result(json.dumps(out, indent=2, default=str), gov_tool,
|
|
707
|
-
args.get("arguments") if name
|
|
713
|
+
args.get("arguments") if name in ("toolserver_call", "ts_call") else args)
|
|
708
714
|
_result(id_, {"content": [{"type": "text", "text": text}],
|
|
709
715
|
"isError": bool(is_err)})
|
|
710
716
|
continue
|
|
@@ -387,9 +387,8 @@ def session_resume(session_id):
|
|
|
387
387
|
|
|
388
388
|
|
|
389
389
|
def get_toolset():
|
|
390
|
-
# seat_rollover (the phase gate) is UNMOUNTED for now (operator 2026-10-01):
|
|
391
|
-
# the serve owns rolls; the session chain endpoints below are the contract.
|
|
392
390
|
return {"seat": {"report": seat_report, "state": seat_state,
|
|
391
|
+
"rollover": seat_rollover,
|
|
393
392
|
"session_register": session_register,
|
|
394
393
|
"session_handoff": session_handoff,
|
|
395
394
|
"session_resume": session_resume}}
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45/src/abstract_toolserver.egg-info}/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: abstract_toolserver
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.45
|
|
4
4
|
Summary: The abstract_* ecosystem exposed as an API-callable AI toolset: functions become self-describing Flask endpoints with /endpoints discovery and ?help.
|
|
5
5
|
Home-page: https://github.com/AbstractEndeavors/abstract-toolserver
|
|
6
6
|
Author: putkoff
|
|
@@ -21,5 +21,5 @@ def test_ts_list_without_category_is_a_guided_start():
|
|
|
21
21
|
def test_ts_list_category_includes_next_call_shape():
|
|
22
22
|
result = ts_list("channel")
|
|
23
23
|
assert result["tools"]
|
|
24
|
-
assert result["next"]["tool"] == "
|
|
24
|
+
assert result["next"]["tool"] == "toolserver_call"
|
|
25
25
|
assert result["next"]["shape"]["name"] == "<tool name above>"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/__init__.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/__main__.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/board_format.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/browser.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/channels.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/claudeauth.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/claudedirs.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/clients.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/discovery.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/exchanges.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/handoff.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/instructions.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/ledgers.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/messages.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/metrics.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/pkg_versions.py
RENAMED
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/provider.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/reuse_gate.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/rolling.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/rolling_reduce.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/routes/__init__.py
RENAMED
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/sessions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/uitools.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{abstract_toolserver-0.0.44 → abstract_toolserver-0.0.45}/src/abstract_toolserver/vmhosts.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|