@kapio/mosaic-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@@kapio/mosaic-mcpcreate a new MCP server with Mosaic sign-in and streamable HTTP"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Mosaic MCP Kit
@kapio/mosaic-mcp is the shared frame for MCP servers that sign people in through a Mosaic instance. A server brings its tools; the kit brings everything around them:
Streamable HTTP transport:
POST /mcp(JSON or SSE), sessions viaMcp-Session-Id, CORS,GET /healthSign-in through Mosaic: Bearer access tokens checked against the instance JWKS (EdDSA,
iss,aud,exp,nbf)OAuth discovery (RFC 9728):
/.well-known/oauth-protected-resource[/mcp]andWWW-Authenticate: Bearer resource_metadata="…"on 401Static token ways for the transition and the emergency access, compared in constant time
One JSON log line per
tools/callwith the person, never arguments, results or token values
No runtime dependency: node:http and node:crypto, Node 20 or newer.
Use
const { createMcpServer } = require('@kapio/mosaic-mcp');
const McpHandler = require('./mcp-handler');
let app;
try {
app = createMcpServer({
service: 'kapio-harvest-mcp',
version: '1.1.0',
protocol: '2025-11-25',
handler: new McpHandler(),
extraHealth: () => ({ harvest: true }),
tokens: [{ name: 'notzugang', value: process.env.MCP_ACCESS_TOKEN }]
});
} catch (err) {
console.error(`FATAL: ${err.message}`);
process.exit(1);
}
app.listen(process.env.PORT || 8080);Environment | Example | Required |
|
| yes |
|
| yes |
|
| no |
Without OAUTH_ISSUER or MCP_RESOURCE, createMcpServer throws ConfigError and the server must not start.
Related MCP server: wazobiatech-nexus-mcp
API
createMcpServer(options)
Option | Meaning |
| name in health and log |
| object with |
| shown in |
| function returning service fields for |
|
|
|
|
| overrides, mainly for tests |
Returns { server, listen(port), close(), describe(), issuer, resource, metadataUrl }. describe() gives { service, version, protocol, resource, issuer, metadataUrl } for a registrar.
identity passed to the handler:
Way | Shape |
Mosaic token |
|
static token |
|
The server decides what scope.instances and scope.write allow; the kit only finds the entry.
verifyAccessToken(token, { issuer, resource, jwks, now? })
Resolves { sub, email, azp, exp, scope } or rejects with TokenError whose reason is one of malformed, alg, kid, signature, iss, aud, exp, nbf, jwks.
Rule | Check |
algorithm |
|
issuer |
|
audience |
|
lifetime |
|
jwks is a client from createJwksClient({ uri }) or a plain { keys } document.
createJwksClient({ uri, fetch?, now?, ttlMs?, minRefreshMs?, fetchTimeoutMs? })
Caches the key set for ten minutes. An unknown kid reloads once, at most once per minute, then counts as unknown. With the issuer unreachable or the fetch hanging (aborted after fetchTimeoutMs, default 5000 ms), cached keys keep working and no more than one reload attempt runs per minute.
matchToken(given, tokens)
Returns the matching entry or null. Compares SHA-256 digests with timingSafeEqual against every entry without leaving early.
Call log
One line on stdout per tools/call:
{"ts":"2026-09-17T08:00:00.000Z","service":"kapio-harvest-mcp","event":"tools/call","tool":"harvest_list_projects","via":"oauth","ok":true,"email":"person@example.com","sub":"…","azp":"…"}Static token ways log query: true|false and the user agent capped at 120 bytes instead of email/sub/azp.
Transition from URL tokens
A server switches to the kit with
allowQueryToken: trueand keeps its static tokens.When the call log shows seven days without
"query":true,allowQueryTokengoes in its own commit.What stays: scoped tokens by header for automations without a person, and the emergency token by header (
via: "notzugang").
Shared test cases
fixtures/verify-cases.json holds signed tokens with expected outcomes at a fixed clock. Other implementations (the Python agent template) run the same file and pin it by fixtures/verify-cases.json.sha256. Regenerate only on purpose with npm run fixtures.
Release
A tag v<version> matching package.json publishes to npm with provenance (.github/workflows/publish.yml).
License
MIT
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Authenticated MCP server for ClearPolicy policy and compliance workflows.
The official Planning Center MCP server for interacting with your ministry's data.
Streamable HTTP MCP server for Google Calendar and Sheets with OAuth login.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA reference implementation for creating an MCP server supporting Streamable HTTP & SSE Transports with OAuth authorization, allowing developers to build OAuth-authorized MCP servers with minimal configuration.107MIT

wazobiatech-nexus-mcpofficial
FlicenseNot gradedqualityBmaintenanceEnables building MCP servers with HMAC signing and verification, providing server scaffolding and middleware for secure request authentication.-- FlicenseNot gradedqualityBmaintenanceEnables developers to build MCP servers with registry-managed tool metadata, runtime hot-reloading, pluggable authentication and authorization, per-audience tool views, and resilient stateless operation.-
- AlicenseBqualityAmaintenanceProvides a reference MCP server that implements every MCP feature so client, gateway, and runtime authors can test against a single endpoint, and publishes a service contract describing its capabilities.311MIT