Skip to content

docs(skills): add graphistry-mcp skill - #32

Open
dess890 wants to merge 5 commits into
mainfrom
feat/graphistry-mcp-skill
Open

docs(skills): add graphistry-mcp skill#32
dess890 wants to merge 5 commits into
mainfrom
feat/graphistry-mcp-skill

Conversation

@dess890

@dess890 dess890 commented Aug 18, 2026

Copy link
Copy Markdown

Adds a graphistry-mcp skill so an external MCP client can drive a live Graphistry
visualization session: connecting to the viz MCP endpoint, personal-key and JWT auth, the
session model, the tool surface, and GFQL as JSON over the wire.

Two servers share the name "graphistry mcp" — the viz MCP endpoint and the PyGraphistry MCP
repo. The skill opens by disambiguating them, since picking the wrong one wastes a whole
session.

Every factual claim was checked against the shipped server and each GFQL shape was executed
rather than read. Eleven were wrong on the first pass and are corrected here — notably that
aggregations need the column they aggregate (only count may be a 2-element pair), that
predicate type names are case-sensitive and the operand key differs by family, and that three
shapes filed under "fails silently" actually fail loudly with named error codes.

Server-side counterpart: graphistry/graphistry#3481.

Covers driving a live Graphistry visualization session from an MCP client:
connecting over Streamable HTTP, personal-key and JWT auth, the session
ownership model, the nine-tool surface, and GFQL as the JSON wire format.

Documents the query shapes that return success with empty or wrong results
rather than erroring. A zero-row answer from any of them reads as a real zero,
which is the most common way an agent reports a confidently wrong finding.

Records two behaviors that are easy to get wrong: only the session owner may
mutate, while reads can succeed for a non-owner with access to the dataset;
and an agent handed a session should use it rather than discover one, since
list_sessions returns bare ids and picking among two open graphs is silent.

Routes MCP client tasks from the graphistry entrypoint skill, and separates
the viz MCP from the unrelated PyGraphistry MCP repository sharing the name.

SKILL.md is 193 lines, with the full GFQL JSON forms in references/ per the
under-200 convention. Decision-critical rules stay inline: the five operation
types, the JSON-string encoding, Edge returning a subgraph rather than a
projection, Let/Ref as a top-level object, and the silent-failure list.
@dess890
dess890 requested review from aucahuasi and lmeyerov August 28, 2026 16:13
@lmeyerov

Copy link
Copy Markdown
Contributor

@dess890 Can you add an eval set with baseline performance?

@lmeyerov lmeyerov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dess890

dess890 commented Aug 31, 2026

Copy link
Copy Markdown
Author

Added eval journeys with baseline. --codex --claude --skills-mode both --skills-delivery native, 56 rows, harness_ok 56/56.

          off             on             delta
claude    8/14  57.1%    14/14 100.0%   +42.9pp
codex     5/14  35.7%    10/14  71.4%   +35.7pp
overall  13/28  46.4%    24/28  85.7%   +39.3pp

by intent (on vs off)
  execution_grade        7/8  88%  vs  4/8  50%
  guardrail              8/10 80%  vs  5/10 50%
  realistic_capability   9/10 90%  vs  4/10 40%

14 cases across three intents, 0 regressions. Reproduce with --skills-profile graphistry_mcp.

@lmeyerov

lmeyerov commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Reviewed against pygraphistry origin/master (0.59.0) and against live viz MCP server behavior.

The wire format holds up. I executed every GFQL claim rather than reading it — the predicate
table across all six families, Edge directions, aggregation arity, Let/Ref, and each
silent-failure shape. All confirmed. Server constants, status codes and the nine tool schemas match
too, and twice the skill is more precise than the tool schema itself.

Two things block shipping; the rest can follow. npx skills add graphistry/graphistry-skills is
unpinned, so merging to main puts this in front of users.


Blocks ship

1. The server changed after the skill was verified, and one bullet now misfires

The skill was corrected against the shipped server in mid-August. The endpoint has moved since, and
create_collection now refuses expressions whose result stops identifying graph nodes — those
that group rows, project the id away, rename or drop it, or read the edge table. Ranking by a
community column is refused separately. The refusal explains the fix: a collection needs an
expression that selects the nodes themselves, such as a Node filter.

That collides with the skill's only advice about a refused collection:

"If a collection is refused because the service could not evaluate the expression, report the
failure. Do not reword the filter and retry — the expression was not the problem."

For this new class the expression is the problem, and the server returns the repair. An agent
following that bullet reports failure while holding the fix.

It also dead-ends the documented workflow: step 5 says reuse the validated JSON unchanged, but the
edge-table aggregation presented in references/gfql-wire-format.md passes query_graph and is
then refused by create_collection. The two tools no longer accept the same set of shapes, and the
skill doesn't say so.

To unblock (small): document the new refusals, rewrite the "don't reword" bullet to cover them,
and add a line to step 5 noting create_collection accepts a narrower set of shapes than
query_graph validates.

