Ctx Research Scanner¶
ctx_research_scanner — AI research discovery and novelty scoring.
Cluster: Uncategorised | Type: component | MCP Tools: 26
Overview¶
Automated research paper discovery and triage system. Scans arXiv and custom URLs for papers relevant to G6 capability gaps, with a deterministic mock source for tests. GitHub and academic conference proceedings are visible as source capabilities but are gated as not_implemented; requests for those sources return completion_state="blocked-escalated" with warning-card/evidence metadata rather than silently scanning. Scores and ranks candidates with scoring_method="keyword_overlap" (heuristic component-name overlap, not semantic gap analysis), deduplicates across arXiv IDs, and maintains a persistent SQLite-backed session registry. Schedule settings are scheduling_mode="config_only" with active_scheduler=false.
When to use:
- Running on-demand arXiv scans for new papers in a domain
- Extracting arXiv paper links from a custom URL
- Identifying heuristic research gaps in the current G6 component set
- Building a curated reading list for a specific capability area
Example:
from mvp.ctx_research_scanner import CtxResearchScannerBlock, ScanInput
block = CtxResearchScannerBlock(name="scanner")
result = block.infer(ScanInput(source="arxiv", query="program synthesis CEGIS 2025"))
# result.ok -> True; result.value -> ScanOutput with completion_state,
# warning_card, evidence, request_id, and run_id envelope fields.
Works well with: ctx_library_mapper, adapt_library_synthesizer, ctx_scrapling
Public API¶
CtxResearchScannerBlock(AIBlock[ScanInput, ScanOutput, None])¶
| Field | Type | Default |
|---|---|---|
name | str | 'ctx_research_scanner' |
resource_bounds | ResourceBounds \| None | None |
usage | ResourceUsage | field(default_factory=ResourceUsage) |
agentic_planner | CtxResearchScannerPlanner \| None | None |
Methods:
infer(data: ScanInput) -> Result[ScanOutput]¶
PaperRecord(BaseModel)¶
| Field | Type | Default |
|---|---|---|
title | str | required |
url | str | required |
abstract | str | '' |
authors | str | '' |
date | str | '' |
source | str | '' |
arxiv_id | str | '' |
key_terms | list[str] | Field(default_factory=list) |
ScanInput(BaseModel)¶
| Field | Type | Default |
|---|---|---|
source | Literal['arxiv', 'github', 'conferences', 'custom', 'mock'] | 'mock' |
query | str | required |
categories | list[str] | Field(default_factory=list) |
max_results | int | Field(default=10, ge=1, le=100) |
url | str | '' |
agentic_rerank | bool \| None | None |
run_mode | Literal['beta', 'production'] | 'beta' |
reviewer_signature | str | '' |
ScanOutput(BaseModel)¶
| Field | Type | Default |
|---|---|---|
source | str | required |
query | str | required |
results | list[PaperRecord] | required |
total_found | int | required |
degraded | bool | False |
degradation_reason | str \| None | None |
completion_state | Literal['verified', 'qualified-draft', 'blocked-escalated'] | 'qualified-draft' |
warning_card | dict[str, Any] | Field(default_factory=dict) |
evidence | dict[str, Any] | Field(default_factory=dict) |
request_id | str | '' |
task_id | str | '' |
run_id | str | '' |
agentic_evidence | dict | Field(default_factory=dict) |
CtxResearchScannerMCPBlock(AIBlock[MCPResearchScannerInput, MCPResearchScannerOutput, dict])¶
25-op research scanner MCP block with SQLite persistence (+1 block-dispatch op).
| Field | Type | Default |
|---|---|---|
name | str | 'ctx_research_scanner_mcp' |
resource_bounds | ResourceBounds \| None | None |
usage | ResourceUsage | field(default_factory=ResourceUsage) |
state | dict | field(default_factory=dict) |
db_path | str | ':memory:' |
agentic_planner | CtxResearchScannerPlanner \| None | None |
Methods:
store() -> ResearchScannerStore¶
infer(data: MCPResearchScannerInput) -> Result[MCPResearchScannerOutput]¶
MCPResearchScannerRecord(BaseModel)¶
| Field | Type | Default |
|---|---|---|
id | str | '' |
record_type | str | '' |
key | str | '' |
value | str | '' |
tags | list[str] | Field(default_factory=list) |
timestamp | str | '' |
metadata | dict[str, Any] | Field(default_factory=dict) |
MCPResearchScannerInput(BaseModel)¶
| Field | Type | Default |
|---|---|---|
op | ResearchScannerOp | required |
paper_id | str | '' |
title | str | '' |
url | str | '' |
abstract | str | '' |
arxiv_id | str | '' |
key_terms | str | '' |
seed_path | str | '' |
query | str | '' |
source | str | '' |
categories | str | '' |
max_results | int | Field(default=10, ge=1, le=100) |
custom_url | str | '' |
session_id | str | '' |
domain | str | '' |
trigger | str | '' |
sources | str | '' |
source_id | str | '' |
source_type | str | '' |
source_url | str | '' |
schedule_hours | int | Field(default=0, ge=0) |
limit | int | Field(default=50, ge=1, le=1000) |
offset | int | Field(default=0, ge=0) |
agentic_rerank | bool \| None | None |
run_mode | Literal['beta', 'production'] | 'beta' |
reviewer_signature | str | '' |
MCPResearchScannerOutput(BaseModel)¶
| Field | Type | Default |
|---|---|---|
op | str | '' |
key | str | '' |
value | str | '' |
found | bool | False |
count | int | 0 |
records | list[MCPResearchScannerRecord] | Field(default_factory=list) |
content | str | '' |
scores | list[float] | Field(default_factory=list) |
message | str | '' |
metadata | dict[str, Any] | Field(default_factory=dict) |
degraded | bool | False |
degradation_reason | str | '' |
completion_state | Literal['verified', 'qualified-draft', 'blocked-escalated'] | 'qualified-draft' |
warning_card | dict[str, Any] | Field(default_factory=dict) |
evidence | dict[str, Any] | Field(default_factory=dict) |
request_id | str | '' |
task_id | str | '' |
run_id | str | '' |
agentic_evidence | dict[str, Any] | Field(default_factory=dict) |
ResearchScannerStore¶
Constructor:
| Parameter | Type | Default |
|---|---|---|
db_path | str | ':memory:' |
Methods:
add_paper(title: str, url: str = '', abstract: str = '', authors: str = '', date: str = '', source: str = '', arxiv_id: str = '', key_terms: list[str] | None = None) -> str¶
get_paper(paper_id: str) -> dict[str, Any] | None¶
remove_paper(paper_id: str) -> bool¶
search_papers(query: str, limit: int = 50) -> list[dict[str, Any]]¶
list_papers(limit: int = 50, offset: int = 0) -> list[dict[str, Any]]¶
count_papers() -> int¶
find_by_arxiv_id(arxiv_id: str) -> dict[str, Any] | None¶
start_session(trigger: str, sources: list[str]) -> str¶
get_session(session_id: str) -> dict[str, Any] | None¶
finish_session(session_id: str, candidates_found: int = 0) -> None¶
list_sessions(limit: int = 50) -> list[dict[str, Any]]¶
add_candidate(session_id: str, title: str, url: str = '', abstract: str = '', arxiv_id: str = '', novelty_score: float = 0.0, capability_gap: str = '', domain: str = '', key_terms: list[str] | None = None) -> str¶
list_candidates(session_id: str = '', limit: int = 50, offset: int = 0) -> list[dict[str, Any]]¶
update_candidate_score(candidate_id: str, novelty_score: float, capability_gap: str = '') -> bool¶
find_duplicates_by_arxiv() -> list[list[dict[str, Any]]]¶
add_source(source_type: str, url: str = '', categories: str = '') -> str¶
remove_source(source_id: str) -> bool¶
list_sources() -> list[dict[str, Any]]¶
MCP Tools¶
| Operation | Source |
|---|---|
import_seed_papers | research_scanner_mcp |
add_paper | research_scanner_mcp |
remove_paper | research_scanner_mcp |
search_papers | research_scanner_mcp |
list_papers | research_scanner_mcp |
scan_arxiv | research_scanner_mcp |
scan_github | research_scanner_mcp |
scan_conferences | research_scanner_mcp |
scan_custom_url | research_scanner_mcp |
scan_all | research_scanner_mcp |
score_candidates | research_scanner_mcp |
get_capability_gaps | research_scanner_mcp |
rank_candidates | research_scanner_mcp |
filter_by_domain | research_scanner_mcp |
deduplicate | research_scanner_mcp |
start_scan_session | research_scanner_mcp |
get_session_status | research_scanner_mcp |
list_sessions | research_scanner_mcp |
get_candidates | research_scanner_mcp |
export_candidates | research_scanner_mcp |
add_source | research_scanner_mcp |
remove_source | research_scanner_mcp |
list_sources | research_scanner_mcp |
set_schedule | research_scanner_mcp |
research_scanner_info | research_scanner_mcp |
list_patterns | research_scanner_mcp |