Skip to content

fix(server): let a custom MCP server name its token header (fixes #817) - #865

Open
azmi2409 wants to merge 1 commit into
CopilotKit:mainfrom
azmi2409:fix/817-custom-server-token-header
Open

azmi2409 wants to merge 1 commit into
CopilotKit:mainfrom
azmi2409:fix/817-custom-server-token-header

Conversation

@azmi2409

Copy link
Copy Markdown

What this changes

Fixes #817. A server added by URL had no catalogue entry to name a header in, so its deployment token could only ever travel as Authorization: Bearer. A vendor that reads its key from a header of its own — as Composio's consumer endpoint reads x-consumer-api-key — could not be reached at all. This adds the general capability rather than special-casing any vendor hostname, and leaves OpenBot's own brokered Composio integration untouched.

  • mcp_servers.token_header (migration 0066, generated with drizzle-kit generate), nullable; null means the Authorization: Bearer default.
  • addCustomServer stores it: a re-add keeps the stored value unless one is named, and an empty string clears it back to the default.
  • The header name is validated as an RFC 7230 field-name token in resolveTokenHeader before anything is stored — a name with whitespace or a control character is refused, since it reaches raw HTTP.
  • The refresh path (refreshTools) and the call path (callTool) send the stored header when no catalogue entry exists, via tokenHeaderForServer. A catalogue entry stays authoritative wherever one exists.
  • POST /api/plugins/servers/custom accepts tokenHeader, and the app's CustomServerInput carries it. No admin UI field: the current UI has no custom-server add/edit form for one to live in (the mutation exists but no screen calls it), so the header is settable through the API.

How it was verified

  • bun test on the plugin/mcp/catalogue unit suites: 369 pass, 0 fail, including a new server/tests/plugin-custom-server-token-header.test.ts covering header validation (rejects spaces, CRLF, /, :, non-strings), catalogue-wins precedence, and — over a real MCP connection to a mock server with a journaled request log — that a named header carries the token exactly as stored with no Authorization sent, and that the default still sends Authorization.
  • bun run typecheck (server and app) clean; bun run typecheck:tests clean against the baseline (0 new errors).

Not verified here

  • The migration has not been applied against a live database, and the addCustomServer database round-trip has not run against one — no Postgres is available in this environment. The column write is plain Drizzle over the generated schema, and the unit + type gates above are green, but a run against a real database is still worth a look before merge.

…ilotKit#817)

A server added by URL had no catalogue entry to name a header in, so its
deployment token could only ever travel as Authorization: Bearer. A vendor
that reads its key from a header of its own, as Composio's consumer endpoint
reads x-consumer-api-key, could not be reached at all.

- mcp_servers.token_header (migration 0066), nullable; null means the
  Authorization: Bearer default
- addCustomServer stores it (re-add keeps it unless named; empty clears it),
  validated as an RFC 7230 field-name token before anything is stored
- refresh and call paths use the stored header when no catalogue entry
  exists; a catalogue entry stays authoritative wherever one exists
- POST /api/plugins/servers/custom accepts tokenHeader; the app mutation
  input carries it (no admin UI field: the current UI has no custom-server
  add/edit form for it to live in)

This branch has not been deployed

No deployments
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.

Composio plugin sends x-api-key, but connect.composio.dev/mcp requires x-consumer-api-key

1 participant