07 implement done#1
Merged
Merged
Conversation
…eline) - Phase 1 (T001-T005): Project scaffolding with TypeScript, Vitest, package.json, folder structure - Phase 2 (T006-T015): Foundational data layer with Zod schemas, data loader, normalization, query primitives, common tools, MCP bootstrap, and 37 passing unit tests - Phase 3 US1 (T016-T022, T041-T043): Implemented 3 core tools (get_event_info, list_schedule, get_current_or_next_item) with contract tests, integration tests, and invalid/malformed input tests Test Status: 102 tests passing across all layers - Unit tests: 37 tests (data loading, queries, normalization) - Contract tests: 13 tests (US1 happy path and empty scenarios) - Integration tests: 11 tests (timeline behavior, overlaps, transitions) - Invalid input tests: 41 tests (invalid/malformed coverage for US1 tools) Next phases: US2 (Discovery tools), US3 (Recommendations), Polish & Documentation
There was a problem hiding this comment.
Pull request overview
Implements a TypeScript/Node MCP server codebase for exploring the Code & Comedy event dataset (loading + schema validation, normalized in-memory model, and tool handlers), and adds a large set of Spec Kit artifacts plus Vitest-based tests/docs to support the workflow.
Changes:
- Added Zod-based parsing/validation + normalization of event JSON into a queryable domain model.
- Added MCP tool handlers (event info, schedule, current/next, search, speakers, categories, session details, recommendations) plus contract/integration/unit tests.
- Added repo scaffolding/config: Vitest + TS config, ESLint, documentation/spec artifacts, and updated event JSON categories.
Reviewed changes
Copilot reviewed 122 out of 124 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| vitest.config.ts | Adds Vitest configuration (env/globals/coverage + path alias). |
| tsconfig.json | Adds TypeScript compiler configuration for build output + path mapping. |
| tests/unit/loadEventData.test.ts | Adds unit tests for schema parsing + event file loading. |
| tests/integration/us3-recommendations.behavior.test.ts | Adds integration behavior tests for recommendations ordering/limits. |
| tests/integration/us1-timeline.behavior.test.ts | Adds integration behavior tests for timeline queries and boundaries. |
| tests/fixtures/malformed-event.json | Adds malformed fixture JSON for negative test scenarios. |
| tests/contract/us3-recommendations.invalid-malformed.test.ts | Adds invalid input + malformed data contract tests for recommendations. |
| tests/contract/us3-recommendations.contract.test.ts | Adds contract tests for recommendations happy/empty paths. |
| tests/contract/us2-session-details.invalid-malformed.test.ts | Adds invalid/malformed tests for session details tool. |
| tests/contract/us2-search-sessions.invalid-malformed.test.ts | Adds invalid/malformed tests for search sessions tool. |
| tests/contract/us2-list-speakers.invalid-malformed.test.ts | Adds invalid/malformed tests for list speakers tool. |
| tests/contract/us2-list-categories.invalid-malformed.test.ts | Adds invalid/malformed tests for list categories tool. |
| tests/contract/us1-list-schedule.invalid-malformed.test.ts | Adds invalid/malformed tests for list schedule tool. |
| tests/contract/us1-get-event-info.invalid-malformed.test.ts | Adds invalid/malformed tests for get event info tool. |
| tests/contract/us1-current-next.invalid-malformed.test.ts | Adds invalid/malformed tests for current/next tool. |
| tests/contract/tools.contract.test.ts | Adds regression suite covering all tools’ baseline behavior. |
| src/tools/searchSessions.ts | Implements search tool handler with match metadata. |
| src/tools/recommendSessions.ts | Implements recommend_sessions tool handler with validation + safe errors. |
| src/tools/listSpeakers.ts | Implements list_speakers tool handler (dedupe/sort/link). |
| src/tools/listSchedule.ts | Implements list_schedule tool handler (chronological schedule output). |
| src/tools/listCategories.ts | Implements list_categories tool handler (dedupe/sort/link). |
| src/tools/getSessionDetails.ts | Implements get_session_details tool handler with partial matching/alternatives. |
| src/tools/getEventInfo.ts | Implements get_event_info tool handler with schedule stats. |
| src/tools/getCurrentOrNextItem.ts | Implements get_current_or_next_item tool handler using time context. |
| src/tools/common.ts | Adds shared input validation + response envelope helpers. |
| src/domain/scheduleQueries.ts | Adds shared query primitives (time window, current/next, search helpers). |
| src/domain/recommendationQueries.ts | Adds deterministic recommendation scoring + ordering. |
| src/domain/normalizeEventData.ts | Normalizes raw JSON into flattened sessions + indices with time validation. |
| src/domain/eventModel.ts | Defines normalized domain types and ToolResponse envelope. |
| src/data/schemas.ts | Adds Zod schemas for canonical raw data + source data mapping. |
| src/data/loadEventData.ts | Adds sync/async JSON loading from codeandcomedy-talks.json. |
| specs/001-mcp-event-server/spec.md | Adds feature specification (user stories, requirements, success criteria). |
| specs/001-mcp-event-server/research.md | Adds planning research decisions and rationale. |
| specs/001-mcp-event-server/quickstart.md | Adds quickstart steps for install/build/test/run. |
| specs/001-mcp-event-server/quickstart-validation.md | Adds quickstart validation checklist for local verification. |
| specs/001-mcp-event-server/plan.md | Adds implementation plan + repo structure outline. |
| specs/001-mcp-event-server/data-model.md | Adds design-level data model description. |
| specs/001-mcp-event-server/contracts/mcp-tools.md | Adds documented tool contracts (inputs/outputs/error rules). |
| specs/001-mcp-event-server/checklists/requirements.md | Adds spec quality checklist for requirements completeness. |
| README.md | Adds repository-level usage docs and tool list. |
| package.json | Adds Node/TS build/test scripts and dependencies for MCP SDK/Zod/Vitest. |
| docs/mcp-config.example.json | Adds example MCP client/server config pointing at dist/index.js. |
| demo-prompts/specify.md | Adds demo prompt content describing desired MCP server behavior. |
| demo-prompts/plan.md | Adds demo-oriented technical plan prompt. |
| demo-prompts/constitution.md | Adds demo constitution/principles prompt. |
| codeandcomedy-talks.json | Adds categories metadata to schedule items and nested sessions. |
| .vscode/settings.json | Adds editor settings for prompt file recommendations and excludes. |
| .specify/templates/spec-template.md | Adds Spec Kit spec template. |
| .specify/templates/plan-template.md | Adds Spec Kit plan template. |
| .specify/templates/constitution-template.md | Adds Spec Kit constitution template. |
| .specify/templates/checklist-template.md | Adds Spec Kit checklist template. |
| .specify/templates/agent-file-template.md | Adds template for generated agent guidance file. |
| .specify/scripts/powershell/setup-plan.ps1 | Adds Spec Kit plan setup helper script. |
| .specify/scripts/powershell/check-prerequisites.ps1 | Adds Spec Kit consolidated prerequisites checker. |
| .specify/memory/constitution.md | Adds/records the repository constitution content. |
| .specify/integrations/speckit.manifest.json | Adds Speckit integration manifest. |
| .specify/integrations/copilot/scripts/update-context.sh | Adds Copilot integration script shim (bash). |
| .specify/integrations/copilot/scripts/update-context.ps1 | Adds Copilot integration script shim (PowerShell). |
| .specify/integrations/copilot.manifest.json | Adds Copilot integration manifest. |
| .specify/integration.json | Adds integration configuration pointing to update-context script. |
| .specify/init-options.json | Adds Spec Kit initialization options. |
| .specify/feature.json | Adds feature directory pointer for Spec Kit. |
| .specify/extensions/git/scripts/powershell/initialize-repo.ps1 | Adds git extension repo init script (PowerShell). |
| .specify/extensions/git/scripts/powershell/git-common.ps1 | Adds git extension shared helpers (PowerShell). |
| .specify/extensions/git/scripts/powershell/auto-commit.ps1 | Adds git extension auto-commit hook script (PowerShell). |
| .specify/extensions/git/scripts/bash/initialize-repo.sh | Adds git extension repo init script (bash). |
| .specify/extensions/git/scripts/bash/git-common.sh | Adds git extension shared helpers (bash). |
| .specify/extensions/git/scripts/bash/auto-commit.sh | Adds git extension auto-commit hook script (bash). |
| .specify/extensions/git/README.md | Adds documentation for Spec Kit git extension. |
| .specify/extensions/git/git-config.yml | Adds git extension configuration defaults. |
| .specify/extensions/git/extension.yml | Adds extension descriptor (commands/hooks/config). |
| .specify/extensions/git/config-template.yml | Adds git config template for extension install. |
| .specify/extensions/git/commands/speckit.git.validate.md | Adds command docs for branch validation. |
| .specify/extensions/git/commands/speckit.git.remote.md | Adds command docs for remote detection. |
| .specify/extensions/git/commands/speckit.git.initialize.md | Adds command docs for repo initialization. |
| .specify/extensions/git/commands/speckit.git.feature.md | Adds command docs for feature branch creation. |
| .specify/extensions/git/commands/speckit.git.commit.md | Adds command docs for auto-commit hook. |
| .specify/extensions/.registry | Adds extensions registry state. |
| .specify/extensions.yml | Adds extension hook configuration enabling git hooks. |
| .npmignore | Defines npm package ignore list. |
| .gitignore | Defines git ignore rules (node/build/test/ide/env). |
| .github/prompts/speckit.taskstoissues.prompt.md | Adds prompt stub for taskstoissues agent. |
| .github/prompts/speckit.tasks.prompt.md | Adds prompt stub for tasks agent. |
| .github/prompts/speckit.specify.prompt.md | Adds prompt stub for specify agent. |
| .github/prompts/speckit.plan.prompt.md | Adds prompt stub for plan agent. |
| .github/prompts/speckit.implement.prompt.md | Adds prompt stub for implement agent. |
| .github/prompts/speckit.git.validate.prompt.md | Adds prompt stub for git.validate agent. |
| .github/prompts/speckit.git.remote.prompt.md | Adds prompt stub for git.remote agent. |
| .github/prompts/speckit.git.initialize.prompt.md | Adds prompt stub for git.initialize agent. |
| .github/prompts/speckit.git.feature.prompt.md | Adds prompt stub for git.feature agent. |
| .github/prompts/speckit.git.commit.prompt.md | Adds prompt stub for git.commit agent. |
| .github/prompts/speckit.constitution.prompt.md | Adds prompt stub for constitution agent. |
| .github/prompts/speckit.clarify.prompt.md | Adds prompt stub for clarify agent. |
| .github/prompts/speckit.checklist.prompt.md | Adds prompt stub for checklist agent. |
| .github/prompts/speckit.analyze.prompt.md | Adds prompt stub for analyze agent. |
| .github/copilot-instructions.md | Adds generated Copilot guidance (tech stack/commands). |
| .github/agents/speckit.taskstoissues.agent.md | Adds agent instructions for tasks-to-issues conversion. |
| .github/agents/speckit.plan.agent.md | Adds agent instructions for plan workflow. |
| .github/agents/speckit.git.validate.agent.md | Adds agent instructions for git.validate workflow. |
| .github/agents/speckit.git.remote.agent.md | Adds agent instructions for git.remote workflow. |
| .github/agents/speckit.git.initialize.agent.md | Adds agent instructions for git.initialize workflow. |
| .github/agents/speckit.git.feature.agent.md | Adds agent instructions for git.feature workflow. |
| .github/agents/speckit.git.commit.agent.md | Adds agent instructions for git.commit workflow. |
| .github/agents/speckit.constitution.agent.md | Adds agent instructions for constitution workflow. |
| .eslintrc.cjs | Adds ESLint configuration for TS/Node project. |
| .eslintignore | Adds ESLint ignore patterns. |
Comment on lines
+44
to
+50
| export function getNextSession( | ||
| model: EventModel, | ||
| currentTime: string | ||
| ): SessionDetail | undefined { | ||
| const upcoming = model.flattenedSessions.filter((s) => s.startTime > currentTime); | ||
| return upcoming.length > 0 ? upcoming[0] : undefined; | ||
| } |
Comment on lines
+13
to
+26
| /** | ||
| * Find sessions with overlapping time window | ||
| * Treats sessions as inclusive: [startTime, endTime] | ||
| */ | ||
| export function findSessionsInTimeWindow( | ||
| model: EventModel, | ||
| startTime: string, | ||
| endTime: string | ||
| ): SessionDetail[] { | ||
| return model.flattenedSessions.filter((session) => { | ||
| // Overlap if: session.start < queryEnd AND session.end > queryStart | ||
| return session.startTime < endTime && session.endTime > startTime; | ||
| }); | ||
| } |
Comment on lines
+33
to
+88
| const query = parseResult.query.toLowerCase(); | ||
| const results: SearchMatch[] = []; | ||
|
|
||
| for (const session of model.flattenedSessions) { | ||
| const matchedFields: string[] = []; | ||
| const matchReasons: string[] = []; | ||
|
|
||
| // Check title match | ||
| if (session.title.toLowerCase().includes(query)) { | ||
| matchedFields.push('title'); | ||
| matchReasons.push(`Title contains "${query}"`); | ||
| } | ||
|
|
||
| // Check abstract match | ||
| if (session.abstract && session.abstract.toLowerCase().includes(query)) { | ||
| matchedFields.push('abstract'); | ||
| matchReasons.push(`Abstract contains "${query}"`); | ||
| } | ||
|
|
||
| // Check speaker matches | ||
| const matchingSpeakers = session.speakers.filter((sp) => | ||
| sp.name.toLowerCase().includes(query) | ||
| ); | ||
| if (matchingSpeakers.length > 0) { | ||
| matchedFields.push('speakers'); | ||
| matchReasons.push( | ||
| `Speaker names: ${matchingSpeakers.map((sp) => sp.name).join(', ')}` | ||
| ); | ||
| } | ||
|
|
||
| // Check category matches | ||
| const matchingCategories = session.categories.filter((c) => | ||
| c.name.toLowerCase().includes(query) | ||
| ); | ||
| if (matchingCategories.length > 0) { | ||
| matchedFields.push('categories'); | ||
| matchReasons.push( | ||
| `Categories: ${matchingCategories.map((c) => c.name).join(', ')}` | ||
| ); | ||
| } | ||
|
|
||
| // Add to results if any match found | ||
| if (matchedFields.length > 0) { | ||
| results.push({ | ||
| sessionId: session.sessionId, | ||
| title: session.title, | ||
| abstract: session.abstract, | ||
| speakers: Array.from(session.speakers), | ||
| categories: session.categories.map((category) => category.name), | ||
| matchedFields, | ||
| matchReasons, | ||
| }); | ||
| } | ||
| } | ||
|
|
||
| return common.successResponse(results); |
Comment on lines
+47
to
+60
| // Link sessions to each speaker | ||
| const results: SpeakerInfo[] = speakers.map((speaker) => ({ | ||
| speakerId: speaker.speakerId, | ||
| name: speaker.name, | ||
| bio: speaker.bio, | ||
| sessions: model.flattenedSessions | ||
| .filter((session) => | ||
| session.speakers.some((sp) => sp.speakerId === speaker.speakerId) | ||
| ) | ||
| .map((session) => ({ | ||
| sessionId: session.sessionId, | ||
| title: session.title, | ||
| })), | ||
| })); |
Comment on lines
+43
to
+55
| // Link sessions to each category | ||
| const results: CategoryInfo[] = categories.map((category) => ({ | ||
| categoryId: category.categoryId, | ||
| name: category.name, | ||
| sessions: model.flattenedSessions | ||
| .filter((session) => | ||
| session.categories.some((c) => c.categoryId === category.categoryId) | ||
| ) | ||
| .map((session) => ({ | ||
| sessionId: session.sessionId, | ||
| title: session.title, | ||
| })), | ||
| })); |
Comment on lines
+6
to
+21
| ## Shared contract rules | ||
| - Input validation errors return: | ||
| - `ok: false` | ||
| - `error.code: "INVALID_INPUT"` | ||
| - `error.message: string` | ||
| - Data availability issues return: | ||
| - `ok: false` | ||
| - `error.code: "DATA_UNAVAILABLE"` | ||
| - No-match queries return: | ||
| - `ok: true` | ||
| - empty arrays or `null` detail fields | ||
| - optional `message` guidance | ||
| - Tool success returns: | ||
| - `ok: true` | ||
| - typed payload fields specific to tool | ||
|
|
Comment on lines
+51
to
+53
| if (matches.length === 0) { | ||
| return common.errorResponse(`Session not found: ${sessionId}`); | ||
| } |
Comment on lines
+6
to
+13
| export const GetCurrentOrNextInputSchema = z | ||
| .object({ | ||
| currentTime: z | ||
| .string() | ||
| .regex(/^\d{2}:\d{2}$/, 'Time must be HH:mm format') | ||
| .optional(), | ||
| }) | ||
| .strict(); |
Comment on lines
+22
to
+26
| ## 4. Start in stdio mode | ||
| ```powershell | ||
| npm run start | ||
| ``` | ||
|
|
Comment on lines
+1
to
+2
| import { defineConfig } from 'vitest/config'; | ||
| import path from 'path'; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.