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
44 changes: 21 additions & 23 deletions mcp-server/src/connection.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { SDKNodePlatform } from '@amp-labs/sdk-node-platform';
import { z } from 'zod';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { logger } from '@amp-labs/ai/mcp';
import { providerSchema } from './schemas';
import { ClientSettings } from '.';

Expand All @@ -27,13 +28,13 @@
provider: provider,
};
const data = await ampersandClient.connections.list(body);
console.log('[CHECK-CONNECTION] API call to listConnections: ', body);
logger.info('[CHECK-CONNECTION] API call to listConnections: ', body);

// @ts-ignore
if (data.length > 0) {
// @ts-ignore
const connection = data[0];
console.log(
logger.info(
'[CHECK-CONNECTION] API response from listConnections:',
connection,
);
Expand All @@ -56,7 +57,7 @@
};
}
} catch (err) {
console.error('Error checking connection:', err);
logger.error('[CHECK-CONNECTION] Error checking connection:', err);
return {
content: [
{
Expand Down Expand Up @@ -90,13 +91,13 @@
process.env.AMPERSAND_INTEGRATION_NAME ||
'',
};
console.log(
logger.info(
'[CHECK-INSTALLATION] API call to listInstallations: ',
body,
);
const data = await ampersandClient.installations.list(body);

console.log(
logger.info(
'[CHECK-INSTALLATION] API response from listInstallations: ',
data,
);
Expand All @@ -105,7 +106,7 @@
// @ts-ignore
(inst) => inst.connection?.provider === provider.toLowerCase(),
);
console.log(
logger.info(
'[CHECK-INSTALLATION] filtered installations: ',
relevantInstallations,
);
Expand Down Expand Up @@ -135,7 +136,7 @@
};
}
} catch (err) {
console.error('Error checking installation:', err);
logger.error('[CHECK-INSTALLATION] Error checking installation:', err);
return {
content: [
{
Expand Down Expand Up @@ -182,7 +183,7 @@
},
},
};
console.log(
logger.info(
'[CREATE-INSTALLATION] API call to createInstallation: ',
requestBody,
);
Expand All @@ -197,7 +198,7 @@
requestBody,
});

console.log(
logger.info(
'[CREATE-INSTALLATION] API response from createInstallation: ',
data,
);
Expand All @@ -222,7 +223,7 @@
],
};
} catch (err) {
console.error('Error creating installation:', err);
logger.error('[CREATE-INSTALLATION] Error creating installation:', err);
return {
content: [
{
Expand Down Expand Up @@ -257,11 +258,11 @@
settings?.project || process.env.AMPERSAND_PROJECT_ID || '',
provider: provider,
};
console.log('[ENSURE-INSTALLATION] API call to listConnections: ', body);
logger.info('[ENSURE-INSTALLATION] API call to listConnections: ', body);

const connectionData = await ampersandClient.connections.list(body);

console.log(
logger.info(
'[ENSURE-INSTALLATION] API response from listConnections: ',
connectionData,
);
Expand Down Expand Up @@ -294,24 +295,21 @@
// @ts-ignore
const relevantInstallations = installationData.filter(
// @ts-ignore
(inst: any) =>

Check warning on line 298 in mcp-server/src/connection.ts

View workflow job for this annotation

GitHub Actions / lint-and-type-check

Unexpected any. Specify a different type
inst.connection?.provider === provider &&
inst.group?.groupRef === groupRef &&
inst.connection?.id === connectionId,
);

console.log(
'[ENSURE-INSTALLATION] existing installation check',
logger.info('[ENSURE-INSTALLATION] existing installation check', {
relevantInstallations,
installationData,
);
});

if (relevantInstallations.length === 0) {
console.log(
logger.info(
'[ENSURE-INSTALLATION] No existing installation found, creating one for connection:',
connectionId,
'group:',
groupRef,
{ connectionId, groupRef },
);

const requestBody = {
Expand All @@ -326,7 +324,7 @@
},
};

console.log(
logger.info(
'[ENSURE-INSTALLATION] API request to createInstallation',
requestBody,
);
Expand All @@ -340,15 +338,15 @@
requestBody,
});

console.log(
logger.info(
'[ENSURE-INSTALLATION] API response from createInstallation',
createData,
);

// @ts-ignore
const installationId = createData.installation?.id;
if (installationId) {
console.log(
logger.info(
`[ENSURE-INSTALLATION]Installation created for ${provider}, Installation ID: ${installationId}`,
);
return installationId;
Expand All @@ -358,7 +356,7 @@
);
}
} else {
console.log(
logger.info(
`[ENSURE-INSTALLATION]Installation already exists for ${provider} with ID: ${relevantInstallations[0].id}`,
);
return relevantInstallations[0].id;
Expand Down
7 changes: 4 additions & 3 deletions mcp-server/src/oauth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { logger } from '@amp-labs/ai/mcp';
import { providerSchema } from './schemas';
import { ClientSettings } from '.';
import crypto from 'crypto';
Expand Down Expand Up @@ -29,7 +30,7 @@ export async function createStartOAuthTool(
},
body: JSON.stringify({ provider, consumerRef, groupRef, projectId }),
};
console.log(
logger.info(
'[START-OAUTH] API request to oauthConnect: ',
options.body,
);
Expand All @@ -39,10 +40,10 @@ export async function createStartOAuthTool(
options,
);
const data = await response.text();
console.log('[START-OAUTH] API response from oauthConnect: ', data);
logger.info('[START-OAUTH] API response from oauthConnect: ', data);
oAuthUrl = data;
} catch (err) {
console.error(err);
logger.error('[START-OAUTH] Error in oauthConnect', err);
}

return {
Expand Down
21 changes: 10 additions & 11 deletions mcp-server/src/request.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { z } from 'zod';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { logger } from '@amp-labs/ai/mcp';
import { ensureInstallation } from './connection';
import {
endpointSchema,
Expand Down Expand Up @@ -111,12 +112,12 @@
headers?: Record<string, string>;
installationId?: string;
settings?: ClientSettings;
body?: Record<string, any>;

Check warning on line 115 in mcp-server/src/request.ts

View workflow job for this annotation

GitHub Actions / lint-and-type-check

Unexpected any. Specify a different type
}) {
try {
installationId =
installationId || (await ensureInstallation(provider, settings));
const fetchOptions: any = {

Check warning on line 120 in mcp-server/src/request.ts

View workflow job for this annotation

GitHub Actions / lint-and-type-check

Unexpected any. Specify a different type
method,
headers: {
...headers,
Expand All @@ -131,12 +132,11 @@
fetchOptions.body = JSON.stringify(body);
}

console.log(
'[SEND-REQUEST] API request to proxy: ',
logger.info('[SEND-REQUEST] API request to proxy: ', {
endpoint,
fetchOptions.body,
);
console.log(
body: fetchOptions.body,
});
logger.info(
'[SEND-REQUEST] Full URL: ',
`https://proxy.withampersand.com/${endpoint}`,
);
Expand All @@ -146,11 +146,10 @@
fetchOptions,
);

console.log(
'[SEND-REQUEST] API response status from proxy: ',
logger.info('[SEND-REQUEST] API response status from proxy: ', {
endpoint,
response.status,
);
status: response.status,
});

const data = await response.text();
return {
Expand All @@ -170,8 +169,8 @@
],
};
} catch (error) {
console.error(
`Error in ${method === 'GET' ? 'sendReadRequest' : 'sendRequest'} tool`,
logger.error(
`[SEND-REQUEST] Error in ${method === 'GET' ? 'sendReadRequest' : 'sendRequest'} tool`,
error,
);
return {
Expand Down
5 changes: 3 additions & 2 deletions mcp-server/src/search.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { TrieveSDK, ChunkMetadata } from 'trieve-ts-sdk';
import { z } from 'zod';
import { logger } from '@amp-labs/ai/mcp';

export const SUBDOMAIN: string = 'ampersand-24eb5c1a';
export const SERVER_URL: string = 'https://leaves.mintlify.com';
Expand Down Expand Up @@ -96,7 +97,7 @@ export async function createSearchTool(server: Server): Promise<void> {
query: z.string(),
},
async ({ query }: { query: string }) => {
console.log('[SEARCH] call: ', query);
logger.info('[SEARCH] call: ', query);
const results = await search(query, config);
const content = results.map((result) => {
const { title, content, link } = result;
Expand All @@ -113,6 +114,6 @@ export async function createSearchTool(server: Server): Promise<void> {
},
);
} catch (error) {
console.warn('Error in registering search tool:', error);
logger.warn('[SEARCH] Error in registering search tool:', error);
}
}
7 changes: 4 additions & 3 deletions mcp-server/src/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
import express, { Request, Response } from 'express';
import { detect } from 'detect-port';
import { logger } from '@amp-labs/ai/mcp';

const DEFAULT_PORT = 3001;
const SSE_SERVER_VERSION = 'v1';
Expand Down Expand Up @@ -47,10 +48,10 @@
export async function connectServer(
server: Server,
useStdioTransport: boolean,
settings: any,

Check warning on line 51 in mcp-server/src/session.ts

View workflow job for this annotation

GitHub Actions / lint-and-type-check

Unexpected any. Specify a different type
): Promise<express.Application | undefined> {
if (useStdioTransport) {
console.log('Connecting to MCP server over stdio');
logger.info('Connecting to MCP server over stdio');
const transport = new StdioServerTransport();
await server.connect(transport);
return;
Expand Down Expand Up @@ -85,7 +86,7 @@
// VS code supports it for example like this: https://github.com/microsoft/vscode-docs/blob/74c4fd5aa3180b218fc389184659b621f05460ca/docs/copilot/chat/mcp-servers.md#configuration-example
settings.apiKey = req.headers['x-api-key'];
}
console.log('[SESSION] Settings: ', settings);
logger.info('[SESSION] Settings: ', settings);
currentTransport = new SSEServerTransport('/messages', res);
transportManager.addTransport(currentTransport, res);
await server.connect(currentTransport);
Expand All @@ -94,7 +95,7 @@
app.post('/messages', async (req: Request, res: Response) => {
const sessionId = req.query.sessionId as string;

console.log('[SESSION] Session ID', sessionId);
logger.info('[SESSION] Session ID', sessionId);
if (!sessionId) {
res.status(400).json({ error: 'Missing session ID param' });
return;
Expand Down
1 change: 1 addition & 0 deletions sdk/lib/adapters/ampersand/core/write.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { WriteResponse } from '../types';
import * as Sentry from '@sentry/node';

interface WriteParams {
objectName: string;
type: 'create' | 'update';
Expand Down
8 changes: 6 additions & 2 deletions sdk/lib/adapters/mcp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import './ampersand/core/instrument';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { z } from 'zod';
import * as Sentry from '@sentry/node';
import { logger } from '../logger';
import {
providerSchema,
associationsSchema,
Expand Down Expand Up @@ -33,6 +34,9 @@ import {
ensureInstallationExists,
} from './common';

// Re-export logger for use by mcp-server package
export { logger };

type MCPResponse = {
content: Array<{ type: string; text: string }>;
isError?: boolean;
Expand Down Expand Up @@ -83,7 +87,7 @@ export const createWriteActionTool = async (
): Promise<MCPResponse> => {
const { objectName, type, record, groupRef, associations } = params;

console.log(`[WRITE] about to perform ${type} operation`, params);
logger.info(`[WRITE] about to perform ${type} operation`, params);

const result = await executeAmpersandWrite({
objectName,
Expand All @@ -100,7 +104,7 @@ export const createWriteActionTool = async (
});

if (result.success) {
console.log(
logger.info(
`[WRITE] ${type} operation on provider succeeded:`,
result.response,
);
Expand Down
49 changes: 49 additions & 0 deletions sdk/lib/logger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Logger utility for SDK.
* Uses stderr (console.error) to avoid interfering with stdio transport JSON-RPC protocol.
* All logs are captured by Claude Desktop and written to logs.
*/

type LogLevel = 'INFO' | 'ERROR' | 'WARN' | 'DEBUG';

function formatLog(level: LogLevel, message: string, data?: any): string {
const timestamp = new Date().toISOString();
const baseMessage = `[${level}] ${timestamp} ${message}`;

if (data !== undefined) {
if (typeof data === 'object') {
// Handle Error objects to preserve stack traces
if (data instanceof Error) {
return `${baseMessage} ${data.stack || data.message}`;
}
// Wrap JSON.stringify in try-catch to handle circular references
try {
return `${baseMessage} ${JSON.stringify(data)}`;
} catch (error) {
// Fallback for circular references or other stringify errors
return `${baseMessage} [Object with circular reference or unserializable content]`;
}
}
return `${baseMessage} ${data}`;
}

return baseMessage;
}

export const logger = {
info: (message: string, data?: any) => {
console.error(formatLog('INFO', message, data));
},

error: (message: string, error?: any) => {
console.error(formatLog('ERROR', message, error));
},

warn: (message: string, data?: any) => {
console.error(formatLog('WARN', message, data));
},

debug: (message: string, data?: any) => {
console.error(formatLog('DEBUG', message, data));
},
};
Loading