MCP server for clinical pharmacogenomics (PGx) with Code Mode execution, API catalog search, GraphQL, and SPARQL support
Five tools with detailed descriptions and parameter schemas, but significant gaps in output documentation and error handling. Tool names follow verb_noun convention (catalog_search, execute, graphql_execute, search, sparql_execute). Descriptions are comprehensive (150-400 chars) and explain WHEN to use each tool. However, output schemas are not formally documented, responses are described in prose but lack structured JSON Schema definitions. Error handling is minimal; no guidance on recovery paths or error classification. Parameters have types and descriptions, but no validation constraints (enums, ranges, patterns) are visible in the schema definitions. The execute/graphql_execute/sparql_execute tools accept arbitrary code, which is powerful but risky without explicit security warnings in descriptions.
Search the API catalog (legacy mode). Returns matching endpoints with full parameter docs. Use this to discover API capabilities before calling execute. Categories are listed. USAGE IN execute: api.get(path, params) for GET, api.post(path, body, params) for POST. Path params like /lookup/{id} are auto-interpolated from params. Remaining params become query string. Large responses (>100KB) are auto-staged: check result.__staged, return the staging info, use query_data to explore. Use limit/pagination params to control response size.
Execute JavaScript code against the API with sandboxed V8 isolate. Code runs with: searchSpec(query) / searchPaths(query) — search the API catalog/spec; listCategories() / listTags() — inspect categories/tags; getEndpoint(path) / getOperation(idOrPath) — get endpoint docs; api.get(path, params) for GET, api.post(path, body, params) for POST; Large responses (>100KB) are auto-staged into SQLite; console.log() capture; optional filesystem access (fs.readFile, fs.writeFile, fs.glob); optional domain-specific preamble helpers. The last expression or return value is the result.
Execute JavaScript code against a GraphQL API with sandboxed V8 isolate. Code runs with: gql.query(queryString, variables?) — execute GraphQL queries; schema.types() / schema.type(name) / schema.search(query) — introspection helpers; db.stage() / db.queryStaged() — staging helpers; optional api.get/api.post for hybrid REST access; console.log() capture; optional filesystem access; optional domain-specific preamble. When introspection is disabled, schema.* reports unavailable but gql.query() still works. The last expression or return value is the result.
Search the OpenAPI spec with JavaScript code or legacy keyword search. Write JavaScript to search the spec using: searchPaths(query, maxResults=10) — keyword search across paths, summaries, tags, parameters; listTags() — list all tags with operation counts; getOperation(idOrPath) — get full operation by operationId or path; describeOperation(idOrPath) — formatted documentation for an operation; spec — the full frozen OpenAPI spec object. Use search to discover endpoints, then write code in execute to call them. USAGE IN execute: api.get(path, params) for GET, api.post(path, body, params) for POST; Path params like /lookup/{id} are auto-interpolated from params; Large responses (>100KB) are auto-staged; use query_data to explore.
Output schemas not formally documented. Descriptions explain what tools return in prose (e.g., 'returns array of plain { variable: value } rows'), but no JSON Schema definitions are visible. LLMs cannot reliably parse unstructured responses or plan downstream tool calls without typed output schemas.
Code execution tools (execute, graphql_execute, sparql_execute) lack explicit security warnings and permission declarations. Descriptions mention 'sandboxed V8 isolate' but do not state what permissions are required, what code can access, or how to handle untrusted input. No scope declarations visible.
No error handling guidance. Descriptions do not explain what errors can occur, how to classify them (retryable vs. fatal), or what recovery steps to take. E.g., 'Large responses auto-staged' but no error message if staging fails.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | F | 46 | 2026-07-28+ | v2 |
Execute JavaScript code against a SPARQL endpoint with sandboxed V8 isolate. Code runs with: sparql.query(queryString, opts?) — run SELECT/CONSTRUCT/DESCRIBE; returns array of plain { variable: value } rows; sparql.ask(queryString) — run ASK; returns boolean; sparql.raw(queryString, opts?) — return unparsed { head, results } envelope; prefixes — object of common ontology prefixes (rdfs, owl, xsd, skos, dcterms, void, obo, uberon, go, ncbigene, efo, obi, sio, up, ensembl, bgee); prefixHeader — pre-built PREFIX block to prepend to queries; console logging (log, warn, error, info) — captured output; optional filesystem access; optional domain-specific preamble. Large SPARQL responses (>30KB) are auto-staged into SQLite. The last expression or return value is the result.
Parameter constraints not enforced in schema. max_results accepts 'number' type but description says 'default 10, max 25', no enum, min/max bounds, or pattern validation visible in Zod schema. LLMs may pass invalid values.
Workspace parameter in execute/graphql_execute is optional but underdocumented. Description says 'Optional workspace ID for shared staging across servers' but does not explain what happens if omitted, how to discover valid workspace IDs, or what 'shared staging' means to the LLM.