Skip to content

full mcp implementation - #4408

Merged
chpy04 merged 3 commits into
developfrom
#4404-mcp-implementation
Sep 2, 2026
Merged

full mcp implementation#4408
chpy04 merged 3 commits into
developfrom
#4404-mcp-implementation

Conversation

@chpy04

@chpy04 chpy04 commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Changes

The actual mcp implementation necessary for agents to connect

Notes

  • needed to add zod for mcp (we should only use this for mcp)
  • Decided not to implement oauth2.0 (technically what mcp wants) and opt for api token approach for simplicity (still configurable in claude with:
claude mcp add --transport http finishline https://api.finishlinebyner.com/mcp \ 
  -H "x-api-key: fl_api_key"

Screenshots

Screenshot 2026-08-29 at 6 13 56 PM

Closes #4404

@wavehassman
wavehassman self-requested a review August 30, 2026 23:25

@wavehassman wavehassman 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.

Since the caller here is a model rather than our UI, the inputs aren't really controlled. We could get 01.1.0, 1.1, sometimes a WBS that doesn't exist. Right now wbsNum is an unconstrained z.string(). I think adding a regex to the tool schema would help return a proper validation error

z.string().regex(/^\d+\.\d+\.\d+$/, 'WBS must look like 1.1.0') 

This would fix the validation issues I flagged in the other pr

}),
annotations: { readOnlyHint: true }
},
async ({ startDate, endDate }) =>

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.

could the model send something like "next Monday" Wouldn't an invalid date slip past both range checks since NaN comparisons are false, and then it would be a 500 that says 'report this to the software team'

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

Comment thread src/backend/index.ts Outdated

// The MCP endpoint, authenticated with the same per-user API tokens. It must accept POST (JSON-RPC),
// so it is mounted separately from the read only /agent router; every tool it exposes is a read.
app.all('/mcp', requireApiToken, attachAuthInfo, (req, res) => void mcpNodeHandler(req, res, req.body));

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.

maybe i'm confused but this doesn't seem to have a readOnly guard, only a requireApiToken guard. If someone later registers a tool that writes, could any API token reach it?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The guard is not on the auth, its just a byproduct of the fact that api token auth can only access the /mcp and /agent routes, which only have readonly calls. Eventually we will want to add write abilities, and so this scoping control is the best way to separate

Comment thread src/backend/index.ts Outdated

// The MCP endpoint, authenticated with the same per-user API tokens. It must accept POST (JSON-RPC),
// so it is mounted separately from the read only /agent router; every tool it exposes is a read.
app.all('/mcp', requireApiToken, attachAuthInfo, (req, res) => void mcpNodeHandler(req, res, req.body));

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.

shouldn't this have an onerror handler?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done

* no progress or logging notifications, and it keeps the endpoint easy to test with curl.
*/
const mcpHandler = createMcpHandler(({ authInfo }) => buildMcpServer(authInfo?.extra as unknown as AgentContext), {
responseMode: 'json'

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.

shouldn't we check that authInfo is there and give a good error if not

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is not user input so that wouldn't really be helpful

Comment thread src/backend/src/mcp/errors.ts Outdated
* Serializes a tool result, truncating long lists.
* @param value the value to return to the model
*/
export const toolJson = (value: unknown): CallToolResult => {

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.

is the MAX_ITEMS cap still doing anything here? looks like it only truncates when the value is an array, but getProjects returns { carNumber, projects } now, so finishline_list_projects might not get capped at all

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

changed to pagination

@chpy04
chpy04 force-pushed the #4404-mcp-implementation branch from 210f21c to c389b03 Compare September 2, 2026 00:08
@chpy04
chpy04 force-pushed the #4404-mcp-implementation branch from c389b03 to 6ee5c41 Compare September 2, 2026 02:37
Base automatically changed from #4404-initial-mcp-routes to develop September 2, 2026 02:38
- constrain wbsNum and event dates in the tool schemas so the model gets a
  validation error instead of a 500 on input like "1.2" or "next Monday"
- guard against unparseable dates in getEvents, which NaN comparisons let past
  both range checks
- page finishline_list_projects and finishline_get_tasks, the two lists that can
  realistically outgrow a response, rather than silently truncating results
- register every tool through registerReadOnlyTool so /mcp stays read only by
  construction now that it cannot use the readOnlyGuard
- forward mcp handler rejections to the error handler instead of dropping them
- fail with a clear error when the request never resolved to a caller
@chpy04
chpy04 force-pushed the #4404-mcp-implementation branch from 6ee5c41 to 2e42bba Compare September 2, 2026 02:40
@chpy04
chpy04 merged commit e399b8e into develop Sep 2, 2026
4 checks passed
@chpy04
chpy04 deleted the #4404-mcp-implementation branch September 2, 2026 02:43
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.

Athena MCP

2 participants