feat(evals): real ServiceNow MCP behind the acme-servicenow demo#2623
Closed
benjaminshafii wants to merge 6 commits into
Closed
feat(evals): real ServiceNow MCP behind the acme-servicenow demo#2623benjaminshafii wants to merge 6 commits into
benjaminshafii wants to merge 6 commits into
Conversation
…y + Connect panel)
…ndary on current dev
… (no duplicate screenshot)
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Member
Author
Member
Author
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.





What & why
The marketplace demo evals (
oauth-mcp-publish/oauth-mcp-install) featured an MCP namedacme-servicenowthat was really the generic mock (scripts/mock-oauth-mcp-server.mjs) with a singlemock_echotool andmcp:read/mcp:writescopes. This PR makes it the real thing: a faithful, spec-correct ServiceNow instance simulator standing behind theacme-servicenowconnector.scripts/mock-oauth-mcp-server.mjsis untouched (other flows/tests depend on it).scripts/servicenow-mcp-server.mjs(new, zero-dependency)MCP spec correctness (Streamable HTTP)
2025-11-25 / 2025-06-18 / 2025-03-26(echoes the client's when supported, else latest).-32700parse,-32600invalid/batch (batching removed in 2025-06-18),-32601unknown method,-32602bad tool args; notifications/client-responses →202;ping→{}.Mcp-Session-Idissued oninitialize, validated on later requests (unknown →404),DELETEterminates.GET /mcp→405withAllow;MCP-Protocol-Versionheader validated; Origin checks (non-loopback →403)./mcpand the realistic native path/sncapps/mcp-server/mcp/sn_openwork_it.OAuth 2.1 on the real ServiceNow endpoint paths
/oauth_auth.do+/oauth_token.do, pre-registered clients only (no DCR) — like a real instance's Application Registry.plain), auth-code + refresh grants,none/client_secret_post/client_secret_basic.registration_endpoint), RFC 8707 resource-audience binding on issued tokens; every401carriesWWW-Authenticate: Bearer resource_metadata=….Real ServiceNow surface
incidenttable (+sys_user/sys_user_group), ServiceNow-shaped Table API (/api/now/table/incident,sysparm_query/_limit/_offset/_fields, ServiceNow error envelopes).search_incidents,get_incident,create_incident,update_incident,add_comment,resolve_incident— with LLM-oriented descriptions, JSON-Schema I/O, annotations, deep-links, and scope enforcement (incidents.read/incidents.write) surfaced as ServiceNow-ACL-style tool errors.RFC 9728 fix worth calling out
The opencode engine follows the
401WWW-Authenticateresource_metadataURL and then validatesPRM.resource === connection URL. Serving one root PRM (resource=/mcp) 500'd the engine on the deep/sncapps/...path. The server now serves path-specific protected-resource metadata and points each path's401at its own PRM, and treats the two MCP URLs as one aliased resource for audience checks. Result: the engine completes OAuth over the realistic deep path with no DCR.Tests —
apps/server/src/mcp.servicenow-spec.e2e.test.ts(new)/register, over/sncapps/mcp-server/mcp/sn_openwork_it, with the RFC 8707resourceparam.How I verified (commands + results)
Frame proof is posted as a follow-up comment.
Flow updates (current-dev reality)
oauth-mcp-publish: pointsacme-servicenowat the real ServiceNow MCP (:3979, deep/sncapps/...path), auto-starts the server, and adapts to the current UI (engine-ready copy + the new Connect panel). Still proves secret redaction on export + publish.oauth-mcp-install: the old member marketplace card→Add path no longer exists on dev for cloud-runnable plugins (member self-connect now requires prior admin provisioning of the org MCP connection). The flow was rewritten to honestly prove, member-side, that the org-shared ServiceNow plugin is available to her and that her member-visible config carriesclientId+scope but never the owner's secret. The member's own end-to-end OAuth against the ServiceNow server is covered by the engine e2e test above.kindand carry per-frame voiceovers.Notes / honesty
mcp-oauth-silent-reauthfails at the silent-heal step on this machine (stuck "Issue"). My diff touches zero files in that flow's path (new files + the two oauth-mcp flows only), so this is pre-existing/environmental, not caused by this change — flagged for transparency.