import { DEFAULT_SCOPES, MCP_SERVER_NAME } from "./constants-BPM_OWt0.js";
import { defineTool } from "./define-2Lj8Lm1t.js";
import { logIssue } from "./logging-DqqDTe02.js";
import { whoami_default } from "./whoami-Bh_uOPqO.js";
import { find_organizations_default } from "./find-organizations-DxH9SS3w.js";
import { find_teams_default } from "./find-teams-D5770X0I.js";
import { find_projects_default } from "./find-projects-DOMBBYAP.js";
import { find_releases_default } from "./find-releases-CfZRMBvh.js";
import { get_issue_details_default } from "./get-issue-details-CucQ2nf7.js";
import { get_trace_details_default } from "./get-trace-details-BL5_jvgs.js";
import { get_event_attachment_default } from "./get-event-attachment-B_BzSfcE.js";
import { update_issue_default } from "./update-issue-CoAkoO66.js";
import { handler_default } from "./handler-B3-dKrMX.js";
import { create_team_default } from "./create-team-BQIns3VD.js";
import { create_project_default } from "./create-project-C0pm6zUK.js";
import { update_project_default } from "./update-project-CuZlyBPN.js";
import { create_dsn_default } from "./create-dsn-Bx2s8Bik.js";
import { find_dsns_default } from "./find-dsns-BPN8wnUr.js";
import { analyze_issue_with_seer_default } from "./analyze-issue-with-seer-DvuKEcbu.js";
import { search_docs_default } from "./search-docs-B9qNTw49.js";
import { get_doc_default } from "./get-doc-D9Xq7et9.js";
import { handler_default as handler_default$1 } from "./handler-JBRPTNfu.js";
import { useSentryAgent } from "./agent-tLRcGXXr.js";
import { formatErrorForUser } from "./error-handling-D_4c-JgK.js";
import { LIB_VERSION } from "./version-BaA5pxTW.js";
import { isToolAllowed } from "./permissions-xBjHy6Qx.js";
import { getConstraintKeysToFilter, getConstraintParametersToInject } from "./constraint-helpers-0jgp7p3K.js";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { setTag, setUser, startNewTrace, startSpan, wrapMcpServerWithSentry } from "@sentry/core";
import { z } from "zod";
import { experimental_createMCPClient } from "ai";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";

//#region src/tools/use-sentry/handler.ts
/**
* Format tool calls into a readable trace
*/
function formatToolCallTrace(toolCalls) {
	let trace = "";
	for (let i = 0; i < toolCalls.length; i++) {
		const call = toolCalls[i];
		trace += `### ${i + 1}. ${call.toolName}\n\n`;
		const args = call.args;
		if (Object.keys(args).length === 0) trace += "_No arguments_\n\n";
		else {
			trace += "**Arguments:**\n```json\n";
			trace += JSON.stringify(args, null, 2);
			trace += "\n```\n\n";
		}
	}
	return trace;
}
var handler_default$2 = defineTool({
	name: "use_sentry",
	requiredScopes: [],
	description: [
		"Use Sentry's MCP Agent to answer questions related to Sentry (sentry.io).",
		"",
		"You should pass the entirety of the user's prompt to the agent. Do not interpret the prompt in any way. Just pass it directly to the agent.",
		""
	].join("\n"),
	inputSchema: {
		request: z.string().trim().min(1).describe("The user's raw input. Do not interpret the prompt in any way. Do not add any additional information to the prompt."),
		trace: z.boolean().optional().describe("Enable tracing to see all tool calls made by the agent. Useful for debugging.")
	},
	annotations: {
		readOnlyHint: true,
		openWorldHint: true
	},
	async handler(params, context) {
		const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
		const { use_sentry,...toolsForAgent } = tools_default;
		const server = buildServer({
			context,
			tools: toolsForAgent
		});
		await server.server.connect(serverTransport);
		const mcpClient = await experimental_createMCPClient({
			name: "mcp.sentry.dev (use-sentry)",
			transport: clientTransport
		});
		try {
			const mcpTools = await mcpClient.tools();
			const agentResult = await useSentryAgent({
				request: params.request,
				tools: mcpTools
			});
			let output = agentResult.result.result;
			if (params.trace && agentResult.toolCalls.length > 0) {
				output += "\n\n---\n\n## Tool Call Trace\n\n";
				output += formatToolCallTrace(agentResult.toolCalls);
			}
			return output;
		} finally {
			await mcpClient.close();
			await server.server.close();
		}
	}
});

//#endregion
//#region src/tools/index.ts
var tools_default = {
	whoami: whoami_default,
	find_organizations: find_organizations_default,
	find_teams: find_teams_default,
	find_projects: find_projects_default,
	find_releases: find_releases_default,
	get_issue_details: get_issue_details_default,
	get_trace_details: get_trace_details_default,
	get_event_attachment: get_event_attachment_default,
	update_issue: update_issue_default,
	search_events: handler_default,
	create_team: create_team_default,
	create_project: create_project_default,
	update_project: update_project_default,
	create_dsn: create_dsn_default,
	find_dsns: find_dsns_default,
	analyze_issue_with_seer: analyze_issue_with_seer_default,
	search_docs: search_docs_default,
	get_doc: get_doc_default,
	search_issues: handler_default$1,
	use_sentry: handler_default$2
};

