Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/server-info-2025-11-25.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@pinmeto/pinmeto-location-mcp": minor
---

Adopt MCP spec 2025-11-25 `Implementation` metadata on `serverInfo`: a human-readable `description` and a `websiteUrl`. Clients now receive richer context during initialization, aligning with the registry `server.json` format.

Per-tool icons (SEP-973) were evaluated but deferred: the high-level `McpServer.registerTool` API in `@modelcontextprotocol/sdk` 1.29.0 does not forward an `icons` field to `tools/list`, so surfacing them would require overriding the list handler via SDK internals. A `serverInfo.icons` field was also evaluated and dropped: no current Claude client renders it (Claude Desktop sources its branding from the `mcpb` manifest, which already references the PinMeTo icon; Claude.ai web does not render `serverInfo` icons), so embedding a data URI would only add payload to every initialize response. Tool calling in sampling requests (`tools`/`toolChoice`) was also evaluated and is not needed: the single sampling-based tool summarizes review text already supplied in the prompt.
6 changes: 6 additions & 0 deletions src/mcp_server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,12 @@ export function createMcpServer() {
const serverInfo = {
name: 'PinMeTo Location MCP',
version: PACKAGE_VERSION,
// Human-readable description (MCP 2025-11-25 Implementation.description): gives
// clients context during initialization and aligns with the registry server.json format.
description:
'Read-only access to the PinMeTo location management platform: locations, ' +
'plus Google/Facebook/Apple insights, ratings, reviews, and keywords.',
websiteUrl: 'https://www.pinmeto.com',
capabilities: {
resources: {},
tools: {}
Expand Down
59 changes: 59 additions & 0 deletions tests/mcp_server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,65 @@ describe('Tool Annotations', () => {
});
});

describe('Server Info (MCP 2025-11-25 Implementation fields)', () => {
it('should advertise description and websiteUrl in the initialize result', async () => {
const server = createMcpServer();
const testTransport = new StdioServerTransport();

// Capture responses from the server, resolving once the initialize reply lands
// (avoids a racey fixed sleep that can flake on slow CI).
const responses: any[] = [];
let resolveInitResponse!: () => void;
const initResponseSeen = new Promise<void>(resolve => {
resolveInitResponse = resolve;
});
const originalWrite = process.stdout.write.bind(process.stdout);
process.stdout.write = ((chunk: any) => {
try {
const message = JSON.parse(chunk.toString());
responses.push(message);
if (message.id === 0) {
resolveInitResponse();
}
} catch {
// Not JSON, ignore
}
return true;
}) as typeof process.stdout.write;

// try/finally guarantees stdout is restored even if the body throws, so a failure
// here can't cascade into unrelated tests sharing the worker.
try {
await server.connect(testTransport);

testTransport.onmessage?.({
method: 'initialize',
params: {
protocolVersion: '2025-06-18',
capabilities: {},
clientInfo: { name: 'test-client', version: '0.0.0' }
},
jsonrpc: '2.0',
id: 0
});

await initResponseSeen;
} finally {
process.stdout.write = originalWrite;
await testTransport.close();
}

const initResponse = responses.find(r => r.id === 0);
expect(initResponse).toBeDefined();
const serverInfo = initResponse.result.serverInfo;
expect(serverInfo).toBeDefined();

expect(typeof serverInfo.description).toBe('string');
expect(serverInfo.description.length).toBeGreaterThan(0);
expect(serverInfo.websiteUrl).toBe('https://www.pinmeto.com');
});
});

describe('Output Schemas', () => {
it('should include outputSchema in all tool definitions', async () => {
const server = createMcpServer();
Expand Down
Loading