Skip to content

Commit 2434f9a

Browse files
committed
feat: update VFB MCP URL and enhance tool descriptions for clarity and batch support
1 parent 57908de commit 2434f9a

1 file changed

Lines changed: 146 additions & 21 deletions

File tree

app/api/chat/route.js

Lines changed: 146 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,8 @@ async function finalizeGovernanceEvent({
343343
let vfbMcpClient = null
344344
let biorxivMcpClient = null
345345

346-
const VFB_MCP_URL = 'https://vfb3-mcp.virtualflybrain.org/'
346+
const DEFAULT_VFB_MCP_URL = 'https://vfb3-mcp-preview.virtualflybrain.org/'
347+
const VFB_MCP_URL = (process.env.VFB_MCP_URL || '').trim() || DEFAULT_VFB_MCP_URL
347348
const BIORXIV_MCP_URL = 'https://mcp.deepsense.ai/biorxiv/mcp'
348349

349350
async function getVfbMcpClient() {
@@ -410,11 +411,17 @@ function getToolConfig() {
410411
tools.push({
411412
type: 'function',
412413
name: 'vfb_get_term_info',
413-
description: 'Get detailed information about a VFB term by ID, including definitions, relationships, images, queries, and references.',
414+
description: 'Get detailed information from VFB by ID. Supports batch requests using an array of IDs.',
414415
parameters: {
415416
type: 'object',
416417
properties: {
417-
id: { type: 'string', description: 'The VFB term ID such as VFB_00102107 or FBbt_00003748' }
418+
id: {
419+
oneOf: [
420+
{ type: 'string', description: 'A single VFB ID such as VFB_00102107 or FBbt_00003748' },
421+
{ type: 'array', items: { type: 'string' }, description: 'Array of VFB IDs for batch lookup' }
422+
],
423+
description: 'One or more VFB IDs to look up'
424+
}
418425
},
419426
required: ['id']
420427
}
@@ -423,14 +430,110 @@ function getToolConfig() {
423430
tools.push({
424431
type: 'function',
425432
name: 'vfb_run_query',
426-
description: 'Run analyses such as PaintedDomains, NBLAST, or connectivity on a VFB entity. Only use query types returned by vfb_get_term_info.',
433+
description: 'Run VFB analyses such as PaintedDomains, NBLAST, or connectivity. Use only query types returned by vfb_get_term_info.',
434+
parameters: {
435+
type: 'object',
436+
properties: {
437+
id: {
438+
oneOf: [
439+
{ type: 'string', description: 'A single VFB ID to query' },
440+
{ type: 'array', items: { type: 'string' }, description: 'Array of VFB IDs to query with the same query_type' }
441+
],
442+
description: 'One or more VFB IDs'
443+
},
444+
query_type: { type: 'string', description: 'A query type returned by vfb_get_term_info for that term' },
445+
queries: {
446+
type: 'array',
447+
description: 'Optional mixed batch input: each item has {id, query_type}. If provided, id/query_type are ignored.',
448+
items: {
449+
type: 'object',
450+
properties: {
451+
id: { type: 'string', description: 'VFB ID' },
452+
query_type: { type: 'string', description: 'Query type for this VFB ID' }
453+
},
454+
required: ['id', 'query_type']
455+
}
456+
}
457+
}
458+
}
459+
})
460+
461+
tools.push({
462+
type: 'function',
463+
name: 'vfb_resolve_entity',
464+
description: 'Resolve an unresolved FlyBase name/synonym to an ID and metadata (EXACT/SYNONYM/BROAD match).',
465+
parameters: {
466+
type: 'object',
467+
properties: {
468+
name: { type: 'string', description: 'Raw unresolved FlyBase-related query, e.g. dpp, MB002B, SS04495, Hb9-GAL4' }
469+
},
470+
required: ['name']
471+
}
472+
})
473+
474+
tools.push({
475+
type: 'function',
476+
name: 'vfb_find_stocks',
477+
description: 'Find fly stocks for a FlyBase feature ID (gene, allele, insertion, combination, or stock).',
478+
parameters: {
479+
type: 'object',
480+
properties: {
481+
feature_id: { type: 'string', description: 'FlyBase ID such as FBgn..., FBal..., FBti..., FBco..., or FBst...' },
482+
collection_filter: { type: 'string', description: 'Optional stock centre filter, e.g. Bloomington, Kyoto, VDRC' }
483+
},
484+
required: ['feature_id']
485+
}
486+
})
487+
488+
tools.push({
489+
type: 'function',
490+
name: 'vfb_resolve_combination',
491+
description: 'Resolve an unresolved split-GAL4 combination name/synonym to FBco ID and components.',
427492
parameters: {
428493
type: 'object',
429494
properties: {
430-
id: { type: 'string', description: 'The VFB term ID to query' },
431-
query_type: { type: 'string', description: 'A query type returned for the term by vfb_get_term_info' }
495+
name: { type: 'string', description: 'Raw unresolved split-GAL4 combination text, e.g. MB002B or SS04495' }
432496
},
433-
required: ['id', 'query_type']
497+
required: ['name']
498+
}
499+
})
500+
501+
tools.push({
502+
type: 'function',
503+
name: 'vfb_find_combo_publications',
504+
description: 'Find publications linked to a split-GAL4 combination by FBco ID, with DOI/PMID/PMCID when available.',
505+
parameters: {
506+
type: 'object',
507+
properties: {
508+
fbco_id: { type: 'string', description: 'FlyBase combination ID such as FBco0000052' }
509+
},
510+
required: ['fbco_id']
511+
}
512+
})
513+
514+
tools.push({
515+
type: 'function',
516+
name: 'vfb_list_connectome_datasets',
517+
description: 'List available connectome dataset symbols/labels for comparative connectivity queries.',
518+
parameters: {
519+
type: 'object',
520+
properties: {}
521+
}
522+
})
523+
524+
tools.push({
525+
type: 'function',
526+
name: 'vfb_query_connectivity',
527+
description: 'Live comparative connectomics query between neuron classes across datasets. Can be slow.',
528+
parameters: {
529+
type: 'object',
530+
properties: {
531+
upstream_type: { type: 'string', description: 'Upstream (presynaptic) neuron class label or FBbt ID' },
532+
downstream_type: { type: 'string', description: 'Downstream (postsynaptic) neuron class label or FBbt ID' },
533+
weight: { type: 'number', description: 'Minimum synapse count threshold (recommended default 5)' },
534+
group_by_class: { type: 'boolean', description: 'Aggregate by class instead of per-neuron pairs' },
535+
exclude_dbs: { type: 'array', items: { type: 'string' }, description: 'Dataset symbols to exclude, e.g. [\"hb\", \"fafb\"]' }
536+
}
434537
}
435538
})
436539

@@ -1038,6 +1141,12 @@ const MCP_TOOL_ROUTING = {
10381141
vfb_search_terms: { server: 'vfb', mcpName: 'search_terms' },
10391142
vfb_get_term_info: { server: 'vfb', mcpName: 'get_term_info' },
10401143
vfb_run_query: { server: 'vfb', mcpName: 'run_query' },
1144+
vfb_resolve_entity: { server: 'vfb', mcpName: 'resolve_entity' },
1145+
vfb_find_stocks: { server: 'vfb', mcpName: 'find_stocks' },
1146+
vfb_resolve_combination: { server: 'vfb', mcpName: 'resolve_combination' },
1147+
vfb_find_combo_publications: { server: 'vfb', mcpName: 'find_combo_publications' },
1148+
vfb_list_connectome_datasets: { server: 'vfb', mcpName: 'list_connectome_datasets' },
1149+
vfb_query_connectivity: { server: 'vfb', mcpName: 'query_connectivity' },
10411150
biorxiv_search_preprints: { server: 'biorxiv', mcpName: 'search_preprints' },
10421151
biorxiv_get_preprint: { server: 'biorxiv', mcpName: 'get_preprint' },
10431152
biorxiv_search_published_preprints: { server: 'biorxiv', mcpName: 'search_published_preprints' },
@@ -1472,6 +1581,9 @@ TOOLS:
14721581
- vfb_search_terms: search VFB terms with filters
14731582
- vfb_get_term_info: fetch detailed VFB term information
14741583
- vfb_run_query: run VFB analyses returned by vfb_get_term_info
1584+
- vfb_resolve_entity / vfb_find_stocks: resolve FlyBase entity names and find relevant stocks
1585+
- vfb_resolve_combination / vfb_find_combo_publications: resolve split-GAL4 combinations and fetch linked publications
1586+
- vfb_list_connectome_datasets / vfb_query_connectivity: comparative class-level or neuron-level connectivity across datasets
14751587
- search_reviewed_docs: search approved VFB, NeuroFly, VFB Connect docs, and reviewed FlyBase pages using a server-side site index
14761588
- get_reviewed_page: fetch and extract content from an approved page returned by search_reviewed_docs
14771589
- search_pubmed / get_pubmed_article: search and fetch peer-reviewed publications
@@ -1480,15 +1592,26 @@ TOOLS:
14801592
${VFB_QUERY_LINK_SKILL}
14811593
14821594
TOOL SELECTION:
1595+
- Choose tools dynamically based on the user request and available evidence; the guidance below is preferred, not a rigid workflow.
14831596
- Questions about VFB terms, anatomy, neurons, genes, or datasets: use VFB tools
1597+
- For VFB entity questions where suitable query types are available, prefer vfb_get_term_info + vfb_run_query as a first pass because vfb_run_query is usually cached and faster.
1598+
- Questions about FlyBase genes/alleles/insertions/stocks: use vfb_resolve_entity first (if unresolved), then vfb_find_stocks
1599+
- Questions about split-GAL4 combination names/synonyms (for example MB002B, SS04495): use vfb_resolve_combination first, then vfb_find_combo_publications (and optionally vfb_find_stocks if the user asks for lines)
1600+
- Questions about comparative connectivity between neuron classes across datasets: use vfb_query_connectivity (optionally vfb_list_connectome_datasets first to pick valid dataset symbols)
14841601
- Questions about published papers or recent literature: use PubMed first, optionally bioRxiv/medRxiv for preprints
14851602
- Questions about VFB, NeuroFly, VFB Connect Python documentation, or approved FlyBase documentation pages, news posts, workshops, conference pages, or event dates: use search_reviewed_docs, then use get_reviewed_page when you need page details
14861603
- For questions about how to run VFB queries in Python or how to use vfb-connect, prioritize search_reviewed_docs/get_reviewed_page on vfb-connect.readthedocs.io alongside VFB tool outputs when useful.
1487-
- For connectivity, synaptic, or NBLAST questions, and especially when the user explicitly asks for vfb_run_query, do not use reviewed-doc search first; use VFB tools (vfb_search_terms/vfb_get_term_info/vfb_run_query).
1604+
- For connectivity, synaptic, or NBLAST questions, and especially when the user explicitly asks for vfb_run_query, do not use reviewed-doc search first; use VFB tools (vfb_search_terms/vfb_get_term_info/vfb_run_query). Use vfb_query_connectivity when the user asks for class-to-class connectivity comparisons across datasets.
14881605
- Do not attempt general web search or browsing outside the approved reviewed-doc index
14891606
1607+
ENTITY RESOLUTION RULES:
1608+
- If vfb_resolve_entity or vfb_resolve_combination returns match_type SYNONYM or BROAD, confirm the resolved entity with the user before running downstream tools.
1609+
- If resolver output includes multiple candidates, show a short disambiguation list and ask the user to choose before continuing.
1610+
- If the user already provided a canonical FlyBase ID (for example FBgn..., FBal..., FBti..., FBco..., FBst...), you may call downstream tools directly.
1611+
14901612
TOOL ECONOMY:
14911613
- Prefer the fewest tool steps needed to produce a useful answer.
1614+
- Start with cached vfb_run_query pathways when they can answer the question, then use other tools for deeper refinement only when needed.
14921615
- Do not keep calling tools just to exhaustively enumerate large result sets.
14931616
- If the question is broad or combinatorial, stop once you have enough evidence to give a partial answer.
14941617
- For broad gene-expression or transgene-pattern requests, prefer a short representative list (about 3-5 items) and ask how the user wants to narrow further instead of trying to enumerate everything in one turn.
@@ -1511,9 +1634,13 @@ TOOL RELAY:
15111634
- If a question needs data and no results are available yet, request tools first, then answer after results arrive.
15121635
15131636
FOLLOW-UP QUESTIONS:
1514-
When useful, suggest 2-3 short follow-up questions relevant to Drosophila neuroscience and actionable in this chat.`
1637+
When useful, suggest 2-3 short potential follow-up questions that are directly answerable with the available tools in this chat.`
15151638

15161639
function getStatusForTool(toolName) {
1640+
if (toolName === 'vfb_query_connectivity') {
1641+
return { message: 'Comparing connectome datasets', phase: 'mcp' }
1642+
}
1643+
15171644
if (toolName.startsWith('vfb_')) {
15181645
return { message: 'Querying the fly hive mind', phase: 'mcp' }
15191646
}
@@ -1688,29 +1815,26 @@ function hasConnectivityIntent(message = '') {
16881815
return /\b(connectome|connectivity|connection|connections|synapse|synaptic|presynaptic|postsynaptic|input|inputs|output|outputs|nblast)\b/i.test(message)
16891816
}
16901817

1691-
function isDocsOnlyToolCallSet(toolCalls = []) {
1692-
if (!Array.isArray(toolCalls) || toolCalls.length === 0) return false
1693-
return toolCalls.every(call => call.name === 'search_reviewed_docs' || call.name === 'get_reviewed_page')
1694-
}
1695-
16961818
function buildToolPolicyCorrectionMessage({
16971819
userMessage = '',
16981820
explicitRunQueryRequested = false,
16991821
connectivityIntent = false,
17001822
missingRunQueryExecution = false
17011823
}) {
17021824
const policyBullets = [
1703-
'- For this request, prioritize VFB tools over reviewed-doc search.',
1704-
'- Use vfb_search_terms and/or vfb_get_term_info to identify the target entity and valid query types.',
1705-
'- Use vfb_run_query when a relevant query_type is available.'
1825+
'- Choose the smallest set of tools that best answers the user request.',
1826+
'- For VFB query-type questions, prefer vfb_get_term_info + vfb_run_query as the first pass because vfb_run_query is typically cached and fast.',
1827+
'- Use more specialized tools (for example vfb_query_connectivity, vfb_resolve_entity, vfb_find_stocks, vfb_resolve_combination, vfb_find_combo_publications) when deeper refinement is needed.',
1828+
'- Prefer direct data tools over documentation search when the question asks for concrete VFB data.',
1829+
'- If existing tool outputs already answer the question, provide the final answer instead of requesting more tools.'
17061830
]
17071831

17081832
if (explicitRunQueryRequested) {
17091833
policyBullets.push('- The user explicitly asked for vfb_run_query, so include a plan that leads to vfb_run_query.')
17101834
}
17111835

17121836
if (connectivityIntent) {
1713-
policyBullets.push('- This is a connectivity-style request; do not default to search_reviewed_docs first.')
1837+
policyBullets.push('- This is a connectivity-style request; favor VFB connectivity/query tools over docs-only search.')
17141838
}
17151839

17161840
if (missingRunQueryExecution) {
@@ -1974,6 +2098,7 @@ Using only the gathered tool outputs already provided in this conversation:
19742098
- clearly say that the answer is partial because the request branched into too many tool steps
19752099
- summarize the strongest findings you already have
19762100
- end with 2-4 direct clarification questions the user can answer so you can continue in a narrower, lower-tool way
2101+
- make those questions concrete and answerable with the tools available in this chat
19772102
19782103
Do not call tools. Do not ask to browse the web.`
19792104

@@ -2016,6 +2141,7 @@ Using only the existing conversation and any tool outputs already provided:
20162141
- give a brief summary of what direction is available so far
20172142
- do not invent missing facts
20182143
- ask 2-4 short clarifying questions the user can answer so the next turn can be narrower and easier to resolve
2144+
- keep clarifying questions concrete and answerable with the tools available in this chat
20192145
20202146
Do not call tools. Do not ask to browse the web.`
20212147

@@ -2062,6 +2188,7 @@ Using only the existing conversation, any tool outputs already provided, and any
20622188
- if the evidence is still too incomplete, say that briefly and ask 2-4 short clarifying questions
20632189
- prefer a short concrete answer over more questions if the available evidence already supports one
20642190
- do not invent missing facts
2191+
- if you ask questions, make them concrete and answerable with the tools available in this chat
20652192
20662193
Do not call tools. Do not ask to browse the web.`
20672194

@@ -2164,10 +2291,8 @@ async function processResponseStream({
21642291

21652292
if (requestedToolCalls.length > 0) {
21662293
const hasVfbToolCall = requestedToolCalls.some(toolCall => toolCall.name.startsWith('vfb_'))
2167-
const docsOnlyToolCalls = isDocsOnlyToolCallSet(requestedToolCalls)
21682294
const shouldCorrectToolChoice = toolPolicyCorrections < maxToolPolicyCorrections && (
2169-
(explicitRunQueryRequested && !hasVfbToolCall) ||
2170-
(connectivityIntent && docsOnlyToolCalls)
2295+
explicitRunQueryRequested && !hasVfbToolCall
21712296
)
21722297

21732298
if (shouldCorrectToolChoice) {

0 commit comments

Comments
 (0)