//#endregion
//#region src/server.ts
/**
* Extracts MCP request parameters for OpenTelemetry attributes.
*
* @example Parameter Transformation
* ```typescript
* const input = { organizationSlug: "my-org", query: "is:unresolved" };
* const output = extractMcpParameters(input);
* // { "mcp.request.argument.organizationSlug": "\"my-org\"", "mcp.request.argument.query": "\"is:unresolved\"" }
* ```
*/
function extractMcpParameters(args) {
	return Object.fromEntries(Object.entries(args).map(([key, value]) => {
		return [`mcp.request.argument.${key}`, JSON.stringify(value)];
	}));
}
/**
* Creates and configures a complete MCP server with Sentry instrumentation.
*
* The server is built with tools filtered based on the granted scopes in the context.
* Context is captured in tool handler closures and passed directly to handlers.
*
* @example Usage with stdio transport
* ```typescript
* import { buildServer } from "@sentry/mcp-server/server";
* import { startStdio } from "@sentry/mcp-server/transports/stdio";
*
* const context = {
*   accessToken: process.env.SENTRY_TOKEN,
*   sentryHost: "sentry.io",
*   userId: "user-123",
*   clientId: "cursor-ide",
*   constraints: {}
* };
*
* const server = buildServer({ context });
* await startStdio(server, context);
* ```
*
* @example Usage with Cloudflare Workers
* ```typescript
* import { buildServer } from "@sentry/mcp-server/server";
* import { experimental_createMcpHandler as createMcpHandler } from "agents/mcp";
*
* const serverContext = buildContextFromOAuth();
* // Context is captured in closures during buildServer()
* const server = buildServer({ context: serverContext });
*
* // Context already available to tool handlers via closures
* return createMcpHandler(server, { route: "/mcp" })(request, env, ctx);
* ```
*/
function buildServer({ context, onToolComplete, tools: customTools }) {
	const server = new McpServer({
		name: MCP_SERVER_NAME,
		version: LIB_VERSION
	});
	configureServer({
		server,
		context,
		onToolComplete,
		tools: customTools
	});
	return wrapMcpServerWithSentry(server);
}
/**
* Configures an MCP server with tools filtered by granted scopes.
*
* Internal function used by buildServer(). Use buildServer() instead for most cases.
* Tools are filtered at registration time based on grantedScopes, and context is
* captured in closures for tool handler execution.
*/
function configureServer({ server, context, onToolComplete, tools: customTools }) {
	const toolsToRegister = customTools ?? tools_default;
	const grantedScopes = context.grantedScopes ? new Set(context.grantedScopes) : new Set(DEFAULT_SCOPES);
	server.server.onerror = (error) => {
		const transportLogOptions = {
			loggerScope: ["server", "transport"],
			contexts: { transport: { phase: "server.onerror" } }
		};
		logIssue(error, transportLogOptions);
	};
	for (const [toolKey, tool$1] of Object.entries(toolsToRegister)) {
		if (!isToolAllowed(tool$1.requiredScopes, grantedScopes)) continue;
		const constraintKeysToFilter = new Set(getConstraintKeysToFilter(context.constraints, tool$1.inputSchema));
		const filteredInputSchema = Object.fromEntries(Object.entries(tool$1.inputSchema).filter(([key]) => !constraintKeysToFilter.has(key)));
		server.tool(tool$1.name, tool$1.description, filteredInputSchema, tool$1.annotations, async (params, extra) => {
			try {
				return await startNewTrace(async () => {
					return await startSpan({
						name: `tools/call ${tool$1.name}`,
						attributes: {
							"mcp.tool.name": tool$1.name,
							"mcp.server.name": MCP_SERVER_NAME,
							"mcp.server.version": LIB_VERSION,
							...extractMcpParameters(params || {})
						}
					}, async (span) => {
						if (context.constraints.organizationSlug) span.setAttribute("sentry-mcp.constraint-organization", context.constraints.organizationSlug);
						if (context.constraints.projectSlug) span.setAttribute("sentry-mcp.constraint-project", context.constraints.projectSlug);
						if (context.userId) setUser({ id: context.userId });
						if (context.clientId) setTag("client.id", context.clientId);
						try {
							const applicableConstraints = getConstraintParametersToInject(context.constraints, tool$1.inputSchema);
							const paramsWithConstraints = {
								...params,
								...applicableConstraints
							};
							const output = await tool$1.handler(paramsWithConstraints, context);
							span.setStatus({ code: 1 });
							if (typeof output === "string") return { content: [{
								type: "text",
								text: output
							}] };
							if (Array.isArray(output)) return { content: output };
							throw new Error(`Invalid tool output: ${output}`);
						} catch (error) {
							span.setStatus({ code: 2 });
							return {
								content: [{
									type: "text",
									text: await formatErrorForUser(error)
								}],
								isError: true
							};
						}
					});
				});
			} finally {
				onToolComplete?.();
			}
		});
	}
}

//#endregion
export { buildServer, handler_default$2 as handler_default, tools_default };
//# sourceMappingURL=server-CDG3HfVV.js.map