The part I can't size: I checked two areas and found problems in both, so there may be more.
Re-reading the prose against the current server is the real task and only you can judge its cost.
Worth naming in the PR body which server revision the claims were checked against — the current
wording ("checked against the shipped server") has no date on it, so it silently ages.

2. README, or the skill is unreachable and the new router edge dangles

README.md lists every user-facing skill, and both install snippets name them explicitly with
--skill. This PR adds a ninth and updates neither, so nobody installs it by the documented path.

Compounding it: the PR edits .agents/skills/graphistry/SKILL.md to route MCP tasks to
graphistry-mcp. A user who installs from the README gets graphistry but not graphistry-mcp, so
the router names a skill that isn't there. The line directly above already handles this case —
use `graphistry-js` if available.

Two one-line edits. CI won't catch it: the install smoke test hardcodes the six pygraphistry*
skills and already skips graphistry and graphistry-rest-api.


Can follow

None of these reach a user — the eval suite is internal, and the rest are precision or editorial.

3. The evals measure whether the doc was supplied, not whether agents do better

All 14 cases ask the model to restate a proposition the skill asserts — "Can Cypher go to
create_collection?", "What does 410 mean?", "How does a client get a session_id?". A model
without the skill can't know server-specific facts; with it, it reads them off. So +39.3pp largely
measures document delivery, and that's the number now standing as this skill's evidence.

This repo already has the better patterns. pygraphistry_persona_journeys_v1 poses multi-step
realistic tasks; pygraphistry_gfql_functional_v1 uses python_ast_parse / python_ast_calls and
executes the generated code. The new journeys use neither — no multi-step case, and no structural
check on a produced payload beyond substring regex.

Suggestion: add cases of the form given this schema and this request, produce the gfql_operations
payload you would send
, then parse the JSON and assert its shape. The wire format is JSON, so it
validates structurally the same way the functional suite validates Python.

4. One eval check rejects its own reference answer

evals/journeys/graphistry_mcp_session_model_v1.jsonempty_list_sessions_not_absence. The
must_not_regex blocks the (session|graph) is (gone|dead|closed|expired), and the case's own
reference answer ends "...rather than concluding the graph is gone". The pattern fires wherever the
phrase lands, including inside a sentence rejecting it. Three of four correct answers I tried fail,
including the shipped reference. status_410_triage writes the same phrase and passes only because
it carries no such pattern.

Fix: delete the must_not_regex. The oracle rubric already says "Concluding the session is gone
should score near zero", and only the oracle can tell asserting from rejecting.

Same bug, smaller, in predicate_type_case_sensitive: must_not_regex: "gt" blocks a correct
answer that explains the rule — "write GT rather than gt". Anchor it to the payload:
"type"\s*:\s*"gt".

5. A large share of the skill restates what the server already sends

Every client receives the tool descriptions at tools/list, and they already cover
inspect-schema-first, unobserved nouns, aggregate-before-filter, filter_dict vs edge_match,
Edge returning a subgraph, Let/Ref, and rows defaulting to nodes — most of Workflow and
Decision Rules. I probed 21 distinctive concepts; 16 appear in both.

Cost is secondary; the risk is two copies of the same rules in two repos with no test between them,
which is how item 1 happened. Worth keeping what the server can't say — server disambiguation, auth,
the status table, the silent-failure list — and letting tools/list carry the rest.

Smaller

  • Workflow step 2 calls the count in (+K more not listed) the real total. It's the number
    omitted — the total is the leading Node columns (N). The list also drops from the middle,
    keeping first and last. The surrounding advice (ask rather than invent a name) is right either way.
  • "gt fails with an opaque error" is unscoped: the server normalizes casing and key names for
    filter_dict in a top-level array, so gt succeeds through query_graph — the path step 4 tells
    the agent to use. references/ scopes this correctly; SKILL.md contradicts it.
  • The IP bullet runs 12 of the 23 lines in "Shapes that fail silently" and describes no shape.
  • The 10-collection cap and 30-second dedup window are per-deployment config — say "by default".
  • SKILL.md calls rows/group_by/order_by/limit "every row-pipeline step", then documents
    where_rows further down.
  • credential_in_authorization_header asks for 10 lines but sets max_lines: 16 — the only one of
    14 cases that disagrees with its own prompt.
  • Head commit reuses a subject already on main; sweep numbers belong in the PR body.

Questions

  1. SKILL.md gives the key-creation page as /users/personal/key/. I couldn't confirm it — happy
    to be pointed at it.
  2. Does this skill supersede the GFQL guidance that used to live alongside the server, or are they
    expected to diverge?

Exact citations, probe scripts and the per-claim evidence are in my working notes — happy to walk
through any item internally.

@lmeyerov
lmeyerov self-requested a review September 2, 2026 07:30

@lmeyerov lmeyerov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment - good for merge/release after review and addressed as desired

@@ -0,0 +1,116 @@
# GFQL wire format

@lmeyerov lmeyerov Sep 2, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok to have this, though unsure why we do, seems better to advocate cypher as LLM's understand it better

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants